]> git.sesse.net Git - vlc/blob - modules/codec/dmo/dmo.c
* modules/codec/dmo/*: added dmo encoder (can't get video encoding to work though).
[vlc] / modules / codec / dmo / dmo.c
1 /*****************************************************************************
2  * dmo.c : DirectMedia Object decoder module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002, 2003 VideoLAN
5  * $Id$
6  *
7  * Author: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #define DMO_DEBUG 1
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/decoder.h>
34 #include <vlc/vout.h>
35
36 #ifndef WIN32
37 #    define LOADER
38 #else
39 #   include <objbase.h>
40 #endif
41
42 #ifdef LOADER
43 /* Need the w32dll loader from mplayer */
44 #   include <wine/winerror.h>
45 #   include <ldt_keeper.h>
46 #   include <wine/windef.h>
47 #endif
48
49 #include "codecs.h"
50 #include "dmo.h"
51
52 #ifdef LOADER
53 /* Not Needed */
54 long CoInitialize( void *pvReserved ) { return -1; }
55 void CoUninitialize( void ) { }
56
57 /* A few prototypes */
58 HMODULE WINAPI LoadLibraryA(LPCSTR);
59 #define LoadLibrary LoadLibraryA
60 FARPROC WINAPI GetProcAddress(HMODULE,LPCSTR);
61 int     WINAPI FreeLibrary(HMODULE);
62 typedef long STDCALL (*GETCLASS) ( const GUID*, const GUID*, void** );
63 #endif /* LOADER */
64
65 static int pi_channels_maps[7] =
66 {
67     0,
68     AOUT_CHAN_CENTER,
69     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
70     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
71     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
72      | AOUT_CHAN_REARRIGHT,
73     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
74      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
75     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
76      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
77 };
78
79 /*****************************************************************************
80  * Module descriptor
81  *****************************************************************************/
82 static int  DecoderOpen  ( vlc_object_t * );
83 static int  DecOpen      ( vlc_object_t * );
84 static void DecoderClose ( vlc_object_t * );
85 static void *DecodeBlock ( decoder_t *, block_t ** );
86
87 static int  EncoderOpen  ( vlc_object_t * );
88 static int  EncOpen      ( vlc_object_t * );
89 static void EncoderClose ( vlc_object_t * );
90 static block_t *EncodeBlock( encoder_t *, void * );
91
92 static int LoadDMO( vlc_object_t *, HINSTANCE *, IMediaObject **,
93                     es_format_t *, vlc_bool_t );
94 static void CopyPicture( decoder_t *, picture_t *, uint8_t * );
95
96 vlc_module_begin();
97     set_description( _("DirectMedia Object decoder") );
98     add_shortcut( "dmo" );
99     set_capability( "decoder", 1 );
100     set_callbacks( DecoderOpen, DecoderClose );
101
102 #   define ENC_CFG_PREFIX "sout-dmo-"
103     add_submodule();
104     set_description( _("DirectMedia Object encoder") );
105     set_capability( "encoder", 10 );
106     set_callbacks( EncoderOpen, EncoderClose );
107
108 vlc_module_end();
109
110 /*****************************************************************************
111  * Local prototypes
112  *****************************************************************************/
113
114 /****************************************************************************
115  * Decoder descriptor declaration
116  ****************************************************************************/
117 struct decoder_sys_t
118 {
119     HINSTANCE hmsdmo_dll;
120     IMediaObject *p_dmo;
121
122     int i_min_output;
123     uint8_t *p_buffer;
124
125     date_t end_date;
126
127 #ifdef LOADER
128     ldt_fs_t    *ldt_fs;
129 #endif
130 };
131
132 #ifdef LOADER
133 static const GUID guid_wmv9 = { 0x724bb6a4, 0xe526, 0x450f, { 0xaf, 0xfa, 0xab, 0x9b, 0x45, 0x12, 0x91, 0x11 } };
134 static const GUID guid_wma9 = { 0x27ca0808, 0x01f5, 0x4e7a, { 0x8b, 0x05, 0x87, 0xf8, 0x07, 0xa2, 0x33, 0xd1 } };
135
136 static const GUID guid_wmv = { 0x82d353df, 0x90bd, 0x4382, { 0x8b, 0xc2, 0x3f, 0x61, 0x92, 0xb7, 0x6e, 0x34 } };
137 static const GUID guid_wma = { 0x874131cb, 0x4ecc, 0x443b, { 0x89, 0x48, 0x74, 0x6b, 0x89, 0x59, 0x5d, 0x20 } };
138
139 static const GUID guid_wmv_enc = { 0x3181343b, 0x94a2, 0x4feb, { 0xad, 0xef, 0x30, 0xa1, 0xdd, 0xe6, 0x17, 0xb4 } };
140 static const GUID guid_wma_enc = { 0x70f598e9, 0xf4ab, 0x495a, { 0x99, 0xe2, 0xa7, 0xc4, 0xd3, 0xd8, 0x9a, 0xbf } };
141
142 typedef struct
143 {
144     vlc_fourcc_t i_fourcc;
145     const char   *psz_dll;
146     const GUID   *p_guid;
147
148 } codec_dll;
149
150 static const codec_dll decoders_table[] =
151 {
152     /* WM3 */
153     { VLC_FOURCC('W','M','V','3'), "wmv9dmod.dll", &guid_wmv9 },
154     { VLC_FOURCC('w','m','v','3'), "wmv9dmod.dll", &guid_wmv9 },
155     /* WMV2 */
156     { VLC_FOURCC('W','M','V','2'), "wmvdmod.dll", &guid_wmv },
157     { VLC_FOURCC('w','m','v','2'), "wmvdmod.dll", &guid_wmv },
158     /* WMV1 */
159     { VLC_FOURCC('W','M','V','1'), "wmvdmod.dll", &guid_wmv },
160     { VLC_FOURCC('w','m','v','1'), "wmvdmod.dll", &guid_wmv },
161
162     /* WMA 3 */
163     { VLC_FOURCC('W','M','A','3'), "wma9dmod.dll", &guid_wma9 },
164     { VLC_FOURCC('w','m','a','3'), "wma9dmod.dll", &guid_wma9 },
165     /* WMA 2 */
166     { VLC_FOURCC('W','M','A','2'), "wma9dmod.dll", &guid_wma9 },
167     { VLC_FOURCC('w','m','a','2'), "wma9dmod.dll", &guid_wma9 },
168
169     /* */
170     { 0, NULL, NULL }
171 };
172
173 static const codec_dll encoders_table[] =
174 {
175     /* WMV2 */
176     { VLC_FOURCC('W','M','V','2'), "wmvdmoe.dll", &guid_wmv_enc },
177     { VLC_FOURCC('w','m','v','1'), "wmvdmoe.dll", &guid_wmv_enc },
178     /* WMV1 */
179     { VLC_FOURCC('W','M','V','1'), "wmvdmoe.dll", &guid_wmv_enc },
180     { VLC_FOURCC('w','m','v','1'), "wmvdmoe.dll", &guid_wmv_enc },
181
182     /* WMA 3 */
183     { VLC_FOURCC('W','M','A','3'), "wmadmoe.dll", &guid_wma_enc },
184     { VLC_FOURCC('w','m','a','3'), "wmadmoe.dll", &guid_wma_enc },
185     /* WMA 2 */
186     { VLC_FOURCC('W','M','A','2'), "wmadmoe.dll", &guid_wma_enc },
187     { VLC_FOURCC('w','m','a','2'), "wmadmoe.dll", &guid_wma_enc },
188
189     /* */
190     { 0, NULL, NULL }
191 };
192
193 #endif /* LOADER */
194
195 static void WINAPI DMOFreeMediaType( DMO_MEDIA_TYPE *mt )
196 {
197     if( mt->cbFormat != 0 ) CoTaskMemFree( (PVOID)mt->pbFormat );
198     if( mt->pUnk != NULL ) mt->pUnk->vt->Release( (IUnknown *)mt->pUnk );
199     mt->cbFormat = 0;
200     mt->pbFormat = NULL;
201     mt->pUnk = NULL;
202 }
203
204 /*****************************************************************************
205  * DecoderOpen: open dmo codec
206  *****************************************************************************/
207 static int DecoderOpen( vlc_object_t *p_this )
208 {
209     decoder_t *p_dec = (decoder_t*)p_this;
210
211 #ifndef LOADER
212     int i_ret = DecOpen( p_this );
213     if( i_ret != VLC_SUCCESS ) return i_ret;
214
215
216 #else
217     /* We can't open it now, because of ldt_keeper or something
218      * Open/Decode/Close has to be done in the same thread */
219     int i;
220
221     p_dec->p_sys = NULL;
222
223     /* Probe if we support it */
224     for( i = 0; decoders_table[i].i_fourcc != 0; i++ )
225     {
226         if( decoders_table[i].i_fourcc == p_dec->fmt_in.i_codec )
227         {
228             msg_Dbg( p_dec, "DMO codec for %4.4s may work with dll=%s",
229                      (char*)&p_dec->fmt_in.i_codec,
230                      decoders_table[i].psz_dll );
231             break;
232         }
233     }
234
235     p_dec->p_sys = NULL;
236     if( !decoders_table[i].i_fourcc ) return VLC_EGENERIC;
237 #endif /* LOADER */
238
239     /* Set callbacks */
240     p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
241         DecodeBlock;
242     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
243         DecodeBlock;
244
245     return VLC_SUCCESS;
246 }
247
248 /*****************************************************************************
249  * DecOpen: open dmo codec
250  *****************************************************************************/
251 static int DecOpen( vlc_object_t *p_this )
252 {
253     decoder_t *p_dec = (decoder_t*)p_this;
254     decoder_sys_t *p_sys = NULL;
255
256     DMO_MEDIA_TYPE dmo_input_type, dmo_output_type;
257     IMediaObject *p_dmo = NULL;
258     HINSTANCE hmsdmo_dll = NULL;
259
260     VIDEOINFOHEADER *p_vih = NULL;
261     WAVEFORMATEX *p_wf = NULL;
262
263 #ifdef LOADER
264     ldt_fs_t *ldt_fs = Setup_LDT_Keeper();
265 #else
266     /* Initialize OLE/COM */
267     CoInitialize( 0 );
268 #endif /* LOADER */
269
270     if( LoadDMO( p_this, &hmsdmo_dll, &p_dmo, &p_dec->fmt_in, VLC_FALSE )
271         != VLC_SUCCESS )
272     {
273         hmsdmo_dll = 0;
274         p_dmo = 0;
275         goto error;
276     }
277
278     /* Setup input format */
279     memset( &dmo_input_type, 0, sizeof(dmo_input_type) );
280     dmo_input_type.pUnk = 0;
281
282     if( p_dec->fmt_in.i_cat == AUDIO_ES )
283     {
284         uint16_t i_tag;
285         int i_size = sizeof(WAVEFORMATEX) + p_dec->fmt_in.i_extra;
286         p_wf = malloc( i_size );
287
288         memset( p_wf, 0, sizeof(WAVEFORMATEX) );
289         if( p_dec->fmt_in.i_extra )
290             memcpy( &p_wf[1], p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra );
291
292         dmo_input_type.majortype  = MEDIATYPE_Audio;
293         dmo_input_type.subtype    = dmo_input_type.majortype;
294         dmo_input_type.subtype.Data1 = p_dec->fmt_in.i_codec;
295         fourcc_to_wf_tag( p_dec->fmt_in.i_codec, &i_tag );
296         if( i_tag ) dmo_input_type.subtype.Data1 = i_tag;
297
298         p_wf->wFormatTag = dmo_input_type.subtype.Data1;
299         p_wf->nSamplesPerSec = p_dec->fmt_in.audio.i_rate;
300         p_wf->nChannels = p_dec->fmt_in.audio.i_channels;
301         p_wf->wBitsPerSample = p_dec->fmt_in.audio.i_bitspersample;
302         p_wf->nBlockAlign = p_dec->fmt_in.audio.i_blockalign;
303         p_wf->nAvgBytesPerSec = p_dec->fmt_in.i_bitrate / 8;
304         p_wf->cbSize = p_dec->fmt_in.i_extra;
305
306         dmo_input_type.formattype = FORMAT_WaveFormatEx;
307         dmo_input_type.cbFormat   = i_size;
308         dmo_input_type.pbFormat   = (char *)p_wf;
309         dmo_input_type.bFixedSizeSamples = 1;
310         dmo_input_type.bTemporalCompression = 0;
311         dmo_input_type.lSampleSize = p_wf->nBlockAlign;
312     }
313     else
314     {
315         BITMAPINFOHEADER *p_bih;
316
317         int i_size = sizeof(VIDEOINFOHEADER) + p_dec->fmt_in.i_extra;
318         p_vih = malloc( i_size );
319
320         memset( p_vih, 0, sizeof(VIDEOINFOHEADER) );
321         if( p_dec->fmt_in.i_extra )
322             memcpy( &p_vih[1], p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra );
323
324         p_bih = &p_vih->bmiHeader;
325         p_bih->biCompression = p_dec->fmt_in.i_codec;
326         p_bih->biWidth = p_dec->fmt_in.video.i_width;
327         p_bih->biHeight = p_dec->fmt_in.video.i_height;
328         p_bih->biBitCount = p_dec->fmt_in.video.i_bits_per_pixel;
329         p_bih->biPlanes = 1;
330         p_bih->biSize = i_size - sizeof(VIDEOINFOHEADER) +
331             sizeof(BITMAPINFOHEADER);
332
333         p_vih->rcSource.left = p_vih->rcSource.top = 0;
334         p_vih->rcSource.right = p_dec->fmt_in.video.i_width;
335         p_vih->rcSource.bottom = p_dec->fmt_in.video.i_height;
336         p_vih->rcTarget = p_vih->rcSource;
337
338         dmo_input_type.majortype  = MEDIATYPE_Video;
339         dmo_input_type.subtype    = dmo_input_type.majortype;
340         dmo_input_type.subtype.Data1 = p_dec->fmt_in.i_codec;
341         dmo_input_type.formattype = FORMAT_VideoInfo;
342         dmo_input_type.bFixedSizeSamples = 0;
343         dmo_input_type.bTemporalCompression = 1;
344         dmo_input_type.cbFormat = i_size;
345         dmo_input_type.pbFormat = (char *)p_vih;
346     }
347
348     if( p_dmo->vt->SetInputType( p_dmo, 0, &dmo_input_type, 0 ) )
349     {
350         msg_Err( p_dec, "can't set DMO input type" );
351         goto error;
352     }
353     msg_Dbg( p_dec, "DMO input type set" );
354
355     /* Setup output format */
356     memset( &dmo_output_type, 0, sizeof(dmo_output_type) );
357     dmo_output_type.pUnk = 0;
358
359     if( p_dec->fmt_in.i_cat == AUDIO_ES )
360     {
361         /* Setup the format */
362         p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE;
363         p_dec->fmt_out.audio.i_rate     = p_dec->fmt_in.audio.i_rate;
364         p_dec->fmt_out.audio.i_channels = p_dec->fmt_in.audio.i_channels;
365         p_dec->fmt_out.audio.i_bitspersample = 16;//p_dec->fmt_in.audio.i_bitspersample; We request 16
366         p_dec->fmt_out.audio.i_physical_channels =
367             p_dec->fmt_out.audio.i_original_channels =
368                 pi_channels_maps[p_dec->fmt_out.audio.i_channels];
369
370         p_wf->wFormatTag = WAVE_FORMAT_PCM;
371         p_wf->nSamplesPerSec = p_dec->fmt_out.audio.i_rate;
372         p_wf->nChannels = p_dec->fmt_out.audio.i_channels;
373         p_wf->wBitsPerSample = p_dec->fmt_out.audio.i_bitspersample;
374         p_wf->nBlockAlign =
375             p_wf->wBitsPerSample / 8 * p_wf->nChannels;
376         p_wf->nAvgBytesPerSec =
377             p_wf->nSamplesPerSec * p_wf->nBlockAlign;
378         p_wf->cbSize = 0;
379
380         dmo_output_type.majortype  = MEDIATYPE_Audio;
381         dmo_output_type.formattype = FORMAT_WaveFormatEx;
382         dmo_output_type.subtype    = MEDIASUBTYPE_PCM;
383         dmo_output_type.cbFormat   = sizeof(WAVEFORMATEX);
384         dmo_output_type.pbFormat   = (char *)p_wf;
385         dmo_output_type.bFixedSizeSamples = 1;
386         dmo_output_type.bTemporalCompression = 0;
387         dmo_output_type.lSampleSize = p_wf->nBlockAlign;
388     }
389     else
390     {
391         BITMAPINFOHEADER *p_bih;
392
393         p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');
394         p_dec->fmt_out.video.i_width = p_dec->fmt_in.video.i_width;
395         p_dec->fmt_out.video.i_height = p_dec->fmt_in.video.i_height;
396         p_dec->fmt_out.video.i_bits_per_pixel = 12;
397         p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
398             p_dec->fmt_out.video.i_width / p_dec->fmt_out.video.i_height;
399
400         dmo_output_type.formattype = FORMAT_VideoInfo;
401         dmo_output_type.subtype = MEDIASUBTYPE_YV12;
402
403         p_bih = &p_vih->bmiHeader;
404         p_bih->biCompression = VLC_FOURCC('Y','V','1','2');
405         p_bih->biHeight *= -1;
406         p_bih->biBitCount = p_dec->fmt_out.video.i_bits_per_pixel;
407         p_bih->biSizeImage = p_dec->fmt_in.video.i_width *
408             p_dec->fmt_in.video.i_height *
409             (p_dec->fmt_in.video.i_bits_per_pixel + 7) / 8;
410
411         //p_bih->biPlanes = 1;
412         p_bih->biSize = sizeof(BITMAPINFOHEADER);
413
414         dmo_output_type.majortype = MEDIATYPE_Video;
415         dmo_output_type.bFixedSizeSamples = VLC_TRUE;
416         dmo_output_type.bTemporalCompression = 0;
417         dmo_output_type.lSampleSize = p_bih->biSizeImage;
418         dmo_output_type.cbFormat = sizeof(VIDEOINFOHEADER);
419         dmo_output_type.pbFormat = (char *)p_vih;
420     }
421
422 #ifdef DMO_DEBUG
423     /* Enumerate output types */
424     if( p_dec->fmt_in.i_cat == VIDEO_ES )
425     {
426         int i = 0;
427         DMO_MEDIA_TYPE mt;
428
429         while( !p_dmo->vt->GetOutputType( p_dmo, 0, i++, &mt ) )
430         {
431             msg_Dbg( p_dec, "available output chroma: %4.4s",
432                      (char *)&mt.subtype.Data1 );
433             DMOFreeMediaType( &mt );
434         }
435     }
436 #endif
437
438     if( p_dmo->vt->SetOutputType( p_dmo, 0, &dmo_output_type, 0 ) )
439     {
440         msg_Err( p_dec, "can't set DMO output type" );
441         goto error;
442     }
443     msg_Dbg( p_dec, "DMO output type set" );
444
445     /* Allocate the memory needed to store the decoder's structure */
446     if( ( p_dec->p_sys = p_sys =
447           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
448     {
449         msg_Err( p_dec, "out of memory" );
450         goto error;
451     }
452
453     p_sys->hmsdmo_dll = hmsdmo_dll;
454     p_sys->p_dmo = p_dmo;
455 #ifdef LOADER
456     p_sys->ldt_fs = ldt_fs;
457 #endif
458
459     /* Find out some properties of the output */
460     {
461         uint32_t i_size, i_align;
462
463         p_sys->i_min_output = 0;
464         if( p_dmo->vt->GetOutputSizeInfo( p_dmo, 0, &i_size, &i_align ) )
465         {
466             msg_Err( p_dec, "GetOutputSizeInfo() failed" );
467             goto error;
468         }
469         else
470         {
471             msg_Dbg( p_dec, "GetOutputSizeInfo(): bytes %i, align %i",
472                      i_size, i_align );
473             p_sys->i_min_output = i_size;
474             p_sys->p_buffer = malloc( i_size );
475             if( !p_sys->p_buffer ) goto error;
476         }
477     }
478
479     /* Set output properties */
480     p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
481     if( p_dec->fmt_out.i_cat == AUDIO_ES )
482         date_Init( &p_sys->end_date, p_dec->fmt_in.audio.i_rate, 1 );
483     else
484         date_Init( &p_sys->end_date, 25 /* FIXME */, 1 );
485
486     if( p_vih ) free( p_vih );
487     if( p_wf ) free( p_wf );
488
489     return VLC_SUCCESS;
490
491  error:
492
493     if( p_dmo ) p_dmo->vt->Release( (IUnknown *)p_dmo );
494     if( hmsdmo_dll ) FreeLibrary( hmsdmo_dll );
495
496 #ifdef LOADER
497     Restore_LDT_Keeper( ldt_fs );
498 #else
499     /* Uninitialize OLE/COM */
500     CoUninitialize();
501 #endif /* LOADER */
502
503     if( p_vih ) free( p_vih );
504     if( p_wf )  free( p_wf );
505     if( p_sys ) free( p_sys );
506
507     return VLC_EGENERIC;
508 }
509
510 /*****************************************************************************
511  * LoadDMO: Load the DMO object
512  *****************************************************************************/
513 static int LoadDMO( vlc_object_t *p_this, HINSTANCE *p_hmsdmo_dll,
514                     IMediaObject **pp_dmo, es_format_t *p_fmt,
515                     vlc_bool_t b_out )
516 {
517     DMO_PARTIAL_MEDIATYPE dmo_partial_type;
518     int i_err;
519
520 #ifndef LOADER
521     IEnumDMO *p_enum_dmo = NULL;
522     WCHAR *psz_dmo_name;
523     GUID clsid_dmo;
524 #else
525
526     GETCLASS GetClass;
527     IClassFactory *cFactory = NULL;
528     IUnknown *cObject = NULL;
529     codec_dll *codecs_table = b_out ? encoders_table : decoders_table;
530     int i_codec;
531 #endif
532
533     /* Look for a DMO which can handle the requested codec */
534     if( p_fmt->i_cat == AUDIO_ES )
535     {
536         uint16_t i_tag;
537         dmo_partial_type.type = MEDIATYPE_Audio;
538         dmo_partial_type.subtype = dmo_partial_type.type;
539         dmo_partial_type.subtype.Data1 = p_fmt->i_codec;
540         fourcc_to_wf_tag( p_fmt->i_codec, &i_tag );
541         if( i_tag ) dmo_partial_type.subtype.Data1 = i_tag;
542     }
543     else
544     {
545         dmo_partial_type.type = MEDIATYPE_Video;
546         dmo_partial_type.subtype = dmo_partial_type.type;
547         dmo_partial_type.subtype.Data1 = p_fmt->i_codec;
548     }
549
550 #ifndef LOADER
551     long (STDCALL *OurDMOEnum)( const GUID *, uint32_t, uint32_t,
552                                const DMO_PARTIAL_MEDIATYPE *,
553                                uint32_t, const DMO_PARTIAL_MEDIATYPE *,
554                                IEnumDMO ** );
555
556     /* Load msdmo DLL */
557     *p_hmsdmo_dll = LoadLibrary( "msdmo.dll" );
558     if( *p_hmsdmo_dll == NULL )
559     {
560         msg_Dbg( p_this, "failed loading msdmo.dll" );
561         return VLC_EGENERIC;
562     }
563     OurDMOEnum = (void *)GetProcAddress( *p_hmsdmo_dll, "DMOEnum" );
564     if( OurDMOEnum == NULL )
565     {
566         msg_Dbg( p_this, "GetProcAddress failed to find DMOEnum()" );
567         FreeLibrary( *p_hmsdmo_dll );
568         return VLC_EGENERIC;
569     }
570
571     if( !b_out )
572     {
573         i_err = OurDMOEnum( &GUID_NULL, 1 /*DMO_ENUMF_INCLUDE_KEYED*/,
574                             1, &dmo_partial_type, 0, NULL, &p_enum_dmo );
575     }
576     else
577     {
578         i_err = OurDMOEnum( &GUID_NULL, 1 /*DMO_ENUMF_INCLUDE_KEYED*/,
579                              0, NULL, 1, &dmo_partial_type, &p_enum_dmo );
580     }
581     if( i_err )
582     {
583         CoUninitialize();
584         FreeLibrary( *p_hmsdmo_dll );
585         return VLC_EGENERIC;
586     }
587
588     /* Pickup the first available codec */
589     if( p_enum_dmo->vt->Next( p_enum_dmo, 1, &clsid_dmo,
590                               &psz_dmo_name, NULL ) )
591     {
592         CoUninitialize();
593         FreeLibrary( *p_hmsdmo_dll );
594         return VLC_EGENERIC;
595     }
596     p_enum_dmo->vt->Release( (IUnknown *)p_enum_dmo );
597
598 #if 1
599     {
600         char psz_temp[MAX_PATH];
601         wcstombs( psz_temp, psz_dmo_name, MAX_PATH );
602         msg_Dbg( p_this, "found DMO: %s", psz_temp );
603     }
604 #endif
605
606     CoTaskMemFree( psz_dmo_name );
607
608     /* Create DMO */
609     if( CoCreateInstance( &clsid_dmo, NULL, CLSCTX_INPROC,
610                           &IID_IMediaObject, (void **)pp_dmo ) )
611     {
612         msg_Err( p_this, "can't create DMO" );
613         CoUninitialize();
614         FreeLibrary( *p_hmsdmo_dll );
615         return VLC_EGENERIC;
616     }
617
618 #else   /* LOADER */
619     for( i_codec = 0; codecs_table[i_codec].i_fourcc != 0; i_codec++ )
620     {
621         if( codecs_table[i_codec].i_fourcc == p_fmt->i_codec )
622             break;
623     }
624     if( codecs_table[i_codec].i_fourcc == 0 )
625         return VLC_EGENERIC;    /* Can't happen */
626
627     *p_hmsdmo_dll = LoadLibrary( codecs_table[i_codec].psz_dll );
628     if( *p_hmsdmo_dll == NULL )
629     {
630         msg_Dbg( p_this, "failed loading '%s'",
631                  codecs_table[i_codec].psz_dll );
632         return VLC_EGENERIC;
633     }
634
635     GetClass = (GETCLASS)GetProcAddress( *p_hmsdmo_dll, "DllGetClassObject" );
636     if (!GetClass)
637     {
638         msg_Dbg( p_this, "GetProcAddress failed to find DllGetClassObject()" );
639         FreeLibrary( *p_hmsdmo_dll );
640         return VLC_EGENERIC;
641     }
642
643     i_err = GetClass( codecs_table[i_codec].p_guid, &IID_IClassFactory,
644                       (void**)&cFactory );
645     if( i_err || cFactory == NULL )
646     {
647         msg_Dbg( p_this, "no such class object" );
648         FreeLibrary( *p_hmsdmo_dll );
649         return VLC_EGENERIC;
650     }
651
652     i_err = cFactory->vt->CreateInstance( cFactory, 0, &IID_IUnknown,
653                                           (void**)&cObject );
654     cFactory->vt->Release( (IUnknown*)cFactory );
655     if( i_err || !cObject )
656     {
657         msg_Dbg( p_this, "class factory failure" );
658         FreeLibrary( *p_hmsdmo_dll );
659         return VLC_EGENERIC;
660     }
661     i_err = cObject->vt->QueryInterface( cObject, &IID_IMediaObject,
662                                         (void**)pp_dmo );
663     cObject->vt->Release( (IUnknown*)cObject );
664     if( i_err || !*pp_dmo )
665     {
666         msg_Dbg( p_this, "QueryInterface failure" );
667         FreeLibrary( *p_hmsdmo_dll );
668         return VLC_EGENERIC;
669     }
670 #endif  /* LOADER */
671
672     return VLC_SUCCESS;
673 }
674
675 /*****************************************************************************
676  * DecoderClose: close codec
677  *****************************************************************************/
678 void DecoderClose( vlc_object_t *p_this )
679 {
680     decoder_t *p_dec = (decoder_t*)p_this;
681     decoder_sys_t *p_sys = p_dec->p_sys;
682
683     if( !p_sys ) return;
684
685     FreeLibrary( p_sys->hmsdmo_dll );
686
687 #ifdef LOADER
688 #if 0
689     Restore_LDT_Keeper( p_sys->ldt_fs );
690 #endif
691 #else
692     /* Uninitialize OLE/COM */
693     CoUninitialize();
694 #endif
695
696     if( p_sys->p_buffer ) free( p_sys->p_buffer );
697     free( p_sys );
698 }
699
700 /****************************************************************************
701  * DecodeBlock: the whole thing
702  ****************************************************************************
703  * This function must be fed with ogg packets.
704  ****************************************************************************/
705 static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
706 {
707     decoder_sys_t *p_sys = p_dec->p_sys;
708     block_t *p_block;
709     int i_result;
710
711     DMO_OUTPUT_DATA_BUFFER db;
712     CMediaBuffer *p_out;
713     block_t block_out;
714     uint32_t i_status;
715
716     if( p_sys == NULL )
717     {
718         if( DecOpen( VLC_OBJECT(p_dec) ) )
719         {
720             msg_Err( p_dec, "DecOpen failed" );
721             return NULL;
722         }
723         p_sys = p_dec->p_sys;
724     }
725
726     if( !pp_block ) return NULL;
727
728     p_block = *pp_block;
729
730     /* Won't work with streams with B-frames, but do we have any ? */
731     if( p_block && p_block->i_pts <= 0 ) p_block->i_pts = p_block->i_dts;
732
733     /* Date management */
734     if( p_block && p_block->i_pts > 0 &&
735         p_block->i_pts != date_Get( &p_sys->end_date ) )
736     {
737         date_Set( &p_sys->end_date, p_block->i_pts );
738     }
739
740 #if 0 /* Breaks the video decoding */
741     if( !date_Get( &p_sys->end_date ) )
742     {
743         /* We've just started the stream, wait for the first PTS. */
744         if( p_block ) block_Release( p_block );
745         return NULL;
746     }
747 #endif
748
749     /* Feed input to the DMO */
750     if( p_block && p_block->i_buffer )
751     {
752         CMediaBuffer *p_in;
753
754         p_in = CMediaBufferCreate( p_block, p_block->i_buffer, VLC_TRUE );
755
756         i_result = p_sys->p_dmo->vt->ProcessInput( p_sys->p_dmo, 0,
757                        (IMediaBuffer *)p_in, DMO_INPUT_DATA_BUFFER_SYNCPOINT,
758                        0, 0 );
759
760         p_in->vt->Release( (IUnknown *)p_in );
761
762         if( i_result == S_FALSE )
763         {
764             /* No output generated */
765 #ifdef DMO_DEBUG
766             msg_Dbg( p_dec, "ProcessInput(): no output generated" );
767 #endif
768             return NULL;
769         }
770         else if( i_result == DMO_E_NOTACCEPTING )
771         {
772             /* Need to call ProcessOutput */
773             msg_Dbg( p_dec, "ProcessInput(): not accepting" );
774         }
775         else if( i_result != S_OK )
776         {
777             msg_Dbg( p_dec, "ProcessInput(): failed" );
778             return NULL;
779         }
780         else
781         {
782             //msg_Dbg( p_dec, "ProcessInput(): successful" );
783             *pp_block = 0;
784         }
785     }
786     else if( p_block && !p_block->i_buffer )
787     {
788         block_Release( p_block );
789         *pp_block = 0;
790     }
791
792     /* Get output from the DMO */
793     block_out.p_buffer = p_sys->p_buffer;
794     block_out.i_buffer = 0;
795
796     p_out = CMediaBufferCreate( &block_out, p_sys->i_min_output, VLC_FALSE );
797     memset( &db, 0, sizeof(db) );
798     db.pBuffer = (IMediaBuffer *)p_out;
799
800     i_result = p_sys->p_dmo->vt->ProcessOutput( p_sys->p_dmo,
801                    DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER,
802                    1, &db, &i_status );
803
804     if( i_result != S_OK )
805     {
806         if( i_result != S_FALSE )
807             msg_Dbg( p_dec, "ProcessOutput(): failed" );
808 #if DMO_DEBUG
809         else
810             msg_Dbg( p_dec, "ProcessOutput(): no output" );
811 #endif
812
813         p_out->vt->Release( (IUnknown *)p_out );
814         return NULL;
815     }
816
817 #if DMO_DEBUG
818     msg_Dbg( p_dec, "ProcessOutput(): success" );
819 #endif
820
821     if( !block_out.i_buffer )
822     {
823 #if DMO_DEBUG
824         msg_Dbg( p_dec, "ProcessOutput(): no output (i_buffer_out == 0)" );
825 #endif
826         p_out->vt->Release( (IUnknown *)p_out );
827         return NULL;
828     }
829
830     if( p_dec->fmt_out.i_cat == VIDEO_ES )
831     {
832         /* Get a new picture */
833         picture_t *p_pic = p_dec->pf_vout_buffer_new( p_dec );
834         if( !p_pic ) return NULL;
835
836         CopyPicture( p_dec, p_pic, block_out.p_buffer );
837
838         /* Date management */
839         p_pic->date = date_Get( &p_sys->end_date );
840         date_Increment( &p_sys->end_date, 1 );
841
842         p_out->vt->Release( (IUnknown *)p_out );
843
844         return p_pic;
845     }
846     else
847     {
848         aout_buffer_t *p_aout_buffer;
849         int i_samples = block_out.i_buffer /
850             ( p_dec->fmt_out.audio.i_bitspersample *
851               p_dec->fmt_out.audio.i_channels / 8 );
852
853         p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, i_samples );
854         memcpy( p_aout_buffer->p_buffer,
855                 block_out.p_buffer, block_out.i_buffer );
856
857         /* Date management */
858         p_aout_buffer->start_date = date_Get( &p_sys->end_date );
859         p_aout_buffer->end_date =
860             date_Increment( &p_sys->end_date, i_samples );
861
862         p_out->vt->Release( (IUnknown *)p_out );
863
864         return p_aout_buffer;
865     }
866
867     return NULL;
868 }
869
870 static void CopyPicture( decoder_t *p_dec, picture_t *p_pic, uint8_t *p_in )
871 {
872     int i_plane, i_line, i_width, i_dst_stride;
873     uint8_t *p_dst, *p_src = p_in;
874
875     p_dst = p_pic->p[1].p_pixels;
876     p_pic->p[1].p_pixels = p_pic->p[2].p_pixels;
877     p_pic->p[2].p_pixels = p_dst;
878
879     for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
880     {
881         p_dst = p_pic->p[i_plane].p_pixels;
882         i_width = p_pic->p[i_plane].i_visible_pitch;
883         i_dst_stride  = p_pic->p[i_plane].i_pitch;
884
885         for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
886         {
887             p_dec->p_vlc->pf_memcpy( p_dst, p_src, i_width );
888             p_src += i_width;
889             p_dst += i_dst_stride;
890         }
891     }
892
893     p_dst = p_pic->p[1].p_pixels;
894     p_pic->p[1].p_pixels = p_pic->p[2].p_pixels;
895     p_pic->p[2].p_pixels = p_dst;
896 }
897
898 /****************************************************************************
899  * Encoder descriptor declaration
900  ****************************************************************************/
901 struct encoder_sys_t
902 {
903     HINSTANCE hmsdmo_dll;
904     IMediaObject *p_dmo;
905
906     int i_min_output;
907
908     date_t end_date;
909
910 #ifdef LOADER
911     ldt_fs_t    *ldt_fs;
912 #endif
913 };
914
915 /*****************************************************************************
916  * EncoderOpen: open dmo codec
917  *****************************************************************************/
918 static int EncoderOpen( vlc_object_t *p_this )
919 {
920     encoder_t *p_enc = (encoder_t*)p_this;
921
922 #ifndef LOADER
923     int i_ret = EncOpen( p_this );
924     if( i_ret != VLC_SUCCESS ) return i_ret;
925
926 #else
927     /* We can't open it now, because of ldt_keeper or something
928      * Open/Encode/Close has to be done in the same thread */
929     int i;
930
931     /* Probe if we support it */
932     for( i = 0; encoders_table[i].i_fourcc != 0; i++ )
933     {
934         if( encoders_table[i].i_fourcc == p_enc->fmt_out.i_codec )
935         {
936             msg_Dbg( p_enc, "DMO codec for %4.4s may work with dll=%s",
937                      (char*)&p_enc->fmt_out.i_codec,
938                      encoders_table[i].psz_dll );
939             break;
940         }
941     }
942
943     p_enc->p_sys = NULL;
944     if( !encoders_table[i].i_fourcc ) return VLC_EGENERIC;
945 #endif /* LOADER */
946
947     /* Set callbacks */
948     p_enc->pf_encode_video = (block_t *(*)(encoder_t *, picture_t *))
949         EncodeBlock;
950     p_enc->pf_encode_audio = (block_t *(*)(encoder_t *, aout_buffer_t *))
951         EncodeBlock;
952
953     return VLC_SUCCESS;
954 }
955
956 /*****************************************************************************
957  * EncoderSetVideoType: configures the input and output types of the dmo
958  *****************************************************************************/
959 static int EncoderSetVideoType( encoder_t *p_enc, IMediaObject *p_dmo )
960 {
961     int i, i_selected, i_err;
962     DMO_MEDIA_TYPE dmo_type;
963     VIDEOINFOHEADER vih, *p_vih;
964     BITMAPINFOHEADER *p_bih;
965
966     /* FIXME */
967     p_enc->fmt_in.video.i_bits_per_pixel = 
968         p_enc->fmt_out.video.i_bits_per_pixel = 12;
969
970     /* Enumerate input format (for debug output) */
971     i = 0;
972     while( !p_dmo->vt->GetInputType( p_dmo, 0, i++, &dmo_type ) )
973     {
974         p_vih = (VIDEOINFOHEADER *)dmo_type.pbFormat;
975
976         msg_Dbg( p_enc, "available input chroma: %4.4s",
977                  (char *)&dmo_type.subtype.Data1 );
978         if( !memcmp( &dmo_type.subtype, &MEDIASUBTYPE_RGB565, 16 ) )
979             msg_Dbg( p_enc, "-> MEDIASUBTYPE_RGB565" );
980         if( !memcmp( &dmo_type.subtype, &MEDIASUBTYPE_RGB24, 16 ) )
981             msg_Dbg( p_enc, "-> MEDIASUBTYPE_RGB24" );
982
983         DMOFreeMediaType( &dmo_type );
984     }
985
986     /* Setup input format */
987     memset( &dmo_type, 0, sizeof(dmo_type) );
988     dmo_type.pUnk = 0;
989     memset( &vih, 0, sizeof(VIDEOINFOHEADER) );
990
991     p_bih = &vih.bmiHeader;
992     p_bih->biCompression = VLC_FOURCC('I','4','2','0');
993     p_bih->biWidth = p_enc->fmt_in.video.i_width;
994     p_bih->biHeight = p_enc->fmt_in.video.i_height;
995     p_bih->biBitCount = p_enc->fmt_in.video.i_bits_per_pixel;
996     p_bih->biSizeImage = p_enc->fmt_in.video.i_width *
997         p_enc->fmt_in.video.i_height * p_enc->fmt_in.video.i_bits_per_pixel /8;
998     p_bih->biPlanes = 3;
999     p_bih->biSize = sizeof(BITMAPINFOHEADER);
1000
1001     vih.rcSource.left = vih.rcSource.top = 0;
1002     vih.rcSource.right = p_enc->fmt_in.video.i_width;
1003     vih.rcSource.bottom = p_enc->fmt_in.video.i_height;
1004     vih.rcTarget = vih.rcSource;
1005
1006     dmo_type.majortype = MEDIATYPE_Video;
1007     //dmo_type.subtype = MEDIASUBTYPE_RGB24;
1008     dmo_type.subtype = MEDIASUBTYPE_I420;
1009     //dmo_type.subtype.Data1 = p_bih->biCompression;
1010     dmo_type.formattype = FORMAT_VideoInfo;
1011     dmo_type.bFixedSizeSamples = TRUE;
1012     dmo_type.bTemporalCompression = FALSE;
1013     dmo_type.lSampleSize = p_bih->biSizeImage;
1014     dmo_type.cbFormat = sizeof(VIDEOINFOHEADER);
1015     dmo_type.pbFormat = (char *)&vih;
1016
1017     if( ( i_err = p_dmo->vt->SetInputType( p_dmo, 0, &dmo_type, 0 ) ) )
1018     {
1019         msg_Err( p_enc, "can't set DMO input type: %x", i_err );
1020         return VLC_EGENERIC;
1021     }
1022
1023     msg_Dbg( p_enc, "successfully set input type" );
1024
1025     /* Setup output format */
1026     memset( &dmo_type, 0, sizeof(dmo_type) );
1027     dmo_type.pUnk = 0;
1028
1029     /* Enumerate output types */
1030     i = 0, i_selected = -1;
1031     while( !p_dmo->vt->GetOutputType( p_dmo, 0, i++, &dmo_type ) )
1032     {
1033         p_vih = (VIDEOINFOHEADER *)dmo_type.pbFormat;
1034
1035         msg_Dbg( p_enc, "available output codec: %4.4s",
1036                  (char *)&dmo_type.subtype.Data1 );
1037
1038         if( p_vih->bmiHeader.biCompression == p_enc->fmt_out.i_codec )
1039             i_selected = i - 1;
1040
1041         DMOFreeMediaType( &dmo_type );
1042     }
1043
1044     if( i_selected < 0 )
1045     {
1046         msg_Err( p_enc, "couldn't find codec: %4.4s",
1047                  (char *)&p_enc->fmt_out.i_codec );
1048         return VLC_EGENERIC;
1049     }
1050
1051     p_dmo->vt->GetOutputType( p_dmo, 0, i_selected, &dmo_type );
1052     ((VIDEOINFOHEADER *)dmo_type.pbFormat)->dwBitRate =
1053         p_enc->fmt_out.i_bitrate;
1054
1055     i_err = p_dmo->vt->SetOutputType( p_dmo, 0, &dmo_type, 0 );
1056     DMOFreeMediaType( &dmo_type );
1057     if( i_err )
1058     {
1059         msg_Err( p_enc, "can't set DMO output type: %i", i_err );
1060         return VLC_EGENERIC;
1061     }
1062
1063     msg_Dbg( p_enc, "successfully set output type" );
1064     return VLC_SUCCESS;
1065 }
1066
1067 /*****************************************************************************
1068  * EncoderSetAudioType: configures the input and output types of the dmo
1069  *****************************************************************************/
1070 static int EncoderSetAudioType( encoder_t *p_enc, IMediaObject *p_dmo )
1071 {
1072     int i, i_selected, i_err;
1073     unsigned int i_last_byterate;
1074     uint16_t i_tag;
1075     DMO_MEDIA_TYPE dmo_type;
1076     WAVEFORMATEX *p_wf;
1077
1078     /* Setup the format structure */
1079     fourcc_to_wf_tag( p_enc->fmt_out.i_codec, &i_tag );
1080     if( i_tag == 0 ) return VLC_EGENERIC;
1081
1082     p_enc->fmt_in.audio.i_bitspersample = 16; // Forced
1083
1084     /* We first need to choose an output type from the predefined
1085      * list of choices (we cycle through the list to select the best match) */
1086     i = 0; i_selected = -1; i_last_byterate = 0;
1087     while( !p_dmo->vt->GetOutputType( p_dmo, 0, i++, &dmo_type ) )
1088     {
1089         p_wf = (WAVEFORMATEX *)dmo_type.pbFormat;
1090         msg_Dbg( p_enc, "available format :%i, sample rate: %i, channels: %i, "
1091                  "bits per sample: %i, bitrate: %i, blockalign: %i",
1092                  (int) p_wf->wFormatTag, (int)p_wf->nSamplesPerSec,
1093                  (int)p_wf->nChannels, (int)p_wf->wBitsPerSample,
1094                  (int)p_wf->nAvgBytesPerSec * 8, (int)p_wf->nBlockAlign );
1095
1096         if( p_wf->wFormatTag == i_tag &&
1097             p_wf->nSamplesPerSec == p_enc->fmt_in.audio.i_rate &&
1098             p_wf->nChannels == p_enc->fmt_in.audio.i_channels &&
1099             p_wf->wBitsPerSample == p_enc->fmt_in.audio.i_bitspersample )
1100         {
1101             if( (int)p_wf->nAvgBytesPerSec <
1102                 p_enc->fmt_out.i_bitrate * 110 / 800 /* + 10% */ &&
1103                 p_wf->nAvgBytesPerSec > i_last_byterate )
1104             {
1105                 i_selected = i - 1;
1106                 i_last_byterate = p_wf->nAvgBytesPerSec;
1107                 msg_Dbg( p_enc, "selected entry %i (bitrate: %i)",
1108                          i_selected, p_wf->nAvgBytesPerSec * 8 );
1109             }
1110         }
1111
1112         DMOFreeMediaType( &dmo_type );
1113     }
1114
1115     if( i_selected < 0 )
1116     {
1117         msg_Err( p_enc, "couldn't find a matching ouput" );
1118         return VLC_EGENERIC;
1119     }
1120
1121     p_dmo->vt->GetOutputType( p_dmo, 0, i_selected, &dmo_type );
1122     p_wf = (WAVEFORMATEX *)dmo_type.pbFormat;
1123
1124     msg_Dbg( p_enc, "selected format: %i, sample rate:%i, "
1125              "channels: %i, bits per sample: %i, bitrate: %i, blockalign: %i",
1126              (int)p_wf->wFormatTag, (int)p_wf->nSamplesPerSec,
1127              (int)p_wf->nChannels, (int)p_wf->wBitsPerSample,
1128              (int)p_wf->nAvgBytesPerSec * 8, (int)p_wf->nBlockAlign );
1129
1130     p_enc->fmt_out.audio.i_rate = p_wf->nSamplesPerSec;
1131     p_enc->fmt_out.audio.i_channels = p_wf->nChannels;
1132     p_enc->fmt_out.audio.i_bitspersample = p_wf->wBitsPerSample;
1133     p_enc->fmt_out.audio.i_blockalign = p_wf->nBlockAlign;
1134     p_enc->fmt_out.i_bitrate = p_wf->nAvgBytesPerSec * 8;
1135
1136     if( p_wf->cbSize )
1137     {
1138         msg_Dbg( p_enc, "found cbSize: %i", p_wf->cbSize );
1139         p_enc->fmt_out.i_extra = p_wf->cbSize;
1140         p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
1141         memcpy( p_enc->fmt_out.p_extra, &p_wf[1], p_enc->fmt_out.i_extra );
1142     }
1143
1144     i_err = p_dmo->vt->SetOutputType( p_dmo, 0, &dmo_type, 0 );
1145     DMOFreeMediaType( &dmo_type );
1146
1147     if( i_err )
1148     {
1149         msg_Err( p_enc, "can't set DMO output type: %i", i_err );
1150         return VLC_EGENERIC;
1151     }
1152
1153     msg_Dbg( p_enc, "successfully set output type" );
1154
1155     /* Setup the input type */
1156     i = 0; i_selected = -1;
1157     while( !p_dmo->vt->GetInputType( p_dmo, 0, i++, &dmo_type ) )
1158     {
1159         p_wf = (WAVEFORMATEX *)dmo_type.pbFormat;
1160         msg_Dbg( p_enc, "available format :%i, sample rate: %i, channels: %i, "
1161                  "bits per sample: %i, bitrate: %i, blockalign: %i",
1162                  (int) p_wf->wFormatTag, (int)p_wf->nSamplesPerSec,
1163                  (int)p_wf->nChannels, (int)p_wf->wBitsPerSample,
1164                  (int)p_wf->nAvgBytesPerSec * 8, (int)p_wf->nBlockAlign );
1165
1166         if( p_wf->wFormatTag == WAVE_FORMAT_PCM &&
1167             p_wf->nSamplesPerSec == p_enc->fmt_in.audio.i_rate &&
1168             p_wf->nChannels == p_enc->fmt_in.audio.i_channels &&
1169             p_wf->wBitsPerSample == p_enc->fmt_in.audio.i_bitspersample )
1170         {
1171             i_selected = i - 1;
1172         }
1173
1174         DMOFreeMediaType( &dmo_type );
1175     }
1176
1177     if( i_selected < 0 )
1178     {
1179         msg_Err( p_enc, "couldn't find a matching input" );
1180         return VLC_EGENERIC;
1181     }
1182
1183     p_dmo->vt->GetInputType( p_dmo, 0, i_selected, &dmo_type );
1184     i_err = p_dmo->vt->SetInputType( p_dmo, 0, &dmo_type, 0 );
1185     DMOFreeMediaType( &dmo_type );
1186     if( i_err )
1187     {
1188         msg_Err( p_enc, "can't set DMO input type: %x", i_err );
1189         return VLC_EGENERIC;
1190     }
1191     msg_Dbg( p_enc, "successfully set input type" );
1192
1193     return VLC_SUCCESS;
1194 }
1195
1196 /*****************************************************************************
1197  * EncOpen: open dmo codec
1198  *****************************************************************************/
1199 static int EncOpen( vlc_object_t *p_this )
1200 {
1201     encoder_t *p_enc = (encoder_t*)p_this;
1202     encoder_sys_t *p_sys = NULL;
1203     IMediaObject *p_dmo = NULL;
1204     HINSTANCE hmsdmo_dll = NULL;
1205
1206 #ifdef LOADER
1207     ldt_fs_t *ldt_fs = Setup_LDT_Keeper();
1208 #else
1209     /* Initialize OLE/COM */
1210     CoInitialize( 0 );
1211 #endif /* LOADER */
1212
1213     if( LoadDMO( p_this, &hmsdmo_dll, &p_dmo, &p_enc->fmt_out, VLC_TRUE )
1214         != VLC_SUCCESS )
1215     {
1216         hmsdmo_dll = 0;
1217         p_dmo = 0;
1218         goto error;
1219     }
1220
1221     if( p_enc->fmt_in.i_cat == VIDEO_ES )
1222     {
1223         if( EncoderSetVideoType( p_enc, p_dmo ) != VLC_SUCCESS ) goto error;
1224     }
1225     else
1226     {
1227         if( EncoderSetAudioType( p_enc, p_dmo ) != VLC_SUCCESS ) goto error;
1228     }
1229
1230     /* Allocate the memory needed to store the decoder's structure */
1231     if( ( p_enc->p_sys = p_sys =
1232           (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
1233     {
1234         msg_Err( p_enc, "out of memory" );
1235         goto error;
1236     }
1237
1238     p_sys->hmsdmo_dll = hmsdmo_dll;
1239     p_sys->p_dmo = p_dmo;
1240 #ifdef LOADER
1241     p_sys->ldt_fs = ldt_fs;
1242 #endif
1243
1244     /* Find out some properties of the inputput */
1245     {
1246         uint32_t i_size, i_align, dum;
1247
1248         if( p_dmo->vt->GetInputSizeInfo( p_dmo, 0, &i_size, &i_align, &dum ) )
1249             msg_Err( p_enc, "GetInputSizeInfo() failed" );
1250         else
1251             msg_Dbg( p_enc, "GetInputSizeInfo(): bytes %i, align %i, %i",
1252                      i_size, i_align, dum );
1253     }
1254
1255     /* Find out some properties of the output */
1256     {
1257         uint32_t i_size, i_align;
1258
1259         p_sys->i_min_output = 0;
1260         if( p_dmo->vt->GetOutputSizeInfo( p_dmo, 0, &i_size, &i_align ) )
1261         {
1262             msg_Err( p_enc, "GetOutputSizeInfo() failed" );
1263             goto error;
1264         }
1265         else
1266         {
1267             msg_Dbg( p_enc, "GetOutputSizeInfo(): bytes %i, align %i",
1268                      i_size, i_align );
1269             p_sys->i_min_output = i_size;
1270         }
1271     }
1272
1273     /* Set output properties */
1274     p_enc->fmt_out.i_cat = p_enc->fmt_out.i_cat;
1275     if( p_enc->fmt_out.i_cat == AUDIO_ES )
1276         date_Init( &p_sys->end_date, p_enc->fmt_out.audio.i_rate, 1 );
1277     else
1278         date_Init( &p_sys->end_date, 25 /* FIXME */, 1 );
1279
1280     return VLC_SUCCESS;
1281
1282  error:
1283
1284     if( p_dmo ) p_dmo->vt->Release( (IUnknown *)p_dmo );
1285     if( hmsdmo_dll ) FreeLibrary( hmsdmo_dll );
1286
1287 #ifdef LOADER
1288     Restore_LDT_Keeper( ldt_fs );
1289 #else
1290     /* Uninitialize OLE/COM */
1291     CoUninitialize();
1292 #endif /* LOADER */
1293
1294     if( p_sys ) free( p_sys );
1295
1296     return VLC_EGENERIC;
1297 }
1298
1299 /****************************************************************************
1300  * Encode: the whole thing
1301  ****************************************************************************/
1302 static block_t *EncodeBlock( encoder_t *p_enc, void *p_data )
1303 {
1304     encoder_sys_t *p_sys = p_enc->p_sys;
1305     CMediaBuffer *p_in;
1306     block_t *p_chain = NULL;
1307     block_t *p_block_in;
1308     uint32_t i_status;
1309     int i_result;
1310     mtime_t i_pts;
1311
1312     if( p_sys == NULL )
1313     {
1314         if( EncOpen( VLC_OBJECT(p_enc) ) )
1315         {
1316             msg_Err( p_enc, "EncOpen failed" );
1317             return NULL;
1318         }
1319         p_sys = p_enc->p_sys;
1320     }
1321
1322     if( !p_data ) return NULL;
1323
1324     if( p_enc->fmt_out.i_cat == VIDEO_ES )
1325     {
1326         /* Get picture data */
1327         picture_t *p_pic = (picture_t *)p_data;
1328         int i_buffer = p_enc->fmt_in.video.i_width *
1329             p_enc->fmt_in.video.i_height *
1330             p_enc->fmt_in.video.i_bits_per_pixel / 8;
1331
1332             msg_Err( p_enc, "EncOpen bpp: %i, size: %i",
1333                      p_enc->fmt_in.video.i_bits_per_pixel, i_buffer );
1334
1335         p_block_in = block_New( p_enc, i_buffer );
1336         // FIXME: Copy stride by stride;
1337 #if 0
1338         memcpy( p_block_in->p_buffer, p_pic->p->p_pixels,
1339                 p_block_in->i_buffer );
1340 #else
1341         memset( p_block_in->p_buffer, 0, p_block_in->i_buffer );
1342 #endif
1343
1344         i_pts = p_pic->date;
1345     }
1346     else
1347     {
1348         aout_buffer_t *p_aout_buffer = (aout_buffer_t *)p_data;
1349         p_block_in = block_New( p_enc, p_aout_buffer->i_nb_bytes );
1350         memcpy( p_block_in->p_buffer, p_aout_buffer->p_buffer,
1351                 p_block_in->i_buffer );
1352
1353         i_pts = p_aout_buffer->start_date;
1354     }
1355
1356     /* Feed input to the DMO */
1357     p_in = CMediaBufferCreate( p_block_in, p_block_in->i_buffer, VLC_TRUE );
1358     i_result = p_sys->p_dmo->vt->ProcessInput( p_sys->p_dmo, 0,
1359        (IMediaBuffer *)p_in, DMO_INPUT_DATA_BUFFERF_TIME, i_pts * 10, 0 );
1360
1361     p_in->vt->Release( (IUnknown *)p_in );
1362     if( i_result == S_FALSE )
1363     {
1364         /* No output generated */
1365 #ifdef DMO_DEBUG
1366         msg_Dbg( p_enc, "ProcessInput(): no output generated "I64Fd, i_pts );
1367 #endif
1368         return NULL;
1369     }
1370     else if( i_result == DMO_E_NOTACCEPTING )
1371     {
1372         /* Need to call ProcessOutput */
1373         msg_Dbg( p_enc, "ProcessInput(): not accepting" );
1374     }
1375     else if( i_result != S_OK )
1376     {
1377         msg_Dbg( p_enc, "ProcessInput(): failed: %x", i_result );
1378         return NULL;
1379     }
1380
1381 #if DMO_DEBUG
1382     msg_Dbg( p_enc, "ProcessInput(): success" );
1383 #endif
1384
1385     /* Get output from the DMO */
1386     while( 1 )
1387     {
1388         DMO_OUTPUT_DATA_BUFFER db;
1389         block_t *p_block_out;
1390         CMediaBuffer *p_out;
1391
1392         p_block_out = block_New( p_enc, p_sys->i_min_output );
1393         p_block_out->i_buffer = 0;
1394         p_out = CMediaBufferCreate(p_block_out, p_sys->i_min_output, VLC_FALSE);
1395         memset( &db, 0, sizeof(db) );
1396         db.pBuffer = (IMediaBuffer *)p_out;
1397
1398         i_result = p_sys->p_dmo->vt->ProcessOutput( p_sys->p_dmo,
1399                                                     0, 1, &db, &i_status );
1400
1401         if( i_result != S_OK )
1402         {
1403             if( i_result != S_FALSE )
1404                 msg_Dbg( p_enc, "ProcessOutput(): failed: %x", i_result );
1405 #if DMO_DEBUG
1406             else
1407                 msg_Dbg( p_enc, "ProcessOutput(): no output" );
1408 #endif
1409
1410             p_out->vt->Release( (IUnknown *)p_out );
1411             return p_chain;
1412         }
1413
1414         if( !p_block_out->i_buffer )
1415         {
1416 #if DMO_DEBUG
1417             msg_Dbg( p_enc, "ProcessOutput(): no output (i_buffer_out == 0)" );
1418 #endif
1419             p_out->vt->Release( (IUnknown *)p_out );
1420             return p_chain;
1421         }
1422
1423         if( db.dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME )
1424         {
1425 #if DMO_DEBUG
1426             msg_Dbg( p_enc, "ProcessOutput(): pts: "I64Fd", "I64Fd,
1427                      i_pts, db.rtTimestamp / 10 );
1428 #endif
1429             i_pts = db.rtTimestamp / 10;
1430         }
1431
1432         if( db.dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH )
1433         {
1434             p_block_out->i_length = db.rtTimelength / 10;
1435 #if DMO_DEBUG
1436             msg_Dbg( p_enc, "ProcessOutput(): length: "I64Fd,
1437                      p_block_out->i_length );
1438 #endif
1439         }
1440
1441         p_block_out->i_dts = p_block_out->i_pts = i_pts;
1442         block_ChainAppend( &p_chain, p_block_out );
1443     }
1444 }
1445
1446 /*****************************************************************************
1447  * EncoderClose: close codec
1448  *****************************************************************************/
1449 void EncoderClose( vlc_object_t *p_this )
1450 {
1451     encoder_t *p_enc = (encoder_t*)p_this;
1452     encoder_sys_t *p_sys = p_enc->p_sys;
1453
1454     if( !p_sys ) return;
1455
1456     FreeLibrary( p_sys->hmsdmo_dll );
1457
1458 #ifdef LOADER
1459 #if 0
1460     Restore_LDT_Keeper( p_sys->ldt_fs );
1461 #endif
1462 #else
1463     /* Uninitialize OLE/COM */
1464     CoUninitialize();
1465 #endif
1466
1467     free( p_sys );
1468 }