]> git.sesse.net Git - vlc/blob - modules/codec/dmo/dmo.c
* dmo: - fixed init of WAVEFORMATEX (cbSize is only the size of extra datas).
[vlc] / modules / codec / dmo / dmo.c
1 /*****************************************************************************\r
2  * dmo.c : DirectMedia Object decoder module for vlc\r
3  *****************************************************************************\r
4  * Copyright (C) 2002, 2003 VideoLAN\r
5  * $Id$\r
6  *\r
7  * Author: Gildas Bazin <gbazin@videolan.org>\r
8  *\r
9  * This program is free software; you can redistribute it and/or modify\r
10  * it under the terms of the GNU General Public License as published by\r
11  * the Free Software Foundation; either version 2 of the License, or\r
12  * (at your option) any later version.\r
13  *\r
14  * This program is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU General Public License for more details.\r
18  *\r
19  * You should have received a copy of the GNU General Public License\r
20  * along with this program; if not, write to the Free Software\r
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.\r
22  *****************************************************************************/\r
23 \r
24 /*****************************************************************************\r
25  * Preamble\r
26  *****************************************************************************/\r
27 #include <stdlib.h>\r
28 #include <stdio.h>\r
29 #include <string.h>\r
30 \r
31 #include <vlc/vlc.h>\r
32 #include <vlc/decoder.h>\r
33 #include <vlc/vout.h>\r
34 \r
35 #define LOADER\r
36 #ifdef LOADER\r
37 /* Need the w32dll loader from mplayer */\r
38 #   include <wine/winerror.h>\r
39 #   include <dmo/dmo.h>\r
40 #   include <dmo/dmo_interfaces.h>\r
41 #   include <dmo/dmo_guids.h>\r
42 #   include <ldt_keeper.h>\r
43 \r
44 /* Avoid  codecs.h to redefine a few symbols */\r
45 #   define _RECT32_\r
46 #   define _GUID_DEFINED\r
47 #   define _REFERENCE_TIME_\r
48 #   define _VIDEOINFOHEADER_\r
49 \r
50 /* Ugly, wine loader and vlc doesn't use the same field name for GUID */\r
51 #define Data1 f1\r
52 #define Data2 f2\r
53 #define Data3 f3\r
54 #define Data4 f4\r
55 \r
56 /* Not Needed */\r
57 HRESULT CoInitialize( LPVOID pvReserved ) { return (HRESULT)-1; }\r
58 void CoUninitialize(void) { }\r
59 \r
60 /* */\r
61 HMODULE   WINAPI LoadLibraryA(LPCSTR);\r
62 FARPROC   WINAPI GetProcAddress(HMODULE,LPCSTR);\r
63 int       WINAPI FreeLibrary(HMODULE);\r
64 \r
65 typedef long STDCALL (*GETCLASS) (const GUID*, const GUID*, void**);\r
66 \r
67 #else\r
68 #   include <objbase.h>\r
69 #endif\r
70 \r
71 #include "dmo.h"\r
72 #include "codecs.h"\r
73 \r
74 static int pi_channels_maps[7] =\r
75 {\r
76     0,\r
77     AOUT_CHAN_CENTER,\r
78     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,\r
79     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,\r
80     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT\r
81      | AOUT_CHAN_REARRIGHT,\r
82     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER\r
83      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,\r
84     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER\r
85      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE\r
86 };\r
87 \r
88 /*****************************************************************************\r
89  * Module descriptor\r
90  *****************************************************************************/\r
91 static int  Open         ( vlc_object_t * );\r
92 static int  DecoderOpen  ( vlc_object_t * );\r
93 static void DecoderClose ( vlc_object_t * );\r
94 static void *DecodeBlock ( decoder_t *, block_t ** );\r
95 \r
96 static void CopyPicture( decoder_t *, picture_t *, uint8_t * );\r
97 \r
98 vlc_module_begin();\r
99     set_description( _("DirectMedia Object decoder") );\r
100     add_shortcut( "dmo" );\r
101     set_capability( "decoder", 1 );\r
102     set_callbacks( Open, DecoderClose );\r
103 vlc_module_end();\r
104 \r
105 /*****************************************************************************\r
106  * Local prototypes\r
107  *****************************************************************************/\r
108 \r
109 /****************************************************************************\r
110  * Decoder descriptor declaration\r
111  ****************************************************************************/\r
112 struct decoder_sys_t\r
113 {\r
114     HINSTANCE hmsdmo_dll;\r
115     IMediaObject *p_dmo;\r
116 \r
117     int i_min_output;\r
118     uint8_t *p_buffer;\r
119 \r
120     audio_date_t end_date;\r
121 \r
122 #ifdef LOADER\r
123     ldt_fs_t    *ldt_fs;\r
124 #endif\r
125 };\r
126 \r
127 #ifdef LOADER\r
128 static const GUID guid_wmv9 = { 0x724bb6a4, 0xe526, 0x450f, { 0xaf, 0xfa, 0xab, 0x9b, 0x45, 0x12, 0x91, 0x11 } };\r
129 static const GUID guid_wma9 = { 0x27ca0808, 0x01f5, 0x4e7a, { 0x8b, 0x05, 0x87, 0xf8, 0x07, 0xa2, 0x33, 0xd1 } };\r
130 \r
131 static const GUID guid_wmv = { 0x82d353df, 0x90bd, 0x4382, { 0x8b, 0xc2, 0x3f, 0x61, 0x92, 0xb7, 0x6e, 0x34 } };\r
132 static const GUID guid_wma = { 0x874131cb, 0x4ecc, 0x443b, { 0x89, 0x48, 0x74, 0x6b, 0x89, 0x59, 0x5d, 0x20 } };\r
133 \r
134 static const struct\r
135 {\r
136     vlc_fourcc_t i_fourcc;\r
137     const char   *psz_dll;\r
138     const GUID   *p_guid;\r
139 } codecs_table[] =\r
140 {\r
141     /* WM3 */\r
142     { VLC_FOURCC('W','M','V','3'), "wmv9dmod.dll", &guid_wmv9 },\r
143     { VLC_FOURCC('w','m','v','3'), "wmv9dmod.dll", &guid_wmv9 },\r
144     /* WMV2 */\r
145     { VLC_FOURCC('W','M','V','2'), "wmvdmod.dll", &guid_wmv },\r
146     { VLC_FOURCC('w','m','v','2'), "wmvdmod.dll", &guid_wmv },\r
147     /* WMV1 */\r
148     { VLC_FOURCC('W','M','V','1'), "wmvdmod.dll", &guid_wmv },\r
149     { VLC_FOURCC('w','m','v','1'), "wmvdmod.dll", &guid_wmv },\r
150 \r
151     /* WMA 3*/\r
152     { VLC_FOURCC('W','M','A','3'), "wma9dmod.dll", &guid_wma9 },\r
153     { VLC_FOURCC('w','m','a','3'), "wma9dmod.dll", &guid_wma9 },\r
154 \r
155     /* */\r
156     { 0, NULL, NULL }\r
157 };\r
158 \r
159 #endif\r
160 \r
161 /*****************************************************************************\r
162  * Open: open dmo codec\r
163  *****************************************************************************/\r
164 static int Open( vlc_object_t *p_this )\r
165 {\r
166 #ifndef LOADER\r
167     return DecoderOpen( p_this );\r
168 #else\r
169     decoder_t *p_dec = (decoder_t*)p_this;\r
170     int i;\r
171     /* We can't open it now, because of ldt_keeper or something\r
172      * Open/Decode/Close has to be done in the same thread */\r
173 \r
174     p_dec->p_sys = NULL;\r
175 \r
176 \r
177     /* Probe if we support it */\r
178     for( i = 0; codecs_table[i].i_fourcc != 0; i++ )\r
179     {\r
180         if( codecs_table[i].i_fourcc == p_dec->fmt_in.i_codec )\r
181         {\r
182             msg_Dbg( p_dec, "DMO codec for %4.4s may work with dll=%s",\r
183                      (char*)&p_dec->fmt_in.i_codec,\r
184                      codecs_table[i].psz_dll );\r
185 \r
186             /* Set callbacks */\r
187             p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))DecodeBlock;\r
188             p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))DecodeBlock;\r
189             return VLC_SUCCESS;\r
190         }\r
191     }\r
192     return VLC_EGENERIC;\r
193 #endif\r
194 }\r
195 \r
196 /*****************************************************************************\r
197  * DecoderOpen: open dmo codec\r
198  *****************************************************************************/\r
199 static int DecoderOpen( vlc_object_t *p_this )\r
200 {\r
201     decoder_t *p_dec = (decoder_t*)p_this;\r
202     decoder_sys_t *p_sys = NULL;\r
203 \r
204     DMO_PARTIAL_MEDIATYPE dmo_partial_type;\r
205     DMO_MEDIA_TYPE dmo_input_type, dmo_output_type;\r
206     IMediaObject *p_dmo = NULL;\r
207 \r
208     VIDEOINFOHEADER *p_vih = NULL;\r
209     WAVEFORMATEX *p_wf = NULL;\r
210 \r
211 #ifdef LOADER\r
212     ldt_fs_t *ldt_fs = Setup_LDT_Keeper();\r
213 #endif /* LOADER */\r
214 \r
215     HINSTANCE hmsdmo_dll = NULL;\r
216 \r
217     /* Look for a DMO which can handle the requested codec */\r
218     if( p_dec->fmt_in.i_cat == AUDIO_ES )\r
219     {\r
220         uint16_t i_tag;\r
221         dmo_partial_type.type = MEDIATYPE_Audio;\r
222         dmo_partial_type.subtype = dmo_partial_type.type;\r
223         dmo_partial_type.subtype.Data1 = p_dec->fmt_in.i_codec;\r
224         fourcc_to_wf_tag( p_dec->fmt_in.i_codec, &i_tag );\r
225         if( i_tag ) dmo_partial_type.subtype.Data1 = i_tag;\r
226     }\r
227     else\r
228     {\r
229         dmo_partial_type.type = MEDIATYPE_Video;\r
230         dmo_partial_type.subtype = dmo_partial_type.type;\r
231         dmo_partial_type.subtype.Data1 = p_dec->fmt_in.i_codec;\r
232     }\r
233 \r
234 #ifndef LOADER\r
235   { /* <- ugly ? yes */\r
236     IEnumDMO *p_enum_dmo = NULL;\r
237     WCHAR *psz_dmo_name;\r
238     GUID clsid_dmo;\r
239     HRESULT (STDCALL *OurDMOEnum)( const GUID *, uint32_t, uint32_t,\r
240                            const DMO_PARTIAL_MEDIATYPE *,\r
241                            uint32_t, const DMO_PARTIAL_MEDIATYPE *,\r
242                            IEnumDMO ** );\r
243 \r
244 \r
245     /* Load msdmo DLL */\r
246     hmsdmo_dll = LoadLibrary( "msdmo.dll" );\r
247     if( hmsdmo_dll == NULL )\r
248     {\r
249         msg_Dbg( p_dec, "failed loading msdmo.dll" );\r
250         return VLC_EGENERIC;\r
251     }\r
252     OurDMOEnum = (void *)GetProcAddress( hmsdmo_dll, "DMOEnum" );\r
253     if( OurDMOEnum == NULL )\r
254     {\r
255         msg_Dbg( p_dec, "GetProcAddress failed to find DMOEnum()" );\r
256         FreeLibrary( hmsdmo_dll );\r
257         return VLC_EGENERIC;\r
258     }\r
259 \r
260 \r
261     /* Initialize OLE/COM */\r
262     CoInitialize( 0 );\r
263 \r
264     if( OurDMOEnum( &GUID_NULL, 1 /*DMO_ENUMF_INCLUDE_KEYED*/,\r
265                     1, &dmo_partial_type, 0, NULL, &p_enum_dmo ) )\r
266     {\r
267         goto error;\r
268     }\r
269 \r
270     /* Pickup the first available codec */\r
271     if( p_enum_dmo->vt->Next( p_enum_dmo, 1, &clsid_dmo,\r
272                               &psz_dmo_name, NULL ) )\r
273     {\r
274         goto error;\r
275     }\r
276     p_enum_dmo->vt->Release( (IUnknown *)p_enum_dmo );\r
277 \r
278 #if 1\r
279     {\r
280         char psz_temp[MAX_PATH];\r
281         wcstombs( psz_temp, psz_dmo_name, MAX_PATH );\r
282         msg_Dbg( p_dec, "found DMO: %s", psz_temp );\r
283     }\r
284 #endif\r
285 \r
286     CoTaskMemFree( psz_dmo_name );\r
287 \r
288     /* Create DMO */\r
289     if( CoCreateInstance( &clsid_dmo, NULL, CLSCTX_INPROC,\r
290                           &IID_IMediaObject, (void **)&p_dmo ) )\r
291     {\r
292         msg_Err( p_dec, "can't create DMO" );\r
293         goto error;\r
294     }\r
295   }\r
296 #else   /* LOADER */\r
297   {\r
298     GETCLASS GetClass;\r
299     struct IClassFactory* cFactory = NULL;\r
300     struct IUnknown* cObject = NULL;\r
301 \r
302     int i_err;\r
303     int i_codec;\r
304     for( i_codec = 0; codecs_table[i_codec].i_fourcc != 0; i_codec++ )\r
305     {\r
306         if( codecs_table[i_codec].i_fourcc == p_dec->fmt_in.i_codec )\r
307             break;\r
308     }\r
309     if( codecs_table[i_codec].i_fourcc == 0 )\r
310         return VLC_EGENERIC;    /* Can't happen */\r
311 \r
312     hmsdmo_dll = LoadLibrary( codecs_table[i_codec].psz_dll );\r
313     if( hmsdmo_dll == NULL )\r
314     {\r
315         msg_Dbg( p_dec, "failed loading '%s'", codecs_table[i_codec].psz_dll );\r
316         return VLC_EGENERIC;\r
317     }\r
318 \r
319     GetClass = (GETCLASS)GetProcAddress( hmsdmo_dll, "DllGetClassObject");\r
320     if (!GetClass)\r
321     {\r
322         msg_Dbg( p_dec, "GetProcAddress failed to find DllGetClassObject()" );\r
323         FreeLibrary( hmsdmo_dll );\r
324         return VLC_EGENERIC;\r
325     }\r
326 \r
327     i_err = GetClass( codecs_table[i_codec].p_guid, &IID_IClassFactory, (void**)&cFactory );\r
328     if( i_err || cFactory == NULL )\r
329     {\r
330         msg_Dbg( p_dec, "no such class object" );\r
331         FreeLibrary( hmsdmo_dll );\r
332         return VLC_EGENERIC;\r
333     }\r
334 \r
335     i_err = cFactory->vt->CreateInstance( cFactory, 0, &IID_IUnknown, (void**)&cObject );\r
336     cFactory->vt->Release((IUnknown*)cFactory );\r
337     if( i_err || !cObject )\r
338     {\r
339         msg_Dbg( p_dec, "class factory failure" );\r
340         FreeLibrary( hmsdmo_dll );\r
341         return VLC_EGENERIC;\r
342     }\r
343     i_err = cObject->vt->QueryInterface( cObject, &IID_IMediaObject, (void**)&p_dmo );\r
344 #if 0\r
345     if (hr == 0)\r
346     {\r
347             /* query for some extra available interface */\r
348         HRESULT r = object->vt->QueryInterface(object, &IID_IMediaObjectInPlace, (void**)&This->m_pInPlace);\r
349             if (r == 0 && This->m_pInPlace)\r
350         printf("DMO dll supports InPlace - PLEASE REPORT to developer\n");\r
351         r = object->vt->QueryInterface(object, &IID_IDMOVideoOutputOptimizations, (void**)&This->m_pOptim);\r
352         if (r == 0 && This->m_pOptim)\r
353         {\r
354                 unsigned long flags;\r
355         r = This->m_pOptim->vt->QueryOperationModePreferences(This->m_pOptim, 0, &flags);\r
356         printf("DMO dll supports VO Optimizations %ld %lx\n", r, flags);\r
357         if (flags & DMO_VOSF_NEEDS_PREVIOUS_SAMPLE)\r
358             printf("DMO dll might use previous sample when requested\n");\r
359         }\r
360     }\r
361 #endif\r
362     cObject->vt->Release((IUnknown*)cObject );\r
363   }\r
364 #endif  /* LOADER */\r
365 \r
366     /* Setup input format */\r
367     memset( &dmo_input_type, 0, sizeof(dmo_input_type) );\r
368     dmo_input_type.majortype = dmo_partial_type.type;\r
369     dmo_input_type.subtype = dmo_partial_type.subtype;\r
370     dmo_input_type.pUnk = 0;\r
371 \r
372     if( p_dec->fmt_in.i_cat == AUDIO_ES )\r
373     {\r
374         int i_size = sizeof(WAVEFORMATEX) + p_dec->fmt_in.i_extra;\r
375         p_wf = malloc( i_size );\r
376 \r
377         memset( p_wf, 0, sizeof(WAVEFORMATEX) );\r
378         if( p_dec->fmt_in.i_extra )\r
379             memcpy( &p_wf[1], p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra );\r
380 \r
381         p_wf->wFormatTag = dmo_partial_type.subtype.Data1;\r
382         p_wf->nSamplesPerSec = p_dec->fmt_in.audio.i_rate;\r
383         p_wf->nChannels = p_dec->fmt_in.audio.i_channels;\r
384         p_wf->wBitsPerSample = p_dec->fmt_in.audio.i_bitspersample;\r
385         p_wf->nBlockAlign = p_dec->fmt_in.audio.i_blockalign;\r
386         p_wf->nAvgBytesPerSec = p_dec->fmt_in.i_bitrate / 8;\r
387         p_wf->cbSize = p_dec->fmt_in.i_extra;\r
388 \r
389         dmo_input_type.formattype = FORMAT_WaveFormatEx;\r
390         dmo_input_type.cbFormat   = i_size;\r
391         dmo_input_type.pbFormat   = (char *)p_wf;\r
392         dmo_input_type.pUnk       = NULL;\r
393         dmo_input_type.bFixedSizeSamples = 1;\r
394         dmo_input_type.bTemporalCompression = 0;\r
395         dmo_input_type.lSampleSize = p_wf->nBlockAlign;\r
396     }\r
397     else\r
398     {\r
399         BITMAPINFOHEADER *p_bih;\r
400 \r
401         int i_size = sizeof(VIDEOINFOHEADER) + p_dec->fmt_in.i_extra;\r
402         p_vih = malloc( i_size );\r
403 \r
404         memset( p_vih, 0, sizeof(VIDEOINFOHEADER) );\r
405         if( p_dec->fmt_in.i_extra )\r
406             memcpy( &p_vih[1], p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra );\r
407 \r
408         p_bih = &p_vih->bmiHeader;\r
409         p_bih->biCompression = dmo_partial_type.subtype.Data1;\r
410         p_bih->biWidth = p_dec->fmt_in.video.i_width;\r
411         p_bih->biHeight = p_dec->fmt_in.video.i_height;\r
412         p_bih->biBitCount = p_dec->fmt_in.video.i_bits_per_pixel;\r
413         p_bih->biPlanes = 1;\r
414         p_bih->biSize = i_size - sizeof(VIDEOINFOHEADER) +\r
415             sizeof(BITMAPINFOHEADER);\r
416 \r
417         p_vih->rcSource.left = p_vih->rcSource.top = 0;\r
418         p_vih->rcSource.right = p_dec->fmt_in.video.i_width;\r
419         p_vih->rcSource.bottom = p_dec->fmt_in.video.i_height;\r
420         p_vih->rcTarget = p_vih->rcSource;\r
421 \r
422         dmo_input_type.formattype = MEDIASUBTYPE_VideoInfo;\r
423         dmo_input_type.bFixedSizeSamples = 0;\r
424         dmo_input_type.bTemporalCompression = 1;\r
425         dmo_input_type.cbFormat = i_size;\r
426         dmo_input_type.pbFormat = (char *)p_vih;\r
427     }\r
428 \r
429     if( p_dmo->vt->SetInputType( p_dmo, 0, &dmo_input_type, 0 ) )\r
430     {\r
431         msg_Err( p_dec, "can't set DMO input type" );\r
432         goto error;\r
433     }\r
434     msg_Dbg( p_dec, "DMO input type set" );\r
435 \r
436     /* Setup output format */\r
437     memset( &dmo_output_type, 0, sizeof(dmo_output_type) );\r
438     dmo_output_type.majortype = dmo_partial_type.type;\r
439     dmo_output_type.pUnk = 0;\r
440 \r
441     if( p_dec->fmt_in.i_cat == AUDIO_ES )\r
442     {\r
443         /* Setup the format */\r
444         p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE;\r
445         p_dec->fmt_out.audio.i_rate     = p_dec->fmt_in.audio.i_rate;\r
446         p_dec->fmt_out.audio.i_channels = p_dec->fmt_in.audio.i_channels;\r
447         p_dec->fmt_out.audio.i_bitspersample = 16;//p_dec->fmt_in.audio.i_bitspersample; We request 16\r
448         p_dec->fmt_out.audio.i_physical_channels =\r
449             p_dec->fmt_out.audio.i_original_channels =\r
450                 pi_channels_maps[p_dec->fmt_out.audio.i_channels];\r
451 \r
452         p_wf->wFormatTag = WAVE_FORMAT_PCM;\r
453         p_wf->nSamplesPerSec = p_dec->fmt_out.audio.i_rate;\r
454         p_wf->nChannels = p_dec->fmt_out.audio.i_channels;\r
455         p_wf->wBitsPerSample = p_dec->fmt_out.audio.i_bitspersample;\r
456         p_wf->nBlockAlign =\r
457             p_wf->wBitsPerSample / 8 * p_wf->nChannels;\r
458         p_wf->nAvgBytesPerSec =\r
459             p_wf->nSamplesPerSec * p_wf->nBlockAlign;\r
460         p_wf->cbSize = 0;\r
461 \r
462         dmo_output_type.formattype = FORMAT_WaveFormatEx;\r
463         dmo_output_type.subtype    = MEDIASUBTYPE_PCM;\r
464         dmo_output_type.cbFormat   = sizeof(WAVEFORMATEX);\r
465         dmo_output_type.pbFormat   = (char *)p_wf;\r
466         dmo_output_type.bFixedSizeSamples = 1;\r
467         dmo_output_type.bTemporalCompression = 0;\r
468         dmo_output_type.lSampleSize = p_wf->nBlockAlign;\r
469         dmo_output_type.pUnk = NULL;\r
470     }\r
471     else\r
472     {\r
473         BITMAPINFOHEADER *p_bih;\r
474 \r
475         p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');\r
476         p_dec->fmt_out.video.i_width = p_dec->fmt_in.video.i_width;\r
477         p_dec->fmt_out.video.i_height = p_dec->fmt_in.video.i_height;\r
478         p_dec->fmt_out.video.i_bits_per_pixel = 12;\r
479         p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *\r
480             p_dec->fmt_out.video.i_width / p_dec->fmt_out.video.i_height;\r
481 \r
482         dmo_output_type.formattype = MEDIASUBTYPE_VideoInfo;\r
483         dmo_output_type.subtype = MEDIASUBTYPE_YV12;\r
484 \r
485         p_bih = &p_vih->bmiHeader;\r
486         p_bih->biCompression = dmo_partial_type.subtype.Data1;\r
487         p_bih->biHeight *= -1;\r
488         p_bih->biBitCount = p_dec->fmt_out.video.i_bits_per_pixel;\r
489         p_bih->biSizeImage = p_dec->fmt_in.video.i_width *\r
490             p_dec->fmt_in.video.i_height *\r
491             (p_dec->fmt_in.video.i_bits_per_pixel + 7) / 8;\r
492 \r
493         //p_bih->biPlanes = 1;\r
494         p_bih->biSize = sizeof(BITMAPINFOHEADER);\r
495 \r
496         dmo_output_type.bFixedSizeSamples = VLC_TRUE;\r
497         dmo_output_type.bTemporalCompression = 0;\r
498         dmo_output_type.lSampleSize = p_bih->biSizeImage;\r
499         dmo_output_type.cbFormat = sizeof(VIDEOINFOHEADER);\r
500         dmo_output_type.pbFormat = (char *)p_vih;\r
501     }\r
502 \r
503     /* Enumerate output types */\r
504     if( p_dec->fmt_in.i_cat == VIDEO_ES )\r
505     {\r
506         int i = 0;\r
507         DMO_MEDIA_TYPE mt;\r
508 \r
509         while( !p_dmo->vt->GetOutputType( p_dmo, 0, i++, &mt ) )\r
510         {\r
511             msg_Dbg( p_dec, "available output chroma: %4.4s",\r
512                      (char *)&mt.subtype.Data1 );\r
513         }\r
514     }\r
515 \r
516     /* Choose an output type.\r
517      * FIXME, get rid of the dmo_output_type code above. */\r
518     if( p_dec->fmt_in.i_cat == VIDEO_ES )\r
519     {\r
520         int i = 0;\r
521         DMO_MEDIA_TYPE mt;\r
522 \r
523         while( !p_dmo->vt->GetOutputType( p_dmo, 0, i++, &mt ) )\r
524         {\r
525             if( dmo_output_type.subtype.Data1 == mt.subtype.Data1 )\r
526             {\r
527                 *p_vih = *(VIDEOINFOHEADER *)mt.pbFormat;\r
528                 break;\r
529             }\r
530         }\r
531     }\r
532 \r
533     if( p_dmo->vt->SetOutputType( p_dmo, 0, &dmo_output_type, 0 ) )\r
534     {\r
535         msg_Err( p_dec, "can't set DMO output type" );\r
536         goto error;\r
537     }\r
538     msg_Dbg( p_dec, "DMO output type set" );\r
539 \r
540     /* Allocate the memory needed to store the decoder's structure */\r
541     if( ( p_dec->p_sys = p_sys =\r
542           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )\r
543     {\r
544         msg_Err( p_dec, "out of memory" );\r
545         goto error;\r
546     }\r
547 \r
548     p_sys->hmsdmo_dll = hmsdmo_dll;\r
549     p_sys->p_dmo = p_dmo;\r
550 #ifdef LOADER\r
551     p_sys->ldt_fs = ldt_fs;\r
552 #endif\r
553 \r
554     /* Find out some properties of the output */\r
555     {\r
556         uint32_t i_size, i_align;\r
557 \r
558         p_sys->i_min_output = 0;\r
559         if( p_dmo->vt->GetOutputSizeInfo( p_dmo, 0, &i_size, &i_align ) )\r
560         {\r
561             msg_Err( p_dec, "GetOutputSizeInfo() failed" );\r
562             goto error;\r
563         }\r
564         else\r
565         {\r
566             msg_Dbg( p_dec, "GetOutputSizeInfo(): bytes %i, align %i",\r
567                      i_size, i_align );\r
568             p_sys->i_min_output = i_size;\r
569             p_sys->p_buffer = malloc( i_size );\r
570             if( !p_sys->p_buffer ) goto error;\r
571         }\r
572     }\r
573 \r
574     /* Set output properties */\r
575     p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;\r
576     if( p_dec->fmt_out.i_cat == AUDIO_ES )\r
577         aout_DateInit( &p_sys->end_date, p_dec->fmt_in.audio.i_rate );\r
578     else\r
579         aout_DateInit( &p_sys->end_date, 25 /* FIXME */ );\r
580     aout_DateSet( &p_sys->end_date, 0 );\r
581 \r
582     /* Set callbacks */\r
583     p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))\r
584         DecodeBlock;\r
585     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))\r
586         DecodeBlock;\r
587 \r
588     if( p_vih ) free( p_vih );\r
589     if( p_wf ) free( p_wf );\r
590 \r
591     return VLC_SUCCESS;\r
592 \r
593  error:\r
594     /* Uninitialize OLE/COM */\r
595     CoUninitialize();\r
596     FreeLibrary( hmsdmo_dll );\r
597 \r
598     if( p_vih ) free( p_vih );\r
599     if( p_wf )  free( p_wf );\r
600     if( p_sys ) free( p_sys );\r
601 \r
602     return VLC_EGENERIC;\r
603 }\r
604 \r
605 /*****************************************************************************\r
606  * DecoderClose: close codec\r
607  *****************************************************************************/\r
608 void DecoderClose( vlc_object_t *p_this )\r
609 {\r
610     decoder_t *p_dec = (decoder_t*)p_this;\r
611     decoder_sys_t *p_sys = p_dec->p_sys;\r
612 \r
613     /* Uninitialize OLE/COM */\r
614     CoUninitialize();\r
615 \r
616     FreeLibrary( p_sys->hmsdmo_dll );\r
617 \r
618 #if 0\r
619 #ifdef LOADER\r
620     Restore_LDT_Keeper( p_sys->ldt_fs );\r
621 #endif\r
622 #endif\r
623 \r
624     if( p_sys->p_buffer ) free( p_sys->p_buffer );\r
625     free( p_sys );\r
626 }\r
627 \r
628 /****************************************************************************\r
629  * DecodeBlock: the whole thing\r
630  ****************************************************************************\r
631  * This function must be fed with ogg packets.\r
632  ****************************************************************************/\r
633 static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )\r
634 {\r
635     decoder_sys_t *p_sys = p_dec->p_sys;\r
636     block_t *p_block;\r
637     int i_result;\r
638 \r
639     DMO_OUTPUT_DATA_BUFFER db;\r
640     CMediaBuffer *p_out;\r
641     block_t block_out;\r
642     uint32_t i_status, i_buffer_out;\r
643     uint8_t *p_buffer_out;\r
644 \r
645     if( p_sys == NULL )\r
646     {\r
647         if( DecoderOpen( VLC_OBJECT(p_dec) ) )\r
648         {\r
649             msg_Err( p_dec, "DecoderOpen failed" );\r
650             return NULL;\r
651         }\r
652         p_sys = p_dec->p_sys;\r
653     }\r
654 \r
655     if( !pp_block ) return NULL;\r
656 \r
657     p_block = *pp_block;\r
658 \r
659     /* Won't work with streams with B-frames, but do we have any ? */\r
660     if( p_block && p_block->i_pts <= 0 ) p_block->i_pts = p_block->i_dts;\r
661 \r
662     /* Date management */\r
663     if( p_block && p_block->i_pts > 0 &&\r
664         p_block->i_pts != aout_DateGet( &p_sys->end_date ) )\r
665     {\r
666         aout_DateSet( &p_sys->end_date, p_block->i_pts );\r
667     }\r
668 \r
669 #if 0 /* Breaks the video decoding */\r
670     if( !aout_DateGet( &p_sys->end_date ) )\r
671     {\r
672         /* We've just started the stream, wait for the first PTS. */\r
673         if( p_block ) block_Release( p_block );\r
674         return NULL;\r
675     }\r
676 #endif\r
677 \r
678     /* Feed input to the DMO */\r
679     if( p_block && p_block->i_buffer )\r
680     {\r
681         CMediaBuffer *p_in;\r
682 \r
683         p_in = CMediaBufferCreate( p_block, p_block->i_buffer, VLC_TRUE );\r
684 \r
685         i_result = p_sys->p_dmo->vt->ProcessInput( p_sys->p_dmo, 0,\r
686                        (IMediaBuffer *)p_in, DMO_INPUT_DATA_BUFFER_SYNCPOINT,\r
687                        0, 0 );\r
688 \r
689         p_in->vt->Release( (IUnknown *)p_in );\r
690 \r
691         if( i_result == S_FALSE )\r
692         {\r
693             /* No output generated */\r
694 #ifdef DMO_DEBUG\r
695             msg_Dbg( p_dec, "ProcessInput(): no output generated" );\r
696 #endif\r
697             return NULL;\r
698         }\r
699         else if( i_result == DMO_E_NOTACCEPTING )\r
700         {\r
701             /* Need to call ProcessOutput */\r
702             msg_Dbg( p_dec, "ProcessInput(): not accepting" );\r
703         }\r
704         else if( i_result != S_OK )\r
705         {\r
706             msg_Dbg( p_dec, "ProcessInput(): failed" );\r
707             return NULL;\r
708         }\r
709         else\r
710         {\r
711             //msg_Dbg( p_dec, "ProcessInput(): successful" );\r
712             *pp_block = 0;\r
713         }\r
714     }\r
715     else if( p_block && !p_block->i_buffer )\r
716     {\r
717         block_Release( p_block );\r
718         *pp_block = 0;\r
719     }\r
720 \r
721     /* Get output from the DMO */\r
722     block_out.p_buffer = p_sys->p_buffer;;\r
723     block_out.i_buffer = 0;\r
724 \r
725     p_out = CMediaBufferCreate( &block_out, p_sys->i_min_output, VLC_FALSE );\r
726     db.rtTimestamp = 0;\r
727     db.rtTimelength = 0;\r
728     db.dwStatus = 0;\r
729     db.pBuffer = (IMediaBuffer *)p_out;\r
730 \r
731     i_result = p_sys->p_dmo->vt->ProcessOutput( p_sys->p_dmo,\r
732                    DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER,\r
733                    1, &db, &i_status );\r
734 \r
735     if( i_result != S_OK )\r
736     {\r
737         if( i_result != S_FALSE )\r
738             msg_Dbg( p_dec, "ProcessOutput(): failed" );\r
739 #if DMO_DEBUG\r
740         else\r
741             msg_Dbg( p_dec, "ProcessOutput(): no output" );\r
742 #endif\r
743 \r
744         p_out->vt->Release( (IUnknown *)p_out );\r
745         return NULL;\r
746     }\r
747 \r
748 #if DMO_DEBUG\r
749     msg_Dbg( p_dec, "ProcessOutput(): success" );\r
750 #endif\r
751 \r
752     i_result = p_out->vt->GetBufferAndLength( (IMediaBuffer *)p_out,\r
753                                               &p_buffer_out, &i_buffer_out );\r
754     if( i_result != S_OK )\r
755     {\r
756         msg_Dbg( p_dec, "GetBufferAndLength(): failed" );\r
757         p_out->vt->Release( (IUnknown *)p_out );\r
758         return NULL;\r
759     }\r
760 \r
761     if( !i_buffer_out )\r
762     {\r
763 #if DMO_DEBUG\r
764         msg_Dbg( p_dec, "ProcessOutput(): no output (i_buffer_out == 0)" );\r
765 #endif\r
766         p_out->vt->Release( (IUnknown *)p_out );\r
767         return NULL;\r
768     }\r
769 \r
770     if( p_dec->fmt_out.i_cat == VIDEO_ES )\r
771     {\r
772         /* Get a new picture */\r
773         picture_t *p_pic = p_dec->pf_vout_buffer_new( p_dec );\r
774         if( !p_pic ) return NULL;\r
775 \r
776         CopyPicture( p_dec, p_pic, block_out.p_buffer );\r
777 \r
778         /* Date management */\r
779         p_pic->date = aout_DateGet( &p_sys->end_date );\r
780         aout_DateIncrement( &p_sys->end_date, 1 );\r
781 \r
782         p_out->vt->Release( (IUnknown *)p_out );\r
783 \r
784         return p_pic;\r
785     }\r
786     else\r
787     {\r
788         aout_buffer_t *p_aout_buffer;\r
789         int i_samples = i_buffer_out /\r
790             ( p_dec->fmt_out.audio.i_bitspersample *\r
791               p_dec->fmt_out.audio.i_channels / 8 );\r
792 \r
793         p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, i_samples );\r
794         memcpy( p_aout_buffer->p_buffer, p_buffer_out, i_buffer_out );\r
795 \r
796         /* Date management */\r
797         p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );\r
798         p_aout_buffer->end_date =\r
799             aout_DateIncrement( &p_sys->end_date, i_samples );\r
800 \r
801         p_out->vt->Release( (IUnknown *)p_out );\r
802 \r
803         return p_aout_buffer;\r
804     }\r
805 \r
806     return NULL;\r
807 }\r
808 \r
809 static void CopyPicture( decoder_t *p_dec, picture_t *p_pic, uint8_t *p_in )\r
810 {\r
811     int i_plane, i_line, i_width, i_dst_stride;\r
812     uint8_t *p_dst, *p_src = p_in;\r
813 \r
814     p_dst = p_pic->p[1].p_pixels;\r
815     p_pic->p[1].p_pixels = p_pic->p[2].p_pixels;\r
816     p_pic->p[2].p_pixels = p_dst;\r
817 \r
818     for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )\r
819     {\r
820         p_dst = p_pic->p[i_plane].p_pixels;\r
821         i_width = p_pic->p[i_plane].i_visible_pitch;\r
822         i_dst_stride  = p_pic->p[i_plane].i_pitch;\r
823 \r
824         for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )\r
825         {\r
826             p_dec->p_vlc->pf_memcpy( p_dst, p_src, i_width );\r
827             p_src += i_width;\r
828             p_dst += i_dst_stride;\r
829         }\r
830     }\r
831 \r
832     p_dst = p_pic->p[1].p_pixels;\r
833     p_pic->p[1].p_pixels = p_pic->p[2].p_pixels;\r
834     p_pic->p[2].p_pixels = p_dst;\r
835 }\r