1*197ed01eSMikhail Tyukin /*
2*197ed01eSMikhail Tyukin * Copyright 2009 Vincent Povirk for CodeWeavers
3*197ed01eSMikhail Tyukin *
4*197ed01eSMikhail Tyukin * This library is free software; you can redistribute it and/or
5*197ed01eSMikhail Tyukin * modify it under the terms of the GNU Lesser General Public
6*197ed01eSMikhail Tyukin * License as published by the Free Software Foundation; either
7*197ed01eSMikhail Tyukin * version 2.1 of the License, or (at your option) any later version.
8*197ed01eSMikhail Tyukin *
9*197ed01eSMikhail Tyukin * This library is distributed in the hope that it will be useful,
10*197ed01eSMikhail Tyukin * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*197ed01eSMikhail Tyukin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12*197ed01eSMikhail Tyukin * Lesser General Public License for more details.
13*197ed01eSMikhail Tyukin *
14*197ed01eSMikhail Tyukin * You should have received a copy of the GNU Lesser General Public
15*197ed01eSMikhail Tyukin * License along with this library; if not, write to the Free Software
16*197ed01eSMikhail Tyukin * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17*197ed01eSMikhail Tyukin */
18*197ed01eSMikhail Tyukin
19*197ed01eSMikhail Tyukin #include <stdarg.h>
20*197ed01eSMikhail Tyukin #include <stdio.h>
21*197ed01eSMikhail Tyukin #include <string.h>
22*197ed01eSMikhail Tyukin #include <setjmp.h>
23*197ed01eSMikhail Tyukin #include <basetsd.h>
24*197ed01eSMikhail Tyukin #include <jpeglib.h>
25*197ed01eSMikhail Tyukin
26*197ed01eSMikhail Tyukin #include "ntstatus.h"
27*197ed01eSMikhail Tyukin #define WIN32_NO_STATUS
28*197ed01eSMikhail Tyukin #include "windef.h"
29*197ed01eSMikhail Tyukin #include "winternl.h"
30*197ed01eSMikhail Tyukin #include "winbase.h"
31*197ed01eSMikhail Tyukin #include "objbase.h"
32*197ed01eSMikhail Tyukin
33*197ed01eSMikhail Tyukin #include "wincodecs_private.h"
34*197ed01eSMikhail Tyukin
35*197ed01eSMikhail Tyukin #include "wine/debug.h"
36*197ed01eSMikhail Tyukin
37*197ed01eSMikhail Tyukin WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38*197ed01eSMikhail Tyukin WINE_DECLARE_DEBUG_CHANNEL(jpeg);
39*197ed01eSMikhail Tyukin
error_exit_fn(j_common_ptr cinfo)40*197ed01eSMikhail Tyukin static void error_exit_fn(j_common_ptr cinfo)
41*197ed01eSMikhail Tyukin {
42*197ed01eSMikhail Tyukin char message[JMSG_LENGTH_MAX];
43*197ed01eSMikhail Tyukin if (ERR_ON(jpeg))
44*197ed01eSMikhail Tyukin {
45*197ed01eSMikhail Tyukin cinfo->err->format_message(cinfo, message);
46*197ed01eSMikhail Tyukin ERR_(jpeg)("%s\n", message);
47*197ed01eSMikhail Tyukin }
48*197ed01eSMikhail Tyukin longjmp(*(jmp_buf*)cinfo->client_data, 1);
49*197ed01eSMikhail Tyukin }
50*197ed01eSMikhail Tyukin
emit_message_fn(j_common_ptr cinfo,int msg_level)51*197ed01eSMikhail Tyukin static void emit_message_fn(j_common_ptr cinfo, int msg_level)
52*197ed01eSMikhail Tyukin {
53*197ed01eSMikhail Tyukin char message[JMSG_LENGTH_MAX];
54*197ed01eSMikhail Tyukin
55*197ed01eSMikhail Tyukin if (msg_level < 0 && ERR_ON(jpeg))
56*197ed01eSMikhail Tyukin {
57*197ed01eSMikhail Tyukin cinfo->err->format_message(cinfo, message);
58*197ed01eSMikhail Tyukin ERR_(jpeg)("%s\n", message);
59*197ed01eSMikhail Tyukin }
60*197ed01eSMikhail Tyukin else if (msg_level == 0 && WARN_ON(jpeg))
61*197ed01eSMikhail Tyukin {
62*197ed01eSMikhail Tyukin cinfo->err->format_message(cinfo, message);
63*197ed01eSMikhail Tyukin WARN_(jpeg)("%s\n", message);
64*197ed01eSMikhail Tyukin }
65*197ed01eSMikhail Tyukin else if (msg_level > 0 && TRACE_ON(jpeg))
66*197ed01eSMikhail Tyukin {
67*197ed01eSMikhail Tyukin cinfo->err->format_message(cinfo, message);
68*197ed01eSMikhail Tyukin TRACE_(jpeg)("%s\n", message);
69*197ed01eSMikhail Tyukin }
70*197ed01eSMikhail Tyukin }
71*197ed01eSMikhail Tyukin
72*197ed01eSMikhail Tyukin struct jpeg_decoder {
73*197ed01eSMikhail Tyukin struct decoder decoder;
74*197ed01eSMikhail Tyukin struct decoder_frame frame;
75*197ed01eSMikhail Tyukin BOOL cinfo_initialized;
76*197ed01eSMikhail Tyukin IStream *stream;
77*197ed01eSMikhail Tyukin struct jpeg_decompress_struct cinfo;
78*197ed01eSMikhail Tyukin struct jpeg_error_mgr jerr;
79*197ed01eSMikhail Tyukin struct jpeg_source_mgr source_mgr;
80*197ed01eSMikhail Tyukin BYTE source_buffer[1024];
81*197ed01eSMikhail Tyukin UINT stride;
82*197ed01eSMikhail Tyukin BYTE *image_data;
83*197ed01eSMikhail Tyukin };
84*197ed01eSMikhail Tyukin
impl_from_decoder(struct decoder * iface)85*197ed01eSMikhail Tyukin static inline struct jpeg_decoder *impl_from_decoder(struct decoder* iface)
86*197ed01eSMikhail Tyukin {
87*197ed01eSMikhail Tyukin return CONTAINING_RECORD(iface, struct jpeg_decoder, decoder);
88*197ed01eSMikhail Tyukin }
89*197ed01eSMikhail Tyukin
decoder_from_decompress(j_decompress_ptr decompress)90*197ed01eSMikhail Tyukin static inline struct jpeg_decoder *decoder_from_decompress(j_decompress_ptr decompress)
91*197ed01eSMikhail Tyukin {
92*197ed01eSMikhail Tyukin return CONTAINING_RECORD(decompress, struct jpeg_decoder, cinfo);
93*197ed01eSMikhail Tyukin }
94*197ed01eSMikhail Tyukin
jpeg_decoder_destroy(struct decoder * iface)95*197ed01eSMikhail Tyukin static void CDECL jpeg_decoder_destroy(struct decoder* iface)
96*197ed01eSMikhail Tyukin {
97*197ed01eSMikhail Tyukin struct jpeg_decoder *This = impl_from_decoder(iface);
98*197ed01eSMikhail Tyukin
99*197ed01eSMikhail Tyukin if (This->cinfo_initialized) jpeg_destroy_decompress(&This->cinfo);
100*197ed01eSMikhail Tyukin free(This->image_data);
101*197ed01eSMikhail Tyukin free(This);
102*197ed01eSMikhail Tyukin }
103*197ed01eSMikhail Tyukin
source_mgr_init_source(j_decompress_ptr cinfo)104*197ed01eSMikhail Tyukin static void source_mgr_init_source(j_decompress_ptr cinfo)
105*197ed01eSMikhail Tyukin {
106*197ed01eSMikhail Tyukin }
107*197ed01eSMikhail Tyukin
source_mgr_fill_input_buffer(j_decompress_ptr cinfo)108*197ed01eSMikhail Tyukin static boolean source_mgr_fill_input_buffer(j_decompress_ptr cinfo)
109*197ed01eSMikhail Tyukin {
110*197ed01eSMikhail Tyukin struct jpeg_decoder *This = decoder_from_decompress(cinfo);
111*197ed01eSMikhail Tyukin HRESULT hr;
112*197ed01eSMikhail Tyukin ULONG bytesread;
113*197ed01eSMikhail Tyukin
114*197ed01eSMikhail Tyukin hr = stream_read(This->stream, This->source_buffer, 1024, &bytesread);
115*197ed01eSMikhail Tyukin
116*197ed01eSMikhail Tyukin if (FAILED(hr) || bytesread == 0)
117*197ed01eSMikhail Tyukin {
118*197ed01eSMikhail Tyukin return FALSE;
119*197ed01eSMikhail Tyukin }
120*197ed01eSMikhail Tyukin else
121*197ed01eSMikhail Tyukin {
122*197ed01eSMikhail Tyukin This->source_mgr.next_input_byte = This->source_buffer;
123*197ed01eSMikhail Tyukin This->source_mgr.bytes_in_buffer = bytesread;
124*197ed01eSMikhail Tyukin return TRUE;
125*197ed01eSMikhail Tyukin }
126*197ed01eSMikhail Tyukin }
127*197ed01eSMikhail Tyukin
source_mgr_skip_input_data(j_decompress_ptr cinfo,long num_bytes)128*197ed01eSMikhail Tyukin static void source_mgr_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
129*197ed01eSMikhail Tyukin {
130*197ed01eSMikhail Tyukin struct jpeg_decoder *This = decoder_from_decompress(cinfo);
131*197ed01eSMikhail Tyukin
132*197ed01eSMikhail Tyukin if (num_bytes > This->source_mgr.bytes_in_buffer)
133*197ed01eSMikhail Tyukin {
134*197ed01eSMikhail Tyukin stream_seek(This->stream, num_bytes - This->source_mgr.bytes_in_buffer, STREAM_SEEK_CUR, NULL);
135*197ed01eSMikhail Tyukin This->source_mgr.bytes_in_buffer = 0;
136*197ed01eSMikhail Tyukin }
137*197ed01eSMikhail Tyukin else if (num_bytes > 0)
138*197ed01eSMikhail Tyukin {
139*197ed01eSMikhail Tyukin This->source_mgr.next_input_byte += num_bytes;
140*197ed01eSMikhail Tyukin This->source_mgr.bytes_in_buffer -= num_bytes;
141*197ed01eSMikhail Tyukin }
142*197ed01eSMikhail Tyukin }
143*197ed01eSMikhail Tyukin
source_mgr_term_source(j_decompress_ptr cinfo)144*197ed01eSMikhail Tyukin static void source_mgr_term_source(j_decompress_ptr cinfo)
145*197ed01eSMikhail Tyukin {
146*197ed01eSMikhail Tyukin }
147*197ed01eSMikhail Tyukin
jpeg_decoder_initialize(struct decoder * iface,IStream * stream,struct decoder_stat * st)148*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_initialize(struct decoder* iface, IStream *stream, struct decoder_stat *st)
149*197ed01eSMikhail Tyukin {
150*197ed01eSMikhail Tyukin struct jpeg_decoder *This = impl_from_decoder(iface);
151*197ed01eSMikhail Tyukin int ret;
152*197ed01eSMikhail Tyukin jmp_buf jmpbuf;
153*197ed01eSMikhail Tyukin UINT data_size, i;
154*197ed01eSMikhail Tyukin
155*197ed01eSMikhail Tyukin if (This->cinfo_initialized)
156*197ed01eSMikhail Tyukin return WINCODEC_ERR_WRONGSTATE;
157*197ed01eSMikhail Tyukin
158*197ed01eSMikhail Tyukin jpeg_std_error(&This->jerr);
159*197ed01eSMikhail Tyukin
160*197ed01eSMikhail Tyukin This->jerr.error_exit = error_exit_fn;
161*197ed01eSMikhail Tyukin This->jerr.emit_message = emit_message_fn;
162*197ed01eSMikhail Tyukin
163*197ed01eSMikhail Tyukin This->cinfo.err = &This->jerr;
164*197ed01eSMikhail Tyukin
165*197ed01eSMikhail Tyukin This->cinfo.client_data = jmpbuf;
166*197ed01eSMikhail Tyukin
167*197ed01eSMikhail Tyukin if (setjmp(jmpbuf))
168*197ed01eSMikhail Tyukin return E_FAIL;
169*197ed01eSMikhail Tyukin
170*197ed01eSMikhail Tyukin jpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
171*197ed01eSMikhail Tyukin
172*197ed01eSMikhail Tyukin This->cinfo_initialized = TRUE;
173*197ed01eSMikhail Tyukin
174*197ed01eSMikhail Tyukin This->stream = stream;
175*197ed01eSMikhail Tyukin
176*197ed01eSMikhail Tyukin stream_seek(This->stream, 0, STREAM_SEEK_SET, NULL);
177*197ed01eSMikhail Tyukin
178*197ed01eSMikhail Tyukin This->source_mgr.bytes_in_buffer = 0;
179*197ed01eSMikhail Tyukin This->source_mgr.init_source = source_mgr_init_source;
180*197ed01eSMikhail Tyukin This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
181*197ed01eSMikhail Tyukin This->source_mgr.skip_input_data = source_mgr_skip_input_data;
182*197ed01eSMikhail Tyukin This->source_mgr.resync_to_restart = jpeg_resync_to_restart;
183*197ed01eSMikhail Tyukin This->source_mgr.term_source = source_mgr_term_source;
184*197ed01eSMikhail Tyukin
185*197ed01eSMikhail Tyukin This->cinfo.src = &This->source_mgr;
186*197ed01eSMikhail Tyukin
187*197ed01eSMikhail Tyukin ret = jpeg_read_header(&This->cinfo, TRUE);
188*197ed01eSMikhail Tyukin
189*197ed01eSMikhail Tyukin if (ret != JPEG_HEADER_OK) {
190*197ed01eSMikhail Tyukin WARN("Jpeg image in stream has bad format, read header returned %d.\n",ret);
191*197ed01eSMikhail Tyukin return E_FAIL;
192*197ed01eSMikhail Tyukin }
193*197ed01eSMikhail Tyukin
194*197ed01eSMikhail Tyukin switch (This->cinfo.jpeg_color_space)
195*197ed01eSMikhail Tyukin {
196*197ed01eSMikhail Tyukin case JCS_GRAYSCALE:
197*197ed01eSMikhail Tyukin This->cinfo.out_color_space = JCS_GRAYSCALE;
198*197ed01eSMikhail Tyukin This->frame.bpp = 8;
199*197ed01eSMikhail Tyukin This->frame.pixel_format = GUID_WICPixelFormat8bppGray;
200*197ed01eSMikhail Tyukin break;
201*197ed01eSMikhail Tyukin case JCS_RGB:
202*197ed01eSMikhail Tyukin case JCS_YCbCr:
203*197ed01eSMikhail Tyukin This->cinfo.out_color_space = JCS_RGB;
204*197ed01eSMikhail Tyukin This->frame.bpp = 24;
205*197ed01eSMikhail Tyukin This->frame.pixel_format = GUID_WICPixelFormat24bppBGR;
206*197ed01eSMikhail Tyukin break;
207*197ed01eSMikhail Tyukin case JCS_CMYK:
208*197ed01eSMikhail Tyukin case JCS_YCCK:
209*197ed01eSMikhail Tyukin This->cinfo.out_color_space = JCS_CMYK;
210*197ed01eSMikhail Tyukin This->frame.bpp = 32;
211*197ed01eSMikhail Tyukin This->frame.pixel_format = GUID_WICPixelFormat32bppCMYK;
212*197ed01eSMikhail Tyukin break;
213*197ed01eSMikhail Tyukin default:
214*197ed01eSMikhail Tyukin ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
215*197ed01eSMikhail Tyukin return E_FAIL;
216*197ed01eSMikhail Tyukin }
217*197ed01eSMikhail Tyukin
218*197ed01eSMikhail Tyukin if (!jpeg_start_decompress(&This->cinfo))
219*197ed01eSMikhail Tyukin {
220*197ed01eSMikhail Tyukin ERR("jpeg_start_decompress failed\n");
221*197ed01eSMikhail Tyukin return E_FAIL;
222*197ed01eSMikhail Tyukin }
223*197ed01eSMikhail Tyukin
224*197ed01eSMikhail Tyukin This->frame.width = This->cinfo.output_width;
225*197ed01eSMikhail Tyukin This->frame.height = This->cinfo.output_height;
226*197ed01eSMikhail Tyukin
227*197ed01eSMikhail Tyukin switch (This->cinfo.density_unit)
228*197ed01eSMikhail Tyukin {
229*197ed01eSMikhail Tyukin case 2: /* pixels per centimeter */
230*197ed01eSMikhail Tyukin This->frame.dpix = This->cinfo.X_density * 2.54;
231*197ed01eSMikhail Tyukin This->frame.dpiy = This->cinfo.Y_density * 2.54;
232*197ed01eSMikhail Tyukin break;
233*197ed01eSMikhail Tyukin
234*197ed01eSMikhail Tyukin case 1: /* pixels per inch */
235*197ed01eSMikhail Tyukin This->frame.dpix = This->cinfo.X_density;
236*197ed01eSMikhail Tyukin This->frame.dpiy = This->cinfo.Y_density;
237*197ed01eSMikhail Tyukin break;
238*197ed01eSMikhail Tyukin
239*197ed01eSMikhail Tyukin case 0: /* unknown */
240*197ed01eSMikhail Tyukin default:
241*197ed01eSMikhail Tyukin This->frame.dpix = This->frame.dpiy = 96.0;
242*197ed01eSMikhail Tyukin break;
243*197ed01eSMikhail Tyukin }
244*197ed01eSMikhail Tyukin
245*197ed01eSMikhail Tyukin This->frame.num_color_contexts = 0;
246*197ed01eSMikhail Tyukin This->frame.num_colors = 0;
247*197ed01eSMikhail Tyukin
248*197ed01eSMikhail Tyukin This->stride = (This->frame.bpp * This->cinfo.output_width + 7) / 8;
249*197ed01eSMikhail Tyukin data_size = This->stride * This->cinfo.output_height;
250*197ed01eSMikhail Tyukin
251*197ed01eSMikhail Tyukin if (data_size / This->stride < This->cinfo.output_height)
252*197ed01eSMikhail Tyukin /* overflow in multiplication */
253*197ed01eSMikhail Tyukin return E_OUTOFMEMORY;
254*197ed01eSMikhail Tyukin
255*197ed01eSMikhail Tyukin This->image_data = malloc(data_size);
256*197ed01eSMikhail Tyukin if (!This->image_data)
257*197ed01eSMikhail Tyukin return E_OUTOFMEMORY;
258*197ed01eSMikhail Tyukin
259*197ed01eSMikhail Tyukin while (This->cinfo.output_scanline < This->cinfo.output_height)
260*197ed01eSMikhail Tyukin {
261*197ed01eSMikhail Tyukin UINT first_scanline = This->cinfo.output_scanline;
262*197ed01eSMikhail Tyukin UINT max_rows;
263*197ed01eSMikhail Tyukin JSAMPROW out_rows[4];
264*197ed01eSMikhail Tyukin JDIMENSION ret;
265*197ed01eSMikhail Tyukin
266*197ed01eSMikhail Tyukin max_rows = min(This->cinfo.output_height-first_scanline, 4);
267*197ed01eSMikhail Tyukin for (i=0; i<max_rows; i++)
268*197ed01eSMikhail Tyukin out_rows[i] = This->image_data + This->stride * (first_scanline+i);
269*197ed01eSMikhail Tyukin
270*197ed01eSMikhail Tyukin ret = jpeg_read_scanlines(&This->cinfo, out_rows, max_rows);
271*197ed01eSMikhail Tyukin if (ret == 0)
272*197ed01eSMikhail Tyukin {
273*197ed01eSMikhail Tyukin ERR("read_scanlines failed\n");
274*197ed01eSMikhail Tyukin return E_FAIL;
275*197ed01eSMikhail Tyukin }
276*197ed01eSMikhail Tyukin }
277*197ed01eSMikhail Tyukin
278*197ed01eSMikhail Tyukin if (This->frame.bpp == 24)
279*197ed01eSMikhail Tyukin {
280*197ed01eSMikhail Tyukin /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
281*197ed01eSMikhail Tyukin reverse_bgr8(3, This->image_data,
282*197ed01eSMikhail Tyukin This->cinfo.output_width, This->cinfo.output_height,
283*197ed01eSMikhail Tyukin This->stride);
284*197ed01eSMikhail Tyukin }
285*197ed01eSMikhail Tyukin
286*197ed01eSMikhail Tyukin if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
287*197ed01eSMikhail Tyukin {
288*197ed01eSMikhail Tyukin /* Adobe JPEG's have inverted CMYK data. */
289*197ed01eSMikhail Tyukin for (i=0; i<data_size; i++)
290*197ed01eSMikhail Tyukin This->image_data[i] ^= 0xff;
291*197ed01eSMikhail Tyukin }
292*197ed01eSMikhail Tyukin
293*197ed01eSMikhail Tyukin st->frame_count = 1;
294*197ed01eSMikhail Tyukin st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
295*197ed01eSMikhail Tyukin WICBitmapDecoderCapabilityCanDecodeSomeImages |
296*197ed01eSMikhail Tyukin WICBitmapDecoderCapabilityCanEnumerateMetadata |
297*197ed01eSMikhail Tyukin DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT;
298*197ed01eSMikhail Tyukin return S_OK;
299*197ed01eSMikhail Tyukin }
300*197ed01eSMikhail Tyukin
jpeg_decoder_get_frame_info(struct decoder * iface,UINT frame,struct decoder_frame * info)301*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_get_frame_info(struct decoder* iface, UINT frame, struct decoder_frame *info)
302*197ed01eSMikhail Tyukin {
303*197ed01eSMikhail Tyukin struct jpeg_decoder *This = impl_from_decoder(iface);
304*197ed01eSMikhail Tyukin *info = This->frame;
305*197ed01eSMikhail Tyukin return S_OK;
306*197ed01eSMikhail Tyukin }
307*197ed01eSMikhail Tyukin
jpeg_decoder_copy_pixels(struct decoder * iface,UINT frame,const WICRect * prc,UINT stride,UINT buffersize,BYTE * buffer)308*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_copy_pixels(struct decoder* iface, UINT frame,
309*197ed01eSMikhail Tyukin const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
310*197ed01eSMikhail Tyukin {
311*197ed01eSMikhail Tyukin struct jpeg_decoder *This = impl_from_decoder(iface);
312*197ed01eSMikhail Tyukin return copy_pixels(This->frame.bpp, This->image_data,
313*197ed01eSMikhail Tyukin This->frame.width, This->frame.height, This->stride,
314*197ed01eSMikhail Tyukin prc, stride, buffersize, buffer);
315*197ed01eSMikhail Tyukin }
316*197ed01eSMikhail Tyukin
jpeg_decoder_get_metadata_blocks(struct decoder * iface,UINT frame,UINT * count,struct decoder_block ** blocks)317*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_get_metadata_blocks(struct decoder* iface, UINT frame,
318*197ed01eSMikhail Tyukin UINT *count, struct decoder_block **blocks)
319*197ed01eSMikhail Tyukin {
320*197ed01eSMikhail Tyukin FIXME("stub\n");
321*197ed01eSMikhail Tyukin *count = 0;
322*197ed01eSMikhail Tyukin *blocks = NULL;
323*197ed01eSMikhail Tyukin return S_OK;
324*197ed01eSMikhail Tyukin }
325*197ed01eSMikhail Tyukin
jpeg_decoder_get_color_context(struct decoder * This,UINT frame,UINT num,BYTE ** data,DWORD * datasize)326*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_decoder_get_color_context(struct decoder* This, UINT frame, UINT num,
327*197ed01eSMikhail Tyukin BYTE **data, DWORD *datasize)
328*197ed01eSMikhail Tyukin {
329*197ed01eSMikhail Tyukin /* This should never be called because we report 0 color contexts and the unsupported flag. */
330*197ed01eSMikhail Tyukin FIXME("stub\n");
331*197ed01eSMikhail Tyukin return E_NOTIMPL;
332*197ed01eSMikhail Tyukin }
333*197ed01eSMikhail Tyukin
334*197ed01eSMikhail Tyukin static const struct decoder_funcs jpeg_decoder_vtable = {
335*197ed01eSMikhail Tyukin jpeg_decoder_initialize,
336*197ed01eSMikhail Tyukin jpeg_decoder_get_frame_info,
337*197ed01eSMikhail Tyukin jpeg_decoder_copy_pixels,
338*197ed01eSMikhail Tyukin jpeg_decoder_get_metadata_blocks,
339*197ed01eSMikhail Tyukin jpeg_decoder_get_color_context,
340*197ed01eSMikhail Tyukin jpeg_decoder_destroy
341*197ed01eSMikhail Tyukin };
342*197ed01eSMikhail Tyukin
jpeg_decoder_create(struct decoder_info * info,struct decoder ** result)343*197ed01eSMikhail Tyukin HRESULT CDECL jpeg_decoder_create(struct decoder_info *info, struct decoder **result)
344*197ed01eSMikhail Tyukin {
345*197ed01eSMikhail Tyukin struct jpeg_decoder *This;
346*197ed01eSMikhail Tyukin
347*197ed01eSMikhail Tyukin This = malloc(sizeof(struct jpeg_decoder));
348*197ed01eSMikhail Tyukin if (!This) return E_OUTOFMEMORY;
349*197ed01eSMikhail Tyukin
350*197ed01eSMikhail Tyukin This->decoder.vtable = &jpeg_decoder_vtable;
351*197ed01eSMikhail Tyukin This->cinfo_initialized = FALSE;
352*197ed01eSMikhail Tyukin This->stream = NULL;
353*197ed01eSMikhail Tyukin This->image_data = NULL;
354*197ed01eSMikhail Tyukin *result = &This->decoder;
355*197ed01eSMikhail Tyukin
356*197ed01eSMikhail Tyukin info->container_format = GUID_ContainerFormatJpeg;
357*197ed01eSMikhail Tyukin info->block_format = GUID_ContainerFormatJpeg;
358*197ed01eSMikhail Tyukin info->clsid = CLSID_WICJpegDecoder;
359*197ed01eSMikhail Tyukin
360*197ed01eSMikhail Tyukin return S_OK;
361*197ed01eSMikhail Tyukin }
362*197ed01eSMikhail Tyukin
363*197ed01eSMikhail Tyukin typedef struct jpeg_compress_format {
364*197ed01eSMikhail Tyukin const WICPixelFormatGUID *guid;
365*197ed01eSMikhail Tyukin int bpp;
366*197ed01eSMikhail Tyukin int num_components;
367*197ed01eSMikhail Tyukin J_COLOR_SPACE color_space;
368*197ed01eSMikhail Tyukin int swap_rgb;
369*197ed01eSMikhail Tyukin } jpeg_compress_format;
370*197ed01eSMikhail Tyukin
371*197ed01eSMikhail Tyukin static const jpeg_compress_format compress_formats[] = {
372*197ed01eSMikhail Tyukin { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 },
373*197ed01eSMikhail Tyukin { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK },
374*197ed01eSMikhail Tyukin { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE },
375*197ed01eSMikhail Tyukin { 0 }
376*197ed01eSMikhail Tyukin };
377*197ed01eSMikhail Tyukin
378*197ed01eSMikhail Tyukin struct jpeg_encoder
379*197ed01eSMikhail Tyukin {
380*197ed01eSMikhail Tyukin struct encoder encoder;
381*197ed01eSMikhail Tyukin IStream *stream;
382*197ed01eSMikhail Tyukin BOOL cinfo_initialized;
383*197ed01eSMikhail Tyukin struct jpeg_compress_struct cinfo;
384*197ed01eSMikhail Tyukin struct jpeg_error_mgr jerr;
385*197ed01eSMikhail Tyukin struct jpeg_destination_mgr dest_mgr;
386*197ed01eSMikhail Tyukin struct encoder_frame encoder_frame;
387*197ed01eSMikhail Tyukin const jpeg_compress_format *format;
388*197ed01eSMikhail Tyukin BYTE dest_buffer[1024];
389*197ed01eSMikhail Tyukin };
390*197ed01eSMikhail Tyukin
impl_from_encoder(struct encoder * iface)391*197ed01eSMikhail Tyukin static inline struct jpeg_encoder *impl_from_encoder(struct encoder* iface)
392*197ed01eSMikhail Tyukin {
393*197ed01eSMikhail Tyukin return CONTAINING_RECORD(iface, struct jpeg_encoder, encoder);
394*197ed01eSMikhail Tyukin }
395*197ed01eSMikhail Tyukin
encoder_from_compress(j_compress_ptr compress)396*197ed01eSMikhail Tyukin static inline struct jpeg_encoder *encoder_from_compress(j_compress_ptr compress)
397*197ed01eSMikhail Tyukin {
398*197ed01eSMikhail Tyukin return CONTAINING_RECORD(compress, struct jpeg_encoder, cinfo);
399*197ed01eSMikhail Tyukin }
400*197ed01eSMikhail Tyukin
dest_mgr_init_destination(j_compress_ptr cinfo)401*197ed01eSMikhail Tyukin static void dest_mgr_init_destination(j_compress_ptr cinfo)
402*197ed01eSMikhail Tyukin {
403*197ed01eSMikhail Tyukin struct jpeg_encoder *This = encoder_from_compress(cinfo);
404*197ed01eSMikhail Tyukin
405*197ed01eSMikhail Tyukin This->dest_mgr.next_output_byte = This->dest_buffer;
406*197ed01eSMikhail Tyukin This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
407*197ed01eSMikhail Tyukin }
408*197ed01eSMikhail Tyukin
dest_mgr_empty_output_buffer(j_compress_ptr cinfo)409*197ed01eSMikhail Tyukin static boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo)
410*197ed01eSMikhail Tyukin {
411*197ed01eSMikhail Tyukin struct jpeg_encoder *This = encoder_from_compress(cinfo);
412*197ed01eSMikhail Tyukin HRESULT hr;
413*197ed01eSMikhail Tyukin ULONG byteswritten;
414*197ed01eSMikhail Tyukin
415*197ed01eSMikhail Tyukin hr = stream_write(This->stream, This->dest_buffer,
416*197ed01eSMikhail Tyukin sizeof(This->dest_buffer), &byteswritten);
417*197ed01eSMikhail Tyukin
418*197ed01eSMikhail Tyukin if (hr != S_OK || byteswritten == 0)
419*197ed01eSMikhail Tyukin {
420*197ed01eSMikhail Tyukin ERR("Failed writing data, hr=%lx\n", hr);
421*197ed01eSMikhail Tyukin return FALSE;
422*197ed01eSMikhail Tyukin }
423*197ed01eSMikhail Tyukin
424*197ed01eSMikhail Tyukin This->dest_mgr.next_output_byte = This->dest_buffer;
425*197ed01eSMikhail Tyukin This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
426*197ed01eSMikhail Tyukin return TRUE;
427*197ed01eSMikhail Tyukin }
428*197ed01eSMikhail Tyukin
dest_mgr_term_destination(j_compress_ptr cinfo)429*197ed01eSMikhail Tyukin static void dest_mgr_term_destination(j_compress_ptr cinfo)
430*197ed01eSMikhail Tyukin {
431*197ed01eSMikhail Tyukin struct jpeg_encoder *This = encoder_from_compress(cinfo);
432*197ed01eSMikhail Tyukin ULONG byteswritten;
433*197ed01eSMikhail Tyukin HRESULT hr;
434*197ed01eSMikhail Tyukin
435*197ed01eSMikhail Tyukin if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer))
436*197ed01eSMikhail Tyukin {
437*197ed01eSMikhail Tyukin hr = stream_write(This->stream, This->dest_buffer,
438*197ed01eSMikhail Tyukin sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten);
439*197ed01eSMikhail Tyukin
440*197ed01eSMikhail Tyukin if (hr != S_OK || byteswritten == 0)
441*197ed01eSMikhail Tyukin ERR("Failed writing data, hr=%lx\n", hr);
442*197ed01eSMikhail Tyukin }
443*197ed01eSMikhail Tyukin }
444*197ed01eSMikhail Tyukin
jpeg_encoder_initialize(struct encoder * iface,IStream * stream)445*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_initialize(struct encoder* iface, IStream *stream)
446*197ed01eSMikhail Tyukin {
447*197ed01eSMikhail Tyukin struct jpeg_encoder *This = impl_from_encoder(iface);
448*197ed01eSMikhail Tyukin jmp_buf jmpbuf;
449*197ed01eSMikhail Tyukin
450*197ed01eSMikhail Tyukin jpeg_std_error(&This->jerr);
451*197ed01eSMikhail Tyukin
452*197ed01eSMikhail Tyukin This->jerr.error_exit = error_exit_fn;
453*197ed01eSMikhail Tyukin This->jerr.emit_message = emit_message_fn;
454*197ed01eSMikhail Tyukin
455*197ed01eSMikhail Tyukin This->cinfo.err = &This->jerr;
456*197ed01eSMikhail Tyukin
457*197ed01eSMikhail Tyukin This->cinfo.client_data = jmpbuf;
458*197ed01eSMikhail Tyukin
459*197ed01eSMikhail Tyukin if (setjmp(jmpbuf))
460*197ed01eSMikhail Tyukin return E_FAIL;
461*197ed01eSMikhail Tyukin
462*197ed01eSMikhail Tyukin jpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
463*197ed01eSMikhail Tyukin
464*197ed01eSMikhail Tyukin This->stream = stream;
465*197ed01eSMikhail Tyukin
466*197ed01eSMikhail Tyukin This->dest_mgr.next_output_byte = This->dest_buffer;
467*197ed01eSMikhail Tyukin This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
468*197ed01eSMikhail Tyukin
469*197ed01eSMikhail Tyukin This->dest_mgr.init_destination = dest_mgr_init_destination;
470*197ed01eSMikhail Tyukin This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
471*197ed01eSMikhail Tyukin This->dest_mgr.term_destination = dest_mgr_term_destination;
472*197ed01eSMikhail Tyukin
473*197ed01eSMikhail Tyukin This->cinfo.dest = &This->dest_mgr;
474*197ed01eSMikhail Tyukin
475*197ed01eSMikhail Tyukin This->cinfo_initialized = TRUE;
476*197ed01eSMikhail Tyukin
477*197ed01eSMikhail Tyukin return S_OK;
478*197ed01eSMikhail Tyukin }
479*197ed01eSMikhail Tyukin
jpeg_encoder_get_supported_format(struct encoder * iface,GUID * pixel_format,DWORD * bpp,BOOL * indexed)480*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_get_supported_format(struct encoder* iface, GUID *pixel_format,
481*197ed01eSMikhail Tyukin DWORD *bpp, BOOL *indexed)
482*197ed01eSMikhail Tyukin {
483*197ed01eSMikhail Tyukin int i;
484*197ed01eSMikhail Tyukin
485*197ed01eSMikhail Tyukin for (i=0; compress_formats[i].guid; i++)
486*197ed01eSMikhail Tyukin {
487*197ed01eSMikhail Tyukin if (memcmp(compress_formats[i].guid, pixel_format, sizeof(GUID)) == 0)
488*197ed01eSMikhail Tyukin break;
489*197ed01eSMikhail Tyukin }
490*197ed01eSMikhail Tyukin
491*197ed01eSMikhail Tyukin if (!compress_formats[i].guid) i = 0;
492*197ed01eSMikhail Tyukin
493*197ed01eSMikhail Tyukin *pixel_format = *compress_formats[i].guid;
494*197ed01eSMikhail Tyukin *bpp = compress_formats[i].bpp;
495*197ed01eSMikhail Tyukin *indexed = FALSE;
496*197ed01eSMikhail Tyukin
497*197ed01eSMikhail Tyukin return S_OK;
498*197ed01eSMikhail Tyukin }
499*197ed01eSMikhail Tyukin
jpeg_encoder_create_frame(struct encoder * iface,const struct encoder_frame * frame)500*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_create_frame(struct encoder* iface, const struct encoder_frame *frame)
501*197ed01eSMikhail Tyukin {
502*197ed01eSMikhail Tyukin struct jpeg_encoder *This = impl_from_encoder(iface);
503*197ed01eSMikhail Tyukin jmp_buf jmpbuf;
504*197ed01eSMikhail Tyukin int i;
505*197ed01eSMikhail Tyukin
506*197ed01eSMikhail Tyukin This->encoder_frame = *frame;
507*197ed01eSMikhail Tyukin
508*197ed01eSMikhail Tyukin if (setjmp(jmpbuf))
509*197ed01eSMikhail Tyukin return E_FAIL;
510*197ed01eSMikhail Tyukin
511*197ed01eSMikhail Tyukin This->cinfo.client_data = jmpbuf;
512*197ed01eSMikhail Tyukin
513*197ed01eSMikhail Tyukin for (i=0; compress_formats[i].guid; i++)
514*197ed01eSMikhail Tyukin {
515*197ed01eSMikhail Tyukin if (memcmp(compress_formats[i].guid, &frame->pixel_format, sizeof(GUID)) == 0)
516*197ed01eSMikhail Tyukin break;
517*197ed01eSMikhail Tyukin }
518*197ed01eSMikhail Tyukin This->format = &compress_formats[i];
519*197ed01eSMikhail Tyukin
520*197ed01eSMikhail Tyukin This->cinfo.image_width = frame->width;
521*197ed01eSMikhail Tyukin This->cinfo.image_height = frame->height;
522*197ed01eSMikhail Tyukin This->cinfo.input_components = This->format->num_components;
523*197ed01eSMikhail Tyukin This->cinfo.in_color_space = This->format->color_space;
524*197ed01eSMikhail Tyukin
525*197ed01eSMikhail Tyukin jpeg_set_defaults(&This->cinfo);
526*197ed01eSMikhail Tyukin
527*197ed01eSMikhail Tyukin if (frame->dpix != 0.0 && frame->dpiy != 0.0)
528*197ed01eSMikhail Tyukin {
529*197ed01eSMikhail Tyukin This->cinfo.density_unit = 1; /* dots per inch */
530*197ed01eSMikhail Tyukin This->cinfo.X_density = frame->dpix;
531*197ed01eSMikhail Tyukin This->cinfo.Y_density = frame->dpiy;
532*197ed01eSMikhail Tyukin }
533*197ed01eSMikhail Tyukin
534*197ed01eSMikhail Tyukin jpeg_start_compress(&This->cinfo, TRUE);
535*197ed01eSMikhail Tyukin
536*197ed01eSMikhail Tyukin return S_OK;
537*197ed01eSMikhail Tyukin }
538*197ed01eSMikhail Tyukin
jpeg_encoder_write_lines(struct encoder * iface,BYTE * data,DWORD line_count,DWORD stride)539*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_write_lines(struct encoder* iface, BYTE *data,
540*197ed01eSMikhail Tyukin DWORD line_count, DWORD stride)
541*197ed01eSMikhail Tyukin {
542*197ed01eSMikhail Tyukin struct jpeg_encoder *This = impl_from_encoder(iface);
543*197ed01eSMikhail Tyukin jmp_buf jmpbuf;
544*197ed01eSMikhail Tyukin BYTE *swapped_data = NULL, *current_row;
545*197ed01eSMikhail Tyukin UINT line;
546*197ed01eSMikhail Tyukin int row_size;
547*197ed01eSMikhail Tyukin
548*197ed01eSMikhail Tyukin if (setjmp(jmpbuf))
549*197ed01eSMikhail Tyukin {
550*197ed01eSMikhail Tyukin free(swapped_data);
551*197ed01eSMikhail Tyukin return E_FAIL;
552*197ed01eSMikhail Tyukin }
553*197ed01eSMikhail Tyukin
554*197ed01eSMikhail Tyukin This->cinfo.client_data = jmpbuf;
555*197ed01eSMikhail Tyukin
556*197ed01eSMikhail Tyukin row_size = This->format->bpp / 8 * This->encoder_frame.width;
557*197ed01eSMikhail Tyukin
558*197ed01eSMikhail Tyukin if (This->format->swap_rgb)
559*197ed01eSMikhail Tyukin {
560*197ed01eSMikhail Tyukin swapped_data = malloc(row_size);
561*197ed01eSMikhail Tyukin if (!swapped_data)
562*197ed01eSMikhail Tyukin return E_OUTOFMEMORY;
563*197ed01eSMikhail Tyukin }
564*197ed01eSMikhail Tyukin
565*197ed01eSMikhail Tyukin for (line=0; line < line_count; line++)
566*197ed01eSMikhail Tyukin {
567*197ed01eSMikhail Tyukin if (This->format->swap_rgb)
568*197ed01eSMikhail Tyukin {
569*197ed01eSMikhail Tyukin UINT x;
570*197ed01eSMikhail Tyukin
571*197ed01eSMikhail Tyukin memcpy(swapped_data, data + (stride * line), row_size);
572*197ed01eSMikhail Tyukin
573*197ed01eSMikhail Tyukin for (x=0; x < This->encoder_frame.width; x++)
574*197ed01eSMikhail Tyukin {
575*197ed01eSMikhail Tyukin BYTE b;
576*197ed01eSMikhail Tyukin
577*197ed01eSMikhail Tyukin b = swapped_data[x*3];
578*197ed01eSMikhail Tyukin swapped_data[x*3] = swapped_data[x*3+2];
579*197ed01eSMikhail Tyukin swapped_data[x*3+2] = b;
580*197ed01eSMikhail Tyukin }
581*197ed01eSMikhail Tyukin
582*197ed01eSMikhail Tyukin current_row = swapped_data;
583*197ed01eSMikhail Tyukin }
584*197ed01eSMikhail Tyukin else
585*197ed01eSMikhail Tyukin current_row = data + (stride * line);
586*197ed01eSMikhail Tyukin
587*197ed01eSMikhail Tyukin if (!jpeg_write_scanlines(&This->cinfo, ¤t_row, 1))
588*197ed01eSMikhail Tyukin {
589*197ed01eSMikhail Tyukin ERR("failed writing scanlines\n");
590*197ed01eSMikhail Tyukin free(swapped_data);
591*197ed01eSMikhail Tyukin return E_FAIL;
592*197ed01eSMikhail Tyukin }
593*197ed01eSMikhail Tyukin }
594*197ed01eSMikhail Tyukin
595*197ed01eSMikhail Tyukin free(swapped_data);
596*197ed01eSMikhail Tyukin
597*197ed01eSMikhail Tyukin return S_OK;
598*197ed01eSMikhail Tyukin }
599*197ed01eSMikhail Tyukin
jpeg_encoder_commit_frame(struct encoder * iface)600*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_commit_frame(struct encoder* iface)
601*197ed01eSMikhail Tyukin {
602*197ed01eSMikhail Tyukin struct jpeg_encoder *This = impl_from_encoder(iface);
603*197ed01eSMikhail Tyukin jmp_buf jmpbuf;
604*197ed01eSMikhail Tyukin
605*197ed01eSMikhail Tyukin if (setjmp(jmpbuf))
606*197ed01eSMikhail Tyukin return E_FAIL;
607*197ed01eSMikhail Tyukin
608*197ed01eSMikhail Tyukin This->cinfo.client_data = jmpbuf;
609*197ed01eSMikhail Tyukin
610*197ed01eSMikhail Tyukin jpeg_finish_compress(&This->cinfo);
611*197ed01eSMikhail Tyukin
612*197ed01eSMikhail Tyukin return S_OK;
613*197ed01eSMikhail Tyukin }
614*197ed01eSMikhail Tyukin
jpeg_encoder_commit_file(struct encoder * iface)615*197ed01eSMikhail Tyukin static HRESULT CDECL jpeg_encoder_commit_file(struct encoder* iface)
616*197ed01eSMikhail Tyukin {
617*197ed01eSMikhail Tyukin return S_OK;
618*197ed01eSMikhail Tyukin }
619*197ed01eSMikhail Tyukin
jpeg_encoder_destroy(struct encoder * iface)620*197ed01eSMikhail Tyukin static void CDECL jpeg_encoder_destroy(struct encoder* iface)
621*197ed01eSMikhail Tyukin {
622*197ed01eSMikhail Tyukin struct jpeg_encoder *This = impl_from_encoder(iface);
623*197ed01eSMikhail Tyukin if (This->cinfo_initialized)
624*197ed01eSMikhail Tyukin jpeg_destroy_compress(&This->cinfo);
625*197ed01eSMikhail Tyukin free(This);
626*197ed01eSMikhail Tyukin };
627*197ed01eSMikhail Tyukin
628*197ed01eSMikhail Tyukin static const struct encoder_funcs jpeg_encoder_vtable = {
629*197ed01eSMikhail Tyukin jpeg_encoder_initialize,
630*197ed01eSMikhail Tyukin jpeg_encoder_get_supported_format,
631*197ed01eSMikhail Tyukin jpeg_encoder_create_frame,
632*197ed01eSMikhail Tyukin jpeg_encoder_write_lines,
633*197ed01eSMikhail Tyukin jpeg_encoder_commit_frame,
634*197ed01eSMikhail Tyukin jpeg_encoder_commit_file,
635*197ed01eSMikhail Tyukin jpeg_encoder_destroy
636*197ed01eSMikhail Tyukin };
637*197ed01eSMikhail Tyukin
jpeg_encoder_create(struct encoder_info * info,struct encoder ** result)638*197ed01eSMikhail Tyukin HRESULT CDECL jpeg_encoder_create(struct encoder_info *info, struct encoder **result)
639*197ed01eSMikhail Tyukin {
640*197ed01eSMikhail Tyukin struct jpeg_encoder *This;
641*197ed01eSMikhail Tyukin
642*197ed01eSMikhail Tyukin This = malloc(sizeof(struct jpeg_encoder));
643*197ed01eSMikhail Tyukin if (!This) return E_OUTOFMEMORY;
644*197ed01eSMikhail Tyukin
645*197ed01eSMikhail Tyukin This->encoder.vtable = &jpeg_encoder_vtable;
646*197ed01eSMikhail Tyukin This->stream = NULL;
647*197ed01eSMikhail Tyukin This->cinfo_initialized = FALSE;
648*197ed01eSMikhail Tyukin *result = &This->encoder;
649*197ed01eSMikhail Tyukin
650*197ed01eSMikhail Tyukin info->flags = ENCODER_FLAGS_SUPPORTS_METADATA;
651*197ed01eSMikhail Tyukin info->container_format = GUID_ContainerFormatJpeg;
652*197ed01eSMikhail Tyukin info->clsid = CLSID_WICJpegEncoder;
653*197ed01eSMikhail Tyukin info->encoder_options[0] = ENCODER_OPTION_IMAGE_QUALITY;
654*197ed01eSMikhail Tyukin info->encoder_options[1] = ENCODER_OPTION_BITMAP_TRANSFORM;
655*197ed01eSMikhail Tyukin info->encoder_options[2] = ENCODER_OPTION_LUMINANCE;
656*197ed01eSMikhail Tyukin info->encoder_options[3] = ENCODER_OPTION_CHROMINANCE;
657*197ed01eSMikhail Tyukin info->encoder_options[4] = ENCODER_OPTION_YCRCB_SUBSAMPLING;
658*197ed01eSMikhail Tyukin info->encoder_options[5] = ENCODER_OPTION_SUPPRESS_APP0;
659*197ed01eSMikhail Tyukin info->encoder_options[6] = ENCODER_OPTION_END;
660*197ed01eSMikhail Tyukin
661*197ed01eSMikhail Tyukin return S_OK;
662*197ed01eSMikhail Tyukin }
663