@@ -29,6 +29,7 @@
#include "libavcodec/raw.h"
#include "objidl.h"
#include "shlwapi.h"
+#include "dxva.h"
static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
@@ -54,6 +55,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(DXVA_ExtendedFormat* fmt_info)
+{
+ switch (fmt_info->NominalRange)
+ {
+ case DXVA_NominalRange_Unknown:
+ return AVCOL_RANGE_UNSPECIFIED;
+ case DXVA_NominalRange_Normal: // equal to DXVA_NominalRange_0_255
+ return AVCOL_RANGE_JPEG;
+ case DXVA_NominalRange_Wide: // equal to DXVA_NominalRange_16_235
+ return AVCOL_RANGE_MPEG;
+ case DXVA_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 DXVA_NominalRange_Unknown;
+ }
+}
+
+static enum AVColorSpace dshow_color_space(DXVA_ExtendedFormat* fmt_info)
+{
+ enum AVColorSpace ret = AVCOL_SPC_UNSPECIFIED;
+
+ switch (fmt_info->VideoTransferMatrix)
+ {
+ case DXVA_VideoTransferMatrix_BT709:
+ ret = AVCOL_SPC_BT709;
+ break;
+ case DXVA_VideoTransferMatrix_BT601:
+ ret = AVCOL_SPC_BT470BG;
+ break;
+ case DXVA_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 DXVA_VideoPrimaries_BT709:
+ ret = AVCOL_SPC_BT709;
+ break;
+ case DXVA_VideoPrimaries_BT470_2_SysM:
+ ret = AVCOL_SPC_FCC;
+ break;
+ case DXVA_VideoPrimaries_BT470_2_SysBG:
+ case DXVA_VideoPrimaries_EBU3213: // this is PAL
+ ret = AVCOL_SPC_BT470BG;
+ break;
+ case DXVA_VideoPrimaries_SMPTE170M:
+ case DXVA_VideoPrimaries_SMPTE_C:
+ ret = AVCOL_SPC_SMPTE170M;
+ break;
+ case DXVA_VideoPrimaries_SMPTE240M:
+ ret = AVCOL_SPC_SMPTE240M;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static enum AVColorPrimaries dshow_color_primaries(DXVA_ExtendedFormat* fmt_info)
+{
+ switch (fmt_info->VideoPrimaries)
+ {
+ case DXVA_VideoPrimaries_Unknown:
+ return AVCOL_PRI_UNSPECIFIED;
+ case DXVA_VideoPrimaries_reserved:
+ return AVCOL_PRI_RESERVED;
+ case DXVA_VideoPrimaries_BT709:
+ return AVCOL_PRI_BT709;
+ case DXVA_VideoPrimaries_BT470_2_SysM:
+ return AVCOL_PRI_BT470M;
+ case DXVA_VideoPrimaries_BT470_2_SysBG:
+ case DXVA_VideoPrimaries_EBU3213: // this is PAL
+ return AVCOL_PRI_BT470BG;
+ case DXVA_VideoPrimaries_SMPTE170M:
+ case DXVA_VideoPrimaries_SMPTE_C:
+ return AVCOL_PRI_SMPTE170M;
+ case DXVA_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(DXVA_ExtendedFormat* fmt_info)
+{
+ switch (fmt_info->VideoTransferFunction)
+ {
+ case DXVA_VideoTransFunc_Unknown:
+ return AVCOL_TRC_UNSPECIFIED;
+ case DXVA_VideoTransFunc_10:
+ return AVCOL_TRC_LINEAR;
+ case DXVA_VideoTransFunc_18:
+ // not an FFmpeg transfer characteristic
+ return AVCOL_TRC_UNSPECIFIED;
+ case DXVA_VideoTransFunc_20:
+ // not an FFmpeg transfer characteristic
+ return AVCOL_TRC_UNSPECIFIED;
+ case DXVA_VideoTransFunc_22:
+ return AVCOL_TRC_GAMMA22;
+ case DXVA_VideoTransFunc_22_709:
+ return AVCOL_TRC_BT709;
+ case DXVA_VideoTransFunc_22_240M:
+ return AVCOL_TRC_SMPTE240M;
+ case DXVA_VideoTransFunc_22_8bit_sRGB:
+ return AVCOL_TRC_IEC61966_2_1;
+ case DXVA_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(DXVA_ExtendedFormat* fmt_info)
+{
+ if (fmt_info->VideoChromaSubsampling == DXVA_VideoChromaSubsampling_Cosited) // that is: (DXVA_VideoChromaSubsampling_Horizontally_Cosited | DXVA_VideoChromaSubsampling_Vertically_Cosited | DXVA_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
+ return AVCHROMA_LOC_TOPLEFT;
+ else if (fmt_info->VideoChromaSubsampling == DXVA_VideoChromaSubsampling_MPEG1) // that is: DXVA_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
+ return AVCHROMA_LOC_CENTER;
+ else if (fmt_info->VideoChromaSubsampling == DXVA_VideoChromaSubsampling_MPEG2) // that is: (DXVA_VideoChromaSubsampling_Horizontally_Cosited | DXVA_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
+ return AVCHROMA_LOC_LEFT;
+ else if (fmt_info->VideoChromaSubsampling == DXVA_VideoChromaSubsampling_DV_PAL)// that is: (DXVA_VideoChromaSubsampling_Horizontally_Cosited | DXVA_VideoChromaSubsampling_Vertically_Cosited)
+ return AVCHROMA_LOC_TOPLEFT;
+ else
+ // unknown
+ return AVCHROMA_LOC_UNSPECIFIED;
+}
+
static int
dshow_read_close(AVFormatContext *s)
{
@@ -522,6 +709,7 @@ dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
BITMAPINFOHEADER *bih;
int64_t *fr;
+ DXVA_ExtendedFormat *extended_format_info = NULL;
const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
#if DSHOWDEBUG
ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
@@ -534,6 +722,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 = (DXVA_ExtendedFormat*)&v->dwControlFlags;
} else {
goto next;
}
@@ -550,11 +740,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) {
@@ -1233,6 +1452,7 @@ dshow_add_device(AVFormatContext *avctx,
if (devtype == VideoDevice) {
BITMAPINFOHEADER *bih = NULL;
AVRational time_base;
+ DXVA_ExtendedFormat* extended_format_info = NULL;
if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
VIDEOINFOHEADER *v = (void *) type.pbFormat;
@@ -1242,6 +1462,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 = (DXVA_ExtendedFormat*)&v->dwControlFlags;
}
if (!bih) {
av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
@@ -1260,6 +1482,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);
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. Signed-off-by: Diederick Niehorster <dcnieho@gmail.com> Co-authored-by: Valerii Zapodovnikov <val.zapod.vz@gmail.com> --- libavdevice/dshow.c | 231 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 1 deletion(-)