* [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements
@ 2021-12-21 12:12 Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 01/12] avdevice/dshow: prevent NULL access Diederick Niehorster
` (11 more replies)
0 siblings, 12 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
This series solves some outstanding bugs in the dshow device, implements
get_device_list so that `ffmpeg -sources dshow` works and adds logic to
select a video format with extended color information (color range,
space, etc) if exposed by the device.
v6 adresses the review comments from Andreas received on the list.
This is a new version of part of the patch series in
https://ffmpeg.org/pipermail/ffmpeg-devel/2021-July/282073.html,
addressing review comments i got there. They have been previously OK'ed
offlist by the dshow maintainer Roger Pack. Specifically, these patches
are the enhancements that should be uncontroversial as they do not touch
the avformat API. I hope they can be swiftly pushed by someone, then
i'll re-send the other more controversial patches on top of these.
Diederick Niehorster (12):
avdevice/dshow: prevent NULL access
avdevice/dshow: implement option to use device video timestamps
avdevice/dshow: query graph and sample time only once
avdevice/dshow: handle unknown sample time
avdevice/dshow: set no-seek flags
avdevice/dshow: implement get_device_list
avdevice/dshow: list_devices: show media type(s) per device
avdevice: add info about media types(s) to AVDeviceInfo
avdevice/dshow: add media type info to get_device_list
fftools: provide media type info for devices
avdevice/dshow: discover source color range/space/etc
avdevice/dshow: select format with extended color info
doc/indevs.texi | 6 +
fftools/cmdutils.c | 34 +-
libavdevice/avdevice.c | 1 +
libavdevice/avdevice.h | 2 +
libavdevice/dshow.c | 854 +++++++++++++++++++++++++++++++-----
libavdevice/dshow_capture.h | 1 +
libavdevice/dshow_pin.c | 52 ++-
libavdevice/version.h | 4 +-
8 files changed, 810 insertions(+), 144 deletions(-)
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 01/12] avdevice/dshow: prevent NULL access
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 02/12] avdevice/dshow: implement option to use device video timestamps Diederick Niehorster
` (10 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
list_options true would crash when both a video and an audio device were
specified as input. Crash would occur on line 784 because
ctx->device_unique_name[otherDevType] would be NULL
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index ef78781865..cc0bef0474 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -708,9 +708,9 @@ dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name)) < 0)
return r;
ctx->device_filter[devtype] = device_filter;
+ ctx->device_unique_name[devtype] = device_unique_name;
if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0)
return r;
- av_freep(&device_unique_name);
return 0;
}
@@ -1143,6 +1143,7 @@ static int dshow_read_header(AVFormatContext *avctx)
}
}
}
+ // don't exit yet, allow it to list crossbar options in dshow_open_device
}
if (ctx->device_name[VideoDevice]) {
if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 02/12] avdevice/dshow: implement option to use device video timestamps
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 01/12] avdevice/dshow: prevent NULL access Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 03/12] avdevice/dshow: query graph and sample time only once Diederick Niehorster
` (9 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
The dshow avdevice ignores timestamps for video frames provided by the
DirectShow device, instead using wallclock time, apparently because the
implementer of this code had a device that provided unreliable
timestamps. Me (and others) would like to use the device's timestamps.
The new use_video_device_timestamps option for dshow device enables them
to do so. Since the majority of video devices out there probably provide
fine timestamps, this patch sets the default to using the device
timestamps, which means best fidelity timestamps are used by default.
Using the new option, the user can switch this off and revert to the old
behavior, so a fall back remains available in case the device provides
broken timestamps.
add use_video_device_timestamps to docs.
Closes: #8620
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
doc/indevs.texi | 6 ++++++
libavdevice/dshow.c | 1 +
libavdevice/dshow_capture.h | 1 +
libavdevice/dshow_pin.c | 11 ++++++-----
4 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/doc/indevs.texi b/doc/indevs.texi
index 5be647f70a..9d8020311a 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -625,6 +625,12 @@ Save the currently used video capture filter device and its
parameters (if the filter supports it) to a file.
If a file with the same name exists it will be overwritten.
+@item use_video_device_timestamps
+If set to @option{false}, the timestamp for video frames will be
+derived from the wallclock instead of the timestamp provided by
+the capture device. This allows working around devices that
+provide unreliable timestamps.
+
@end table
@subsection Examples
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index cc0bef0474..5e6eb9c85d 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -1310,6 +1310,7 @@ static const AVOption options[] = {
{ "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 },
{ "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 },
{ "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 },
+ { "use_video_device_timestamps", "use device instead of wallclock timestamps for video frames", OFFSET(use_video_device_timestamps), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC },
{ NULL },
};
diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h
index 06ded2ba96..5a2691518c 100644
--- a/libavdevice/dshow_capture.h
+++ b/libavdevice/dshow_capture.h
@@ -312,6 +312,7 @@ struct dshow_ctx {
char *audio_filter_save_file;
char *video_filter_load_file;
char *video_filter_save_file;
+ int use_video_device_timestamps;
IBaseFilter *device_filter[2];
IPin *device_pin[2];
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c
index 3dae405e65..8e56dccbfe 100644
--- a/libavdevice/dshow_pin.c
+++ b/libavdevice/dshow_pin.c
@@ -309,10 +309,14 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
if (!sample)
return E_POINTER;
+ priv_data = pin->filter->priv_data;
+ s = priv_data;
+ ctx = s->priv_data;
+
IMediaSample_GetTime(sample, &orig_curtime, &dummy);
orig_curtime += pin->filter->start_time;
IReferenceClock_GetTime(clock, &graphtime);
- if (devtype == VideoDevice) {
+ if (devtype == VideoDevice && !ctx->use_video_device_timestamps) {
/* PTS from video devices is unreliable. */
IReferenceClock_GetTime(clock, &curtime);
} else {
@@ -322,7 +326,7 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
like 437650244077016960 which FFmpeg doesn't like.
TODO figure out math. For now just drop them. */
av_log(NULL, AV_LOG_DEBUG,
- "dshow dropping initial (or ending) audio frame with odd PTS too high %"PRId64"\n", curtime);
+ "dshow dropping initial (or ending) frame with odd PTS too high %"PRId64"\n", curtime);
return S_OK;
}
curtime += pin->filter->start_time;
@@ -330,9 +334,6 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
buf_size = IMediaSample_GetActualDataLength(sample);
IMediaSample_GetPointer(sample, &buf);
- priv_data = pin->filter->priv_data;
- s = priv_data;
- ctx = s->priv_data;
index = pin->filter->stream_index;
av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %8d "
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 03/12] avdevice/dshow: query graph and sample time only once
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 01/12] avdevice/dshow: prevent NULL access Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 02/12] avdevice/dshow: implement option to use device video timestamps Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 04/12] avdevice/dshow: handle unknown sample time Diederick Niehorster
` (8 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
No need to query twice, use value we've already unconditionally got.
Improve variable names
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow_pin.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c
index 8e56dccbfe..1d0e880480 100644
--- a/libavdevice/dshow_pin.c
+++ b/libavdevice/dshow_pin.c
@@ -295,9 +295,10 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
uint8_t *buf;
int buf_size; /* todo should be a long? */
int index;
- int64_t curtime;
- int64_t orig_curtime;
+ int64_t chosentime;
+ int64_t sampletime;
int64_t graphtime;
+ int use_sample_time = 1;
const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
IReferenceClock *clock = pin->filter->clock;
int64_t dummy;
@@ -313,24 +314,27 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
s = priv_data;
ctx = s->priv_data;
- IMediaSample_GetTime(sample, &orig_curtime, &dummy);
- orig_curtime += pin->filter->start_time;
+ IMediaSample_GetTime(sample, &sampletime, &dummy);
IReferenceClock_GetTime(clock, &graphtime);
if (devtype == VideoDevice && !ctx->use_video_device_timestamps) {
/* PTS from video devices is unreliable. */
- IReferenceClock_GetTime(clock, &curtime);
+ chosentime = graphtime;
+ use_sample_time = 0;
} else {
- IMediaSample_GetTime(sample, &curtime, &dummy);
- if(curtime > 400000000000000000LL) {
+ if (sampletime > 400000000000000000LL) {
/* initial frames sometimes start < 0 (shown as a very large number here,
- like 437650244077016960 which FFmpeg doesn't like.
+ like 437650244077016960 which FFmpeg doesn't like).
TODO figure out math. For now just drop them. */
av_log(NULL, AV_LOG_DEBUG,
- "dshow dropping initial (or ending) frame with odd PTS too high %"PRId64"\n", curtime);
+ "dshow dropping initial (or ending) frame with odd PTS too high %"PRId64"\n", sampletime);
return S_OK;
}
- curtime += pin->filter->start_time;
+ chosentime = sampletime;
}
+ // media sample time is relative to graph start time
+ sampletime += pin->filter->start_time;
+ if (use_sample_time)
+ chosentime += pin->filter->start_time;
buf_size = IMediaSample_GetActualDataLength(sample);
IMediaSample_GetPointer(sample, &buf);
@@ -338,8 +342,8 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %8d "
"timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n",
- devtypename, buf_size, curtime, orig_curtime, graphtime, graphtime - orig_curtime, ctx->device_name[devtype]);
- pin->filter->callback(priv_data, index, buf, buf_size, curtime, devtype);
+ devtypename, buf_size, chosentime, sampletime, graphtime, graphtime - sampletime, ctx->device_name[devtype]);
+ pin->filter->callback(priv_data, index, buf, buf_size, chosentime, devtype);
return S_OK;
}
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 04/12] avdevice/dshow: handle unknown sample time
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (2 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 03/12] avdevice/dshow: query graph and sample time only once Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 05/12] avdevice/dshow: set no-seek flags Diederick Niehorster
` (7 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
GetTime may return an error indication that the sample has not
timestamps, or may return a NULL start time. In those cases, fall back
to graph time. Emit log when that happens.
Improve logging in the frame receive function: now logged against
correct avclass instead of NULL.
Better debug message in case sample dropped: could now be audio or
video frame.
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow_pin.c | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c
index 1d0e880480..2d1fa0e882 100644
--- a/libavdevice/dshow_pin.c
+++ b/libavdevice/dshow_pin.c
@@ -295,14 +295,15 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
uint8_t *buf;
int buf_size; /* todo should be a long? */
int index;
- int64_t chosentime;
- int64_t sampletime;
- int64_t graphtime;
+ int64_t chosentime = 0;
+ int64_t sampletime = 0;
+ int64_t graphtime = 0;
int use_sample_time = 1;
const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
IReferenceClock *clock = pin->filter->clock;
int64_t dummy;
struct dshow_ctx *ctx;
+ HRESULT hr;
dshowdebug("ff_dshow_meminputpin_Receive(%p)\n", this);
@@ -314,22 +315,28 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
s = priv_data;
ctx = s->priv_data;
- IMediaSample_GetTime(sample, &sampletime, &dummy);
+ hr = IMediaSample_GetTime(sample, &sampletime, &dummy);
IReferenceClock_GetTime(clock, &graphtime);
if (devtype == VideoDevice && !ctx->use_video_device_timestamps) {
/* PTS from video devices is unreliable. */
chosentime = graphtime;
use_sample_time = 0;
} else {
- if (sampletime > 400000000000000000LL) {
+ if (hr == VFW_E_SAMPLE_TIME_NOT_SET || sampletime == 0) {
+ chosentime = graphtime;
+ use_sample_time = 0;
+ av_log(s, AV_LOG_DEBUG,
+ "frame with missing sample timestamp encountered, falling back to graph timestamp\n");
+ }
+ else if (sampletime > 400000000000000000LL) {
/* initial frames sometimes start < 0 (shown as a very large number here,
like 437650244077016960 which FFmpeg doesn't like).
TODO figure out math. For now just drop them. */
- av_log(NULL, AV_LOG_DEBUG,
- "dshow dropping initial (or ending) frame with odd PTS too high %"PRId64"\n", sampletime);
+ av_log(s, AV_LOG_DEBUG,
+ "dropping initial (or ending) sample with odd PTS too high %"PRId64"\n", sampletime);
return S_OK;
- }
- chosentime = sampletime;
+ } else
+ chosentime = sampletime;
}
// media sample time is relative to graph start time
sampletime += pin->filter->start_time;
@@ -340,7 +347,7 @@ long ff_dshow_meminputpin_Receive(DShowMemInputPin *this, IMediaSample *sample)
IMediaSample_GetPointer(sample, &buf);
index = pin->filter->stream_index;
- av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %8d "
+ av_log(s, AV_LOG_VERBOSE, "passing through packet of type %s size %8d "
"timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n",
devtypename, buf_size, chosentime, sampletime, graphtime, graphtime - sampletime, ctx->device_name[devtype]);
pin->filter->callback(priv_data, index, buf, buf_size, chosentime, devtype);
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 05/12] avdevice/dshow: set no-seek flags
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (3 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 04/12] avdevice/dshow: handle unknown sample time Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 06/12] avdevice/dshow: implement get_device_list Diederick Niehorster
` (6 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
avdevice/dshow is a realtime device and as such does not support
seeking. Therefore, its demuxer format should define the
AVFMT_NOBINSEARCH, AVFMT_NOGENSEARCH and AVFMT_NO_BYTE_SEEK flags.
With these flags set, attempting to seek (with, e.g.,
avformat_seek_file()) correctly yields -1 (operation not permitted)
instead of -22 (invalid argument).
This actually seems to apply to many other devices, at least the
gdigrab, v4l2, vfwcap, x11grab, fbdev, kmsgrab and android_camera
devices, from reading the source.
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index 5e6eb9c85d..0ef3b3d13e 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -1329,6 +1329,6 @@ const AVInputFormat ff_dshow_demuxer = {
.read_header = dshow_read_header,
.read_packet = dshow_read_packet,
.read_close = dshow_read_close,
- .flags = AVFMT_NOFILE,
+ .flags = AVFMT_NOFILE | AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
.priv_class = &dshow_class,
};
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 06/12] avdevice/dshow: implement get_device_list
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (4 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 05/12] avdevice/dshow: set no-seek flags Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 07/12] avdevice/dshow: list_devices: show media type(s) per device Diederick Niehorster
` (5 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
Needed to enable programmatic discovery of DirectShow devices
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 96 ++++++++++++++++++++++++++++++++++++++-------
1 file changed, 81 insertions(+), 15 deletions(-)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index 0ef3b3d13e..e1702c8519 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -202,11 +202,14 @@ fail:
* retrieve the device with type specified by devtype and return the
* pointer to the object found in *pfilter.
* If pfilter is NULL, list all device names.
+ * If device_list is not NULL, populate it with found devices instead of
+ * outputting device names to log
*/
static int
dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype,
- IBaseFilter **pfilter, char **device_unique_name)
+ IBaseFilter **pfilter, char **device_unique_name,
+ AVDeviceInfoList **device_list)
{
struct dshow_ctx *ctx = avctx->priv_data;
IBaseFilter *device_filter = NULL;
@@ -238,18 +241,19 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
IBindCtx *bind_ctx = NULL;
LPOLESTR olestr = NULL;
LPMALLOC co_malloc = NULL;
+ AVDeviceInfo *device = NULL;
int i;
r = CoGetMalloc(1, &co_malloc);
if (r != S_OK)
- goto fail1;
+ goto fail;
r = CreateBindCtx(0, &bind_ctx);
if (r != S_OK)
- goto fail1;
+ goto fail;
/* GetDisplayname works for both video and audio, DevicePath doesn't */
r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr);
if (r != S_OK)
- goto fail1;
+ goto fail;
unique_name = dup_wchar_to_utf8(olestr);
/* replace ':' with '_' since we use : to delineate between sources */
for (i = 0; i < strlen(unique_name); i++) {
@@ -259,34 +263,62 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
if (r != S_OK)
- goto fail1;
+ goto fail;
var.vt = VT_BSTR;
r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
if (r != S_OK)
- goto fail1;
+ goto fail;
friendly_name = dup_wchar_to_utf8(var.bstrVal);
if (pfilter) {
if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name))
- goto fail1;
+ goto fail;
if (!skip--) {
r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
if (r != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name);
- goto fail1;
+ goto fail;
}
*device_unique_name = unique_name;
unique_name = NULL;
// success, loop will end now
}
} else {
- av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name);
- av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
+ if (device_list) {
+ device = av_mallocz(sizeof(AVDeviceInfo));
+ if (!device)
+ goto fail;
+
+ device->device_name = av_strdup(friendly_name);
+ device->device_description = av_strdup(unique_name);
+ if (!device->device_name || !device->device_description)
+ goto fail;
+
+ // make space in device_list for this new device
+ if (av_reallocp_array(&(*device_list)->devices,
+ (*device_list)->nb_devices + 1,
+ sizeof(*(*device_list)->devices)) < 0)
+ goto fail;
+
+ // store device in list
+ (*device_list)->devices[(*device_list)->nb_devices] = device;
+ (*device_list)->nb_devices++;
+ device = NULL; // copied into array, make sure not freed below
+ }
+ else {
+ av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name);
+ av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
+ }
}
-fail1:
+fail:
+ if (device) {
+ av_freep(&device->device_name);
+ av_freep(&device->device_description);
+ av_free(device);
+ }
if (olestr && co_malloc)
IMalloc_Free(co_malloc, olestr);
if (bind_ctx)
@@ -312,6 +344,39 @@ fail1:
return 0;
}
+static int dshow_get_device_list(AVFormatContext *avctx, AVDeviceInfoList *device_list)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ ICreateDevEnum *devenum = NULL;
+ int r;
+ int ret = AVERROR(EIO);
+
+ if (!device_list)
+ return AVERROR(EINVAL);
+
+ CoInitialize(0);
+
+ r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
+ &IID_ICreateDevEnum, (void**)&devenum);
+ if (r != S_OK) {
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
+ goto error;
+ }
+
+ ret = dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, &device_list);
+ if (ret < S_OK)
+ goto error;
+ ret = dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, &device_list);
+
+error:
+ if (devenum)
+ ICreateDevEnum_Release(devenum);
+
+ CoUninitialize();
+
+ return ret;
+}
+
/**
* Cycle through available formats using the specified pin,
* try to set parameters specified through AVOptions and if successful
@@ -705,7 +770,7 @@ dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
char *device_unique_name = NULL;
int r;
- if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name)) < 0)
+ if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name, NULL)) < 0)
return r;
ctx->device_filter[devtype] = device_filter;
ctx->device_unique_name[devtype] = device_unique_name;
@@ -765,7 +830,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
av_log(avctx, AV_LOG_INFO, "Capture filter loaded successfully from file \"%s\".\n", filename);
} else {
- if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_filter_unique_name)) < 0) {
+ if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_filter_unique_name, NULL)) < 0) {
ret = r;
goto error;
}
@@ -1122,9 +1187,9 @@ static int dshow_read_header(AVFormatContext *avctx)
if (ctx->list_devices) {
av_log(avctx, AV_LOG_INFO, "DirectShow video devices (some may be both video and audio devices)\n");
- dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL);
+ dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, NULL);
av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n");
- dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL);
+ dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, NULL);
ret = AVERROR_EXIT;
goto error;
}
@@ -1329,6 +1394,7 @@ const AVInputFormat ff_dshow_demuxer = {
.read_header = dshow_read_header,
.read_packet = dshow_read_packet,
.read_close = dshow_read_close,
+ .get_device_list= dshow_get_device_list,
.flags = AVFMT_NOFILE | AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
.priv_class = &dshow_class,
};
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 07/12] avdevice/dshow: list_devices: show media type(s) per device
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (5 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 06/12] avdevice/dshow: implement get_device_list Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 08/12] avdevice: add info about media types(s) to AVDeviceInfo Diederick Niehorster
` (4 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
the list_devices option of dshow didn't indicate whether a specific
device provides audio or video output. This patch iterates through all
media formats of all pins exposed by the device to see what types it
provides for capture, and prints this to the console for each device.
Importantly, this now allows to find devices that provide both audio and
video, and devices that provide neither.
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 103 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 98 insertions(+), 5 deletions(-)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index e1702c8519..8dba04a787 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -197,6 +197,80 @@ fail:
return;
}
+static void
+dshow_get_device_media_types(AVFormatContext *avctx, enum dshowDeviceType devtype,
+ enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter,
+ enum AVMediaType **media_types, int *nb_media_types)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+ IEnumPins *pins = 0;
+ IPin *pin;
+ int has_audio = 0, has_video = 0;
+
+ if (IBaseFilter_EnumPins(device_filter, &pins) != S_OK)
+ return;
+
+ while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
+ IKsPropertySet *p = NULL;
+ PIN_INFO info = { 0 };
+ GUID category;
+ DWORD r2;
+ IEnumMediaTypes *types = NULL;
+ AM_MEDIA_TYPE *type;
+
+ if (IPin_QueryPinInfo(pin, &info) != S_OK)
+ goto next;
+ IBaseFilter_Release(info.pFilter);
+
+ if (info.dir != PINDIR_OUTPUT)
+ goto next;
+ if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
+ goto next;
+ if (IKsPropertySet_Get(p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
+ NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
+ goto next;
+ if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
+ goto next;
+
+ if (IPin_EnumMediaTypes(pin, &types) != S_OK)
+ goto next;
+
+ // enumerate media types exposed by pin
+ // NB: don't know if a pin can expose both audio and video, check 'm all to be safe
+ IEnumMediaTypes_Reset(types);
+ while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
+ if (IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) {
+ has_video = 1;
+ } else if (IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) {
+ has_audio = 1;
+ }
+ CoTaskMemFree(type);
+ }
+
+ next:
+ if (types)
+ IEnumMediaTypes_Release(types);
+ if (p)
+ IKsPropertySet_Release(p);
+ if (pin)
+ IPin_Release(pin);
+ }
+
+ IEnumPins_Release(pins);
+
+ if (has_audio || has_video) {
+ int nb_types = has_audio + has_video;
+ *media_types = av_malloc_array(nb_types, sizeof(enum AVMediaType));
+ if (*media_types) {
+ if (has_audio)
+ (*media_types)[0] = AVMEDIA_TYPE_AUDIO;
+ if (has_video)
+ (*media_types)[0 + has_audio] = AVMEDIA_TYPE_VIDEO;
+ *nb_media_types = nb_types;
+ }
+ }
+}
+
/**
* Cycle through available devices using the device enumerator devenum,
* retrieve the device with type specified by devtype and return the
@@ -242,6 +316,8 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
LPOLESTR olestr = NULL;
LPMALLOC co_malloc = NULL;
AVDeviceInfo *device = NULL;
+ enum AVMediaType *media_types = NULL;
+ int nb_media_types = 0;
int i;
r = CoGetMalloc(1, &co_malloc);
@@ -286,6 +362,12 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
// success, loop will end now
}
} else {
+ // get media types exposed by pins of device
+ if (IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void* ) &device_filter) == S_OK) {
+ dshow_get_device_media_types(avctx, devtype, sourcetype, device_filter, &media_types, &nb_media_types);
+ IBaseFilter_Release(device_filter);
+ device_filter = NULL;
+ }
if (device_list) {
device = av_mallocz(sizeof(AVDeviceInfo));
if (!device)
@@ -308,12 +390,25 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
device = NULL; // copied into array, make sure not freed below
}
else {
- av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name);
- av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
+ av_log(avctx, AV_LOG_INFO, "\"%s\"", friendly_name);
+ if (nb_media_types > 0) {
+ const char* media_type = av_get_media_type_string(media_types[0]);
+ av_log(avctx, AV_LOG_INFO, " (%s", media_type ? media_type : "unknown");
+ for (int i = 1; i < nb_media_types; ++i) {
+ media_type = av_get_media_type_string(media_types[i]);
+ av_log(avctx, AV_LOG_INFO, ", %s", media_type ? media_type : "unknown");
+ }
+ av_log(avctx, AV_LOG_INFO, ")");
+ } else {
+ av_log(avctx, AV_LOG_INFO, " (none)");
+ }
+ av_log(avctx, AV_LOG_INFO, "\n");
+ av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
}
}
-fail:
+ fail:
+ av_freep(&media_types);
if (device) {
av_freep(&device->device_name);
av_freep(&device->device_description);
@@ -1186,9 +1281,7 @@ static int dshow_read_header(AVFormatContext *avctx)
}
if (ctx->list_devices) {
- av_log(avctx, AV_LOG_INFO, "DirectShow video devices (some may be both video and audio devices)\n");
dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, NULL);
- av_log(avctx, AV_LOG_INFO, "DirectShow audio devices\n");
dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, NULL);
ret = AVERROR_EXIT;
goto error;
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 08/12] avdevice: add info about media types(s) to AVDeviceInfo
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (6 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 07/12] avdevice/dshow: list_devices: show media type(s) per device Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 09/12] avdevice/dshow: add media type info to get_device_list Diederick Niehorster
` (3 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
An avdevice, regardless of whether its category says its an audio or
video device, may provide access to devices providing different media
types, or even single devices providing multiple media types. Also, some
devices may provide no media types. dshow is an example encompassing all
of these cases. Users should be provided with this information, so
AVDeviceInfo is extended to provide it.
Bump avdevice version
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/avdevice.c | 1 +
libavdevice/avdevice.h | 2 ++
libavdevice/version.h | 4 ++--
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c
index 2ae26ab8e3..8f460c7564 100644
--- a/libavdevice/avdevice.c
+++ b/libavdevice/avdevice.c
@@ -157,6 +157,7 @@ void avdevice_free_list_devices(AVDeviceInfoList **device_list)
if (dev) {
av_freep(&dev->device_name);
av_freep(&dev->device_description);
+ av_freep(&dev->media_types);
av_free(dev);
}
}
diff --git a/libavdevice/avdevice.h b/libavdevice/avdevice.h
index 8370bbc7f2..6f24976dcc 100644
--- a/libavdevice/avdevice.h
+++ b/libavdevice/avdevice.h
@@ -457,6 +457,8 @@ void avdevice_capabilities_free(AVDeviceCapabilitiesQuery **caps, AVFormatContex
typedef struct AVDeviceInfo {
char *device_name; /**< device name, format depends on device */
char *device_description; /**< human friendly name */
+ enum AVMediaType *media_types; /**< array indicating what media types(s), if any, a device can provide. If null, cannot provide any */
+ int nb_media_types; /**< length of media_types array, 0 if device cannot provide any media types */
} AVDeviceInfo;
/**
diff --git a/libavdevice/version.h b/libavdevice/version.h
index 914e156ec7..41f568d6b0 100644
--- a/libavdevice/version.h
+++ b/libavdevice/version.h
@@ -28,8 +28,8 @@
#include "libavutil/version.h"
#define LIBAVDEVICE_VERSION_MAJOR 59
-#define LIBAVDEVICE_VERSION_MINOR 0
-#define LIBAVDEVICE_VERSION_MICRO 101
+#define LIBAVDEVICE_VERSION_MINOR 1
+#define LIBAVDEVICE_VERSION_MICRO 100
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
LIBAVDEVICE_VERSION_MINOR, \
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 09/12] avdevice/dshow: add media type info to get_device_list
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (7 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 08/12] avdevice: add info about media types(s) to AVDeviceInfo Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 10/12] fftools: provide media type info for devices Diederick Niehorster
` (2 subsequent siblings)
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
The list returned by get_device_list now contains info about what media
type(s), if any, can be provided by each device.
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index 8dba04a787..4b1e942c7a 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -384,6 +384,12 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
sizeof(*(*device_list)->devices)) < 0)
goto fail;
+ // attach media_types to device
+ device->nb_media_types = nb_media_types;
+ device->media_types = media_types;
+ nb_media_types = 0;
+ media_types = NULL;
+
// store device in list
(*device_list)->devices[(*device_list)->nb_devices] = device;
(*device_list)->nb_devices++;
@@ -412,6 +418,7 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
if (device) {
av_freep(&device->device_name);
av_freep(&device->device_description);
+ // NB: no need to av_freep(&device->media_types), its only moved to device once nothing can fail anymore
av_free(device);
}
if (olestr && co_malloc)
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 10/12] fftools: provide media type info for devices
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (8 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 09/12] avdevice/dshow: add media type info to get_device_list Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 12/12] avdevice/dshow: select format with extended color info Diederick Niehorster
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
fftools now print info about what media type(s), if any, are provided by
sink and source avdevices.
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
fftools/cmdutils.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c
index 3c8e5a82cd..8b2dc030bc 100644
--- a/fftools/cmdutils.c
+++ b/fftools/cmdutils.c
@@ -2244,9 +2244,29 @@ double get_rotation(int32_t *displaymatrix)
}
#if CONFIG_AVDEVICE
+static void print_device_list(const AVDeviceInfoList *device_list)
+{
+ // print devices
+ for (int i = 0; i < device_list->nb_devices; i++) {
+ const AVDeviceInfo *device = device_list->devices[i];
+ printf("%c %s [%s] (", device_list->default_device == i ? '*' : ' ',
+ device->device_name, device->device_description);
+ if (device->nb_media_types > 0) {
+ for (int j = 0; j < device->nb_media_types; ++j) {
+ const char* media_type = av_get_media_type_string(device->media_types[j]);
+ if (j > 0)
+ printf(", ");
+ printf("%s", media_type ? media_type : "unknown");
+ }
+ } else {
+ printf("none");
+ }
+ printf(")\n");
+ }
+}
static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
{
- int ret, i;
+ int ret;
AVDeviceInfoList *device_list = NULL;
if (!fmt || !fmt->priv_class || !AV_IS_INPUT_DEVICE(fmt->priv_class->category))
@@ -2258,10 +2278,7 @@ static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
goto fail;
}
- for (i = 0; i < device_list->nb_devices; i++) {
- printf("%c %s [%s]\n", device_list->default_device == i ? '*' : ' ',
- device_list->devices[i]->device_name, device_list->devices[i]->device_description);
- }
+ print_device_list(device_list);
fail:
avdevice_free_list_devices(&device_list);
@@ -2270,7 +2287,7 @@ static int print_device_sources(const AVInputFormat *fmt, AVDictionary *opts)
static int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts)
{
- int ret, i;
+ int ret;
AVDeviceInfoList *device_list = NULL;
if (!fmt || !fmt->priv_class || !AV_IS_OUTPUT_DEVICE(fmt->priv_class->category))
@@ -2282,10 +2299,7 @@ static int print_device_sinks(const AVOutputFormat *fmt, AVDictionary *opts)
goto fail;
}
- for (i = 0; i < device_list->nb_devices; i++) {
- printf("%c %s [%s]\n", device_list->default_device == i ? '*' : ' ',
- device_list->devices[i]->device_name, device_list->devices[i]->device_description);
- }
+ print_device_list(device_list);
fail:
avdevice_free_list_devices(&device_list);
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (9 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 10/12] fftools: provide media type info for devices Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
2021-12-21 12:35 ` Hendrik Leppkes
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 12/12] avdevice/dshow: select format with extended color info Diederick Niehorster
11 siblings, 1 reply; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster, Valerii Zapodovnikov
Enabled discovering a DirectShow device's color range, space, primaries,
transfer characteristics and chroma location, if the device exposes that
information. Sets them in the stream's codecpars.
Co-authored-by: Valerii Zapodovnikov <val.zapod.vz@gmail.com>
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 255 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 254 insertions(+), 1 deletion(-)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index 4b1e942c7a..79be32b255 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -29,6 +29,31 @@
#include "libavcodec/raw.h"
#include "objidl.h"
#include "shlwapi.h"
+// NB: technically, we should include dxva.h and use
+// DXVA_ExtendedFormat, but that type is not defined in
+// the MinGW headers. The DXVA2_ExtendedFormat and the
+// contents of its fields is identical to
+// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
+// and is provided by MinGW as well, so we use that
+// instead. NB also that per the Microsoft docs, the
+// lowest 8 bits of the structure, i.e. the SampleFormat
+// field, contain AMCONTROL_xxx flags instead of sample
+// format information, and should thus not be used.
+// NB further that various values in the structure's
+// fields (e.g. BT.2020 color space) are not provided
+// for either of the DXVA structs, but are provided in
+// the flags of the corresponding fields of Media Foundation.
+// These may be provided by DirectShow devices (e.g. LAVFilters
+// does so). So we use those values here too (the equivalence is
+// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
+typedef DWORD D3DFORMAT; // dxva2api.h header needs these types defined before include apparently in WinSDK (not MinGW).
+typedef DWORD D3DPOOL;
+#include "dxva2api.h"
+
+#ifndef AMCONTROL_COLORINFO_PRESENT
+// not defined in some versions of MinGW's dvdmedia.h
+# define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
+#endif
static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
@@ -54,6 +79,192 @@ static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
}
+static enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
+{
+ switch (fmt_info->NominalRange)
+ {
+ case DXVA2_NominalRange_Unknown:
+ return AVCOL_RANGE_UNSPECIFIED;
+ case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
+ return AVCOL_RANGE_JPEG;
+ case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
+ return AVCOL_RANGE_MPEG;
+ case DXVA2_NominalRange_48_208:
+ // not an ffmpeg color range
+ return AVCOL_RANGE_UNSPECIFIED;
+
+ // values from MediaFoundation SDK (mfobjects.h)
+ case 4: // MFNominalRange_64_127
+ // not an ffmpeg color range
+ return AVCOL_RANGE_UNSPECIFIED;
+
+ default:
+ return DXVA2_NominalRange_Unknown;
+ }
+}
+
+static enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
+{
+ enum AVColorSpace ret = AVCOL_SPC_UNSPECIFIED;
+
+ switch (fmt_info->VideoTransferMatrix)
+ {
+ case DXVA2_VideoTransferMatrix_BT709:
+ ret = AVCOL_SPC_BT709;
+ break;
+ case DXVA2_VideoTransferMatrix_BT601:
+ ret = AVCOL_SPC_BT470BG;
+ break;
+ case DXVA2_VideoTransferMatrix_SMPTE240M:
+ ret = AVCOL_SPC_SMPTE240M;
+ break;
+
+ // values from MediaFoundation SDK (mfobjects.h)
+ case 4: // MFVideoTransferMatrix_BT2020_10
+ case 5: // MFVideoTransferMatrix_BT2020_12
+ if (fmt_info->VideoTransferFunction==12) // MFVideoTransFunc_2020_const
+ ret = AVCOL_SPC_BT2020_CL;
+ else
+ ret = AVCOL_SPC_BT2020_NCL;
+ break;
+ }
+
+ if (ret == AVCOL_SPC_UNSPECIFIED)
+ {
+ // if color space not known from transfer matrix,
+ // fall back to using primaries to guess color space
+ switch (fmt_info->VideoPrimaries)
+ {
+ case DXVA2_VideoPrimaries_BT709:
+ ret = AVCOL_SPC_BT709;
+ break;
+ case DXVA2_VideoPrimaries_BT470_2_SysM:
+ ret = AVCOL_SPC_FCC;
+ break;
+ case DXVA2_VideoPrimaries_BT470_2_SysBG:
+ case DXVA2_VideoPrimaries_EBU3213: // this is PAL
+ ret = AVCOL_SPC_BT470BG;
+ break;
+ case DXVA2_VideoPrimaries_SMPTE170M:
+ case DXVA2_VideoPrimaries_SMPTE_C:
+ ret = AVCOL_SPC_SMPTE170M;
+ break;
+ case DXVA2_VideoPrimaries_SMPTE240M:
+ ret = AVCOL_SPC_SMPTE240M;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static enum AVColorPrimaries dshow_color_primaries(DXVA2_ExtendedFormat *fmt_info)
+{
+ switch (fmt_info->VideoPrimaries)
+ {
+ case DXVA2_VideoPrimaries_Unknown:
+ return AVCOL_PRI_UNSPECIFIED;
+ case DXVA2_VideoPrimaries_reserved:
+ return AVCOL_PRI_RESERVED;
+ case DXVA2_VideoPrimaries_BT709:
+ return AVCOL_PRI_BT709;
+ case DXVA2_VideoPrimaries_BT470_2_SysM:
+ return AVCOL_PRI_BT470M;
+ case DXVA2_VideoPrimaries_BT470_2_SysBG:
+ case DXVA2_VideoPrimaries_EBU3213: // this is PAL
+ return AVCOL_PRI_BT470BG;
+ case DXVA2_VideoPrimaries_SMPTE170M:
+ case DXVA2_VideoPrimaries_SMPTE_C:
+ return AVCOL_PRI_SMPTE170M;
+ case DXVA2_VideoPrimaries_SMPTE240M:
+ return AVCOL_PRI_SMPTE240M;
+
+ // values from MediaFoundation SDK (mfobjects.h)
+ case 9: // MFVideoPrimaries_BT2020
+ return AVCOL_PRI_BT2020;
+ case 10: // MFVideoPrimaries_XYZ
+ return AVCOL_PRI_SMPTE428;
+ case 11: // MFVideoPrimaries_DCI_P3
+ return AVCOL_PRI_SMPTE431;
+ case 12: // MFVideoPrimaries_ACES (Academy Color Encoding System)
+ // not an FFmpeg color primary
+ return AVCOL_PRI_UNSPECIFIED;
+
+ default:
+ return AVCOL_PRI_UNSPECIFIED;
+ }
+}
+
+static enum AVColorTransferCharacteristic dshow_color_trc(DXVA2_ExtendedFormat *fmt_info)
+{
+ switch (fmt_info->VideoTransferFunction)
+ {
+ case DXVA2_VideoTransFunc_Unknown:
+ return AVCOL_TRC_UNSPECIFIED;
+ case DXVA2_VideoTransFunc_10:
+ return AVCOL_TRC_LINEAR;
+ case DXVA2_VideoTransFunc_18:
+ // not an FFmpeg transfer characteristic
+ return AVCOL_TRC_UNSPECIFIED;
+ case DXVA2_VideoTransFunc_20:
+ // not an FFmpeg transfer characteristic
+ return AVCOL_TRC_UNSPECIFIED;
+ case DXVA2_VideoTransFunc_22:
+ return AVCOL_TRC_GAMMA22;
+ case DXVA2_VideoTransFunc_709:
+ return AVCOL_TRC_BT709;
+ case DXVA2_VideoTransFunc_240M:
+ return AVCOL_TRC_SMPTE240M;
+ case DXVA2_VideoTransFunc_sRGB:
+ return AVCOL_TRC_IEC61966_2_1;
+ case DXVA2_VideoTransFunc_28:
+ return AVCOL_TRC_GAMMA28;
+
+ // values from MediaFoundation SDK (mfobjects.h)
+ case 9: // MFVideoTransFunc_Log_100
+ return AVCOL_TRC_LOG;
+ case 10: // MFVideoTransFunc_Log_316
+ return AVCOL_TRC_LOG_SQRT;
+ case 11: // MFVideoTransFunc_709_sym
+ // not an FFmpeg transfer characteristic
+ return AVCOL_TRC_UNSPECIFIED;
+ case 12: // MFVideoTransFunc_2020_const
+ case 13: // MFVideoTransFunc_2020
+ if (fmt_info->VideoTransferMatrix==5) // MFVideoTransferMatrix_BT2020_12
+ return AVCOL_TRC_BT2020_12;
+ else
+ return AVCOL_TRC_BT2020_10;
+ case 14: // MFVideoTransFunc_26
+ // not an FFmpeg transfer characteristic
+ return AVCOL_TRC_UNSPECIFIED;
+ case 15: // MFVideoTransFunc_2084
+ return AVCOL_TRC_SMPTEST2084;
+ case 16: // MFVideoTransFunc_HLG
+ return AVCOL_TRC_ARIB_STD_B67;
+ case 17: // MFVideoTransFunc_10_rel
+ // not an FFmpeg transfer characteristic? Undocumented also by MS
+ return AVCOL_TRC_UNSPECIFIED;
+
+ default:
+ return AVCOL_TRC_UNSPECIFIED;
+ }
+}
+
+static enum AVChromaLocation dshow_chroma_loc(DXVA2_ExtendedFormat *fmt_info)
+{
+ if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_Cosited) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
+ return AVCHROMA_LOC_TOPLEFT;
+ else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG1) // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
+ return AVCHROMA_LOC_CENTER;
+ else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG2) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
+ return AVCHROMA_LOC_LEFT;
+ else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_DV_PAL) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
+ return AVCHROMA_LOC_TOPLEFT;
+ else
+ // unknown
+ return AVCHROMA_LOC_UNSPECIFIED;
+}
+
static int
dshow_read_close(AVFormatContext *s)
{
@@ -517,6 +728,7 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
BITMAPINFOHEADER *bih;
int64_t *fr;
+ DXVA2_ExtendedFormat *extended_format_info = NULL;
const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
#if DSHOWDEBUG
ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
@@ -529,6 +741,8 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
fr = &v->AvgTimePerFrame;
bih = &v->bmiHeader;
+ if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
+ extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
} else {
goto next;
}
@@ -545,11 +759,40 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
} else {
av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt));
}
- av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n",
+ av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g",
vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
1e7 / vcaps->MaxFrameInterval,
vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
1e7 / vcaps->MinFrameInterval);
+ if (extended_format_info) {
+ enum AVColorRange col_range = dshow_color_range(extended_format_info);
+ enum AVColorSpace col_space = dshow_color_space(extended_format_info);
+ enum AVColorPrimaries col_prim = dshow_color_primaries(extended_format_info);
+ enum AVColorTransferCharacteristic col_trc = dshow_color_trc(extended_format_info);
+ enum AVChromaLocation chroma_loc = dshow_chroma_loc(extended_format_info);
+ if (col_range != AVCOL_RANGE_UNSPECIFIED || col_space != AVCOL_SPC_UNSPECIFIED || col_prim != AVCOL_PRI_UNSPECIFIED || col_trc != AVCOL_TRC_UNSPECIFIED) {
+ const char *range = av_color_range_name(col_range);
+ const char *space = av_color_space_name(col_space);
+ const char *prim = av_color_primaries_name(col_prim);
+ const char *trc = av_color_transfer_name(col_trc);
+ av_log(avctx, AV_LOG_INFO, " (%s, %s/%s/%s",
+ range ? range : "unknown",
+ space ? space : "unknown",
+ prim ? prim : "unknown",
+ trc ? trc : "unknown");
+ if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED) {
+ const char *chroma = av_chroma_location_name(chroma_loc);
+ av_log(avctx, AV_LOG_INFO, ", %s", chroma ? chroma : "unknown");
+ }
+ av_log(avctx, AV_LOG_INFO, ")");
+ }
+ else if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED) {
+ const char *chroma = av_chroma_location_name(chroma_loc);
+ av_log(avctx, AV_LOG_INFO, "(%s)", chroma ? chroma : "unknown");
+ }
+ }
+
+ av_log(avctx, AV_LOG_INFO, "\n");
continue;
}
if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
@@ -1118,6 +1361,7 @@ dshow_add_device(AVFormatContext *avctx,
if (devtype == VideoDevice) {
BITMAPINFOHEADER *bih = NULL;
AVRational time_base;
+ DXVA2_ExtendedFormat *extended_format_info = NULL;
if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
VIDEOINFOHEADER *v = (void *) type.pbFormat;
@@ -1127,6 +1371,8 @@ dshow_add_device(AVFormatContext *avctx,
VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
bih = &v->bmiHeader;
+ if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
+ extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
}
if (!bih) {
av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
@@ -1145,6 +1391,13 @@ dshow_add_device(AVFormatContext *avctx,
av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
par->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
}
+ if (extended_format_info) {
+ par->color_range = dshow_color_range(extended_format_info);
+ par->color_space = dshow_color_space(extended_format_info);
+ par->color_primaries = dshow_color_primaries(extended_format_info);
+ par->color_trc = dshow_color_trc(extended_format_info);
+ par->chroma_location = dshow_chroma_loc(extended_format_info);
+ }
if (par->format == AV_PIX_FMT_NONE) {
const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
par->codec_id = av_codec_get_id(tags, bih->biCompression);
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* [FFmpeg-devel] [PATCH v6 12/12] avdevice/dshow: select format with extended color info
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
` (10 preceding siblings ...)
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc Diederick Niehorster
@ 2021-12-21 12:12 ` Diederick Niehorster
11 siblings, 0 replies; 17+ messages in thread
From: Diederick Niehorster @ 2021-12-21 12:12 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Diederick Niehorster
Some DirectShow devices (Logitech C920 webcam) expose each DirectShow
format they support twice, once without and once with extended color
information. During format selection, both match, this patch ensures
that the format with extended color information is selected if it is
available, else it falls back to a matching format without such
information. This also necessitated a new code path taken for default
formats of a device (when user didn't request any specific video size,
etc), because the default format may be one without extended color
information when a twin with extended color information is also
available. Getting the extended color information when available is
important as it allows setting the color space, range, primaries,
transfer characteristics and chroma location of the stream provided by
dshow, enabling users to get more correct color automatically out of
their device.
Closes: #9271
Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
---
libavdevice/dshow.c | 471 ++++++++++++++++++++++++++++++++------------
1 file changed, 340 insertions(+), 131 deletions(-)
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
index 79be32b255..b87313acb9 100644
--- a/libavdevice/dshow.c
+++ b/libavdevice/dshow.c
@@ -23,6 +23,7 @@
#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/opt.h"
+#include "libavutil/mem.h"
#include "libavformat/internal.h"
#include "libavformat/riff.h"
#include "avdevice.h"
@@ -690,9 +691,111 @@ error:
return ret;
}
+static int dshow_should_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype)
+{
+ struct dshow_ctx *ctx = avctx->priv_data;
+
+ return (devtype == VideoDevice && (ctx->framerate ||
+ (ctx->requested_width && ctx->requested_height) ||
+ ctx->pixel_format != AV_PIX_FMT_NONE ||
+ ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO))
+ || (devtype == AudioDevice && (ctx->channels || ctx->sample_size || ctx->sample_rate));
+}
+
+
+struct dshow_format_info {
+ enum dshowDeviceType devtype;
+ // video
+ int64_t framerate;
+ enum AVPixelFormat pix_fmt;
+ enum AVCodecID codec_id;
+ enum AVColorRange col_range;
+ enum AVColorSpace col_space;
+ enum AVColorPrimaries col_prim;
+ enum AVColorTransferCharacteristic col_trc;
+ enum AVChromaLocation chroma_loc;
+ int width;
+ int height;
+ // audio
+ int sample_rate;
+ int sample_size;
+ int channels;
+};
+
+// user must av_free the returned pointer
+static struct dshow_format_info *dshow_get_format_info(AM_MEDIA_TYPE *type)
+{
+ struct dshow_format_info *fmt_info = NULL;
+ BITMAPINFOHEADER *bih;
+ DXVA2_ExtendedFormat *extended_format_info = NULL;
+ WAVEFORMATEX *fx;
+ enum dshowDeviceType devtype;
+ int64_t framerate;
+
+ if (!type)
+ return NULL;
+
+ if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *v = (void *) type->pbFormat;
+ framerate = v->AvgTimePerFrame;
+ bih = &v->bmiHeader;
+ devtype = VideoDevice;
+ } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
+ VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
+ devtype = VideoDevice;
+ framerate = v->AvgTimePerFrame;
+ bih = &v->bmiHeader;
+ if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
+ extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
+ } else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
+ fx = (void *) type->pbFormat;
+ devtype = AudioDevice;
+ } else {
+ return NULL;
+ }
+
+ fmt_info = av_mallocz(sizeof(struct dshow_format_info));
+ if (!fmt_info)
+ return NULL;
+ // initialize fields where unset is not zero
+ fmt_info->pix_fmt = AV_PIX_FMT_NONE;
+ fmt_info->col_space = AVCOL_SPC_UNSPECIFIED;
+ fmt_info->col_prim = AVCOL_PRI_UNSPECIFIED;
+ fmt_info->col_trc = AVCOL_TRC_UNSPECIFIED;
+ // now get info about format
+ fmt_info->devtype = devtype;
+ if (devtype == VideoDevice) {
+ fmt_info->width = bih->biWidth;
+ fmt_info->height = bih->biHeight;
+ fmt_info->framerate = framerate;
+ fmt_info->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
+ if (fmt_info->pix_fmt == AV_PIX_FMT_NONE) {
+ const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
+ fmt_info->codec_id = av_codec_get_id(tags, bih->biCompression);
+ }
+ else
+ fmt_info->codec_id = AV_CODEC_ID_RAWVIDEO;
+
+ if (extended_format_info) {
+ fmt_info->col_range = dshow_color_range(extended_format_info);
+ fmt_info->col_space = dshow_color_space(extended_format_info);
+ fmt_info->col_prim = dshow_color_primaries(extended_format_info);
+ fmt_info->col_trc = dshow_color_trc(extended_format_info);
+ fmt_info->chroma_loc = dshow_chroma_loc(extended_format_info);
+ }
+ } else {
+ fmt_info->sample_rate = fx->nSamplesPerSec;
+ fmt_info->sample_size = fx->wBitsPerSample;
+ fmt_info->channels = fx->nChannels;
+ }
+
+ return fmt_info;
+}
+
/**
- * Cycle through available formats using the specified pin,
- * try to set parameters specified through AVOptions and if successful
+ * Cycle through available formats available from the specified pin,
+ * try to set parameters specified through AVOptions, or the pin's
+ * default format if no such parameters were set. If successful,
* return 1 in *pformat_set.
* If pformat_set is NULL, list all pin capabilities.
*/
@@ -703,9 +806,27 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
struct dshow_ctx *ctx = avctx->priv_data;
IAMStreamConfig *config = NULL;
AM_MEDIA_TYPE *type = NULL;
+ AM_MEDIA_TYPE *previous_match_type = NULL;
int format_set = 0;
void *caps = NULL;
int i, n, size, r;
+ int wait_for_better = 0;
+ int use_default;
+
+ // format parameters requested by user
+ // if none are requested by user, the values will below be set to
+ // those of the default format
+ // video
+ enum AVCodecID requested_video_codec_id = ctx->video_codec_id;
+ enum AVPixelFormat requested_pixel_format = ctx->pixel_format;
+ int64_t requested_framerate = ctx->framerate ? ((int64_t)ctx->requested_framerate.den * 10000000)
+ / ctx->requested_framerate.num : 0;
+ int requested_width = ctx->requested_width;
+ int requested_height = ctx->requested_height;
+ // audio
+ int requested_sample_rate = ctx->sample_rate;
+ int requested_sample_size = ctx->sample_size;
+ int requested_channels = ctx->channels;
if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
return;
@@ -716,7 +837,83 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
if (!caps)
goto end;
+ /**
+ * If we should open the device with the default format,
+ * then:
+ * 1. check what the format of the default device is, and
+ * 2. below we iterate all formats till we find a matching
+ * one, with most info exposed (see comment below).
+ */
+ use_default = !dshow_should_set_format(avctx, devtype);
+ if (use_default && pformat_set)
+ {
+ HRESULT hr;
+
+ // get default
+ if ((hr = IAMStreamConfig_GetFormat(config, &type)) != S_OK) {
+ if (hr == E_NOTIMPL || !IsEqualGUID(&type->majortype, devtype==VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
+ // default not available or of wrong type,
+ // fall back to iterating exposed formats
+ // until one of the right type is found
+ IEnumMediaTypes *types = NULL;
+ if (IPin_EnumMediaTypes(pin, &types) != S_OK)
+ goto end;
+ IEnumMediaTypes_Reset(types);
+ while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
+ if (IsEqualGUID(&type->majortype, devtype==VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
+ break;
+ }
+ CoTaskMemFree(type);
+ type = NULL;
+ }
+ IEnumMediaTypes_Release(types);
+ }
+
+ if (!type)
+ // this pin does not expose any formats of the expected type
+ goto end;
+ }
+
+ if (type) {
+ // interrogate default format, so we know what to search for below
+ struct dshow_format_info *fmt_info = dshow_get_format_info(type);
+ if (fmt_info) {
+ if (fmt_info->devtype == VideoDevice) {
+ requested_video_codec_id = fmt_info->codec_id;
+ requested_pixel_format = fmt_info->pix_fmt;
+ requested_framerate = fmt_info->framerate;
+ requested_width = fmt_info->width;
+ requested_height = fmt_info->height;
+ } else {
+ requested_sample_rate = fmt_info->sample_rate;
+ requested_sample_size = fmt_info->sample_size;
+ requested_channels = fmt_info->channels;
+ }
+ av_free(fmt_info); // free but don't set to NULL to enable below check
+ }
+
+ if (type && type->pbFormat)
+ CoTaskMemFree(type->pbFormat);
+ CoTaskMemFree(type);
+ type = NULL;
+ if (!fmt_info)
+ // default format somehow invalid, can't continue with this pin
+ goto end;
+ fmt_info = NULL;
+ }
+ }
+
+ // NB: some devices (e.g. Logitech C920) expose each video format twice:
+ // both a format containing a VIDEOINFOHEADER and a format containing
+ // a VIDEOINFOHEADER2. We want, if possible, to select a format with a
+ // VIDEOINFOHEADER2, as this potentially provides more info about the
+ // format. So, if in the iteration below we have found a matching format,
+ // but it is a VIDEOINFOHEADER, keep looking for a matching format that
+ // exposes contains a VIDEOINFOHEADER2. Fall back to the VIDEOINFOHEADER
+ // format if no corresponding VIDEOINFOHEADER2 is found when we finish
+ // iterating.
for (i = 0; i < n && !format_set; i++) {
+ struct dshow_format_info *fmt_info = NULL;
r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps);
if (r != S_OK)
goto next;
@@ -724,106 +921,101 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
ff_print_AM_MEDIA_TYPE(type);
#endif
+ fmt_info = dshow_get_format_info(type);
+ if (!fmt_info)
+ goto next;
+
if (devtype == VideoDevice) {
VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
BITMAPINFOHEADER *bih;
int64_t *fr;
- DXVA2_ExtendedFormat *extended_format_info = NULL;
- const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
#if DSHOWDEBUG
ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
#endif
+
+ if (fmt_info->devtype != VideoDevice)
+ goto next;
+
if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
VIDEOINFOHEADER *v = (void *) type->pbFormat;
- fr = &v->AvgTimePerFrame;
+ fr = &v->AvgTimePerFrame;
bih = &v->bmiHeader;
+ wait_for_better = 1;
} else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
- fr = &v->AvgTimePerFrame;
+ fr = &v->AvgTimePerFrame;
bih = &v->bmiHeader;
- if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
- extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
- } else {
- goto next;
+ wait_for_better = 0;
}
+
if (!pformat_set) {
- enum AVPixelFormat pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
- if (pix_fmt == AV_PIX_FMT_NONE) {
- enum AVCodecID codec_id = av_codec_get_id(tags, bih->biCompression);
- const AVCodec *codec = avcodec_find_decoder(codec_id);
- if (codec_id == AV_CODEC_ID_NONE || !codec) {
+ if (fmt_info->pix_fmt == AV_PIX_FMT_NONE) {
+ const AVCodec *codec = avcodec_find_decoder(fmt_info->codec_id);
+ if (fmt_info->codec_id == AV_CODEC_ID_NONE || !codec) {
av_log(avctx, AV_LOG_INFO, " unknown compression type 0x%X", (int) bih->biCompression);
} else {
av_log(avctx, AV_LOG_INFO, " vcodec=%s", codec->name);
}
} else {
- av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt));
+ av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(fmt_info->pix_fmt));
}
av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g",
vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
1e7 / vcaps->MaxFrameInterval,
vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
1e7 / vcaps->MinFrameInterval);
- if (extended_format_info) {
- enum AVColorRange col_range = dshow_color_range(extended_format_info);
- enum AVColorSpace col_space = dshow_color_space(extended_format_info);
- enum AVColorPrimaries col_prim = dshow_color_primaries(extended_format_info);
- enum AVColorTransferCharacteristic col_trc = dshow_color_trc(extended_format_info);
- enum AVChromaLocation chroma_loc = dshow_chroma_loc(extended_format_info);
- if (col_range != AVCOL_RANGE_UNSPECIFIED || col_space != AVCOL_SPC_UNSPECIFIED || col_prim != AVCOL_PRI_UNSPECIFIED || col_trc != AVCOL_TRC_UNSPECIFIED) {
- const char *range = av_color_range_name(col_range);
- const char *space = av_color_space_name(col_space);
- const char *prim = av_color_primaries_name(col_prim);
- const char *trc = av_color_transfer_name(col_trc);
- av_log(avctx, AV_LOG_INFO, " (%s, %s/%s/%s",
- range ? range : "unknown",
- space ? space : "unknown",
- prim ? prim : "unknown",
- trc ? trc : "unknown");
- if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED) {
- const char *chroma = av_chroma_location_name(chroma_loc);
- av_log(avctx, AV_LOG_INFO, ", %s", chroma ? chroma : "unknown");
- }
- av_log(avctx, AV_LOG_INFO, ")");
- }
- else if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED) {
- const char *chroma = av_chroma_location_name(chroma_loc);
- av_log(avctx, AV_LOG_INFO, "(%s)", chroma ? chroma : "unknown");
- }
+
+ const char *chroma = av_chroma_location_name(fmt_info->chroma_loc);
+ if (fmt_info->col_range != AVCOL_RANGE_UNSPECIFIED ||
+ fmt_info->col_space != AVCOL_SPC_UNSPECIFIED ||
+ fmt_info->col_prim != AVCOL_PRI_UNSPECIFIED ||
+ fmt_info->col_trc != AVCOL_TRC_UNSPECIFIED) {
+ const char *range = av_color_range_name(fmt_info->col_range);
+ const char *space = av_color_space_name(fmt_info->col_space);
+ const char *prim = av_color_primaries_name(fmt_info->col_prim);
+ const char *trc = av_color_transfer_name(fmt_info->col_trc);
+ av_log(avctx, AV_LOG_INFO, " (%s, %s/%s/%s",
+ range ? range : "unknown",
+ space ? space : "unknown",
+ prim ? prim : "unknown",
+ trc ? trc : "unknown");
+ if (fmt_info->chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
+ av_log(avctx, AV_LOG_INFO, ", %s", chroma ? chroma : "unknown");
+ av_log(avctx, AV_LOG_INFO, ")");
}
+ else if (fmt_info->chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
+ av_log(avctx, AV_LOG_INFO, "(%s)", chroma ? chroma : "unknown");
av_log(avctx, AV_LOG_INFO, "\n");
continue;
}
- if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
- if (ctx->video_codec_id != av_codec_get_id(tags, bih->biCompression))
+ if (requested_video_codec_id != AV_CODEC_ID_RAWVIDEO) {
+ if (requested_video_codec_id != fmt_info->codec_id)
goto next;
}
- if (ctx->pixel_format != AV_PIX_FMT_NONE &&
- ctx->pixel_format != dshow_pixfmt(bih->biCompression, bih->biBitCount)) {
+ if (requested_pixel_format != AV_PIX_FMT_NONE &&
+ requested_pixel_format != fmt_info->pix_fmt) {
goto next;
}
- if (ctx->framerate) {
- int64_t framerate = ((int64_t) ctx->requested_framerate.den*10000000)
- / ctx->requested_framerate.num;
- if (framerate > vcaps->MaxFrameInterval ||
- framerate < vcaps->MinFrameInterval)
+ if (requested_framerate) {
+ if (requested_framerate > vcaps->MaxFrameInterval ||
+ requested_framerate < vcaps->MinFrameInterval)
goto next;
- *fr = framerate;
+ *fr = requested_framerate;
}
- if (ctx->requested_width && ctx->requested_height) {
- if (ctx->requested_width > vcaps->MaxOutputSize.cx ||
- ctx->requested_width < vcaps->MinOutputSize.cx ||
- ctx->requested_height > vcaps->MaxOutputSize.cy ||
- ctx->requested_height < vcaps->MinOutputSize.cy)
+ if (requested_width && requested_height) {
+ if (requested_width > vcaps->MaxOutputSize.cx ||
+ requested_width < vcaps->MinOutputSize.cx ||
+ requested_height > vcaps->MaxOutputSize.cy ||
+ requested_height < vcaps->MinOutputSize.cy)
goto next;
- bih->biWidth = ctx->requested_width;
- bih->biHeight = ctx->requested_height;
+ bih->biWidth = requested_width;
+ bih->biHeight = requested_height;
}
} else {
WAVEFORMATEX *fx;
-#if DSHOWDEBUG
AUDIO_STREAM_CONFIG_CAPS *acaps = caps;
+#if DSHOWDEBUG
ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps);
#endif
if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
@@ -840,23 +1032,62 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
);
continue;
}
- if (
- (ctx->sample_rate && ctx->sample_rate != fx->nSamplesPerSec) ||
- (ctx->sample_size && ctx->sample_size != fx->wBitsPerSample) ||
- (ctx->channels && ctx->channels != fx->nChannels )
- ) {
- goto next;
+ if (requested_sample_rate) {
+ if (requested_sample_rate > acaps->MaximumSampleFrequency ||
+ requested_sample_rate < acaps->MinimumSampleFrequency)
+ goto next;
+ fx->nSamplesPerSec = requested_sample_rate;
+ }
+ if (requested_sample_size) {
+ if (requested_sample_size > acaps->MaximumBitsPerSample ||
+ requested_sample_size < acaps->MinimumBitsPerSample)
+ goto next;
+ fx->wBitsPerSample = requested_sample_size;
+ }
+ if (requested_channels) {
+ if (requested_channels > acaps->MaximumChannels ||
+ requested_channels < acaps->MinimumChannels)
+ goto next;
+ fx->nChannels = requested_channels;
}
}
- if (IAMStreamConfig_SetFormat(config, type) != S_OK)
- goto next;
- format_set = 1;
+
+ // found a matching format. Either apply or store
+ // for safekeeping if we might maybe find a better
+ // format with more info attached to it (see comment
+ // above loop)
+ if (!wait_for_better) {
+ if (IAMStreamConfig_SetFormat(config, type) != S_OK)
+ goto next;
+ format_set = 1;
+ }
+ else if (!previous_match_type) {
+ // store this matching format for possible later use.
+ // If we have already found a matching format, ignore it
+ previous_match_type = type;
+ type = NULL;
+ }
next:
- if (type->pbFormat)
+ av_freep(&fmt_info);
+ if (type && type->pbFormat)
CoTaskMemFree(type->pbFormat);
CoTaskMemFree(type);
}
+ // previously found a matching VIDEOINFOHEADER format and stored
+ // it for safe keeping. Searching further for a matching
+ // VIDEOINFOHEADER2 format yielded nothing. So set the pin's
+ // format based on the VIDEOINFOHEADER format.
+ // NB: this never applies to an audio format because
+ // previous_match_type always NULL in that case
+ if (!format_set && previous_match_type) {
+ if (IAMStreamConfig_SetFormat(config, previous_match_type) == S_OK)
+ format_set = 1;
+ }
+
end:
+ if (previous_match_type && previous_match_type->pbFormat)
+ CoTaskMemFree(previous_match_type->pbFormat);
+ CoTaskMemFree(previous_match_type);
IAMStreamConfig_Release(config);
av_free(caps);
if (pformat_set)
@@ -975,11 +1206,7 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
- int set_format = (devtype == VideoDevice && (ctx->framerate ||
- (ctx->requested_width && ctx->requested_height) ||
- ctx->pixel_format != AV_PIX_FMT_NONE ||
- ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO))
- || (devtype == AudioDevice && (ctx->channels || ctx->sample_rate || ctx->sample_size));
+ int set_format = dshow_should_set_format(avctx, devtype);
int format_set = 0;
int should_show_properties = (devtype == VideoDevice) ? ctx->show_video_device_dialog : ctx->show_audio_device_dialog;
@@ -999,9 +1226,7 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
IKsPropertySet *p = NULL;
- IEnumMediaTypes *types = NULL;
PIN_INFO info = {0};
- AM_MEDIA_TYPE *type;
GUID category;
DWORD r2;
char *name_buf = NULL;
@@ -1044,35 +1269,24 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
}
}
- if (set_format) {
- dshow_cycle_formats(avctx, devtype, pin, &format_set);
- if (!format_set) {
- goto next;
- }
+ // will either try to find format matching options supplied by user
+ // or try to open default format. Successful if returns with format_set==1
+ dshow_cycle_formats(avctx, devtype, pin, &format_set);
+ if (!format_set) {
+ goto next;
}
+
if (devtype == AudioDevice && ctx->audio_buffer_size) {
if (dshow_set_audio_buffer_size(avctx, pin) < 0) {
av_log(avctx, AV_LOG_ERROR, "unable to set audio buffer size %d to pin, using pin anyway...", ctx->audio_buffer_size);
}
}
- if (IPin_EnumMediaTypes(pin, &types) != S_OK)
- goto next;
-
- IEnumMediaTypes_Reset(types);
- /* in case format_set was not called, just verify the majortype */
- while (!device_pin && IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
- if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
- device_pin = pin;
- av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename);
- goto next;
- }
- CoTaskMemFree(type);
+ if (format_set) {
+ device_pin = pin;
+ av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename);
}
-
next:
- if (types)
- IEnumMediaTypes_Release(types);
if (p)
IKsPropertySet_Release(p);
if (device_pin != pin)
@@ -1342,6 +1556,7 @@ dshow_add_device(AVFormatContext *avctx,
AM_MEDIA_TYPE type;
AVCodecParameters *par;
AVStream *st;
+ struct dshow_format_info *fmt_info = NULL;
int ret = AVERROR(EIO);
type.pbFormat = NULL;
@@ -1356,12 +1571,16 @@ dshow_add_device(AVFormatContext *avctx,
ctx->capture_filter[devtype]->stream_index = st->index;
ff_dshow_pin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
+ fmt_info = dshow_get_format_info(&type);
+ if (!fmt_info) {
+ ret = AVERROR(EIO);
+ goto error;
+ }
par = st->codecpar;
if (devtype == VideoDevice) {
BITMAPINFOHEADER *bih = NULL;
AVRational time_base;
- DXVA2_ExtendedFormat *extended_format_info = NULL;
if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
VIDEOINFOHEADER *v = (void *) type.pbFormat;
@@ -1371,8 +1590,6 @@ dshow_add_device(AVFormatContext *avctx,
VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
bih = &v->bmiHeader;
- if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
- extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
}
if (!bih) {
av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
@@ -1383,33 +1600,21 @@ dshow_add_device(AVFormatContext *avctx,
st->r_frame_rate = av_inv_q(time_base);
par->codec_type = AVMEDIA_TYPE_VIDEO;
- par->width = bih->biWidth;
- par->height = bih->biHeight;
+ par->width = fmt_info->width;
+ par->height = fmt_info->height;
par->codec_tag = bih->biCompression;
- par->format = dshow_pixfmt(bih->biCompression, bih->biBitCount);
+ par->format = fmt_info->pix_fmt;
if (bih->biCompression == MKTAG('H', 'D', 'Y', 'C')) {
av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
par->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
}
- if (extended_format_info) {
- par->color_range = dshow_color_range(extended_format_info);
- par->color_space = dshow_color_space(extended_format_info);
- par->color_primaries = dshow_color_primaries(extended_format_info);
- par->color_trc = dshow_color_trc(extended_format_info);
- par->chroma_location = dshow_chroma_loc(extended_format_info);
- }
- if (par->format == AV_PIX_FMT_NONE) {
- const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
- par->codec_id = av_codec_get_id(tags, bih->biCompression);
- if (par->codec_id == AV_CODEC_ID_NONE) {
- av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
- "Please report type 0x%X.\n", (int) bih->biCompression);
- ret = AVERROR_PATCHWELCOME;
- goto error;
- }
- par->bits_per_coded_sample = bih->biBitCount;
- } else {
- par->codec_id = AV_CODEC_ID_RAWVIDEO;
+ par->color_range = fmt_info->col_range;
+ par->color_space = fmt_info->col_space;
+ par->color_primaries = fmt_info->col_prim;
+ par->color_trc = fmt_info->col_trc;
+ par->chroma_location = fmt_info->chroma_loc;
+ par->codec_id = fmt_info->codec_id;
+ if (par->codec_id == AV_CODEC_ID_RAWVIDEO) {
if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
par->bits_per_coded_sample = bih->biBitCount;
if (par->height < 0) {
@@ -1422,23 +1627,26 @@ dshow_add_device(AVFormatContext *avctx,
}
}
}
+ } else {
+ if (par->codec_id == AV_CODEC_ID_NONE) {
+ av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
+ "Please report type 0x%X.\n", (int) bih->biCompression);
+ ret = AVERROR_PATCHWELCOME;
+ goto error;
+ }
+ par->bits_per_coded_sample = bih->biBitCount;
}
} else {
- WAVEFORMATEX *fx = NULL;
-
- if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
- fx = (void *) type.pbFormat;
- }
- if (!fx) {
+ if (!IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
goto error;
}
par->codec_type = AVMEDIA_TYPE_AUDIO;
- par->format = sample_fmt_bits_per_sample(fx->wBitsPerSample);
+ par->format = sample_fmt_bits_per_sample(fmt_info->sample_size);
par->codec_id = waveform_codec_id(par->format);
- par->sample_rate = fx->nSamplesPerSec;
- par->channels = fx->nChannels;
+ par->sample_rate = fmt_info->sample_rate;
+ par->channels = fmt_info->channels;
}
avpriv_set_pts_info(st, 64, 1, 10000000);
@@ -1446,6 +1654,7 @@ dshow_add_device(AVFormatContext *avctx,
ret = 0;
error:
+ av_freep(&fmt_info);
if (type.pbFormat)
CoTaskMemFree(type.pbFormat);
return ret;
--
2.28.0.windows.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc Diederick Niehorster
@ 2021-12-21 12:35 ` Hendrik Leppkes
2021-12-21 13:11 ` Diederick C. Niehorster
0 siblings, 1 reply; 17+ messages in thread
From: Hendrik Leppkes @ 2021-12-21 12:35 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Tue, Dec 21, 2021 at 1:15 PM Diederick Niehorster <dcnieho@gmail.com> wrote:
>
> Enabled discovering a DirectShow device's color range, space, primaries,
> transfer characteristics and chroma location, if the device exposes that
> information. Sets them in the stream's codecpars.
>
> Co-authored-by: Valerii Zapodovnikov <val.zapod.vz@gmail.com>
> Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
> ---
> libavdevice/dshow.c | 255 +++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 254 insertions(+), 1 deletion(-)
>
> diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> index 4b1e942c7a..79be32b255 100644
> --- a/libavdevice/dshow.c
> +++ b/libavdevice/dshow.c
> @@ -29,6 +29,31 @@
> #include "libavcodec/raw.h"
> #include "objidl.h"
> #include "shlwapi.h"
> +// NB: technically, we should include dxva.h and use
> +// DXVA_ExtendedFormat, but that type is not defined in
> +// the MinGW headers. The DXVA2_ExtendedFormat and the
> +// contents of its fields is identical to
> +// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
> +// and is provided by MinGW as well, so we use that
> +// instead. NB also that per the Microsoft docs, the
> +// lowest 8 bits of the structure, i.e. the SampleFormat
> +// field, contain AMCONTROL_xxx flags instead of sample
> +// format information, and should thus not be used.
> +// NB further that various values in the structure's
> +// fields (e.g. BT.2020 color space) are not provided
> +// for either of the DXVA structs, but are provided in
> +// the flags of the corresponding fields of Media Foundation.
> +// These may be provided by DirectShow devices (e.g. LAVFilters
> +// does so). So we use those values here too (the equivalence is
> +// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
> +typedef DWORD D3DFORMAT; // dxva2api.h header needs these types defined before include apparently in WinSDK (not MinGW).
> +typedef DWORD D3DPOOL;
These come from d3d9types.h, through d3d9.h, which presumably you need
anyway due to the other D3D9 interfaces used in dxva2api.h, so I'm not
quite sure when these typedefs are required?
> +#include "dxva2api.h"
> +
> +#ifndef AMCONTROL_COLORINFO_PRESENT
> +// not defined in some versions of MinGW's dvdmedia.h
> +# define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
> +#endif
>
>
> static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> @@ -54,6 +79,192 @@ static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
> }
>
> +static enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
> +{
> + switch (fmt_info->NominalRange)
> + {
> + case DXVA2_NominalRange_Unknown:
> + return AVCOL_RANGE_UNSPECIFIED;
> + case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
> + return AVCOL_RANGE_JPEG;
> + case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
> + return AVCOL_RANGE_MPEG;
> + case DXVA2_NominalRange_48_208:
> + // not an ffmpeg color range
> + return AVCOL_RANGE_UNSPECIFIED;
> +
> + // values from MediaFoundation SDK (mfobjects.h)
> + case 4: // MFNominalRange_64_127
> + // not an ffmpeg color range
> + return AVCOL_RANGE_UNSPECIFIED;
> +
> + default:
> + return DXVA2_NominalRange_Unknown;
The default return here should be an AVCOL_RANGE_ constant as well
> + }
> +}
> +
> +static enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
> +{
> + enum AVColorSpace ret = AVCOL_SPC_UNSPECIFIED;
> +
> + switch (fmt_info->VideoTransferMatrix)
> + {
> + case DXVA2_VideoTransferMatrix_BT709:
> + ret = AVCOL_SPC_BT709;
> + break;
> + case DXVA2_VideoTransferMatrix_BT601:
> + ret = AVCOL_SPC_BT470BG;
> + break;
> + case DXVA2_VideoTransferMatrix_SMPTE240M:
> + ret = AVCOL_SPC_SMPTE240M;
> + break;
> +
> + // values from MediaFoundation SDK (mfobjects.h)
> + case 4: // MFVideoTransferMatrix_BT2020_10
> + case 5: // MFVideoTransferMatrix_BT2020_12
> + if (fmt_info->VideoTransferFunction==12) // MFVideoTransFunc_2020_const
Spaces around the == operator please.
> + ret = AVCOL_SPC_BT2020_CL;
> + else
> + ret = AVCOL_SPC_BT2020_NCL;
> + break;
> + }
> +
> + if (ret == AVCOL_SPC_UNSPECIFIED)
> + {
> + // if color space not known from transfer matrix,
> + // fall back to using primaries to guess color space
Guessing color space from primaries seems unusual, especially since
the behavior of unknown is actually defined in MSDN docs. IMHO it
would be better to forward information provided and not try to
interpret it.
> + switch (fmt_info->VideoPrimaries)
> + {
> + case DXVA2_VideoPrimaries_BT709:
> + ret = AVCOL_SPC_BT709;
> + break;
> + case DXVA2_VideoPrimaries_BT470_2_SysM:
> + ret = AVCOL_SPC_FCC;
> + break;
> + case DXVA2_VideoPrimaries_BT470_2_SysBG:
> + case DXVA2_VideoPrimaries_EBU3213: // this is PAL
> + ret = AVCOL_SPC_BT470BG;
> + break;
> + case DXVA2_VideoPrimaries_SMPTE170M:
> + case DXVA2_VideoPrimaries_SMPTE_C:
> + ret = AVCOL_SPC_SMPTE170M;
> + break;
> + case DXVA2_VideoPrimaries_SMPTE240M:
> + ret = AVCOL_SPC_SMPTE240M;
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static enum AVColorPrimaries dshow_color_primaries(DXVA2_ExtendedFormat *fmt_info)
> +{
> + switch (fmt_info->VideoPrimaries)
> + {
> + case DXVA2_VideoPrimaries_Unknown:
> + return AVCOL_PRI_UNSPECIFIED;
> + case DXVA2_VideoPrimaries_reserved:
> + return AVCOL_PRI_RESERVED;
> + case DXVA2_VideoPrimaries_BT709:
> + return AVCOL_PRI_BT709;
> + case DXVA2_VideoPrimaries_BT470_2_SysM:
> + return AVCOL_PRI_BT470M;
> + case DXVA2_VideoPrimaries_BT470_2_SysBG:
> + case DXVA2_VideoPrimaries_EBU3213: // this is PAL
> + return AVCOL_PRI_BT470BG;
> + case DXVA2_VideoPrimaries_SMPTE170M:
> + case DXVA2_VideoPrimaries_SMPTE_C:
> + return AVCOL_PRI_SMPTE170M;
> + case DXVA2_VideoPrimaries_SMPTE240M:
> + return AVCOL_PRI_SMPTE240M;
> +
> + // values from MediaFoundation SDK (mfobjects.h)
> + case 9: // MFVideoPrimaries_BT2020
> + return AVCOL_PRI_BT2020;
> + case 10: // MFVideoPrimaries_XYZ
> + return AVCOL_PRI_SMPTE428;
> + case 11: // MFVideoPrimaries_DCI_P3
> + return AVCOL_PRI_SMPTE431;
> + case 12: // MFVideoPrimaries_ACES (Academy Color Encoding System)
> + // not an FFmpeg color primary
> + return AVCOL_PRI_UNSPECIFIED;
> +
> + default:
> + return AVCOL_PRI_UNSPECIFIED;
> + }
> +}
> +
> +static enum AVColorTransferCharacteristic dshow_color_trc(DXVA2_ExtendedFormat *fmt_info)
> +{
> + switch (fmt_info->VideoTransferFunction)
> + {
> + case DXVA2_VideoTransFunc_Unknown:
> + return AVCOL_TRC_UNSPECIFIED;
> + case DXVA2_VideoTransFunc_10:
> + return AVCOL_TRC_LINEAR;
> + case DXVA2_VideoTransFunc_18:
> + // not an FFmpeg transfer characteristic
> + return AVCOL_TRC_UNSPECIFIED;
> + case DXVA2_VideoTransFunc_20:
> + // not an FFmpeg transfer characteristic
> + return AVCOL_TRC_UNSPECIFIED;
> + case DXVA2_VideoTransFunc_22:
> + return AVCOL_TRC_GAMMA22;
> + case DXVA2_VideoTransFunc_709:
> + return AVCOL_TRC_BT709;
> + case DXVA2_VideoTransFunc_240M:
> + return AVCOL_TRC_SMPTE240M;
> + case DXVA2_VideoTransFunc_sRGB:
> + return AVCOL_TRC_IEC61966_2_1;
> + case DXVA2_VideoTransFunc_28:
> + return AVCOL_TRC_GAMMA28;
> +
> + // values from MediaFoundation SDK (mfobjects.h)
> + case 9: // MFVideoTransFunc_Log_100
> + return AVCOL_TRC_LOG;
> + case 10: // MFVideoTransFunc_Log_316
> + return AVCOL_TRC_LOG_SQRT;
> + case 11: // MFVideoTransFunc_709_sym
> + // not an FFmpeg transfer characteristic
> + return AVCOL_TRC_UNSPECIFIED;
> + case 12: // MFVideoTransFunc_2020_const
> + case 13: // MFVideoTransFunc_2020
> + if (fmt_info->VideoTransferMatrix==5) // MFVideoTransferMatrix_BT2020_12
> + return AVCOL_TRC_BT2020_12;
> + else
> + return AVCOL_TRC_BT2020_10;
> + case 14: // MFVideoTransFunc_26
> + // not an FFmpeg transfer characteristic
> + return AVCOL_TRC_UNSPECIFIED;
> + case 15: // MFVideoTransFunc_2084
> + return AVCOL_TRC_SMPTEST2084;
> + case 16: // MFVideoTransFunc_HLG
> + return AVCOL_TRC_ARIB_STD_B67;
> + case 17: // MFVideoTransFunc_10_rel
> + // not an FFmpeg transfer characteristic? Undocumented also by MS
> + return AVCOL_TRC_UNSPECIFIED;
> +
> + default:
> + return AVCOL_TRC_UNSPECIFIED;
> + }
> +}
> +
> +static enum AVChromaLocation dshow_chroma_loc(DXVA2_ExtendedFormat *fmt_info)
> +{
> + if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_Cosited) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
> + return AVCHROMA_LOC_TOPLEFT;
> + else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG1) // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
> + return AVCHROMA_LOC_CENTER;
> + else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG2) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
> + return AVCHROMA_LOC_LEFT;
> + else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_DV_PAL) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
> + return AVCHROMA_LOC_TOPLEFT;
> + else
> + // unknown
> + return AVCHROMA_LOC_UNSPECIFIED;
> +}
> +
> static int
> dshow_read_close(AVFormatContext *s)
> {
> @@ -517,6 +728,7 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
> VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
> BITMAPINFOHEADER *bih;
> int64_t *fr;
> + DXVA2_ExtendedFormat *extended_format_info = NULL;
> const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
> #if DSHOWDEBUG
> ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
> @@ -529,6 +741,8 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
> VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
> fr = &v->AvgTimePerFrame;
> bih = &v->bmiHeader;
> + if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
> + extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
> } else {
> goto next;
> }
> @@ -545,11 +759,40 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
> } else {
> av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt));
> }
> - av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n",
> + av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g",
> vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
> 1e7 / vcaps->MaxFrameInterval,
> vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
> 1e7 / vcaps->MinFrameInterval);
> + if (extended_format_info) {
> + enum AVColorRange col_range = dshow_color_range(extended_format_info);
> + enum AVColorSpace col_space = dshow_color_space(extended_format_info);
> + enum AVColorPrimaries col_prim = dshow_color_primaries(extended_format_info);
> + enum AVColorTransferCharacteristic col_trc = dshow_color_trc(extended_format_info);
> + enum AVChromaLocation chroma_loc = dshow_chroma_loc(extended_format_info);
> + if (col_range != AVCOL_RANGE_UNSPECIFIED || col_space != AVCOL_SPC_UNSPECIFIED || col_prim != AVCOL_PRI_UNSPECIFIED || col_trc != AVCOL_TRC_UNSPECIFIED) {
> + const char *range = av_color_range_name(col_range);
> + const char *space = av_color_space_name(col_space);
> + const char *prim = av_color_primaries_name(col_prim);
> + const char *trc = av_color_transfer_name(col_trc);
> + av_log(avctx, AV_LOG_INFO, " (%s, %s/%s/%s",
> + range ? range : "unknown",
> + space ? space : "unknown",
> + prim ? prim : "unknown",
> + trc ? trc : "unknown");
> + if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED) {
> + const char *chroma = av_chroma_location_name(chroma_loc);
> + av_log(avctx, AV_LOG_INFO, ", %s", chroma ? chroma : "unknown");
> + }
> + av_log(avctx, AV_LOG_INFO, ")");
> + }
> + else if (chroma_loc != AVCHROMA_LOC_UNSPECIFIED) {
> + const char *chroma = av_chroma_location_name(chroma_loc);
> + av_log(avctx, AV_LOG_INFO, "(%s)", chroma ? chroma : "unknown");
> + }
> + }
> +
> + av_log(avctx, AV_LOG_INFO, "\n");
> continue;
> }
> if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
> @@ -1118,6 +1361,7 @@ dshow_add_device(AVFormatContext *avctx,
> if (devtype == VideoDevice) {
> BITMAPINFOHEADER *bih = NULL;
> AVRational time_base;
> + DXVA2_ExtendedFormat *extended_format_info = NULL;
>
> if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
> VIDEOINFOHEADER *v = (void *) type.pbFormat;
> @@ -1127,6 +1371,8 @@ dshow_add_device(AVFormatContext *avctx,
> VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
> time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
> bih = &v->bmiHeader;
> + if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
> + extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
> }
> if (!bih) {
> av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
> @@ -1145,6 +1391,13 @@ dshow_add_device(AVFormatContext *avctx,
> av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
> par->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
> }
> + if (extended_format_info) {
> + par->color_range = dshow_color_range(extended_format_info);
> + par->color_space = dshow_color_space(extended_format_info);
> + par->color_primaries = dshow_color_primaries(extended_format_info);
> + par->color_trc = dshow_color_trc(extended_format_info);
> + par->chroma_location = dshow_chroma_loc(extended_format_info);
> + }
> if (par->format == AV_PIX_FMT_NONE) {
> const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
> par->codec_id = av_codec_get_id(tags, bih->biCompression);
> --
> 2.28.0.windows.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc
2021-12-21 12:35 ` Hendrik Leppkes
@ 2021-12-21 13:11 ` Diederick C. Niehorster
2021-12-21 13:35 ` Hendrik Leppkes
0 siblings, 1 reply; 17+ messages in thread
From: Diederick C. Niehorster @ 2021-12-21 13:11 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Hi Hendrik,
Thanks for the review! Comments/questions below:
On Tue, Dec 21, 2021 at 1:35 PM Hendrik Leppkes <h.leppkes@gmail.com> wrote:
>
> On Tue, Dec 21, 2021 at 1:15 PM Diederick Niehorster <dcnieho@gmail.com> wrote:
> >
> > Enabled discovering a DirectShow device's color range, space, primaries,
> > transfer characteristics and chroma location, if the device exposes that
> > information. Sets them in the stream's codecpars.
> >
> > Co-authored-by: Valerii Zapodovnikov <val.zapod.vz@gmail.com>
> > Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
> > ---
> > libavdevice/dshow.c | 255 +++++++++++++++++++++++++++++++++++++++++++-
> > 1 file changed, 254 insertions(+), 1 deletion(-)
> >
> > diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> > index 4b1e942c7a..79be32b255 100644
> > --- a/libavdevice/dshow.c
> > +++ b/libavdevice/dshow.c
> > @@ -29,6 +29,31 @@
> > #include "libavcodec/raw.h"
> > #include "objidl.h"
> > #include "shlwapi.h"
> > +// NB: technically, we should include dxva.h and use
> > +// DXVA_ExtendedFormat, but that type is not defined in
> > +// the MinGW headers. The DXVA2_ExtendedFormat and the
> > +// contents of its fields is identical to
> > +// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
> > +// and is provided by MinGW as well, so we use that
> > +// instead. NB also that per the Microsoft docs, the
> > +// lowest 8 bits of the structure, i.e. the SampleFormat
> > +// field, contain AMCONTROL_xxx flags instead of sample
> > +// format information, and should thus not be used.
> > +// NB further that various values in the structure's
> > +// fields (e.g. BT.2020 color space) are not provided
> > +// for either of the DXVA structs, but are provided in
> > +// the flags of the corresponding fields of Media Foundation.
> > +// These may be provided by DirectShow devices (e.g. LAVFilters
> > +// does so). So we use those values here too (the equivalence is
> > +// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
> > +typedef DWORD D3DFORMAT; // dxva2api.h header needs these types defined before include apparently in WinSDK (not MinGW).
> > +typedef DWORD D3DPOOL;
>
> These come from d3d9types.h, through d3d9.h, which presumably you need
> anyway due to the other D3D9 interfaces used in dxva2api.h, so I'm not
> quite sure when these typedefs are required?
I tried to keep the includes minimal (I don't need any of the d3d9
headers), and to be able to include dxva2api.h, these two typedefs
were needed and nothing else. You prefer i include d3d9types.h instead
of the typedefs?
> > +#include "dxva2api.h"
> > +
> > +#ifndef AMCONTROL_COLORINFO_PRESENT
> > +// not defined in some versions of MinGW's dvdmedia.h
> > +# define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
> > +#endif
> >
> >
> > static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> > @@ -54,6 +79,192 @@ static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> > return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
> > }
> >
> > +static enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
> > +{
> > + switch (fmt_info->NominalRange)
> > + {
> > + case DXVA2_NominalRange_Unknown:
> > + return AVCOL_RANGE_UNSPECIFIED;
> > + case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
> > + return AVCOL_RANGE_JPEG;
> > + case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
> > + return AVCOL_RANGE_MPEG;
> > + case DXVA2_NominalRange_48_208:
> > + // not an ffmpeg color range
> > + return AVCOL_RANGE_UNSPECIFIED;
> > +
> > + // values from MediaFoundation SDK (mfobjects.h)
> > + case 4: // MFNominalRange_64_127
> > + // not an ffmpeg color range
> > + return AVCOL_RANGE_UNSPECIFIED;
> > +
> > + default:
> > + return DXVA2_NominalRange_Unknown;
>
> The default return here should be an AVCOL_RANGE_ constant as well
Absolutely, good catch!
> > + }
> > +}
> > +
> > +static enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
> > +{
> > + enum AVColorSpace ret = AVCOL_SPC_UNSPECIFIED;
> > +
> > + switch (fmt_info->VideoTransferMatrix)
> > + {
> > + case DXVA2_VideoTransferMatrix_BT709:
> > + ret = AVCOL_SPC_BT709;
> > + break;
> > + case DXVA2_VideoTransferMatrix_BT601:
> > + ret = AVCOL_SPC_BT470BG;
> > + break;
> > + case DXVA2_VideoTransferMatrix_SMPTE240M:
> > + ret = AVCOL_SPC_SMPTE240M;
> > + break;
> > +
> > + // values from MediaFoundation SDK (mfobjects.h)
> > + case 4: // MFVideoTransferMatrix_BT2020_10
> > + case 5: // MFVideoTransferMatrix_BT2020_12
> > + if (fmt_info->VideoTransferFunction==12) // MFVideoTransFunc_2020_const
>
> Spaces around the == operator please.
ok
> > + ret = AVCOL_SPC_BT2020_CL;
> > + else
> > + ret = AVCOL_SPC_BT2020_NCL;
> > + break;
> > + }
> > +
> > + if (ret == AVCOL_SPC_UNSPECIFIED)
> > + {
> > + // if color space not known from transfer matrix,
> > + // fall back to using primaries to guess color space
>
> Guessing color space from primaries seems unusual, especially since
> the behavior of unknown is actually defined in MSDN docs. IMHO it
> would be better to forward information provided and not try to
> interpret it.
You think i should remove this whole if (ret == AVCOL_SPC_UNSPECIFIED)
code block? I indeed see the docs comment about how
DXVA2_VideoTransferMatrix_Unknown should be interpreted (nothing we
can do here in this function).
> > + switch (fmt_info->VideoPrimaries)
> > + {
> > + case DXVA2_VideoPrimaries_BT709:
> > + ret = AVCOL_SPC_BT709;
> > + break;
> > + case DXVA2_VideoPrimaries_BT470_2_SysM:
> > + ret = AVCOL_SPC_FCC;
> > + break;
> > + case DXVA2_VideoPrimaries_BT470_2_SysBG:
> > + case DXVA2_VideoPrimaries_EBU3213: // this is PAL
> > + ret = AVCOL_SPC_BT470BG;
> > + break;
> > + case DXVA2_VideoPrimaries_SMPTE170M:
> > + case DXVA2_VideoPrimaries_SMPTE_C:
> > + ret = AVCOL_SPC_SMPTE170M;
> > + break;
> > + case DXVA2_VideoPrimaries_SMPTE240M:
> > + ret = AVCOL_SPC_SMPTE240M;
> > + break;
> > + }
> > + }
> > +
> > + return ret;
> > +}
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc
2021-12-21 13:11 ` Diederick C. Niehorster
@ 2021-12-21 13:35 ` Hendrik Leppkes
2021-12-21 13:44 ` Diederick C. Niehorster
0 siblings, 1 reply; 17+ messages in thread
From: Hendrik Leppkes @ 2021-12-21 13:35 UTC (permalink / raw)
To: FFmpeg development discussions and patches
On Tue, Dec 21, 2021 at 2:11 PM Diederick C. Niehorster
<dcnieho@gmail.com> wrote:
>
> Hi Hendrik,
>
> Thanks for the review! Comments/questions below:
>
> On Tue, Dec 21, 2021 at 1:35 PM Hendrik Leppkes <h.leppkes@gmail.com> wrote:
> >
> > On Tue, Dec 21, 2021 at 1:15 PM Diederick Niehorster <dcnieho@gmail.com> wrote:
> > >
> > > Enabled discovering a DirectShow device's color range, space, primaries,
> > > transfer characteristics and chroma location, if the device exposes that
> > > information. Sets them in the stream's codecpars.
> > >
> > > Co-authored-by: Valerii Zapodovnikov <val.zapod.vz@gmail.com>
> > > Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
> > > ---
> > > libavdevice/dshow.c | 255 +++++++++++++++++++++++++++++++++++++++++++-
> > > 1 file changed, 254 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> > > index 4b1e942c7a..79be32b255 100644
> > > --- a/libavdevice/dshow.c
> > > +++ b/libavdevice/dshow.c
> > > @@ -29,6 +29,31 @@
> > > #include "libavcodec/raw.h"
> > > #include "objidl.h"
> > > #include "shlwapi.h"
> > > +// NB: technically, we should include dxva.h and use
> > > +// DXVA_ExtendedFormat, but that type is not defined in
> > > +// the MinGW headers. The DXVA2_ExtendedFormat and the
> > > +// contents of its fields is identical to
> > > +// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
> > > +// and is provided by MinGW as well, so we use that
> > > +// instead. NB also that per the Microsoft docs, the
> > > +// lowest 8 bits of the structure, i.e. the SampleFormat
> > > +// field, contain AMCONTROL_xxx flags instead of sample
> > > +// format information, and should thus not be used.
> > > +// NB further that various values in the structure's
> > > +// fields (e.g. BT.2020 color space) are not provided
> > > +// for either of the DXVA structs, but are provided in
> > > +// the flags of the corresponding fields of Media Foundation.
> > > +// These may be provided by DirectShow devices (e.g. LAVFilters
> > > +// does so). So we use those values here too (the equivalence is
> > > +// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
> > > +typedef DWORD D3DFORMAT; // dxva2api.h header needs these types defined before include apparently in WinSDK (not MinGW).
> > > +typedef DWORD D3DPOOL;
> >
> > These come from d3d9types.h, through d3d9.h, which presumably you need
> > anyway due to the other D3D9 interfaces used in dxva2api.h, so I'm not
> > quite sure when these typedefs are required?
>
> I tried to keep the includes minimal (I don't need any of the d3d9
> headers), and to be able to include dxva2api.h, these two typedefs
> were needed and nothing else. You prefer i include d3d9types.h instead
> of the typedefs?
Definitely prefer including a header for those types then re-defining
them, yes. That can get a bit out of hand quickly otherwise. And these
older Windows headers are also well defined, so there shouldn't be any
issues.
>
> > > +#include "dxva2api.h"
> > > +
> > > +#ifndef AMCONTROL_COLORINFO_PRESENT
> > > +// not defined in some versions of MinGW's dvdmedia.h
> > > +# define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
> > > +#endif
> > >
> > >
> > > static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> > > @@ -54,6 +79,192 @@ static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> > > return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
> > > }
> > >
> > > +static enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
> > > +{
> > > + switch (fmt_info->NominalRange)
> > > + {
> > > + case DXVA2_NominalRange_Unknown:
> > > + return AVCOL_RANGE_UNSPECIFIED;
> > > + case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
> > > + return AVCOL_RANGE_JPEG;
> > > + case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
> > > + return AVCOL_RANGE_MPEG;
> > > + case DXVA2_NominalRange_48_208:
> > > + // not an ffmpeg color range
> > > + return AVCOL_RANGE_UNSPECIFIED;
> > > +
> > > + // values from MediaFoundation SDK (mfobjects.h)
> > > + case 4: // MFNominalRange_64_127
> > > + // not an ffmpeg color range
> > > + return AVCOL_RANGE_UNSPECIFIED;
> > > +
> > > + default:
> > > + return DXVA2_NominalRange_Unknown;
> >
> > The default return here should be an AVCOL_RANGE_ constant as well
>
> Absolutely, good catch!
>
> > > + }
> > > +}
> > > +
> > > +static enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
> > > +{
> > > + enum AVColorSpace ret = AVCOL_SPC_UNSPECIFIED;
> > > +
> > > + switch (fmt_info->VideoTransferMatrix)
> > > + {
> > > + case DXVA2_VideoTransferMatrix_BT709:
> > > + ret = AVCOL_SPC_BT709;
> > > + break;
> > > + case DXVA2_VideoTransferMatrix_BT601:
> > > + ret = AVCOL_SPC_BT470BG;
> > > + break;
> > > + case DXVA2_VideoTransferMatrix_SMPTE240M:
> > > + ret = AVCOL_SPC_SMPTE240M;
> > > + break;
> > > +
> > > + // values from MediaFoundation SDK (mfobjects.h)
> > > + case 4: // MFVideoTransferMatrix_BT2020_10
> > > + case 5: // MFVideoTransferMatrix_BT2020_12
> > > + if (fmt_info->VideoTransferFunction==12) // MFVideoTransFunc_2020_const
> >
> > Spaces around the == operator please.
>
> ok
>
> > > + ret = AVCOL_SPC_BT2020_CL;
> > > + else
> > > + ret = AVCOL_SPC_BT2020_NCL;
> > > + break;
> > > + }
> > > +
> > > + if (ret == AVCOL_SPC_UNSPECIFIED)
> > > + {
> > > + // if color space not known from transfer matrix,
> > > + // fall back to using primaries to guess color space
> >
> > Guessing color space from primaries seems unusual, especially since
> > the behavior of unknown is actually defined in MSDN docs. IMHO it
> > would be better to forward information provided and not try to
> > interpret it.
>
> You think i should remove this whole if (ret == AVCOL_SPC_UNSPECIFIED)
> code block? I indeed see the docs comment about how
> DXVA2_VideoTransferMatrix_Unknown should be interpreted (nothing we
> can do here in this function).
Thats what I would've suggested, but I don't know if you had that in
there for any specific cases with capture hardware or the likes.
>
> > > + switch (fmt_info->VideoPrimaries)
> > > + {
> > > + case DXVA2_VideoPrimaries_BT709:
> > > + ret = AVCOL_SPC_BT709;
> > > + break;
> > > + case DXVA2_VideoPrimaries_BT470_2_SysM:
> > > + ret = AVCOL_SPC_FCC;
> > > + break;
> > > + case DXVA2_VideoPrimaries_BT470_2_SysBG:
> > > + case DXVA2_VideoPrimaries_EBU3213: // this is PAL
> > > + ret = AVCOL_SPC_BT470BG;
> > > + break;
> > > + case DXVA2_VideoPrimaries_SMPTE170M:
> > > + case DXVA2_VideoPrimaries_SMPTE_C:
> > > + ret = AVCOL_SPC_SMPTE170M;
> > > + break;
> > > + case DXVA2_VideoPrimaries_SMPTE240M:
> > > + ret = AVCOL_SPC_SMPTE240M;
> > > + break;
> > > + }
> > > + }
> > > +
> > > + return ret;
> > > +}
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc
2021-12-21 13:35 ` Hendrik Leppkes
@ 2021-12-21 13:44 ` Diederick C. Niehorster
0 siblings, 0 replies; 17+ messages in thread
From: Diederick C. Niehorster @ 2021-12-21 13:44 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Hi Hendrik,
On Tue, Dec 21, 2021 at 2:35 PM Hendrik Leppkes <h.leppkes@gmail.com> wrote:
>
> On Tue, Dec 21, 2021 at 2:11 PM Diederick C. Niehorster
> <dcnieho@gmail.com> wrote:
> >
> > Hi Hendrik,
> >
> > Thanks for the review! Comments/questions below:
> >
> > On Tue, Dec 21, 2021 at 1:35 PM Hendrik Leppkes <h.leppkes@gmail.com> wrote:
> > >
> > > On Tue, Dec 21, 2021 at 1:15 PM Diederick Niehorster <dcnieho@gmail.com> wrote:
> > > >
> > > > Enabled discovering a DirectShow device's color range, space, primaries,
> > > > transfer characteristics and chroma location, if the device exposes that
> > > > information. Sets them in the stream's codecpars.
> > > >
> > > > Co-authored-by: Valerii Zapodovnikov <val.zapod.vz@gmail.com>
> > > > Signed-off-by: Diederick Niehorster <dcnieho@gmail.com>
> > > > ---
> > > > libavdevice/dshow.c | 255 +++++++++++++++++++++++++++++++++++++++++++-
> > > > 1 file changed, 254 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> > > > index 4b1e942c7a..79be32b255 100644
> > > > --- a/libavdevice/dshow.c
> > > > +++ b/libavdevice/dshow.c
> > > > @@ -29,6 +29,31 @@
> > > > #include "libavcodec/raw.h"
> > > > #include "objidl.h"
> > > > #include "shlwapi.h"
> > > > +// NB: technically, we should include dxva.h and use
> > > > +// DXVA_ExtendedFormat, but that type is not defined in
> > > > +// the MinGW headers. The DXVA2_ExtendedFormat and the
> > > > +// contents of its fields is identical to
> > > > +// DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
> > > > +// and is provided by MinGW as well, so we use that
> > > > +// instead. NB also that per the Microsoft docs, the
> > > > +// lowest 8 bits of the structure, i.e. the SampleFormat
> > > > +// field, contain AMCONTROL_xxx flags instead of sample
> > > > +// format information, and should thus not be used.
> > > > +// NB further that various values in the structure's
> > > > +// fields (e.g. BT.2020 color space) are not provided
> > > > +// for either of the DXVA structs, but are provided in
> > > > +// the flags of the corresponding fields of Media Foundation.
> > > > +// These may be provided by DirectShow devices (e.g. LAVFilters
> > > > +// does so). So we use those values here too (the equivalence is
> > > > +// indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
> > > > +typedef DWORD D3DFORMAT; // dxva2api.h header needs these types defined before include apparently in WinSDK (not MinGW).
> > > > +typedef DWORD D3DPOOL;
> > >
> > > These come from d3d9types.h, through d3d9.h, which presumably you need
> > > anyway due to the other D3D9 interfaces used in dxva2api.h, so I'm not
> > > quite sure when these typedefs are required?
> >
> > I tried to keep the includes minimal (I don't need any of the d3d9
> > headers), and to be able to include dxva2api.h, these two typedefs
> > were needed and nothing else. You prefer i include d3d9types.h instead
> > of the typedefs?
>
> Definitely prefer including a header for those types then re-defining
> them, yes. That can get a bit out of hand quickly otherwise. And these
> older Windows headers are also well defined, so there shouldn't be any
> issues.
Ok, I'll replace with an include of d3d9types.h
> > > > +#include "dxva2api.h"
> > > > +
> > > > +#ifndef AMCONTROL_COLORINFO_PRESENT
> > > > +// not defined in some versions of MinGW's dvdmedia.h
> > > > +# define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
> > > > +#endif
> > > >
> > > >
> > > > static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> > > > @@ -54,6 +79,192 @@ static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> > > > return avpriv_find_pix_fmt(avpriv_get_raw_pix_fmt_tags(), biCompression); // all others
> > > > }
> > > >
> > > > +static enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
> > > > +{
> > > > + switch (fmt_info->NominalRange)
> > > > + {
> > > > + case DXVA2_NominalRange_Unknown:
> > > > + return AVCOL_RANGE_UNSPECIFIED;
> > > > + case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
> > > > + return AVCOL_RANGE_JPEG;
> > > > + case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
> > > > + return AVCOL_RANGE_MPEG;
> > > > + case DXVA2_NominalRange_48_208:
> > > > + // not an ffmpeg color range
> > > > + return AVCOL_RANGE_UNSPECIFIED;
> > > > +
> > > > + // values from MediaFoundation SDK (mfobjects.h)
> > > > + case 4: // MFNominalRange_64_127
> > > > + // not an ffmpeg color range
> > > > + return AVCOL_RANGE_UNSPECIFIED;
> > > > +
> > > > + default:
> > > > + return DXVA2_NominalRange_Unknown;
> > >
> > > The default return here should be an AVCOL_RANGE_ constant as well
> >
> > Absolutely, good catch!
> >
> > > > + }
> > > > +}
> > > > +
> > > > +static enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
> > > > +{
> > > > + enum AVColorSpace ret = AVCOL_SPC_UNSPECIFIED;
> > > > +
> > > > + switch (fmt_info->VideoTransferMatrix)
> > > > + {
> > > > + case DXVA2_VideoTransferMatrix_BT709:
> > > > + ret = AVCOL_SPC_BT709;
> > > > + break;
> > > > + case DXVA2_VideoTransferMatrix_BT601:
> > > > + ret = AVCOL_SPC_BT470BG;
> > > > + break;
> > > > + case DXVA2_VideoTransferMatrix_SMPTE240M:
> > > > + ret = AVCOL_SPC_SMPTE240M;
> > > > + break;
> > > > +
> > > > + // values from MediaFoundation SDK (mfobjects.h)
> > > > + case 4: // MFVideoTransferMatrix_BT2020_10
> > > > + case 5: // MFVideoTransferMatrix_BT2020_12
> > > > + if (fmt_info->VideoTransferFunction==12) // MFVideoTransFunc_2020_const
> > >
> > > Spaces around the == operator please.
> >
> > ok
> >
> > > > + ret = AVCOL_SPC_BT2020_CL;
> > > > + else
> > > > + ret = AVCOL_SPC_BT2020_NCL;
> > > > + break;
> > > > + }
> > > > +
> > > > + if (ret == AVCOL_SPC_UNSPECIFIED)
> > > > + {
> > > > + // if color space not known from transfer matrix,
> > > > + // fall back to using primaries to guess color space
> > >
> > > Guessing color space from primaries seems unusual, especially since
> > > the behavior of unknown is actually defined in MSDN docs. IMHO it
> > > would be better to forward information provided and not try to
> > > interpret it.
> >
> > You think i should remove this whole if (ret == AVCOL_SPC_UNSPECIFIED)
> > code block? I indeed see the docs comment about how
> > DXVA2_VideoTransferMatrix_Unknown should be interpreted (nothing we
> > can do here in this function).
>
> Thats what I would've suggested, but I don't know if you had that in
> there for any specific cases with capture hardware or the likes.
No, no specific case this fixes. I'll remove.
Thanks,
Dee
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2021-12-21 13:44 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-21 12:12 [FFmpeg-devel] [PATCH v6 00/12] dshow enhancements Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 01/12] avdevice/dshow: prevent NULL access Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 02/12] avdevice/dshow: implement option to use device video timestamps Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 03/12] avdevice/dshow: query graph and sample time only once Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 04/12] avdevice/dshow: handle unknown sample time Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 05/12] avdevice/dshow: set no-seek flags Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 06/12] avdevice/dshow: implement get_device_list Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 07/12] avdevice/dshow: list_devices: show media type(s) per device Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 08/12] avdevice: add info about media types(s) to AVDeviceInfo Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 09/12] avdevice/dshow: add media type info to get_device_list Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 10/12] fftools: provide media type info for devices Diederick Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 11/12] avdevice/dshow: discover source color range/space/etc Diederick Niehorster
2021-12-21 12:35 ` Hendrik Leppkes
2021-12-21 13:11 ` Diederick C. Niehorster
2021-12-21 13:35 ` Hendrik Leppkes
2021-12-21 13:44 ` Diederick C. Niehorster
2021-12-21 12:12 ` [FFmpeg-devel] [PATCH v6 12/12] avdevice/dshow: select format with extended color info Diederick Niehorster
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git