|
|
@@ -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) |
|
|
|
|
|
CloseHandle(ctx->event); |
|
|
|
|
|
|
|
|
if(ctx->event[0]) |
|
|
|
|
|
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); |
|
|
|
|
|
if (!ctx->event) { |
|
|
|
|
|
|
|
|
ctx->event[1] = CreateEvent(NULL, 1, 0, NULL); |
|
|
|
|
|
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) |
|
|
|