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