]> git.sesse.net Git - vlc/blob - modules/access/dshow/dshow.cpp
* configure.ac, modules/access/dshow/: brand new DirectShow input plugin.
[vlc] / modules / access / dshow / dshow.cpp
1 /*****************************************************************************
2  * dshow.c : DirectShow access module for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: dshow.cpp,v 1.1 2003/08/24 11:17:39 gbazin Exp $
6  *
7  * Author: Gildas Bazin <gbazin@netcourrier.com>
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/vout.h>
34
35 #ifndef _MSC_VER
36 #   include <wtypes.h>
37 #   include <unknwn.h>
38 #   include <ole2.h>
39 #   include <limits.h>
40 #   define _WINGDI_ 1
41 #   define AM_NOVTABLE
42 #   define _OBJBASE_H_
43 #   undef _X86_
44 #   define _I64_MAX LONG_LONG_MAX
45 #   define LONGLONG long long
46 #endif
47
48 #include <dshow.h>
49
50 #include "filter.h"
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 static int  AccessOpen  ( vlc_object_t * );
56 static void AccessClose ( vlc_object_t * );
57 static int  Read        ( input_thread_t *, byte_t *, size_t );
58
59 static int  DemuxOpen  ( vlc_object_t * );
60 static void DemuxClose ( vlc_object_t * );
61 static int  Demux      ( input_thread_t * );
62
63 static int OpenDevice( input_thread_t *, string );
64 static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
65                                        list<string> * );
66 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
67                             IPin *p_input_pin );
68
69 /*****************************************************************************
70  * Module descriptior
71  *****************************************************************************/
72 #define CACHING_TEXT N_("Caching value in ms")
73 #define CACHING_LONGTEXT N_( \
74     "Allows you to modify the default caching value for directshow streams. " \
75     "This value should be set in miliseconds units." )
76
77 vlc_module_begin();
78     set_description( _("DirectShow input") );
79     add_category_hint( N_("dshow"), NULL, VLC_TRUE );
80     add_integer( "dshow-caching", DEFAULT_PTS_DELAY / 1000, NULL,
81                  CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
82     add_shortcut( "dshow" );
83     set_capability( "access", 10 );
84     set_callbacks( AccessOpen, AccessClose );
85
86     add_submodule();
87     set_description( _("DirectShow demuxer") );
88     add_shortcut( "dshow" );
89     set_capability( "demux", 200 );
90     set_callbacks( DemuxOpen, DemuxClose );
91
92 vlc_module_end();
93
94 /****************************************************************************
95  * I. Access Part
96  ****************************************************************************/
97
98 /*
99  * header:
100  *  fcc  ".dsh"
101  *  u32    stream count
102  *      fcc "auds"|"vids"       0
103  *      fcc codec               4
104  *      if vids
105  *          u32 width           8
106  *          u32 height          12
107  *          u32 padding         16
108  *      if auds
109  *          u32 channels        12
110  *          u32 samplerate      8
111  *          u32 samplesize      16
112  *
113  * data:
114  *  u32     stream number
115  *  u32     data size
116  *  u8      data
117  */
118
119 static void SetDWBE( uint8_t *p, uint32_t dw )
120 {
121     p[0] = (dw >> 24)&0xff;
122     p[1] = (dw >> 16)&0xff;
123     p[2] = (dw >>  8)&0xff;
124     p[3] = (dw      )&0xff;
125 }
126
127 static void SetQWBE( uint8_t *p, uint64_t qw )
128 {
129     SetDWBE( p, (qw >> 32)&0xffffffff );
130     SetDWBE( &p[4], qw&0xffffffff );
131 }
132
133 /****************************************************************************
134  * Access descriptor declaration
135  ****************************************************************************/
136 struct access_sys_t
137 {
138     IFilterGraph  *p_graph;
139     IBaseFilter   *p_device_filter;
140     CaptureFilter *p_capture_filter;
141     IMediaControl *p_control;
142
143     AM_MEDIA_TYPE mt;
144
145     /* video */
146     char *psz_video_device;
147     int  i_fourcc;
148     int  i_width;
149     int  i_height;
150     VIDEOINFOHEADER vid_header;
151
152     /* audio */
153
154     /* header */
155     int     i_header_size;
156     int     i_header_pos;
157     uint8_t *p_header;      // at lest 8 bytes allocated
158
159     /* data */
160     int     i_data_size;
161     int     i_data_pos;
162     uint8_t *p_data;
163
164     VLCMediaSample sample;
165 };
166
167 /*****************************************************************************
168  * Open: open direct show device
169  *****************************************************************************/
170 static int AccessOpen( vlc_object_t *p_this )
171 {
172     input_thread_t *p_input = (input_thread_t *)p_this;
173     access_sys_t   *p_sys;
174
175 #if 0
176     /* parse url and open device(s) */
177     char *psz_dup, *psz_parser;
178     psz_dup = strdup( p_input->psz_name );
179     psz_parser = psz_dup;
180
181     while( *psz_parser && *psz_parser != ':' )
182     {
183         psz_parser++;
184     }
185 #endif
186
187     p_input->pf_read        = Read;
188     p_input->pf_seek        = NULL;
189     p_input->pf_set_area    = NULL;
190     p_input->pf_set_program = NULL;
191
192     vlc_mutex_lock( &p_input->stream.stream_lock );
193     p_input->stream.b_pace_control = 0;
194     p_input->stream.b_seekable = 0;
195     p_input->stream.p_selected_area->i_size = 0;
196     p_input->stream.p_selected_area->i_tell = 0;
197     p_input->stream.i_method = INPUT_METHOD_FILE;
198     vlc_mutex_unlock( &p_input->stream.stream_lock );
199
200     /* Update default_pts to a suitable value for access */
201     p_input->i_pts_delay = config_GetInt( p_input, "dshow-caching" ) * 1000;
202
203     /* Initialize OLE/COM */
204     CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
205
206     /* create access private data */
207     p_input->p_access_data = p_sys =
208         (access_sys_t *)malloc( sizeof( access_sys_t ) );
209     memset( p_sys, 0, sizeof( access_sys_t ) );
210
211     /* Initialize some data */
212     p_sys->psz_video_device = NULL;
213     p_sys->sample.p_sample  = NULL;
214     p_sys->i_data_size = 0;
215     p_sys->i_data_pos = 0;
216
217     if( OpenDevice( p_input, p_input->psz_name ) != VLC_SUCCESS )
218     {
219         /* Uninitialize OLE/COM */
220         CoUninitialize();   
221
222         free( p_sys );
223         return VLC_EGENERIC;
224     }
225
226     return VLC_SUCCESS;
227 }
228
229 /*****************************************************************************
230  * AccessClose: close device
231  *****************************************************************************/
232 static void AccessClose( vlc_object_t *p_this )
233 {
234     input_thread_t *p_input = (input_thread_t *)p_this;
235     access_sys_t    *p_sys  = p_input->p_access_data;
236
237     /* Stop capturing stuff */
238     p_sys->p_control->Stop();
239     p_sys->p_control->Release();
240
241     /* Remove filters from graph */
242     //p_sys->p_graph->RemoveFilter( p_sys->p_capture_filter );
243     //p_sys->p_graph->RemoveFilter( p_sys->p_device_filter );
244
245     /* Release objects */
246     //p_sys->p_device_filter->Release();
247     //p_sys->p_capture_filter->Release();
248     //p_sys->p_graph->Release();
249
250     /* Uninitialize OLE/COM */
251     CoUninitialize();   
252
253     free( p_sys );
254 }
255
256 /****************************************************************************
257  * ConnectFilters
258  ****************************************************************************/
259 static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
260                             IPin *p_input_pin )
261 {
262     IEnumPins *p_enumpins;
263     IPin *p_output_pin;
264     ULONG i_fetched;
265
266     if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
267
268     while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
269     {
270         if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
271         {
272             p_enumpins->Release();
273             return true;
274         }
275     }
276
277     p_enumpins->Release();
278     return false;
279 }
280
281 static int OpenDevice( input_thread_t *p_input, string devicename )
282 {
283     access_sys_t *p_sys = p_input->p_access_data;
284     list<string> list_devices;
285
286 #if 1
287     // Enum devices and display their names
288     FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices );
289
290     list<string>::iterator iter;
291     for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
292         msg_Err( p_input, "found device: %s", iter->c_str() );
293 #endif
294
295     /* If no device name was specified, pick the 1st one */
296     if( devicename.size() == 0 )
297     {
298         devicename = *list_devices.begin();
299     }
300
301     // Use the system device enumerator and class enumerator to find
302     // a video capture/preview device, such as a desktop USB video camera.
303     p_sys->p_device_filter =
304         FindCaptureDevice( (vlc_object_t *)p_input, &devicename, NULL );
305
306     if( p_sys->p_device_filter )
307         msg_Dbg( p_input, "found device: %s", devicename.c_str() );
308
309     /* Build graph */
310     CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
311                       (REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
312
313     p_sys->p_graph->QueryInterface( IID_IMediaControl,
314                                     (void **)&p_sys->p_control );
315
316     /* Create and add our capture filter */
317     p_sys->p_capture_filter = new CaptureFilter( p_input );
318     p_sys->p_graph->AddFilter( p_sys->p_capture_filter, 0 );
319
320     /* Add the device filter to the graph (seems necessary with VfW before
321      * accessing pin attributes). */
322     p_sys->p_graph->AddFilter( p_sys->p_device_filter, 0 );
323
324     // Attempt to connect one of this device's capture output pins
325     msg_Dbg( p_input, "connecting filters" );
326     if( ConnectFilters( p_sys->p_graph, p_sys->p_device_filter,
327                         p_sys->p_capture_filter->CustomGetPin() ) )
328     {
329         /* Success */
330         int i_fourcc = VLC_FOURCC( ' ', ' ', ' ', ' ' );
331         AM_MEDIA_TYPE *pmt = &p_sys->mt;
332         p_sys->mt = p_sys->p_capture_filter->CustomGetPin()->
333                         CustomGetMediaType();
334
335         if( pmt->majortype == MEDIATYPE_Video )
336         {
337             if( pmt->subtype == MEDIASUBTYPE_RGB8 )
338               {
339                 i_fourcc = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
340               }
341             else if( pmt->subtype == MEDIASUBTYPE_RGB555 )
342               {
343                 i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
344               }
345             else if( pmt->subtype == MEDIASUBTYPE_RGB565 )
346               {
347                 i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
348               }
349             else if( pmt->subtype == MEDIASUBTYPE_RGB24 )
350               {
351                 i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
352               }
353             else if( pmt->subtype == MEDIASUBTYPE_RGB32 )
354               {
355                 i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
356               }
357             else if( pmt->subtype == MEDIASUBTYPE_ARGB32 )
358               {
359                 i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
360               }
361             
362             else if( pmt->subtype == MEDIASUBTYPE_YUYV )
363               {
364                 i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
365               }
366             else if( pmt->subtype == MEDIASUBTYPE_Y411 )
367               {
368                 i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
369               }
370             else if( pmt->subtype == MEDIASUBTYPE_Y41P )
371               {
372                 i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
373               }
374             else if( pmt->subtype == MEDIASUBTYPE_YUY2 )
375               {
376                 i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
377               }
378             else if( pmt->subtype == MEDIASUBTYPE_YVYU )
379               {
380                 i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
381               }
382             else if( pmt->subtype == MEDIASUBTYPE_Y411 )
383               {
384                 i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
385               }
386             else if( pmt->subtype == MEDIASUBTYPE_YV12 )
387               {
388                 i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
389               }
390
391             p_sys->i_fourcc = i_fourcc;
392             p_sys->vid_header = *(VIDEOINFOHEADER *)pmt->pbFormat;
393         }
394
395         /* create header */
396         p_sys->i_header_size = 8 + 20;
397         p_sys->i_header_pos  = 0;
398         p_sys->p_header      = (uint8_t *)malloc( p_sys->i_header_size );
399
400         memcpy(  &p_sys->p_header[0], ".dsh", 4 );
401         SetDWBE( &p_sys->p_header[4], 1 );
402         memcpy(  &p_sys->p_header[ 8], "vids", 4 );
403         memcpy(  &p_sys->p_header[12], &i_fourcc, 4 );
404         SetDWBE( &p_sys->p_header[16], p_sys->vid_header.bmiHeader.biWidth );
405         SetDWBE( &p_sys->p_header[20], p_sys->vid_header.bmiHeader.biHeight );
406         SetDWBE( &p_sys->p_header[24], 0 );
407
408         p_sys->p_control->Run();
409
410         // We're done
411         return VLC_SUCCESS;
412     }
413
414     /* Remove filters from graph */
415     p_sys->p_graph->RemoveFilter( p_sys->p_device_filter );
416     p_sys->p_graph->RemoveFilter( p_sys->p_capture_filter );
417
418     /* Release objects */
419     p_sys->p_device_filter->Release();
420     p_sys->p_capture_filter->Release();
421     p_sys->p_control->Release();
422     p_sys->p_graph->Release();
423
424     return VLC_EGENERIC;
425 }
426
427 static IBaseFilter *
428 FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
429                    list<string> *p_listdevices )
430 {
431     IBaseFilter *pBaseFilter = NULL;
432     IMoniker *pMoniker = NULL;
433     ULONG lFetched;
434     HRESULT hr;
435
436     /* Create the system device enumerator */
437     ICreateDevEnum *pDevEnum = NULL;
438
439     hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
440                            IID_ICreateDevEnum, (void **)&pDevEnum );
441     if( FAILED(hr) )
442     {
443         msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
444         return NULL;
445     }
446
447     /* Create an enumerator for the video capture devices */
448     IEnumMoniker *pClassEnum = NULL;
449     hr = pDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
450                                           &pClassEnum, 0 );
451     if( FAILED(hr) )
452     {
453         msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
454         return NULL;
455     }
456
457     /* If there are no enumerators for the requested type, then 
458      * CreateClassEnumerator will succeed, but pClassEnum will be NULL */
459     if( pClassEnum == NULL )
460     {
461         msg_Err( p_this, "no video capture device was detected." );
462         return NULL;
463     }
464
465     /* Enumerate the devices */
466
467     /* Note that if the Next() call succeeds but there are no monikers,
468      * it will return S_FALSE (which is not a failure). Therefore, we check
469      * that the return code is S_OK instead of using SUCCEEDED() macro. */
470
471     while( pClassEnum->Next( 1, &pMoniker, &lFetched ) == S_OK )
472     {
473         /* Getting the property page to get the device name */
474         IPropertyBag *pBag;
475         hr = pMoniker->BindToStorage( 0, 0, IID_IPropertyBag,
476                                       reinterpret_cast<PVOID *>( &pBag ) );
477         if( SUCCEEDED(hr) )
478         {
479             VARIANT var;
480             var.vt = VT_BSTR;
481             hr = pBag->Read( L"FriendlyName", &var, NULL );
482             pBag->Release();
483             if( SUCCEEDED(hr) )
484             {
485                 int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
486                 char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
487                 WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
488                                      i_convert, NULL, NULL );
489                 SysFreeString(var.bstrVal);
490
491                 if( p_listdevices ) p_listdevices->push_back( p_buf );
492
493                 if( p_devicename && *p_devicename == string(p_buf) )
494                 {
495                     /* Bind Moniker to a filter object */
496                     hr = pMoniker->BindToObject( 0, 0, IID_IBaseFilter,
497                              reinterpret_cast<LPVOID *>(&pBaseFilter) );
498                     if( FAILED(hr) )
499                     {
500                         msg_Err( p_this, "couldn't bind moniker to filter "
501                                  "object (0x%x)", hr );
502                         return NULL;
503                     }
504                     return pBaseFilter;
505                 }
506             }
507         }
508     }
509
510     return NULL;
511 }
512
513 /*****************************************************************************
514  * Read: reads from the device into PES packets.
515  *****************************************************************************
516  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
517  * bytes.
518  *****************************************************************************/
519 static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
520 {
521     access_sys_t *p_sys = p_input->p_access_data;
522     int          i_data = 0;
523
524 #if 0
525     msg_Info( p_input, "access read data_size %i, data_pos %i",
526               p_sys->i_data_size, p_sys->i_data_pos );
527 #endif
528
529     while( i_len > 0 )
530     {
531         /* First copy header if any */
532         if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
533         {
534             int i_copy;
535
536             i_copy = __MIN( p_sys->i_header_size -
537                             p_sys->i_header_pos, (int)i_len );
538             memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );
539             p_sys->i_header_pos += i_copy;
540
541             p_buffer += i_copy;
542             i_len -= i_copy;
543             i_data += i_copy;
544         }
545
546         /* Then copy data */
547         if( i_len > 0 && p_sys->i_data_pos < p_sys->i_data_size )
548         {
549             int i_copy;
550
551             i_copy = __MIN( p_sys->i_data_size -
552                             p_sys->i_data_pos, (int)i_len );
553
554             memcpy( p_buffer, &p_sys->p_data[p_sys->i_data_pos], i_copy );
555             p_sys->i_data_pos += i_copy;
556
557             p_buffer += i_copy;
558             i_len -= i_copy;
559             i_data += i_copy;
560         }
561
562         /* The caller got what he wanted */
563         if( i_len <= 0 )
564         {
565             return i_data;
566         }
567
568         /* Read no more than one frame at a time, otherwise we kill latency */
569         if( p_sys->i_data_size && i_data &&
570             p_sys->i_data_pos == p_sys->i_data_size )
571         {
572             p_sys->i_data_pos = 0; p_sys->i_data_size = 0;
573             return i_data;
574         }
575
576         /* Start new audio/video frame */
577         if( p_sys->sample.p_sample )
578         {
579           //p_sys->sample.p_sample->Release();
580         }
581
582         if( p_sys->p_capture_filter->CustomGetPin()
583                 ->CustomGetSample( &p_sys->sample ) == S_OK )
584         {
585             p_sys->i_data_pos = 0;
586             p_sys->i_data_size = p_sys->sample.p_sample->GetActualDataLength();
587             p_sys->sample.p_sample->GetPointer( &p_sys->p_data );
588
589             REFERENCE_TIME i_pts, i_end_date;
590             HRESULT hr = p_sys->sample.p_sample
591                              ->GetTime( &i_pts, &i_end_date );
592             if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
593
594             if( !i_pts )
595             {
596                 /* Use our data timestamp */
597                 i_pts = p_sys->sample.i_timestamp;
598             }
599
600 #if 0
601             msg_Dbg( p_input, "Read() PTS: "I64Fd, i_pts );
602 #endif
603
604             /* create pseudo header */
605             p_sys->i_header_size = 16;
606             p_sys->i_header_pos  = 0;
607             SetDWBE( &p_sys->p_header[0], 0 /*i_stream*/ );
608             SetDWBE( &p_sys->p_header[4], p_sys->i_data_size );
609             SetQWBE( &p_sys->p_header[8], i_pts  * 9 / 1000 );
610         }
611         else msleep( 10000 );
612     }
613
614     return i_data;
615 }
616
617 /****************************************************************************
618  * I. Demux Part
619  ****************************************************************************/
620 static int DemuxOpen( vlc_object_t *p_this )
621 {
622     input_thread_t *p_input = (input_thread_t *)p_this;
623
624     uint8_t        *p_peek;
625     int            i_streams;
626     int            i;
627
628     data_packet_t  *p_pk;
629
630     /* Initialize access plug-in structures. */
631     if( p_input->i_mtu == 0 )
632     {
633         /* Improve speed. */
634         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
635     }
636
637     /* a little test to see if it's a v4l stream */
638     if( input_Peek( p_input, &p_peek, 8 ) < 8 )
639     {
640         msg_Warn( p_input, "v4l plugin discarded (cannot peek)" );
641         return( VLC_EGENERIC );
642     }
643
644     if( strcmp( (const char *)p_peek, ".dsh" ) ||
645         GetDWBE( &p_peek[4] ) <= 0 )
646     {
647         msg_Warn( p_input, "v4l plugin discarded (not a valid stream)" );
648         return VLC_EGENERIC;
649     }
650
651     /*  create one program */
652     vlc_mutex_lock( &p_input->stream.stream_lock );
653     if( input_InitStream( p_input, 0 ) == -1)
654     {
655         vlc_mutex_unlock( &p_input->stream.stream_lock );
656         msg_Err( p_input, "cannot init stream" );
657         return( VLC_EGENERIC );
658     }
659     if( input_AddProgram( p_input, 0, 0) == NULL )
660     {
661         vlc_mutex_unlock( &p_input->stream.stream_lock );
662         msg_Err( p_input, "cannot add program" );
663         return( VLC_EGENERIC );
664     }
665
666     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
667     p_input->stream.i_mux_rate =  0;
668
669     i_streams = GetDWBE( &p_peek[4] );
670     if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
671         < 8 + 20 * i_streams )
672     {
673         msg_Err( p_input, "v4l plugin discarded (cannot peek)" );
674         return( VLC_EGENERIC );
675     }
676     p_peek += 8;
677
678     for( i = 0; i < i_streams; i++ )
679     {
680         es_descriptor_t *p_es;
681
682         if( !strncmp( (const char *)p_peek, "auds", 4 ) )
683         {
684 #define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
685             p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
686                                 i + 1, AUDIO_ES, NULL, 0 );
687             p_es->i_stream_id   = i + 1;
688             p_es->i_fourcc      =
689                 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
690
691             p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
692
693             wf->wFormatTag      = 0;//WAVE_FORMAT_UNKNOWN;
694             wf->nChannels       = GetDWBE( &p_peek[8] );
695             wf->nSamplesPerSec  = GetDWBE( &p_peek[12] );
696             wf->wBitsPerSample  = GetDWBE( &p_peek[16] );
697             wf->nBlockAlign     = wf->wBitsPerSample * wf->nChannels / 8;
698             wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
699             wf->cbSize          = 0;
700
701             msg_Dbg( p_input, "added new audio es %d channels %dHz",
702                      wf->nChannels, wf->nSamplesPerSec );
703
704             input_SelectES( p_input, p_es );
705 #undef wf
706         }
707         else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
708         {
709 #define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
710             p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
711                                 i + 1, VIDEO_ES, NULL, 0 );
712             p_es->i_stream_id   = i + 1;
713             p_es->i_fourcc  =
714                 VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
715
716             p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
717
718             bih->biSize     = sizeof( BITMAPINFOHEADER );
719             bih->biWidth    = GetDWBE( &p_peek[8] );
720             bih->biHeight   = GetDWBE( &p_peek[12] );
721             bih->biPlanes   = 0;
722             bih->biBitCount = 0;
723             bih->biCompression      = 0;
724             bih->biSizeImage= 0;
725             bih->biXPelsPerMeter    = 0;
726             bih->biYPelsPerMeter    = 0;
727             bih->biClrUsed  = 0;
728             bih->biClrImportant     = 0;
729
730             msg_Dbg( p_input, "added new video es %4.4s %dx%d",
731                      (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
732
733             input_SelectES( p_input, p_es );
734 #undef bih
735         }
736
737         p_peek += 20;
738     }
739
740     p_input->stream.p_selected_program->b_is_ok = 1;
741     vlc_mutex_unlock( &p_input->stream.stream_lock );
742
743     if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
744     {
745         input_DeletePacket( p_input->p_method_data, p_pk );
746     }
747
748     p_input->pf_demux = Demux;
749     return VLC_SUCCESS;
750 }
751
752 static void DemuxClose( vlc_object_t *p_this )
753 {
754     return;
755 }
756
757 static int Demux( input_thread_t *p_input )
758 {
759     es_descriptor_t *p_es;
760     pes_packet_t    *p_pes;
761
762     int i_stream;
763     int i_size;
764     uint8_t *p_peek;
765     mtime_t i_pcr;
766
767     if( input_Peek( p_input, &p_peek, 16 ) < 16 )
768     {
769         msg_Warn( p_input, "cannot peek (EOF ?)" );
770         return( 0 );
771     }
772
773     i_stream = GetDWBE( &p_peek[0] );
774     i_size   = GetDWBE( &p_peek[4] );
775     i_pcr    = GetQWBE( &p_peek[8] );
776
777     //msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
778     //p_es = input_FindES( p_input, i_stream );
779
780     p_es = p_input->stream.p_selected_program->pp_es[i_stream];
781     if( !p_es )
782     {
783         msg_Err( p_input, "cannot find ES" );
784     }
785
786     p_pes = input_NewPES( p_input->p_method_data );
787     if( p_pes == NULL )
788     {
789         msg_Warn( p_input, "cannot allocate PES" );
790         msleep( 1000 );
791         return( 1 );
792     }
793     i_size += 16;
794     while( i_size > 0 )
795     {
796         data_packet_t   *p_data;
797         int i_read;
798
799         if( (i_read = input_SplitBuffer( p_input, &p_data,
800                                          __MIN( i_size, 10000 ) ) ) <= 0 )
801         {
802             input_DeletePES( p_input->p_method_data, p_pes );
803             return( 0 );
804         }
805         if( !p_pes->p_first )
806         {
807             p_pes->p_first = p_data;
808             p_pes->i_nb_data = 1;
809             p_pes->i_pes_size = i_read;
810         }
811         else
812         {
813             p_pes->p_last->p_next  = p_data;
814             p_pes->i_nb_data++;
815             p_pes->i_pes_size += i_read;
816         }
817         p_pes->p_last  = p_data;
818         i_size -= i_read;
819     }
820
821     p_pes->p_first->p_payload_start += 16;
822     p_pes->i_pes_size               -= 16;
823
824     if( p_es && p_es->p_decoder_fifo )
825     {
826         /* Call the pace control. */
827         input_ClockManageRef( p_input, p_input->stream.p_selected_program,
828                               i_pcr );
829
830         p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
831             input_ClockGetTS( p_input, p_input->stream.p_selected_program,
832                               i_pcr );
833
834         input_DecodePES( p_es->p_decoder_fifo, p_pes );
835     }
836     else
837     {
838         input_DeletePES( p_input->p_method_data, p_pes );
839     }
840
841     return 1;
842 }