Signed-off-by: Mate Sebok <smfinc.org@gmail.com>
Reviewed-by: Roger Pack <rogerdpack2@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -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]; |