Commit 6bc91ea5 authored by Gildas Bazin's avatar Gildas Bazin

* modules/access/dshow/*:

  - switch to access_demux module for raw video/audio streams.
  - massive cleanup and simplifications.
  - a bunch of fixes.
parent b2c7b5a0
SOURCES_dshow = dshow.cpp filter.cpp filter.h
SOURCES_dshow = dshow.cpp common.h filter.cpp filter.h crossbar.cpp
/*****************************************************************************
* common.h : DirectShow access module for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id$
*
* Author: Gildas Bazin <gbazin@videolan.org>
*
* 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;
#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>
typedef struct dshow_stream_t dshow_stream_t;
/****************************************************************************
* Crossbar stuff
****************************************************************************/
#define MAX_CROSSBAR_DEPTH 10
typedef struct CrossbarRouteRec
{
IAMCrossbar *pXbar;
LONG VideoInputIndex;
LONG VideoOutputIndex;
LONG AudioInputIndex;
LONG AudioOutputIndex;
} CrossbarRoute;
void DeleteCrossbarRoutes( access_sys_t * );
HRESULT FindCrossbarRoutes( vlc_object_t *, access_sys_t *,
IPin *, LONG, int = 0 );
/****************************************************************************
* Access descriptor declaration
****************************************************************************/
struct access_sys_t
{
/* These 2 must be left at the beginning */
vlc_mutex_t lock;
vlc_cond_t wait;
IFilterGraph *p_graph;
ICaptureGraphBuilder2 *p_capture_graph_builder2;
IMediaControl *p_control;
int i_crossbar_route_depth;
CrossbarRoute crossbar_routes[MAX_CROSSBAR_DEPTH];
/* list of elementary streams */
dshow_stream_t **pp_streams;
int i_streams;
int i_current_stream;
/* misc properties */
int i_width;
int i_height;
int i_chroma;
};
/*****************************************************************************
* crossbar.c : DirectShow access module for vlc
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id$
*
* Author: Damien Fouilleul <damien dot fouilleul at laposte dot net>
*
* 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>
#include "common.h"
/*****************************************************************************
* DeleteCrossbarRoutes
*****************************************************************************/
void DeleteCrossbarRoutes( access_sys_t *p_sys )
{
/* Remove crossbar filters from graph */
for( int i = 0; i < p_sys->i_crossbar_route_depth; i++ )
{
p_sys->crossbar_routes[i].pXbar->Release();
}
p_sys->i_crossbar_route_depth = 0;
}
/*****************************************************************************
* RouteCrossbars (Does not AddRef the returned *Pin)
*****************************************************************************/
static HRESULT GetCrossbarIPinAtIndex( IAMCrossbar *pXbar, LONG PinIndex,
BOOL IsInputPin, IPin ** ppPin )
{
LONG cntInPins, cntOutPins;
IPin *pP = 0;
IBaseFilter *pFilter = NULL;
IEnumPins *pins=0;
ULONG n;
if( !pXbar || !ppPin ) return E_POINTER;
*ppPin = 0;
if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) ) return E_FAIL;
LONG TrueIndex = IsInputPin ? PinIndex : PinIndex + cntInPins;
if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
{
if( SUCCEEDED(pFilter->EnumPins(&pins)) )
{
LONG i = 0;
while( pins->Next(1, &pP, &n) == S_OK )
{
pP->Release();
if( i == TrueIndex )
{
*ppPin = pP;
break;
}
i++;
}
pins->Release();
}
pFilter->Release();
}
return *ppPin ? S_OK : E_FAIL;
}
/*****************************************************************************
* GetCrossbarIndexFromIPin: Find corresponding index of an IPin on a crossbar
*****************************************************************************/
static HRESULT GetCrossbarIndexFromIPin( IAMCrossbar * pXbar, LONG * PinIndex,
BOOL IsInputPin, IPin * pPin )
{
LONG cntInPins, cntOutPins;
IPin *pP = 0;
IBaseFilter *pFilter = NULL;
IEnumPins *pins = 0;
ULONG n;
BOOL fOK = FALSE;
if(!pXbar || !PinIndex || !pPin )
return E_POINTER;
if( S_OK != pXbar->get_PinCounts(&cntOutPins, &cntInPins) )
return E_FAIL;
if( pXbar->QueryInterface(IID_IBaseFilter, (void **)&pFilter) == S_OK )
{
if( SUCCEEDED(pFilter->EnumPins(&pins)) )
{
LONG i=0;
while( pins->Next(1, &pP, &n) == S_OK )
{
pP->Release();
if( pPin == pP )
{
*PinIndex = IsInputPin ? i : i - cntInPins;
fOK = TRUE;
break;
}
i++;
}
pins->Release();
}
pFilter->Release();
}
return fOK ? S_OK : E_FAIL;
}
/*****************************************************************************
* FindCrossbarRoutes
*****************************************************************************/
HRESULT FindCrossbarRoutes( vlc_object_t *p_this, access_sys_t *p_sys,
IPin *p_input_pin, LONG physicalType, int depth )
{
HRESULT result = S_FALSE;
IPin *p_output_pin;
if( FAILED(p_input_pin->ConnectedTo(&p_output_pin)) ) return S_FALSE;
// It is connected, so now find out if the filter supports IAMCrossbar
PIN_INFO pinInfo;
if( FAILED(p_output_pin->QueryPinInfo(&pinInfo)) ||
PINDIR_OUTPUT != pinInfo.dir )
{
p_output_pin->Release ();
return S_FALSE;
}
IAMCrossbar *pXbar=0;
if( FAILED(pinInfo.pFilter->QueryInterface(IID_IAMCrossbar,
(void **)&pXbar)) )
{
pinInfo.pFilter->Release();
p_output_pin->Release ();
return S_FALSE;
}
LONG inputPinCount, outputPinCount;
if( FAILED(pXbar->get_PinCounts(&outputPinCount, &inputPinCount)) )
{
pXbar->Release();
pinInfo.pFilter->Release();
p_output_pin->Release ();
return S_FALSE;
}
LONG inputPinIndexRelated, outputPinIndexRelated;
LONG inputPinPhysicalType, outputPinPhysicalType;
LONG inputPinIndex, outputPinIndex;
if( FAILED(GetCrossbarIndexFromIPin( pXbar, &outputPinIndex,
FALSE, p_output_pin )) ||
FAILED(pXbar->get_CrossbarPinInfo( FALSE, outputPinIndex,
&outputPinIndexRelated,
&outputPinPhysicalType )) )
{
pXbar->Release();
pinInfo.pFilter->Release();
p_output_pin->Release ();
return S_FALSE;
}
//
// for all input pins
//
for( inputPinIndex = 0; S_OK != result && inputPinIndex < inputPinCount;
inputPinIndex++ )
{
if( FAILED(pXbar->get_CrossbarPinInfo( TRUE, inputPinIndex,
&inputPinIndexRelated, &inputPinPhysicalType )) ) continue;
// Is the pin a video pin?
if( inputPinPhysicalType != physicalType ) continue;
// Can we route it?
if( FAILED(pXbar->CanRoute(outputPinIndex, inputPinIndex)) ) continue;
IPin *pPin;
if( FAILED(GetCrossbarIPinAtIndex( pXbar, inputPinIndex,
TRUE, &pPin)) ) continue;
result = FindCrossbarRoutes( p_this, p_sys, pPin,
physicalType, depth+1 );
if( S_OK == result || (S_FALSE == result &&
physicalType == inputPinPhysicalType &&
(p_sys->i_crossbar_route_depth = depth+1) < MAX_CROSSBAR_DEPTH) )
{
// hold on crossbar
pXbar->AddRef();
// remember crossbar route
p_sys->crossbar_routes[depth].pXbar = pXbar;
p_sys->crossbar_routes[depth].VideoInputIndex = inputPinIndex;
p_sys->crossbar_routes[depth].VideoOutputIndex = outputPinIndex;
p_sys->crossbar_routes[depth].AudioInputIndex = inputPinIndexRelated;
p_sys->crossbar_routes[depth].AudioOutputIndex = outputPinIndexRelated;
msg_Dbg( p_this, "Crossbar at depth %d, Found Route For "
"ouput %ld (type %ld) to input %ld (type %ld)", depth,
outputPinIndex, outputPinPhysicalType, inputPinIndex,
inputPinPhysicalType );
result = S_OK;
}
}
pXbar->Release();
pinInfo.pFilter->Release();
p_output_pin->Release ();
return result;
}
This diff is collapsed.
......@@ -37,17 +37,11 @@
# define QACONTAINERFLAGS QACONTAINERFLAGS_SOMETHINGELSE
#endif
#include "common.h"
#include "filter.h"
#define DEBUG_DSHOW 1
struct access_sys_t
{
vlc_mutex_t lock;
vlc_cond_t wait;
};
#define FILTER_NAME L"VideoLAN Capture Filter"
#define PIN_NAME L"Capture"
......@@ -218,71 +212,71 @@ HRESULT WINAPI CopyMediaType( AM_MEDIA_TYPE *pmtTarget,
return S_OK;
}
int GetFourCCFromMediaType(const AM_MEDIA_TYPE &media_type)
int GetFourCCFromMediaType( const AM_MEDIA_TYPE &media_type )
{
int i_fourcc = 0;
if( media_type.majortype == MEDIATYPE_Video )
{
/* currently only support this type of video info format */
if( media_type.formattype == FORMAT_VideoInfo )
{
/* Packed RGB formats */
if( media_type.subtype == MEDIASUBTYPE_RGB1 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
else if( media_type.subtype == MEDIASUBTYPE_RGB4 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
else if( media_type.subtype == MEDIASUBTYPE_RGB8 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
else if( media_type.subtype == MEDIASUBTYPE_RGB555 )
i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
else if( media_type.subtype == MEDIASUBTYPE_RGB565 )
i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
else if( media_type.subtype == MEDIASUBTYPE_RGB24 )
i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
else if( media_type.subtype == MEDIASUBTYPE_RGB32 )
i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
else if( media_type.subtype == MEDIASUBTYPE_ARGB32 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
/* Planar YUV formats */
else if( media_type.subtype == MEDIASUBTYPE_I420 )
i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
else if( media_type.subtype == MEDIASUBTYPE_Y41P )
i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
else if( media_type.subtype == MEDIASUBTYPE_YV12 )
i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
else if( media_type.subtype == MEDIASUBTYPE_IYUV )
i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
else if( media_type.subtype == MEDIASUBTYPE_YVU9 )
i_fourcc = VLC_FOURCC( 'Y', 'V', 'U', '9' );
/* Packed YUV formats */
else if( media_type.subtype == MEDIASUBTYPE_YVYU )
i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
else if( media_type.subtype == MEDIASUBTYPE_YUYV )
i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
else if( media_type.subtype == MEDIASUBTYPE_Y411 )
i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
else if( media_type.subtype == MEDIASUBTYPE_Y211 )
i_fourcc = VLC_FOURCC( 'Y', '2', '1', '1' );
else if( media_type.subtype == MEDIASUBTYPE_YUY2 )
i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
else if( media_type.subtype == MEDIASUBTYPE_UYVY )
i_fourcc = VLC_FOURCC( 'U', 'Y', 'V', 'Y' );
/* MPEG2 video elementary stream */
else if( media_type.subtype == MEDIASUBTYPE_MPEG2_VIDEO )
i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'v' );
/* DV formats */
else if( media_type.subtype == MEDIASUBTYPE_dvsl )
i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
else if( media_type.subtype == MEDIASUBTYPE_dvsd )
i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'd' );
else if( media_type.subtype == MEDIASUBTYPE_dvhd )
i_fourcc = VLC_FOURCC( 'd', 'v', 'h', 'd' );
}
if( media_type.formattype == FORMAT_VideoInfo )
{
/* Packed RGB formats */
if( media_type.subtype == MEDIASUBTYPE_RGB1 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '1' );
else if( media_type.subtype == MEDIASUBTYPE_RGB4 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '4' );
else if( media_type.subtype == MEDIASUBTYPE_RGB8 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', '8' );
else if( media_type.subtype == MEDIASUBTYPE_RGB555 )
i_fourcc = VLC_FOURCC( 'R', 'V', '1', '5' );
else if( media_type.subtype == MEDIASUBTYPE_RGB565 )
i_fourcc = VLC_FOURCC( 'R', 'V', '1', '6' );
else if( media_type.subtype == MEDIASUBTYPE_RGB24 )
i_fourcc = VLC_FOURCC( 'R', 'V', '2', '4' );
else if( media_type.subtype == MEDIASUBTYPE_RGB32 )
i_fourcc = VLC_FOURCC( 'R', 'V', '3', '2' );
else if( media_type.subtype == MEDIASUBTYPE_ARGB32 )
i_fourcc = VLC_FOURCC( 'R', 'G', 'B', 'A' );
/* Planar YUV formats */
else if( media_type.subtype == MEDIASUBTYPE_I420 )
i_fourcc = VLC_FOURCC( 'I', '4', '2', '0' );
else if( media_type.subtype == MEDIASUBTYPE_Y41P )
i_fourcc = VLC_FOURCC( 'I', '4', '1', '1' );
else if( media_type.subtype == MEDIASUBTYPE_YV12 )
i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
else if( media_type.subtype == MEDIASUBTYPE_IYUV )
i_fourcc = VLC_FOURCC( 'Y', 'V', '1', '2' );
else if( media_type.subtype == MEDIASUBTYPE_YVU9 )
i_fourcc = VLC_FOURCC( 'Y', 'V', 'U', '9' );
/* Packed YUV formats */
else if( media_type.subtype == MEDIASUBTYPE_YVYU )
i_fourcc = VLC_FOURCC( 'Y', 'V', 'Y', 'U' );
else if( media_type.subtype == MEDIASUBTYPE_YUYV )
i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
else if( media_type.subtype == MEDIASUBTYPE_Y411 )
i_fourcc = VLC_FOURCC( 'I', '4', '1', 'N' );
else if( media_type.subtype == MEDIASUBTYPE_Y211 )
i_fourcc = VLC_FOURCC( 'Y', '2', '1', '1' );
else if( media_type.subtype == MEDIASUBTYPE_YUY2 )
i_fourcc = VLC_FOURCC( 'Y', 'U', 'Y', '2' );
else if( media_type.subtype == MEDIASUBTYPE_UYVY )
i_fourcc = VLC_FOURCC( 'U', 'Y', 'V', 'Y' );
/* MPEG2 video elementary stream */
else if( media_type.subtype == MEDIASUBTYPE_MPEG2_VIDEO )
i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'v' );
/* DV formats */
else if( media_type.subtype == MEDIASUBTYPE_dvsl )
i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'l' );
else if( media_type.subtype == MEDIASUBTYPE_dvsd )
i_fourcc = VLC_FOURCC( 'd', 'v', 's', 'd' );
else if( media_type.subtype == MEDIASUBTYPE_dvhd )
i_fourcc = VLC_FOURCC( 'd', 'v', 'h', 'd' );
}
}
else if( media_type.majortype == MEDIATYPE_Audio )
{
......@@ -296,12 +290,13 @@ int GetFourCCFromMediaType(const AM_MEDIA_TYPE &media_type)
}
}
else if( media_type.majortype == MEDIATYPE_Stream )
{
{
if( media_type.subtype == MEDIASUBTYPE_MPEG2_PROGRAM )
i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'p' );
i_fourcc = VLC_FOURCC( 'm', 'p', '2', 'p' );
else if( media_type.subtype == MEDIASUBTYPE_MPEG2_TRANSPORT )
i_fourcc = VLC_FOURCC( 'm', 'p', '2', 't' );
i_fourcc = VLC_FOURCC( 'm', 'p', '2', 't' );
}
return i_fourcc;
}
......@@ -309,10 +304,12 @@ int GetFourCCFromMediaType(const AM_MEDIA_TYPE &media_type)
* Implementation of our dummy directshow filter pin class
****************************************************************************/
CapturePin::CapturePin( access_t * _p_input, CaptureFilter *_p_filter,
CapturePin::CapturePin( vlc_object_t *_p_input, access_sys_t *_p_sys,
CaptureFilter *_p_filter,
AM_MEDIA_TYPE *mt, size_t mt_count )
: p_input( _p_input ), p_filter( _p_filter ), p_connected_pin( NULL ),
media_types(mt), media_type_count(mt_count), i_ref( 1 )
: p_input( _p_input ), p_sys( _p_sys ), p_filter( _p_filter ),
p_connected_pin( NULL ), media_types(mt), media_type_count(mt_count),
i_ref( 1 )
{
cx_media_type.majortype = mt[0].majortype;
cx_media_type.subtype = GUID_NULL;
......@@ -338,7 +335,6 @@ HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
msg_Dbg( p_input, "CapturePin::CustomGetSample" );
#endif
access_sys_t *p_sys = p_input->p_sys;
vlc_mutex_lock( &p_sys->lock );
if( samples_queue.size() )
{
......@@ -415,70 +411,73 @@ STDMETHODIMP_(ULONG) CapturePin::Release()
STDMETHODIMP CapturePin::Connect( IPin * pReceivePin,
const AM_MEDIA_TYPE *pmt )
{
if( State_Running != p_filter->state )
if( State_Running == p_filter->state )
{
if( ! p_connected_pin )
{
if( ! pmt )
return S_OK;
msg_Dbg( p_input, "CapturePin::Connect [not stopped]" );
return VFW_E_NOT_STOPPED;
}
if( p_connected_pin )
{
msg_Dbg( p_input, "CapturePin::Connect [already connected]" );
return VFW_E_ALREADY_CONNECTED;
}
if( !pmt ) return S_OK;
if( (GUID_NULL != pmt->majortype) && (media_types[0].majortype != pmt->majortype) )
msg_Dbg( p_input, "CapturePin::Connect [media major type mismatch]" );
return S_FALSE;
if( (GUID_NULL != pmt->subtype) && (! GetFourCCFromMediaType(*pmt)) )
msg_Dbg( p_input, "CapturePin::Connect [media subtype type not supported]" );
return S_FALSE;
if( pmt->pbFormat )
{
if( pmt->majortype == MEDIATYPE_Video )
{
if( (((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight == 0) )
{
msg_Dbg( p_input, "CapturePin::Connect [video height == 0]" );
return S_FALSE;
}
if( (((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth == 0) )
{
msg_Dbg( p_input, "CapturePin::Connect [video width == 0]" );
return S_FALSE;
}
}
}
msg_Dbg( p_input, "CapturePin::Connect [OK]" );
return S_OK;
if( GUID_NULL != pmt->majortype &&
media_types[0].majortype != pmt->majortype )
{
msg_Dbg( p_input, "CapturePin::Connect [media major type mismatch]" );
return S_FALSE;
}
if( GUID_NULL != pmt->subtype && !GetFourCCFromMediaType(*pmt) )
{
msg_Dbg( p_input, "CapturePin::Connect [media subtype type "
"not supported]" );
return S_FALSE;
}
if( pmt->pbFormat && pmt->majortype == MEDIATYPE_Video )
{
if( !((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biHeight ||
!((VIDEOINFOHEADER *)pmt->pbFormat)->bmiHeader.biWidth )
{
msg_Dbg( p_input, "CapturePin::Connect "
"[video width/height == 0 ]" );
return S_FALSE;
}
msg_Dbg( p_input, "CapturePin::Connect [already connected]" );
return VFW_E_ALREADY_CONNECTED;
}
msg_Dbg( p_input, "CapturePin::Connect [not stopped]" );
return VFW_E_NOT_STOPPED;
msg_Dbg( p_input, "CapturePin::Connect [OK]" );
return S_OK;
}
STDMETHODIMP CapturePin::ReceiveConnection( IPin * pConnector,
const AM_MEDIA_TYPE *pmt )
{
if( State_Stopped != p_filter->state )
{
msg_Dbg( p_input, "CapturePin::ReceiveConnection [not stopped]" );
msg_Dbg( p_input, "CapturePin::ReceiveConnection [not stopped]" );
return VFW_E_NOT_STOPPED;
}
if( !pConnector || !pmt )
{
msg_Dbg( p_input, "CapturePin::ReceiveConnection [null pointer]" );
msg_Dbg( p_input, "CapturePin::ReceiveConnection [null pointer]" );
return E_POINTER;
}
if( p_connected_pin )
{
msg_Dbg( p_input, "CapturePin::ReceiveConnection [already connected]" );
msg_Dbg( p_input, "CapturePin::ReceiveConnection [already connected]"