diff mbox series

[FFmpeg-devel,2/6] avdevice/dshow: implement control_message interface

Message ID 20210602112901.2163-3-dcnieho@gmail.com
State Superseded, archived
Headers show
Series avdevice/dshow: control_message interface | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Diederick C. Niehorster June 2, 2021, 11:28 a.m. UTC
This allows programmatic users of avdevice to start and stop the DirectShow Capture graph (i.e. receive frames or not). This is important because now the buffer fills up and starts dropping samples when enqueued packets are not read out immediately after the demuxer is opened.

Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
 libavdevice/dshow.c         | 41 +++++++++++++++++++++++++++++++++++++
 libavdevice/dshow_capture.h |  1 +
 2 files changed, 42 insertions(+)
diff mbox series

Patch

diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index 8d0a6fcc09..6e0147aed7 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -912,6 +912,44 @@  error:
     return ret;
 }
 
+static int dshow_control_message(AVFormatContext* avctx, int type, void* data, size_t data_size)
+{
+    struct dshow_ctx* ctx = avctx->priv_data;
+    int run_state = ctx->is_running;
+    int r;
+
+    switch (type) {
+    case AV_APP_TO_DEV_PAUSE:
+        run_state = 0;
+        break;
+    case AV_APP_TO_DEV_PLAY:
+        run_state = 1;
+        break;
+    case AV_APP_TO_DEV_TOGGLE_PAUSE:
+        run_state = !run_state;
+        break;
+    }
+
+    if (run_state != ctx->is_running) {
+        if (run_state)
+            r = IMediaControl_Run(ctx->control);
+        else
+            r = IMediaControl_Pause(ctx->control);
+
+        if (r == S_FALSE) {
+            OAFilterState pfs;
+            r = IMediaControl_GetState(ctx->control, 0, &pfs);
+        }
+        if (r != S_OK) {
+            av_log(avctx, AV_LOG_ERROR, "Could not run/pause graph\n");
+            return AVERROR(EIO);
+        }
+        ctx->is_running = run_state;
+    }
+
+    return 0;
+}
+
 static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
 {
     switch (sample_fmt) {
@@ -1152,6 +1190,7 @@  static int dshow_read_header(AVFormatContext *avctx)
             }
         }
     }
+    ctx->is_running = 0;
     if (ctx->device_name[VideoDevice]) {
         if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
             (r = dshow_add_device(avctx, VideoDevice)) < 0) {
@@ -1225,6 +1264,7 @@  static int dshow_read_header(AVFormatContext *avctx)
         av_log(avctx, AV_LOG_ERROR, "Could not run graph (sometimes caused by a device already in use by other application)\n");
         goto error;
     }
+    ctx->is_running = 1;
 
     ret = 0;
 
@@ -1335,6 +1375,7 @@  const AVInputFormat ff_dshow_demuxer = {
     .read_header    = dshow_read_header,
     .read_packet    = dshow_read_packet,
     .read_close     = dshow_read_close,
+    .control_message = dshow_control_message,
     .flags          = AVFMT_NOFILE,
     .priv_class     = &dshow_class,
 };
diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h
index 06ded2ba96..b7ef3770df 100644
--- a/libavdevice/dshow_capture.h
+++ b/libavdevice/dshow_capture.h
@@ -330,6 +330,7 @@  struct dshow_ctx {
 
     IMediaControl *control;
     IMediaEvent *media_event;
+    int is_running;
 
     enum AVPixelFormat pixel_format;
     enum AVCodecID video_codec_id;