@ -45,13 +45,17 @@ struct dshow_ctx {
libAVPin * capture_pin [ 2 ] ;
libAVPin * capture_pin [ 2 ] ;
HANDLE mutex ;
HANDLE mutex ;
HANDLE event ;
HANDLE event [ 2 ] ; /* event[0] is set by DirectShow
* event [ 1 ] is set by callback ( ) */
AVPacketList * pktl ;
AVPacketList * pktl ;
int eof ;
int64_t curbufsize ;
int64_t curbufsize ;
unsigned int video_frame_num ;
unsigned int video_frame_num ;
IMediaControl * control ;
IMediaControl * control ;
IMediaEvent * media_event ;
enum AVPixelFormat pixel_format ;
enum AVPixelFormat pixel_format ;
enum AVCodecID video_codec_id ;
enum AVCodecID video_codec_id ;
@ -118,6 +122,9 @@ dshow_read_close(AVFormatContext *s)
IMediaControl_Release ( ctx - > control ) ;
IMediaControl_Release ( ctx - > control ) ;
}
}
if ( ctx - > media_event )
IMediaEvent_Release ( ctx - > media_event ) ;
if ( ctx - > graph ) {
if ( ctx - > graph ) {
IEnumFilters * fenum ;
IEnumFilters * fenum ;
int r ;
int r ;
@ -161,8 +168,10 @@ dshow_read_close(AVFormatContext *s)
if ( ctx - > mutex )
if ( ctx - > mutex )
CloseHandle ( ctx - > mutex ) ;
CloseHandle ( ctx - > mutex ) ;
if ( ctx - > event )
if ( ctx - > event [ 0 ] )
CloseHandle ( ctx - > event ) ;
CloseHandle ( ctx - > event [ 0 ] ) ;
if ( ctx - > event [ 1 ] )
CloseHandle ( ctx - > event [ 1 ] ) ;
pktl = ctx - > pktl ;
pktl = ctx - > pktl ;
while ( pktl ) {
while ( pktl ) {
@ -233,7 +242,7 @@ callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
ctx - > curbufsize + = buf_size ;
ctx - > curbufsize + = buf_size ;
SetEvent ( ctx - > event ) ;
SetEvent ( ctx - > event [ 1 ] ) ;
ReleaseMutex ( ctx - > mutex ) ;
ReleaseMutex ( ctx - > mutex ) ;
return ;
return ;
@ -868,6 +877,9 @@ static int dshow_read_header(AVFormatContext *avctx)
IGraphBuilder * graph = NULL ;
IGraphBuilder * graph = NULL ;
ICreateDevEnum * devenum = NULL ;
ICreateDevEnum * devenum = NULL ;
IMediaControl * control = NULL ;
IMediaControl * control = NULL ;
IMediaEvent * media_event = NULL ;
HANDLE media_event_handle ;
HANDLE proc ;
int ret = AVERROR ( EIO ) ;
int ret = AVERROR ( EIO ) ;
int r ;
int r ;
@ -948,8 +960,8 @@ static int dshow_read_header(AVFormatContext *avctx)
av_log ( avctx , AV_LOG_ERROR , " Could not create Mutex \n " ) ;
av_log ( avctx , AV_LOG_ERROR , " Could not create Mutex \n " ) ;
goto error ;
goto error ;
}
}
ctx - > event = CreateEvent ( NULL , 1 , 0 , NULL ) ;
ctx - > event [ 1 ] = CreateEvent ( NULL , 1 , 0 , NULL ) ;
if ( ! ctx - > event ) {
if ( ! ctx - > event [ 1 ] ) {
av_log ( avctx , AV_LOG_ERROR , " Could not create Event \n " ) ;
av_log ( avctx , AV_LOG_ERROR , " Could not create Event \n " ) ;
goto error ;
goto error ;
}
}
@ -961,6 +973,26 @@ static int dshow_read_header(AVFormatContext *avctx)
}
}
ctx - > control = control ;
ctx - > control = control ;
r = IGraphBuilder_QueryInterface ( graph , & IID_IMediaEvent , ( void * * ) & media_event ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not get media event. \n " ) ;
goto error ;
}
ctx - > media_event = media_event ;
r = IMediaEvent_GetEventHandle ( media_event , ( void * ) & media_event_handle ) ;
if ( r ! = S_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Could not get media event handle. \n " ) ;
goto error ;
}
proc = GetCurrentProcess ( ) ;
r = DuplicateHandle ( proc , media_event_handle , proc , & ctx - > event [ 0 ] ,
0 , 0 , DUPLICATE_SAME_ACCESS ) ;
if ( ! r ) {
av_log ( avctx , AV_LOG_ERROR , " Could not duplicate media event handle. \n " ) ;
goto error ;
}
r = IMediaControl_Run ( control ) ;
r = IMediaControl_Run ( control ) ;
if ( r = = S_FALSE ) {
if ( r = = S_FALSE ) {
OAFilterState pfs ;
OAFilterState pfs ;
@ -984,12 +1016,32 @@ error:
return ret ;
return ret ;
}
}
/**
* Checks media events from DirectShow and returns - 1 on error or EOF . Also
* purges all events that might be in the event queue to stop the trigger
* of event notification .
*/
static int dshow_check_event_queue ( IMediaEvent * media_event )
{
LONG_PTR p1 , p2 ;
long code ;
int ret = 0 ;
while ( IMediaEvent_GetEvent ( media_event , & code , & p1 , & p2 , 0 ) ! = E_ABORT ) {
if ( code = = EC_COMPLETE | | code = = EC_DEVICE_LOST | | code = = EC_ERRORABORT )
ret = - 1 ;
IMediaEvent_FreeEventParams ( media_event , code , p1 , p2 ) ;
}
return ret ;
}
static int dshow_read_packet ( AVFormatContext * s , AVPacket * pkt )
static int dshow_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
{
struct dshow_ctx * ctx = s - > priv_data ;
struct dshow_ctx * ctx = s - > priv_data ;
AVPacketList * pktl = NULL ;
AVPacketList * pktl = NULL ;
while ( ! pktl ) {
while ( ! ctx - > eof & & ! pktl ) {
WaitForSingleObject ( ctx - > mutex , INFINITE ) ;
WaitForSingleObject ( ctx - > mutex , INFINITE ) ;
pktl = ctx - > pktl ;
pktl = ctx - > pktl ;
if ( pktl ) {
if ( pktl ) {
@ -998,18 +1050,20 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
av_free ( pktl ) ;
av_free ( pktl ) ;
ctx - > curbufsize - = pkt - > size ;
ctx - > curbufsize - = pkt - > size ;
}
}
ResetEvent ( ctx - > event ) ;
ResetEvent ( ctx - > event [ 1 ] ) ;
ReleaseMutex ( ctx - > mutex ) ;
ReleaseMutex ( ctx - > mutex ) ;
if ( ! pktl ) {
if ( ! pktl ) {
if ( s - > flags & AVFMT_FLAG_NONBLOCK ) {
if ( dshow_check_event_queue ( ctx - > media_event ) < 0 ) {
ctx - > eof = 1 ;
} else if ( s - > flags & AVFMT_FLAG_NONBLOCK ) {
return AVERROR ( EAGAIN ) ;
return AVERROR ( EAGAIN ) ;
} else {
} else {
WaitForSingleObject ( ctx - > event , INFINITE ) ;
WaitForMultipleObjects ( 2 , ctx - > event , 0 , INFINITE ) ;
}
}
}
}
}
}
return pkt - > size ;
return ctx - > eof ? AVERROR ( EIO ) : pkt - > size ;
}
}
# define OFFSET(x) offsetof(struct dshow_ctx, x)
# define OFFSET(x) offsetof(struct dshow_ctx, x)