Commit b34227c1 authored by Gildas Bazin's avatar Gildas Bazin

* configure.ac, modules/access/dshow/: brand new DirectShow input plugin.
   Much work still needs to be done, like audio support, adding plenty of configuration options, etc... But the video part is already working quite well here.
parent 026eb767
dnl Autoconf settings for vlc dnl Autoconf settings for vlc
dnl $Id: configure.ac,v 1.67 2003/08/23 22:49:50 fenrir Exp $ dnl $Id: configure.ac,v 1.68 2003/08/24 11:17:39 gbazin Exp $
AC_INIT(vlc,0.6.3-cvs) AC_INIT(vlc,0.6.3-cvs)
...@@ -1212,6 +1212,22 @@ then ...@@ -1212,6 +1212,22 @@ then
fi fi
fi fi
dnl
dnl Windows DirectShow access module
dnl
AC_ARG_ENABLE(dshow,
[ --enable-dshow Win32 DirectShow support (default enabled on Win32)])
if test "${enable_dshow}" != "no"
then
if test "${SYS}" = "mingw32" -o "${SYS}" = "cygwin"
then
AC_CHECK_HEADERS(dshow.h,
[ AX_ADD_PLUGINS([dshow])
AX_ADD_CXXFLAGS([dshow],[])
AX_ADD_LDFLAGS([dshow],[-lole32 -loleaut32]) ])
fi
fi
dnl dnl
dnl libdvbpsi ts demux/mux dnl libdvbpsi ts demux/mux
dnl dnl
...@@ -3261,6 +3277,7 @@ AC_OUTPUT([ ...@@ -3261,6 +3277,7 @@ AC_OUTPUT([
src/Makefile src/Makefile
modules/access/Makefile modules/access/Makefile
modules/access/dshow/Makefile
modules/access/dvb/Makefile modules/access/dvb/Makefile
modules/access/dvd/Makefile modules/access/dvd/Makefile
modules/access/dvdplay/Makefile modules/access/dvdplay/Makefile
......
.deps
.dirstamp
*.lo
*.la
*.dll
*.dylib
*.sl
*.so
Makefile.am
Makefile.in
Makefile
SOURCES_dshow = dshow.cpp filter.cpp filter.h
/*****************************************************************************
* dshow.c : DirectShow access module for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: dshow.cpp,v 1.1 2003/08/24 11:17:39 gbazin Exp $
*
* Author: Gildas Bazin <gbazin@netcourrier.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/vout.h>
#ifndef _MSC_VER
# include <wtypes.h>
# include <unknwn.h>
# include <ole2.h>
# include <limits.h>
# define _WINGDI_ 1
# define AM_NOVTABLE
# define _OBJBASE_H_
# undef _X86_
# define _I64_MAX LONG_LONG_MAX
# define LONGLONG long long
#endif
#include <dshow.h>
#include "filter.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int AccessOpen ( vlc_object_t * );
static void AccessClose ( vlc_object_t * );
static int Read ( input_thread_t *, byte_t *, size_t );
static int DemuxOpen ( vlc_object_t * );
static void DemuxClose ( vlc_object_t * );
static int Demux ( input_thread_t * );
static int OpenDevice( input_thread_t *, string );
static IBaseFilter *FindCaptureDevice( vlc_object_t *, string *,
list<string> * );
static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
IPin *p_input_pin );
/*****************************************************************************
* Module descriptior
*****************************************************************************/
#define CACHING_TEXT N_("Caching value in ms")
#define CACHING_LONGTEXT N_( \
"Allows you to modify the default caching value for directshow streams. " \
"This value should be set in miliseconds units." )
vlc_module_begin();
set_description( _("DirectShow input") );
add_category_hint( N_("dshow"), NULL, VLC_TRUE );
add_integer( "dshow-caching", DEFAULT_PTS_DELAY / 1000, NULL,
CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
add_shortcut( "dshow" );
set_capability( "access", 10 );
set_callbacks( AccessOpen, AccessClose );
add_submodule();
set_description( _("DirectShow demuxer") );
add_shortcut( "dshow" );
set_capability( "demux", 200 );
set_callbacks( DemuxOpen, DemuxClose );
vlc_module_end();
/****************************************************************************
* I. Access Part
****************************************************************************/
/*
* header:
* fcc ".dsh"
* u32 stream count
* fcc "auds"|"vids" 0
* fcc codec 4
* if vids
* u32 width 8
* u32 height 12
* u32 padding 16
* if auds
* u32 channels 12
* u32 samplerate 8
* u32 samplesize 16
*
* data:
* u32 stream number
* u32 data size
* u8 data
*/
static void SetDWBE( uint8_t *p, uint32_t dw )
{
p[0] = (dw >> 24)&0xff;
p[1] = (dw >> 16)&0xff;
p[2] = (dw >> 8)&0xff;
p[3] = (dw )&0xff;
}
static void SetQWBE( uint8_t *p, uint64_t qw )
{
SetDWBE( p, (qw >> 32)&0xffffffff );
SetDWBE( &p[4], qw&0xffffffff );
}
/****************************************************************************
* Access descriptor declaration
****************************************************************************/
struct access_sys_t
{
IFilterGraph *p_graph;
IBaseFilter *p_device_filter;
CaptureFilter *p_capture_filter;
IMediaControl *p_control;
AM_MEDIA_TYPE mt;
/* video */
char *psz_video_device;
int i_fourcc;
int i_width;
int i_height;
VIDEOINFOHEADER vid_header;
/* audio */
/* header */
int i_header_size;
int i_header_pos;
uint8_t *p_header; // at lest 8 bytes allocated
/* data */
int i_data_size;
int i_data_pos;
uint8_t *p_data;
VLCMediaSample sample;
};
/*****************************************************************************
* Open: open direct show device
*****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
access_sys_t *p_sys;
#if 0
/* parse url and open device(s) */
char *psz_dup, *psz_parser;
psz_dup = strdup( p_input->psz_name );
psz_parser = psz_dup;
while( *psz_parser && *psz_parser != ':' )
{
psz_parser++;
}
#endif
p_input->pf_read = Read;
p_input->pf_seek = NULL;
p_input->pf_set_area = NULL;
p_input->pf_set_program = NULL;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = 0;
p_input->stream.b_seekable = 0;
p_input->stream.p_selected_area->i_size = 0;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.i_method = INPUT_METHOD_FILE;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* Update default_pts to a suitable value for access */
p_input->i_pts_delay = config_GetInt( p_input, "dshow-caching" ) * 1000;
/* Initialize OLE/COM */
CoInitializeEx( 0, COINIT_APARTMENTTHREADED );
/* create access private data */
p_input->p_access_data = p_sys =
(access_sys_t *)malloc( sizeof( access_sys_t ) );
memset( p_sys, 0, sizeof( access_sys_t ) );
/* Initialize some data */
p_sys->psz_video_device = NULL;
p_sys->sample.p_sample = NULL;
p_sys->i_data_size = 0;
p_sys->i_data_pos = 0;
if( OpenDevice( p_input, p_input->psz_name ) != VLC_SUCCESS )
{
/* Uninitialize OLE/COM */
CoUninitialize();
free( p_sys );
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* AccessClose: close device
*****************************************************************************/
static void AccessClose( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
access_sys_t *p_sys = p_input->p_access_data;
/* Stop capturing stuff */
p_sys->p_control->Stop();
p_sys->p_control->Release();
/* Remove filters from graph */
//p_sys->p_graph->RemoveFilter( p_sys->p_capture_filter );
//p_sys->p_graph->RemoveFilter( p_sys->p_device_filter );
/* Release objects */
//p_sys->p_device_filter->Release();
//p_sys->p_capture_filter->Release();
//p_sys->p_graph->Release();
/* Uninitialize OLE/COM */
CoUninitialize();
free( p_sys );
}
/****************************************************************************
* ConnectFilters
****************************************************************************/
static bool ConnectFilters( IFilterGraph *p_graph, IBaseFilter *p_filter,
IPin *p_input_pin )
{
IEnumPins *p_enumpins;
IPin *p_output_pin;
ULONG i_fetched;
if( S_OK != p_filter->EnumPins( &p_enumpins ) ) return false;
while( S_OK == p_enumpins->Next( 1, &p_output_pin, &i_fetched ) )
{
if( S_OK == p_graph->ConnectDirect( p_output_pin, p_input_pin, 0 ) )
{
p_enumpins->Release();
return true;
}
}
p_enumpins->Release();
return false;
}
static int OpenDevice( input_thread_t *p_input, string devicename )
{
access_sys_t *p_sys = p_input->p_access_data;
list<string> list_devices;
#if 1
// Enum devices and display their names
FindCaptureDevice( (vlc_object_t *)p_input, NULL, &list_devices );
list<string>::iterator iter;
for( iter = list_devices.begin(); iter != list_devices.end(); iter++ )
msg_Err( p_input, "found device: %s", iter->c_str() );
#endif
/* If no device name was specified, pick the 1st one */
if( devicename.size() == 0 )
{
devicename = *list_devices.begin();
}
// Use the system device enumerator and class enumerator to find
// a video capture/preview device, such as a desktop USB video camera.
p_sys->p_device_filter =
FindCaptureDevice( (vlc_object_t *)p_input, &devicename, NULL );
if( p_sys->p_device_filter )
msg_Dbg( p_input, "found device: %s", devicename.c_str() );
/* Build graph */
CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,
(REFIID)IID_IFilterGraph, (void **)&p_sys->p_graph );
p_sys->p_graph->QueryInterface( IID_IMediaControl,
(void **)&p_sys->p_control );
/* Create and add our capture filter */
p_sys->p_capture_filter = new CaptureFilter( p_input );
p_sys->p_graph->AddFilter( p_sys->p_capture_filter, 0 );
/* Add the device filter to the graph (seems necessary with VfW before
* accessing pin attributes). */
p_sys->p_graph->AddFilter( p_sys->p_device_filter, 0 );
// Attempt to connect one of this device's capture output pins
msg_Dbg( p_input, "connecting filters" );
if( ConnectFilters( p_sys->p_graph, p_sys->p_device_filter,
p_sys->p_capture_filter->CustomGetPin() ) )
{
/* Success */
int i_fourcc = VLC_FOURCC( ' ', ' ', ' ', ' ' );
AM_MEDIA_TYPE *pmt = &p_sys->mt;
p_sys->mt = p_sys->p_capture_filter->CustomGetPin()->
CustomGetMediaType();
if( pmt->majortype == MEDIATYPE_Video )
{
if( pmt->subtype == MEDIASUBTYPE_RGB8 )
{
i_fourcc = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
}
else if( pmt->subtype == MEDIASUBTYPE_RGB555 )
{
i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
}
else if( pmt->subtype == MEDIASUBTYPE_RGB565 )
{
i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
}
else if( pmt->subtype == MEDIASUBTYPE_RGB24 )
{
i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
}
else if( pmt->subtype == MEDIASUBTYPE_RGB32 )
{
i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
}
else if( pmt->subtype == MEDIASUBTYPE_ARGB32 )
{
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
}
else if( pmt->subtype == MEDIASUBTYPE_YUYV )
{
i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
}
else if( pmt->subtype == MEDIASUBTYPE_Y411 )
{
i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
}
else if( pmt->subtype == MEDIASUBTYPE_Y41P )
{
i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
}
else if( pmt->subtype == MEDIASUBTYPE_YUY2 )
{
i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
}
else if( pmt->subtype == MEDIASUBTYPE_YVYU )
{
i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
}
else if( pmt->subtype == MEDIASUBTYPE_Y411 )
{
i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
}
else if( pmt->subtype == MEDIASUBTYPE_YV12 )
{
i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
}
p_sys->i_fourcc = i_fourcc;
p_sys->vid_header = *(VIDEOINFOHEADER *)pmt->pbFormat;
}
/* create header */
p_sys->i_header_size = 8 + 20;
p_sys->i_header_pos = 0;
p_sys->p_header = (uint8_t *)malloc( p_sys->i_header_size );
memcpy( &p_sys->p_header[0], ".dsh", 4 );
SetDWBE( &p_sys->p_header[4], 1 );
memcpy( &p_sys->p_header[ 8], "vids", 4 );
memcpy( &p_sys->p_header[12], &i_fourcc, 4 );
SetDWBE( &p_sys->p_header[16], p_sys->vid_header.bmiHeader.biWidth );
SetDWBE( &p_sys->p_header[20], p_sys->vid_header.bmiHeader.biHeight );
SetDWBE( &p_sys->p_header[24], 0 );
p_sys->p_control->Run();
// We're done
return VLC_SUCCESS;
}
/* Remove filters from graph */
p_sys->p_graph->RemoveFilter( p_sys->p_device_filter );
p_sys->p_graph->RemoveFilter( p_sys->p_capture_filter );
/* Release objects */
p_sys->p_device_filter->Release();
p_sys->p_capture_filter->Release();
p_sys->p_control->Release();
p_sys->p_graph->Release();
return VLC_EGENERIC;
}
static IBaseFilter *
FindCaptureDevice( vlc_object_t *p_this, string *p_devicename,
list<string> *p_listdevices )
{
IBaseFilter *pBaseFilter = NULL;
IMoniker *pMoniker = NULL;
ULONG lFetched;
HRESULT hr;
/* Create the system device enumerator */
ICreateDevEnum *pDevEnum = NULL;
hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum );
if( FAILED(hr) )
{
msg_Err( p_this, "failed to create the device enumerator (0x%x)", hr);
return NULL;
}
/* Create an enumerator for the video capture devices */
IEnumMoniker *pClassEnum = NULL;
hr = pDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory,
&pClassEnum, 0 );
if( FAILED(hr) )
{
msg_Err( p_this, "failed to create the class enumerator (0x%x)", hr );
return NULL;
}
/* If there are no enumerators for the requested type, then
* CreateClassEnumerator will succeed, but pClassEnum will be NULL */
if( pClassEnum == NULL )
{
msg_Err( p_this, "no video capture device was detected." );
return NULL;
}
/* Enumerate the devices */
/* Note that if the Next() call succeeds but there are no monikers,
* it will return S_FALSE (which is not a failure). Therefore, we check
* that the return code is S_OK instead of using SUCCEEDED() macro. */
while( pClassEnum->Next( 1, &pMoniker, &lFetched ) == S_OK )
{
/* Getting the property page to get the device name */
IPropertyBag *pBag;
hr = pMoniker->BindToStorage( 0, 0, IID_IPropertyBag,
reinterpret_cast<PVOID *>( &pBag ) );
if( SUCCEEDED(hr) )
{
VARIANT var;
var.vt = VT_BSTR;
hr = pBag->Read( L"FriendlyName", &var, NULL );
pBag->Release();
if( SUCCEEDED(hr) )
{
int i_convert = ( lstrlenW( var.bstrVal ) + 1 ) * 2;
char *p_buf = (char *)alloca( i_convert ); p_buf[0] = 0;
WideCharToMultiByte( CP_ACP, 0, var.bstrVal, -1, p_buf,
i_convert, NULL, NULL );
SysFreeString(var.bstrVal);
if( p_listdevices ) p_listdevices->push_back( p_buf );
if( p_devicename && *p_devicename == string(p_buf) )
{
/* Bind Moniker to a filter object */
hr = pMoniker->BindToObject( 0, 0, IID_IBaseFilter,
reinterpret_cast<LPVOID *>(&pBaseFilter) );
if( FAILED(hr) )
{
msg_Err( p_this, "couldn't bind moniker to filter "
"object (0x%x)", hr );
return NULL;
}
return pBaseFilter;
}
}
}
}
return NULL;
}
/*****************************************************************************
* Read: reads from the device into PES packets.
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* bytes.
*****************************************************************************/
static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
{
access_sys_t *p_sys = p_input->p_access_data;
int i_data = 0;
#if 0
msg_Info( p_input, "access read data_size %i, data_pos %i",
p_sys->i_data_size, p_sys->i_data_pos );
#endif
while( i_len > 0 )
{
/* First copy header if any */
if( i_len > 0 && p_sys->i_header_pos < p_sys->i_header_size )
{
int i_copy;
i_copy = __MIN( p_sys->i_header_size -
p_sys->i_header_pos, (int)i_len );
memcpy( p_buffer, &p_sys->p_header[p_sys->i_header_pos], i_copy );
p_sys->i_header_pos += i_copy;
p_buffer += i_copy;
i_len -= i_copy;
i_data += i_copy;
}
/* Then copy data */
if( i_len > 0 && p_sys->i_data_pos < p_sys->i_data_size )
{
int i_copy;
i_copy = __MIN( p_sys->i_data_size -
p_sys->i_data_pos, (int)i_len );
memcpy( p_buffer, &p_sys->p_data[p_sys->i_data_pos], i_copy );
p_sys->i_data_pos += i_copy;
p_buffer += i_copy;
i_len -= i_copy;
i_data += i_copy;
}
/* The caller got what he wanted */
if( i_len <= 0 )
{
return i_data;
}
/* Read no more than one frame at a time, otherwise we kill latency */
if( p_sys->i_data_size && i_data &&
p_sys->i_data_pos == p_sys->i_data_size )
{
p_sys->i_data_pos = 0; p_sys->i_data_size = 0;
return i_data;
}
/* Start new audio/video frame */
if( p_sys->sample.p_sample )
{
//p_sys->sample.p_sample->Release();
}
if( p_sys->p_capture_filter->CustomGetPin()
->CustomGetSample( &p_sys->sample ) == S_OK )
{
p_sys->i_data_pos = 0;
p_sys->i_data_size = p_sys->sample.p_sample->GetActualDataLength();
p_sys->sample.p_sample->GetPointer( &p_sys->p_data );
REFERENCE_TIME i_pts, i_end_date;
HRESULT hr = p_sys->sample.p_sample
->GetTime( &i_pts, &i_end_date );
if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
if( !i_pts )
{
/* Use our data timestamp */
i_pts = p_sys->sample.i_timestamp;
}
#if 0
msg_Dbg( p_input, "Read() PTS: "I64Fd, i_pts );
#endif
/* create pseudo header */
p_sys->i_header_size = 16;
p_sys->i_header_pos = 0;
SetDWBE( &p_sys->p_header[0], 0 /*i_stream*/ );
SetDWBE( &p_sys->p_header[4], p_sys->i_data_size );
SetQWBE( &p_sys->p_header[8], i_pts * 9 / 1000 );
}
else msleep( 10000 );
}
return i_data;
}
/****************************************************************************
* I. Demux Part
****************************************************************************/
static int DemuxOpen( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
uint8_t *p_peek;
int i_streams;
int i;
data_packet_t *p_pk;
/* Initialize access plug-in structures. */
if( p_input->i_mtu == 0 )
{
/* Improve speed. */
p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
}
/* a little test to see if it's a v4l stream */
if( input_Peek( p_input, &p_peek, 8 ) < 8 )
{
msg_Warn( p_input, "v4l plugin discarded (cannot peek)" );
return( VLC_EGENERIC );
}
if( strcmp( (const char *)p_peek, ".dsh" ) ||
GetDWBE( &p_peek[4] ) <= 0 )
{
msg_Warn( p_input, "v4l plugin discarded (not a valid stream)" );
return VLC_EGENERIC;
}
/* create one program */
vlc_mutex_lock( &p_input->stream.stream_lock );
if( input_InitStream( p_input, 0 ) == -1)
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
msg_Err( p_input, "cannot init stream" );
return( VLC_EGENERIC );
}
if( input_AddProgram( p_input, 0, 0) == NULL )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
msg_Err( p_input, "cannot add program" );
return( VLC_EGENERIC );
}
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
p_input->stream.i_mux_rate = 0;
i_streams = GetDWBE( &p_peek[4] );
if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
< 8 + 20 * i_streams )
{
msg_Err( p_input, "v4l plugin discarded (cannot peek)" );
return( VLC_EGENERIC );
}
p_peek += 8;
for( i = 0; i < i_streams; i++ )
{
es_descriptor_t *p_es;
if( !strncmp( (const char *)p_peek, "auds", 4 ) )
{
#define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
i + 1, AUDIO_ES, NULL, 0 );
p_es->i_stream_id = i + 1;
p_es->i_fourcc =
VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
wf->wFormatTag = 0;//WAVE_FORMAT_UNKNOWN;
wf->nChannels = GetDWBE( &p_peek[8] );
wf->nSamplesPerSec = GetDWBE( &p_peek[12] );
wf->wBitsPerSample = GetDWBE( &p_peek[16] );
wf->nBlockAlign = wf->wBitsPerSample * wf->nChannels / 8;
wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
wf->cbSize = 0;
msg_Dbg( p_input, "added new audio es %d channels %dHz",
wf->nChannels, wf->nSamplesPerSec );
input_SelectES( p_input, p_es );
#undef wf
}
else if( !strncmp( (const char *)p_peek, "vids", 4 ) )
{
#define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
i + 1, VIDEO_ES, NULL, 0 );
p_es->i_stream_id = i + 1;
p_es->i_fourcc =
VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
bih->biSize = sizeof( BITMAPINFOHEADER );
bih->biWidth = GetDWBE( &p_peek[8] );
bih->biHeight = GetDWBE( &p_peek[12] );
bih->biPlanes = 0;
bih->biBitCount = 0;
bih->biCompression = 0;
bih->biSizeImage= 0;
bih->biXPelsPerMeter = 0;
bih->biYPelsPerMeter = 0;
bih->biClrUsed = 0;
bih->biClrImportant = 0;
msg_Dbg( p_input, "added new video es %4.4s %dx%d",
(char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
input_SelectES( p_input, p_es );
#undef bih
}
p_peek += 20;
}
p_input->stream.p_selected_program->b_is_ok = 1;
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
{
input_DeletePacket( p_input->p_method_data, p_pk );
}
p_input->pf_demux = Demux;
return VLC_SUCCESS;
}
static void DemuxClose( vlc_object_t *p_this )
{
return;
}
static int Demux( input_thread_t *p_input )
{
es_descriptor_t *p_es;
pes_packet_t *p_pes;
int i_stream;
int i_size;
uint8_t *p_peek;
mtime_t i_pcr;
if( input_Peek( p_input, &p_peek, 16 ) < 16 )
{
msg_Warn( p_input, "cannot peek (EOF ?)" );
return( 0 );
}
i_stream = GetDWBE( &p_peek[0] );
i_size = GetDWBE( &p_peek[4] );
i_pcr = GetQWBE( &p_peek[8] );
//msg_Dbg( p_input, "stream=%d size=%d", i_stream, i_size );
//p_es = input_FindES( p_input, i_stream );
p_es = p_input->stream.p_selected_program->pp_es[i_stream];
if( !p_es )
{
msg_Err( p_input, "cannot find ES" );
}
p_pes = input_NewPES( p_input->p_method_data );
if( p_pes == NULL )
{
msg_Warn( p_input, "cannot allocate PES" );
msleep( 1000 );
return( 1 );
}
i_size += 16;
while( i_size > 0 )
{
data_packet_t *p_data;
int i_read;
if( (i_read = input_SplitBuffer( p_input, &p_data,
__MIN( i_size, 10000 ) ) ) <= 0 )
{
input_DeletePES( p_input->p_method_data, p_pes );
return( 0 );
}
if( !p_pes->p_first )
{
p_pes->p_first = p_data;
p_pes->i_nb_data = 1;
p_pes->i_pes_size = i_read;
}
else
{
p_pes->p_last->p_next = p_data;
p_pes->i_nb_data++;
p_pes->i_pes_size += i_read;
}
p_pes->p_last = p_data;
i_size -= i_read;
}
p_pes->p_first->p_payload_start += 16;
p_pes->i_pes_size -= 16;
if( p_es && p_es->p_decoder_fifo )
{
/* Call the pace control. */
input_ClockManageRef( p_input, p_input->stream.p_selected_program,
i_pcr );
p_pes->i_pts = p_pes->i_dts = i_pcr <= 0 ? 0 :
input_ClockGetTS( p_input, p_input->stream.p_selected_program,
i_pcr );
input_DecodePES( p_es->p_decoder_fifo, p_pes );
}
else
{
input_DeletePES( p_input->p_method_data, p_pes );
}
return 1;
}
/*****************************************************************************
* filter.c : DirectShow access module for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: filter.cpp,v 1.1 2003/08/24 11:17:39 gbazin Exp $
*
* Author: Gildas Bazin <gbazin@netcourrier.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/vout.h>
#ifndef _MSC_VER
# include <wtypes.h>
# include <unknwn.h>
# include <ole2.h>
# include <limits.h>
# define _WINGDI_ 1
# define AM_NOVTABLE
# define _OBJBASE_H_
# undef _X86_
# define _I64_MAX LONG_LONG_MAX
# define LONGLONG long long
#endif
#include <dshow.h>
#include "filter.h"
#define DEBUG_DSHOW 1
/*****************************************************************************
* DirectShow GUIDs.
* Easier to define them hear as mingw doesn't provide them all.
*****************************************************************************/
const GUID CLSID_SystemDeviceEnum = {0x62be5d10, 0x60eb, 0x11d0, {0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
const GUID CLSID_VideoInputDeviceCategory = {0x860BB310,0x5D01,0x11d0,{0xBD,0x3B,0x00,0xA0,0xC9,0x11,0xCE,0x86}};
const GUID IID_IPropertyBag = {0x55272A00, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
const GUID IID_ICreateDevEnum = {0x29840822, 0x5b84, 0x11d0, {0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86}};
const GUID IID_IFilterGraph = {0x56a8689f, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID IID_IMediaControl = {0x56a868b1, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID CLSID_FilterGraph = {0xe436ebb3, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID IID_IUnknown = {0x00000000, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46}};
const GUID IID_IMediaFilter = {0x56a86899, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IBaseFilter = {0x56a86895, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID IID_IPin = {0x56a86891, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IMemInputPin = {0x56a8689d, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IEnumPins = {0x56a86892, 0x0ad4, 0x11ce, {0xb0,0x3a, 0x00,0x20,0xaf,0x0b,0xa7,0x70}};
const GUID IID_IEnumMediaTypes = {0x89c31040, 0x846b, 0x11ce, {0x97,0xd3, 0x00,0xaa,0x00,0x55,0x59,0x5a}};
/*
* MEDIATYPEs and MEDIASUBTYPEs
*/
const GUID MEDIATYPE_Video = {0x73646976, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_RGB8 = {0xe436eb7a, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB565 = {0xe436eb7b, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB555 = {0xe436eb7c, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB24 = {0xe436eb7d, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_RGB32 = {0xe436eb7e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
const GUID MEDIASUBTYPE_ARGB32 = {0x773c9ac0, 0x3274, 0x11d0, {0xb7, 0x24, 0x0, 0xaa, 0x0, 0x6c, 0x1a, 0x1}};
const GUID MEDIASUBTYPE_YUYV = {0x56595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_Y411 = {0x31313459, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_Y41P = {0x50313459, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_YUY2 = {0x32595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_YVYU = {0x55595659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_UYVY = {0x59565955, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_Y211 = {0x31313259, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
const GUID MEDIASUBTYPE_YV12 = {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt )
{
if( mt.cbFormat != 0 )
{
CoTaskMemFree( (PVOID)mt.pbFormat );
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if( mt.pUnk != NULL )
{
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
HRESULT WINAPI CopyMediaType( AM_MEDIA_TYPE *pmtTarget,
const AM_MEDIA_TYPE *pmtSource )
{
*pmtTarget = *pmtSource;
if( pmtSource->cbFormat != 0 )
{
pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc( pmtSource->cbFormat );
if( pmtTarget->pbFormat == NULL )
{
pmtTarget->cbFormat = 0;
return E_OUTOFMEMORY;
}
else
{
CopyMemory( (PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
pmtTarget->cbFormat );
}
}
if( pmtTarget->pUnk != NULL )
{
pmtTarget->pUnk->AddRef();
}
return S_OK;
}
/****************************************************************************
* Implementation of our dummy directshow filter pin class
****************************************************************************/
CapturePin::CapturePin( input_thread_t * _p_input, CaptureFilter *_p_filter )
: p_input( _p_input ), p_filter( _p_filter ), p_connected_pin( NULL ),
i_ref( 1 )
{
}
CapturePin::~CapturePin()
{
}
HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
{
if( samples_queue.size() )
{
*vlc_sample = samples_queue.back();
samples_queue.pop_back();
return S_OK;
}
return S_FALSE;
}
AM_MEDIA_TYPE CapturePin::CustomGetMediaType()
{
return media_type;
}
/* IUnknown methods */
STDMETHODIMP CapturePin::QueryInterface(REFIID riid, void **ppv)
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::QueryInterface" );
#endif
if( riid == IID_IUnknown ||
riid == IID_IPin )
{
*ppv = (IPin *)this;
return NOERROR;
}
if( riid == IID_IMemInputPin )
{
*ppv = (IMemInputPin *)this;
return NOERROR;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) CapturePin::AddRef()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::AddRef" );
#endif
i_ref++;
return NOERROR;
};
STDMETHODIMP_(ULONG) CapturePin::Release()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::Release" );
#endif
i_ref--;
if( !i_ref ) delete this;
return NOERROR;
};
/* IPin methods */
STDMETHODIMP CapturePin::Connect( IPin * pReceivePin,
const AM_MEDIA_TYPE *pmt )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::Connect" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::ReceiveConnection( IPin * pConnector,
const AM_MEDIA_TYPE *pmt )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::ReceiveConnection" );
#endif
p_connected_pin = pConnector;
p_connected_pin->AddRef();
return CopyMediaType( &media_type, pmt );
}
STDMETHODIMP CapturePin::Disconnect()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::Disconnect" );
#endif
p_connected_pin->Release();
p_connected_pin = NULL;
FreeMediaType( media_type );
return S_OK;
}
STDMETHODIMP CapturePin::ConnectedTo( IPin **pPin )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::ConnectedTo" );
#endif
p_connected_pin->AddRef();
*pPin = p_connected_pin;
return S_OK;
}
STDMETHODIMP CapturePin::ConnectionMediaType( AM_MEDIA_TYPE *pmt )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::ConnectionMediaType" );
#endif
return CopyMediaType( pmt, &media_type );
}
STDMETHODIMP CapturePin::QueryPinInfo( PIN_INFO * pInfo )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::QueryPinInfo" );
#endif
pInfo->pFilter = p_filter;
if( p_filter ) p_filter->AddRef();
pInfo->achName[0] = L'\0';
pInfo->dir = PINDIR_INPUT;
return NOERROR;
}
STDMETHODIMP CapturePin::QueryDirection( PIN_DIRECTION * pPinDir )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::QueryDirection" );
#endif
*pPinDir = PINDIR_INPUT;
return NOERROR;
}
STDMETHODIMP CapturePin::QueryId( LPWSTR * Id )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::QueryId" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::QueryAccept( const AM_MEDIA_TYPE *pmt )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::QueryAccept" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::EnumMediaTypes" );
#endif
*ppEnum = new CaptureEnumMediaTypes( p_input, this, NULL );
if( *ppEnum == NULL ) return E_OUTOFMEMORY;
return NOERROR;
}
STDMETHODIMP CapturePin::QueryInternalConnections( IPin* *apPin, ULONG *nPin )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::QueryInternalConnections" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::EndOfStream( void )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::EndOfStream" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::BeginFlush( void )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::BeginFlush" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::EndFlush( void )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::EndFlush" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::NewSegment( REFERENCE_TIME tStart,
REFERENCE_TIME tStop,
double dRate )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::NewSegment" );
#endif
return E_NOTIMPL;
}
/* IMemInputPin methods */
STDMETHODIMP CapturePin::GetAllocator( IMemAllocator **ppAllocator )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::GetAllocator" );
#endif
return VFW_E_NO_ALLOCATOR;
}
STDMETHODIMP CapturePin::NotifyAllocator( IMemAllocator *pAllocator,
BOOL bReadOnly )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::NotifyAllocator" );
#endif
return S_OK;
}
STDMETHODIMP CapturePin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::GetAllocatorRequirements" );
#endif
return E_NOTIMPL;
}
STDMETHODIMP CapturePin::Receive( IMediaSample *pSample )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::Receive" );
#endif
//pSample->AddRef();
mtime_t i_timestamp = mdate() * 10;
VLCMediaSample vlc_sample = {pSample, i_timestamp};
samples_queue.push_front( vlc_sample );
/* Make sure we don't cache too many samples */
if( samples_queue.size() > 10 )
{
vlc_sample = samples_queue.back();
samples_queue.pop_back();
msg_Dbg( p_input, "CapturePin::Receive trashing late input sample" );
// vlc_sample.p_sample->Release();
}
return S_OK;
}
STDMETHODIMP CapturePin::ReceiveMultiple( IMediaSample **pSamples,
long nSamples,
long *nSamplesProcessed )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::ReceiveMultiple" );
#endif
HRESULT hr = S_OK;
*nSamplesProcessed = 0;
while( nSamples-- > 0 )
{
hr = Receive( pSamples[*nSamplesProcessed] );
if( hr != S_OK ) break;
(*nSamplesProcessed)++;
}
return hr;
}
STDMETHODIMP CapturePin::ReceiveCanBlock( void )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CapturePin::ReceiveCanBlock" );
#endif
return S_FALSE; /* Thou shalt not block */
}
/****************************************************************************
* Implementation of our dummy directshow filter class
****************************************************************************/
CaptureFilter::CaptureFilter( input_thread_t * _p_input )
: p_input( _p_input ), p_pin( new CapturePin( _p_input, this ) ),
i_ref( 1 )
{
}
CaptureFilter::~CaptureFilter()
{
p_pin->Release();
}
/* IUnknown methods */
STDMETHODIMP CaptureFilter::QueryInterface( REFIID riid, void **ppv )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::QueryInterface" );
#endif
if( riid == IID_IUnknown )
{
*ppv = (IUnknown *)this;
return NOERROR;
}
if( riid == IID_IPersist )
{
*ppv = (IPersist *)this;
return NOERROR;
}
if( riid == IID_IMediaFilter )
{
*ppv = (IMediaFilter *)this;
return NOERROR;
}
if( riid == IID_IBaseFilter )
{
*ppv = (IBaseFilter *)this;
return NOERROR;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
};
STDMETHODIMP_(ULONG) CaptureFilter::AddRef()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::AddRef" );
#endif
i_ref++;
return NOERROR;
};
STDMETHODIMP_(ULONG) CaptureFilter::Release()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::Release" );
#endif
i_ref--;
if( !i_ref ) delete this;
return NOERROR;
};
/* IPersist method */
STDMETHODIMP CaptureFilter::GetClassID(CLSID *pClsID)
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::GetClassID" );
#endif
return E_NOTIMPL;
};
/* IMediaFilter methods */
STDMETHODIMP CaptureFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::GetStat" );
#endif
return E_NOTIMPL;
};
STDMETHODIMP CaptureFilter::SetSyncSource(IReferenceClock *pClock)
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::SetSyncSource" );
#endif
return NOERROR;
};
STDMETHODIMP CaptureFilter::GetSyncSource(IReferenceClock **pClock)
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::GetSyncSource" );
#endif
return E_NOTIMPL;
};
STDMETHODIMP CaptureFilter::Stop()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::Stop" );
#endif
return E_NOTIMPL;
};
STDMETHODIMP CaptureFilter::Pause()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::Pause" );
#endif
return E_NOTIMPL;
};
STDMETHODIMP CaptureFilter::Run(REFERENCE_TIME tStart)
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::Run" );
#endif
return E_NOTIMPL;
};
/* IBaseFilter methods */
STDMETHODIMP CaptureFilter::EnumPins( IEnumPins ** ppEnum )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::EnumPins" );
#endif
/* Create a new ref counted enumerator */
*ppEnum = new CaptureEnumPins( p_input, this, NULL );
return *ppEnum == NULL ? E_OUTOFMEMORY : NOERROR;
};
STDMETHODIMP CaptureFilter::FindPin( LPCWSTR Id, IPin ** ppPin )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::FindPin" );
#endif
return E_NOTIMPL;
};
STDMETHODIMP CaptureFilter::QueryFilterInfo( FILTER_INFO * pInfo )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::QueryFilterInfo" );
#endif
pInfo->achName[0] = L'\0';
pInfo->pGraph = p_graph;
if( p_graph ) p_graph->AddRef();
return NOERROR;
};
STDMETHODIMP CaptureFilter::JoinFilterGraph( IFilterGraph * pGraph,
LPCWSTR pName )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::JoinFilterGraph" );
#endif
p_graph = pGraph;
return NOERROR;
};
STDMETHODIMP CaptureFilter::QueryVendorInfo( LPWSTR* pVendorInfo )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureFilter::QueryVendorInfo" );
#endif
return E_NOTIMPL;
};
/* Custom methods */
CapturePin *CaptureFilter::CustomGetPin()
{
return p_pin;
}
/****************************************************************************
* Implementation of our dummy directshow enumpins class
****************************************************************************/
CaptureEnumPins::CaptureEnumPins( input_thread_t * _p_input,
CaptureFilter *_p_filter,
CaptureEnumPins *pEnumPins )
: p_input( _p_input ), p_filter( _p_filter ), i_ref( 1 )
{
/* Hold a reference count on our filter */
p_filter->AddRef();
/* Are we creating a new enumerator */
if( pEnumPins == NULL )
{
i_position = 0;
}
else
{
i_position = pEnumPins->i_position;
}
}
CaptureEnumPins::~CaptureEnumPins()
{
p_filter->Release();
}
/* IUnknown methods */
STDMETHODIMP CaptureEnumPins::QueryInterface( REFIID riid, void **ppv )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::QueryInterface" );
#endif
if( riid == IID_IUnknown ||
riid == IID_IEnumPins )
{
*ppv = (IEnumPins *)this;
return NOERROR;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
};
STDMETHODIMP_(ULONG) CaptureEnumPins::AddRef()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::AddRef" );
#endif
i_ref++;
return NOERROR;
};
STDMETHODIMP_(ULONG) CaptureEnumPins::Release()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::Release" );
#endif
i_ref--;
if( !i_ref ) delete this;
return NOERROR;
};
/* IEnumPins */
STDMETHODIMP CaptureEnumPins::Next( ULONG cPins, IPin ** ppPins,
ULONG * pcFetched )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::Next" );
#endif
*pcFetched = 0;
if( i_position < 1 && cPins > 0 )
{
IPin *pPin = p_filter->CustomGetPin();
*ppPins = pPin;
pPin->AddRef();
*pcFetched = 1;
i_position++;
return NOERROR;
}
return S_FALSE;
};
STDMETHODIMP CaptureEnumPins::Skip( ULONG cPins )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::Skip" );
#endif
if( cPins > 1 )
{
return S_FALSE;
}
i_position += cPins;
return NOERROR;
};
STDMETHODIMP CaptureEnumPins::Reset()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::Reset" );
#endif
i_position = 0;
return S_OK;
};
STDMETHODIMP CaptureEnumPins::Clone( IEnumPins **ppEnum )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumPins::Clone" );
#endif
*ppEnum = new CaptureEnumPins( p_input, p_filter, this );
if( *ppEnum == NULL ) return E_OUTOFMEMORY;
return NOERROR;
};
/****************************************************************************
* Implementation of our dummy directshow enummediatypes class
****************************************************************************/
CaptureEnumMediaTypes::CaptureEnumMediaTypes( input_thread_t * _p_input,
CapturePin *_p_pin,
CaptureEnumMediaTypes *pEnumMediaTypes )
: p_input( _p_input ), p_pin( _p_pin ), i_ref( 1 )
{
/* Hold a reference count on our filter */
p_pin->AddRef();
/* Are we creating a new enumerator */
if( pEnumMediaTypes == NULL )
{
i_position = 0;
}
else
{
i_position = pEnumMediaTypes->i_position;
}
}
CaptureEnumMediaTypes::~CaptureEnumMediaTypes()
{
p_pin->Release();
}
/* IUnknown methods */
STDMETHODIMP CaptureEnumMediaTypes::QueryInterface( REFIID riid, void **ppv )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::QueryInterface" );
#endif
if( riid == IID_IUnknown ||
riid == IID_IEnumMediaTypes )
{
*ppv = (IEnumMediaTypes *)this;
return NOERROR;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
};
STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::AddRef()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::AddRef" );
#endif
i_ref++;
return NOERROR;
};
STDMETHODIMP_(ULONG) CaptureEnumMediaTypes::Release()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::Release" );
#endif
i_ref--;
if( !i_ref ) delete this;
return NOERROR;
};
/* IEnumMediaTypes */
STDMETHODIMP CaptureEnumMediaTypes::Next( ULONG cMediaTypes,
AM_MEDIA_TYPE ** ppMediaTypes,
ULONG * pcFetched )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::Next" );
#endif
*pcFetched = 0;
#if 0
if( i_position < 1 && cMediaTypes > 0 )
{
IPin *pPin = p_pin->CustomGetPin();
*ppMediaTypes = pPin;
pPin->AddRef();
*pcFetched = 1;
i_position++;
return NOERROR;
}
#endif
return S_FALSE;
};
STDMETHODIMP CaptureEnumMediaTypes::Skip( ULONG cMediaTypes )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::Skip" );
#endif
if( cMediaTypes > 1 )
{
return S_FALSE;
}
i_position += cMediaTypes;
return NOERROR;
};
STDMETHODIMP CaptureEnumMediaTypes::Reset()
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::Reset" );
#endif
i_position = 0;
return S_OK;
};
STDMETHODIMP CaptureEnumMediaTypes::Clone( IEnumMediaTypes **ppEnum )
{
#ifdef DEBUG_DSHOW
msg_Dbg( p_input, "CaptureEnumMediaTypes::Clone" );
#endif
*ppEnum = new CaptureEnumMediaTypes( p_input, p_pin, this );
if( *ppEnum == NULL ) return E_OUTOFMEMORY;
return NOERROR;
};
/*****************************************************************************
* filter.h : DirectShow access module for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: filter.h,v 1.1 2003/08/24 11:17:39 gbazin Exp $
*
* Author: Gildas Bazin <gbazin@netcourrier.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <string>
#include <list>
#include <deque>
using namespace std;
typedef struct VLCMediaSample
{
IMediaSample *p_sample;
mtime_t i_timestamp;
} VLCMediaSample;
class CaptureFilter;
void WINAPI FreeMediaType( AM_MEDIA_TYPE& mt );
HRESULT WINAPI CopyMediaType( AM_MEDIA_TYPE *pmtTarget,
const AM_MEDIA_TYPE *pmtSource );
/****************************************************************************
* Declaration of our dummy directshow filter pin class
****************************************************************************/
class CapturePin: public IPin, public IMemInputPin
{
input_thread_t * p_input;
CaptureFilter *p_filter;
IPin *p_connected_pin;
AM_MEDIA_TYPE media_type;
deque<VLCMediaSample> samples_queue;
int i_ref;
public:
CapturePin( input_thread_t * _p_input, CaptureFilter *_p_filter );
virtual ~CapturePin();
/* IUnknown methods */
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
/* IPin methods */
STDMETHODIMP Connect( IPin * pReceivePin, const AM_MEDIA_TYPE *pmt );
STDMETHODIMP ReceiveConnection( IPin * pConnector,
const AM_MEDIA_TYPE *pmt );
STDMETHODIMP Disconnect();
STDMETHODIMP ConnectedTo( IPin **pPin );
STDMETHODIMP ConnectionMediaType( AM_MEDIA_TYPE *pmt );
STDMETHODIMP QueryPinInfo( PIN_INFO * pInfo );
STDMETHODIMP QueryDirection( PIN_DIRECTION * pPinDir );
STDMETHODIMP QueryId( LPWSTR * Id );
STDMETHODIMP QueryAccept( const AM_MEDIA_TYPE *pmt );
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
STDMETHODIMP QueryInternalConnections( IPin* *apPin, ULONG *nPin );
STDMETHODIMP EndOfStream( void );
STDMETHODIMP BeginFlush( void );
STDMETHODIMP EndFlush( void );
STDMETHODIMP NewSegment( REFERENCE_TIME tStart, REFERENCE_TIME tStop,
double dRate );
/* IMemInputPin methods */
STDMETHODIMP GetAllocator( IMemAllocator **ppAllocator );
STDMETHODIMP NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly );
STDMETHODIMP GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps );
STDMETHODIMP Receive( IMediaSample *pSample );
STDMETHODIMP ReceiveMultiple( IMediaSample **pSamples, long nSamples,
long *nSamplesProcessed );
STDMETHODIMP ReceiveCanBlock( void );
/* Custom methods */
HRESULT CustomGetSample( VLCMediaSample * );
AM_MEDIA_TYPE CustomGetMediaType();
};
/****************************************************************************
* Declaration of our dummy directshow filter class
****************************************************************************/
class CaptureFilter : public IBaseFilter
{
input_thread_t * p_input;
CapturePin *p_pin;
IFilterGraph * p_graph;
int i_ref;
public:
CaptureFilter( input_thread_t * _p_input );
virtual ~CaptureFilter();
/* IUnknown methods */
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
/* IPersist method */
STDMETHODIMP GetClassID(CLSID *pClsID);
/* IMediaFilter methods */
STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State);
STDMETHODIMP SetSyncSource(IReferenceClock *pClock);
STDMETHODIMP GetSyncSource(IReferenceClock **pClock);
STDMETHODIMP Stop();
STDMETHODIMP Pause();
STDMETHODIMP Run(REFERENCE_TIME tStart);
/* IBaseFilter methods */
STDMETHODIMP EnumPins( IEnumPins ** ppEnum );
STDMETHODIMP FindPin( LPCWSTR Id, IPin ** ppPin );
STDMETHODIMP QueryFilterInfo( FILTER_INFO * pInfo );
STDMETHODIMP JoinFilterGraph( IFilterGraph * pGraph, LPCWSTR pName );
STDMETHODIMP QueryVendorInfo( LPWSTR* pVendorInfo );
/* Custom methods */
CapturePin *CustomGetPin();
};
/****************************************************************************
* Declaration of our dummy directshow enumpins class
****************************************************************************/
class CaptureEnumPins : public IEnumPins
{
input_thread_t * p_input;
int i_position;
CaptureFilter *p_filter;
int i_ref;
public:
CaptureEnumPins( input_thread_t * _p_input, CaptureFilter *_p_filter,
CaptureEnumPins *pEnumPins );
virtual ~CaptureEnumPins();
// IUnknown
STDMETHODIMP QueryInterface( REFIID riid, void **ppv );
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IEnumPins
STDMETHODIMP Next( ULONG cPins, IPin ** ppPins, ULONG * pcFetched );
STDMETHODIMP Skip( ULONG cPins );
STDMETHODIMP Reset();
STDMETHODIMP Clone( IEnumPins **ppEnum );
};
/****************************************************************************
* Declaration of our dummy directshow enummediatypes class
****************************************************************************/
class CaptureEnumMediaTypes : public IEnumMediaTypes
{
input_thread_t * p_input;
int i_position;
CapturePin *p_pin;
int i_ref;
public:
CaptureEnumMediaTypes( input_thread_t * _p_input, CapturePin *_p_pin,
CaptureEnumMediaTypes *pEnumMediaTypes );
virtual ~CaptureEnumMediaTypes();
// IUnknown
STDMETHODIMP QueryInterface( REFIID riid, void **ppv );
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IEnumMediaTypes
STDMETHODIMP Next( ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes,
ULONG * pcFetched );
STDMETHODIMP Skip( ULONG cMediaTypes );
STDMETHODIMP Reset();
STDMETHODIMP Clone( IEnumMediaTypes **ppEnum );
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment