summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2012-12-17 14:38:22 +0100
committerMichael Niedermayer <michaelni@gmx.at>2012-12-17 14:38:26 +0100
commit8505daacc55d551d6a83ad1a0f75c30821bf21ce (patch)
tree14c7f19fffe4a396971b9c90fd9aec50c6f3c33c
parent082dd17bd267c39e5a681a78132a1849db70d478 (diff)
parent83a9f29f60d9f442989232bacb70d954ffbdc316 (diff)
Merge remote-tracking branch 'ramiro/dshow'
* ramiro/dshow: dshow: call CoUninitialize() on dshow_read_close() dshow: handle events in graph Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--libavdevice/dshow.c87
-rw-r--r--libavdevice/dshow_capture.h5
2 files changed, 76 insertions, 16 deletions
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index d57323e46e..83b5e01042 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -45,13 +45,17 @@ struct dshow_ctx {
libAVPin *capture_pin[2];
HANDLE mutex;
- HANDLE event;
+ HANDLE event[2]; /* event[0] is set by DirectShow
+ * event[1] is set by callback() */
AVPacketList *pktl;
+ int eof;
+
int64_t curbufsize;
unsigned int video_frame_num;
IMediaControl *control;
+ IMediaEvent *media_event;
enum AVPixelFormat pixel_format;
enum AVCodecID video_codec_id;
@@ -118,6 +122,9 @@ dshow_read_close(AVFormatContext *s)
IMediaControl_Release(ctx->control);
}
+ if (ctx->media_event)
+ IMediaEvent_Release(ctx->media_event);
+
if (ctx->graph) {
IEnumFilters *fenum;
int r;
@@ -161,8 +168,10 @@ dshow_read_close(AVFormatContext *s)
if(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;
while (pktl) {
@@ -172,6 +181,8 @@ dshow_read_close(AVFormatContext *s)
pktl = next;
}
+ CoUninitialize();
+
return 0;
}
@@ -233,7 +244,7 @@ callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
ctx->curbufsize += buf_size;
- SetEvent(ctx->event);
+ SetEvent(ctx->event[1]);
ReleaseMutex(ctx->mutex);
return;
@@ -784,7 +795,6 @@ dshow_add_device(AVFormatContext *avctx,
if (codec->codec_id == AV_CODEC_ID_NONE) {
av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
"Please report verbose (-v 9) debug information.\n");
- dshow_read_close(avctx);
return AVERROR_PATCHWELCOME;
}
codec->bits_per_coded_sample = bih->biBitCount;
@@ -868,9 +878,14 @@ static int dshow_read_header(AVFormatContext *avctx)
IGraphBuilder *graph = NULL;
ICreateDevEnum *devenum = NULL;
IMediaControl *control = NULL;
+ IMediaEvent *media_event = NULL;
+ HANDLE media_event_handle;
+ HANDLE proc;
int ret = AVERROR(EIO);
int r;
+ CoInitialize(0);
+
if (!ctx->list_devices && !parse_device_name(avctx)) {
av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
goto error;
@@ -894,8 +909,6 @@ static int dshow_read_header(AVFormatContext *avctx)
}
}
- CoInitialize(0);
-
r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
&IID_IGraphBuilder, (void **) &graph);
if (r != S_OK) {
@@ -948,8 +961,8 @@ static int dshow_read_header(AVFormatContext *avctx)
av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
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");
goto error;
}
@@ -961,6 +974,26 @@ static int dshow_read_header(AVFormatContext *avctx)
}
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);
if (r == S_FALSE) {
OAFilterState pfs;
@@ -975,11 +1008,31 @@ static int dshow_read_header(AVFormatContext *avctx)
error:
+ if (devenum)
+ ICreateDevEnum_Release(devenum);
+
if (ret < 0)
dshow_read_close(avctx);
- if (devenum)
- ICreateDevEnum_Release(devenum);
+ 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;
}
@@ -989,7 +1042,7 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
struct dshow_ctx *ctx = s->priv_data;
AVPacketList *pktl = NULL;
- while (!pktl) {
+ while (!ctx->eof && !pktl) {
WaitForSingleObject(ctx->mutex, INFINITE);
pktl = ctx->pktl;
if (pktl) {
@@ -998,18 +1051,20 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
av_free(pktl);
ctx->curbufsize -= pkt->size;
}
- ResetEvent(ctx->event);
+ ResetEvent(ctx->event[1]);
ReleaseMutex(ctx->mutex);
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);
} 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)
diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h
index 2446c7cd5f..aff5019b30 100644
--- a/libavdevice/dshow_capture.h
+++ b/libavdevice/dshow_capture.h
@@ -32,6 +32,11 @@
#include <dshow.h>
#include <dvdmedia.h>
+/* EC_DEVICE_LOST is not defined in MinGW dshow headers. */
+#ifndef EC_DEVICE_LOST
+#define EC_DEVICE_LOST 0x1f
+#endif
+
long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
void ff_print_VIDEO_STREAM_CONFIG_CAPS(const VIDEO_STREAM_CONFIG_CAPS *caps);
void ff_print_AUDIO_STREAM_CONFIG_CAPS(const AUDIO_STREAM_CONFIG_CAPS *caps);