Browse code

dshow: add capture device save and load

Signed-off-by: Mate Sebok <smfinc.org@gmail.com>
Reviewed-by: Roger Pack <rogerdpack2@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Mate Sebok authored on 2015/04/23 01:38:38
Showing 4 changed files
... ...
@@ -2543,7 +2543,7 @@ decklink_outdev_extralibs="-lstdc++"
2543 2543
 decklink_indev_deps="decklink pthreads"
2544 2544
 decklink_indev_extralibs="-lstdc++"
2545 2545
 dshow_indev_deps="IBaseFilter"
2546
-dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32"
2546
+dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi"
2547 2547
 dv1394_indev_deps="dv1394"
2548 2548
 dv1394_indev_select="dv_demuxer"
2549 2549
 fbdev_indev_deps="linux_fb_h"
... ...
@@ -350,6 +350,30 @@ If set to @option{true}, before capture starts, popup a display
350 350
 dialog to the end user, allowing them to manually
351 351
 modify TV audio (like mono vs. stereo, Language A,B or C).
352 352
 
353
+@item audio_device_load
354
+Load an audio capture filter device from file instead of searching
355
+it by name. It may load additional parameters too, if the filter
356
+supports the serialization of its properties to.
357
+To use this an audio capture source has to be specified, but it can
358
+be anything even fake one.
359
+
360
+@item audio_device_save
361
+Save the currently used audio capture filter device and its
362
+parameters (if the filter supports it) to a file.
363
+If a file with the same name exists it will be overwritten.
364
+
365
+@item video_device_load
366
+Load a video capture filter device from file instead of searching
367
+it by name. It may load additional parameters too, if the filter
368
+supports the serialization of its properties to.
369
+To use this a video capture source has to be specified, but it can
370
+be anything even fake one.
371
+
372
+@item video_device_save
373
+Save the currently used video capture filter device and its
374
+parameters (if the filter supports it) to a file.
375
+If a file with the same name exists it will be overwritten.
376
+
353 377
 @end table
354 378
 
355 379
 @subsection Examples
... ...
@@ -27,6 +27,8 @@
27 27
 #include "libavformat/riff.h"
28 28
 #include "avdevice.h"
29 29
 #include "libavcodec/raw.h"
30
+#include "objidl.h"
31
+#include "shlwapi.h"
30 32
 
31 33
 
32 34
 static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
... ...
@@ -728,12 +730,46 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
728 728
     ICaptureGraphBuilder2 *graph_builder2 = NULL;
729 729
     int ret = AVERROR(EIO);
730 730
     int r;
731
+    IStream *ifile_stream = NULL;
732
+    IStream *ofile_stream = NULL;
733
+    IPersistStream *pers_stream = NULL;
731 734
 
732 735
     const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
733 736
 
734
-    if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) {
735
-        ret = r;
736
-        goto error;
737
+
738
+    if ( ((ctx->audio_filter_load_file) && (strlen(ctx->audio_filter_load_file)>0) && (sourcetype == AudioSourceDevice)) ||
739
+            ((ctx->video_filter_load_file) && (strlen(ctx->video_filter_load_file)>0) && (sourcetype == VideoSourceDevice)) ) {
740
+        HRESULT hr;
741
+        char *filename = NULL;
742
+
743
+        if (sourcetype == AudioSourceDevice)
744
+            filename = ctx->audio_filter_load_file;
745
+        else
746
+            filename = ctx->video_filter_load_file;
747
+
748
+        hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_READ, &ifile_stream);
749
+        if (S_OK != hr) {
750
+            av_log(avctx, AV_LOG_ERROR, "Could not open capture filter description file.\n");
751
+            goto error;
752
+        }
753
+
754
+        hr = OleLoadFromStream(ifile_stream, &IID_IBaseFilter, (void **) &device_filter);
755
+        if (hr != S_OK) {
756
+            av_log(avctx, AV_LOG_ERROR, "Could not load capture filter from file.\n");
757
+            goto error;
758
+        }
759
+
760
+        if (sourcetype == AudioSourceDevice)
761
+            av_log(avctx, AV_LOG_INFO, "Audio-");
762
+        else
763
+            av_log(avctx, AV_LOG_INFO, "Video-");
764
+        av_log(avctx, AV_LOG_INFO, "Capture filter loaded successfully from file \"%s\".\n", filename);
765
+    } else {
766
+
767
+        if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter)) < 0) {
768
+            ret = r;
769
+            goto error;
770
+        }
737 771
     }
738 772
 
739 773
     ctx->device_filter [devtype] = device_filter;
... ...
@@ -758,6 +794,48 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
758 758
     }
759 759
     ctx->capture_filter[devtype] = capture_filter;
760 760
 
761
+    if ( ((ctx->audio_filter_save_file) && (strlen(ctx->audio_filter_save_file)>0) && (sourcetype == AudioSourceDevice)) ||
762
+            ((ctx->video_filter_save_file) && (strlen(ctx->video_filter_save_file)>0) && (sourcetype == VideoSourceDevice)) ) {
763
+
764
+        HRESULT hr;
765
+        char *filename = NULL;
766
+
767
+        if (sourcetype == AudioSourceDevice)
768
+            filename = ctx->audio_filter_save_file;
769
+        else
770
+            filename = ctx->video_filter_save_file;
771
+
772
+        hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_CREATE | STGM_READWRITE, &ofile_stream);
773
+        if (S_OK != hr) {
774
+            av_log(avctx, AV_LOG_ERROR, "Could not create capture filter description file.\n");
775
+            goto error;
776
+        }
777
+
778
+        hr  = IBaseFilter_QueryInterface(device_filter, &IID_IPersistStream, (void **) &pers_stream);
779
+        if (hr != S_OK) {
780
+            av_log(avctx, AV_LOG_ERROR, "Query for IPersistStream failed.\n");
781
+            goto error;
782
+        }
783
+
784
+        hr = OleSaveToStream(pers_stream, ofile_stream);
785
+        if (hr != S_OK) {
786
+            av_log(avctx, AV_LOG_ERROR, "Could not save capture filter \n");
787
+            goto error;
788
+        }
789
+
790
+        hr = IStream_Commit(ofile_stream, STGC_DEFAULT);
791
+        if (S_OK != hr) {
792
+            av_log(avctx, AV_LOG_ERROR, "Could not commit capture filter data to file.\n");
793
+            goto error;
794
+        }
795
+
796
+        if (sourcetype == AudioSourceDevice)
797
+            av_log(avctx, AV_LOG_INFO, "Audio-");
798
+        else
799
+            av_log(avctx, AV_LOG_INFO, "Video-");
800
+        av_log(avctx, AV_LOG_INFO, "Capture filter saved successfully to file \"%s\".\n", filename);
801
+    }
802
+
761 803
     r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
762 804
                                 filter_name[devtype]);
763 805
     if (r != S_OK) {
... ...
@@ -802,6 +880,15 @@ error:
802 802
     if (graph_builder2 != NULL)
803 803
         ICaptureGraphBuilder2_Release(graph_builder2);
804 804
 
805
+    if (pers_stream)
806
+        IPersistStream_Release(pers_stream);
807
+
808
+    if (ifile_stream)
809
+        IStream_Release(ifile_stream);
810
+
811
+    if (ofile_stream)
812
+        IStream_Release(ofile_stream);
813
+
805 814
     return ret;
806 815
 }
807 816
 
... ...
@@ -1211,6 +1298,10 @@ static const AVOption options[] = {
1211 1211
     { "show_analog_tv_tuner_audio_dialog", "display property dialog for analog tuner audio filter", OFFSET(show_analog_tv_tuner_audio_dialog), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC, "show_analog_tv_tuner_dialog" },
1212 1212
     { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "show_analog_tv_tuner_audio_dialog" },
1213 1213
     { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "show_analog_tv_tuner_audio_dialog" },
1214
+    { "audio_device_load", "load audio capture filter device (and properties) from file", OFFSET(audio_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1215
+    { "audio_device_save", "save audio capture filter device (and properties) to file", OFFSET(audio_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1216
+    { "video_device_load", "load video capture filter device (and properties) from file", OFFSET(video_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1217
+    { "video_device_save", "save video capture filter device (and properties) to file", OFFSET(video_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1214 1218
     { NULL },
1215 1219
 };
1216 1220
 
... ...
@@ -307,6 +307,10 @@ struct dshow_ctx {
307 307
     int   show_audio_crossbar_connection_dialog;
308 308
     int   show_analog_tv_tuner_dialog;
309 309
     int   show_analog_tv_tuner_audio_dialog;
310
+    char *audio_filter_load_file;
311
+    char *audio_filter_save_file;
312
+    char *video_filter_load_file;
313
+    char *video_filter_save_file;
310 314
 
311 315
     IBaseFilter *device_filter[2];
312 316
     IPin        *device_pin[2];