[FFmpeg-devel] [PATCH] avdevice/decklink: new options 'list_pixelformats' and 'pixelformat_code' to allow pixelformat selection by code

Marton Balint cus at passwd.hu
Sun Sep 3 02:22:04 EEST 2017



On Fri, 1 Sep 2017, Gildas Fargeas wrote:

> I removed the option bm_v210 as it is replaced with a more complete pixel format selection option.

Well, you can't do that, you can only deprecate an option and keep 
compatibility for some time. E.g. if bm_v210 is set then force pixel 
format to 10bit.

> The main objective for this patch was to enable RGB capture.
> The pixel format codes are directly copied from the Decklink API.
>
> Signed-off-by: Gildas Fargeas <fargeas.gildas at gmail.com>
> ---
> libavdevice/decklink_common.cpp | 34 ++++++++++++++++++++++++--
> libavdevice/decklink_common.h   | 17 +++++++++++++
> libavdevice/decklink_common_c.h |  3 ++-
> libavdevice/decklink_dec.cpp    | 53 ++++++++++++++++++++++++++++++++++-------
> libavdevice/decklink_dec_c.c    |  3 ++-
> 5 files changed, 98 insertions(+), 12 deletions(-)
>
> diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp
> index cbb591ce64..6c3d2cc2c1 100644
> --- a/libavdevice/decklink_common.cpp
> +++ b/libavdevice/decklink_common.cpp
> @@ -203,6 +203,18 @@ int ff_decklink_set_format(AVFormatContext *avctx,
>     if (cctx->format_code)
>         memcpy(format_buf, cctx->format_code, FFMIN(strlen(cctx->format_code), sizeof(format_buf)));
>     BMDDisplayMode target_mode = (BMDDisplayMode)AV_RB32(format_buf);
> +
> +    char pixel_buf[] = "    ";
> +    ctx->bmd_pixel= bmdFormat8BitYUV;
> +    if (cctx->pixel_code) {
> +        if (!strcmp(cctx->pixel_code, "ARGB")) {

Why the special handling?

> +            ctx->bmd_pixel = bmdFormat8BitARGB;
> +        } else {
> +            memcpy(pixel_buf, cctx->pixel_code, FFMIN(strlen(cctx->pixel_code), sizeof(pixel_buf)));
> +            ctx->bmd_pixel = (BMDPixelFormat)AV_RB32(pixel_buf);
> +        }
> +    }
> +
>     AVRational target_tb = av_make_q(tb_num, tb_den);
>     ctx->bmd_mode = bmdModeUnknown;
>     while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
> @@ -241,12 +253,12 @@ int ff_decklink_set_format(AVFormatContext *avctx,
>     if (ctx->bmd_mode == bmdModeUnknown)
>         return -1;
>     if (direction == DIRECTION_IN) {
> -        if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
> +        if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, ctx->bmd_pixel,
>                                            bmdVideoOutputFlagDefault,
>                                            &support, NULL) != S_OK)
>             return -1;
>     } else {
> -        if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
> +        if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, ctx->bmd_pixel,
>                                            bmdVideoOutputFlagDefault,
>                                            &support, NULL) != S_OK)

You are not adding output support, so this change seems unrelated.

>         return -1;
> @@ -332,6 +344,24 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct
>     return 0;
> }
> 
> +
> +int ff_decklink_list_pixelformats(AVFormatContext *avctx)
> +{
> +	unsigned i = 0;
> +
> +
> +    av_log(avctx, AV_LOG_INFO, "List of pixel formats for '%s':\n\tformat_code",
> +               avctx->filename);
> +    for (i=0; i < sizeof(decklink_pixelformat)/sizeof(char*);i++) {
> +        av_log(avctx, AV_LOG_INFO, "\n\t%.4s",
> +                decklink_pixelformat[i]);
> +    }
> +    av_log(avctx, AV_LOG_INFO, "\n");
> +
> +    return 0;
> +}

If this is a fixed list, then remove this function, and add the supported 
types to the documentation. Also it is unnecessary to list pixel formats 
which are only supported by DeckLink but not ffmpeg, the user can't do 
anything with it.

> +
> +
> void ff_decklink_cleanup(AVFormatContext *avctx)
> {
>     struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h
> index 749eb0f8b8..964781ff72 100644
> --- a/libavdevice/decklink_common.h
> +++ b/libavdevice/decklink_common.h
> @@ -56,6 +56,7 @@ struct decklink_ctx {
>     BMDTimeValue bmd_tb_den;
>     BMDTimeValue bmd_tb_num;
>     BMDDisplayMode bmd_mode;
> +    BMDPixelFormat bmd_pixel;
>     BMDVideoConnection video_input;
>     BMDAudioConnection audio_input;
>     int bmd_width;
> @@ -82,6 +83,7 @@ struct decklink_ctx {
>     /* Options */
>     int list_devices;
>     int list_formats;
> +    int list_pixelformats;
>     int64_t teletext_lines;
>     double preroll;
>     int duplex_mode;
> @@ -132,11 +134,26 @@ static const BMDVideoConnection decklink_video_connection_map[] = {
>     bmdVideoConnectionSVideo,
> };
> 
> +static const char * const decklink_pixelformat[] = {
> +	"2vuy",     /* bmdFormat8BitYUV     */
> +	"v210",     /* bmdFormat10BitYUV    */
> +	"ARGB",     /* bmdFormat8BitARGB    */
> +	"BGRA",     /* bmdFormat8BitBGRA    */
> +	"r210",     /* bmdFormat10BitRGB    */
> +	"R12B",     /* bmdFormat12BitRGB    */
> +	"R12L",     /* bmdFormat12BitRGBLE  */
> +	"R10l",     /* bmdFormat10BitRGBXLE */
> +	"R10b",     /* bmdFormat10BitRGBX   */
> +	"hev1",     /* bmdFormatH265        */
> +	"AVdh"      /* bmdFormatDNxHR       */
> +};
> +
> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName);
> int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0);
> int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num);
> int ff_decklink_list_devices(AVFormatContext *avctx);
> int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT);
> +int ff_decklink_list_pixelformats(AVFormatContext *avctx);
> void ff_decklink_cleanup(AVFormatContext *avctx);
> int ff_decklink_init_device(AVFormatContext *avctx, const char* name);
> 
> diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
> index e263480474..d2f993310f 100644
> --- a/libavdevice/decklink_common_c.h
> +++ b/libavdevice/decklink_common_c.h
> @@ -38,9 +38,9 @@ struct decklink_cctx {
>     /* Options */
>     int list_devices;
>     int list_formats;
> +    int list_pixelformats;
>     int64_t teletext_lines;
>     double preroll;
> -    int v210;
>     int audio_channels;
>     int duplex_mode;
>     DecklinkPtsSource audio_pts_source;
> @@ -49,6 +49,7 @@ struct decklink_cctx {
>     int video_input;
>     int draw_bars;
>     char *format_code;
> +    char *pixel_code;
>     int64_t queue_size;
> };
> 
> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
> index c271ff3639..c9418828ee 100644
> --- a/libavdevice/decklink_dec.cpp
> +++ b/libavdevice/decklink_dec.cpp
> @@ -622,6 +622,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
>         return AVERROR(ENOMEM);
>     ctx->list_devices = cctx->list_devices;
>     ctx->list_formats = cctx->list_formats;
> +    ctx->list_pixelformats = cctx->list_pixelformats;
>     ctx->teletext_lines = cctx->teletext_lines;
>     ctx->preroll      = cctx->preroll;
>     ctx->duplex_mode  = cctx->duplex_mode;
> @@ -677,11 +678,17 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
>         ret = AVERROR_EXIT;
>         goto error;
>     }
> +    /* List supported pixel formats. */
> +    if (ctx->list_pixelformats) {
> +        ff_decklink_list_pixelformats(avctx);
> +        ret = AVERROR_EXIT;
> +        goto error;
> +    }
>
>     if (mode_num > 0 || cctx->format_code) {
>         if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) {
> -            av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n",
> -                mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname);
> +            av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d, format code %s or pixel format %s for %s\n",
> +                mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", (cctx->pixel_code) ? cctx->pixel_code : "(unset)", fname);
>             ret = AVERROR(EIO);
>             goto error;
>         }
> @@ -723,15 +730,45 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
>     st->time_base.num      = ctx->bmd_tb_num;
>     av_stream_set_r_frame_rate(st, av_make_q(st->time_base.den, st->time_base.num));
> 
> -    if (cctx->v210) {
> +    switch(ctx->bmd_pixel) {
> +    case bmdFormat8BitYUV:
> +        st->codecpar->codec_id    = AV_CODEC_ID_RAWVIDEO;
> +        st->codecpar->format      = AV_PIX_FMT_UYVY422;
> +        st->codecpar->bit_rate    = av_rescale(ctx->bmd_width * ctx->bmd_height * 16, st->time_base.den, st->time_base.num);
> +        break;
> +    case bmdFormat10BitYUV:
>         st->codecpar->codec_id    = AV_CODEC_ID_V210;
>         st->codecpar->codec_tag   = MKTAG('V', '2', '1', '0');
> +        st->codecpar->bits_per_coded_sample = 10;
>         st->codecpar->bit_rate    = av_rescale(ctx->bmd_width * ctx->bmd_height * 64, st->time_base.den, st->time_base.num * 3);
> -    } else {
> +
> +        break;
> +    case bmdFormat8BitARGB:
>         st->codecpar->codec_id    = AV_CODEC_ID_RAWVIDEO;
> -        st->codecpar->format      = AV_PIX_FMT_UYVY422;
> -        st->codecpar->codec_tag   = MKTAG('U', 'Y', 'V', 'Y');
> -        st->codecpar->bit_rate    = av_rescale(ctx->bmd_width * ctx->bmd_height * 16, st->time_base.den, st->time_base.num);
> +        st->codecpar->codec_tag   = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format);
> +        st->codecpar->format    = AV_PIX_FMT_ARGB;
> +        break;
> +    case bmdFormat8BitBGRA:
> +        st->codecpar->codec_id    = AV_CODEC_ID_RAWVIDEO;
> +        st->codecpar->codec_tag   = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format);
> +        st->codecpar->format    = AV_PIX_FMT_BGRA;
> +        break;
> +    case bmdFormat10BitRGB:
> +        st->codecpar->codec_id    = AV_CODEC_ID_R210;
> +        st->codecpar->format    = AV_PIX_FMT_RGB48LE;
> +        st->codecpar->codec_tag   = MKTAG('R', '2', '1', '0');
> +        st->codecpar->bits_per_coded_sample = 10;
> +        break;
> +    case bmdFormat12BitRGB:
> +    case bmdFormat12BitRGBLE:
> +    case bmdFormat10BitRGBXLE:
> +    case bmdFormat10BitRGBX:
> +    case bmdFormatH265:
> +    case bmdFormatDNxHR:

Uneeded to specify these.

> +    default:
> +        av_log(avctx, AV_LOG_ERROR, "Pixel Format %s not supported\n", cctx->pixel_code);
> +        ret = AVERROR(ENOMEM);

AVERROR(EINVAL).

> +        goto error;
>     }
>
>     switch (ctx->bmd_field_dominance) {
> @@ -776,7 +813,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx)
>     }
>
>     result = ctx->dli->EnableVideoInput(ctx->bmd_mode,
> -                                        cctx->v210 ? bmdFormat10BitYUV : bmdFormat8BitYUV,
> +                                        ctx->bmd_pixel,
>                                         bmdVideoInputFlagDefault);
>
>     if (result != S_OK) {
> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
> index e2118a619c..9b53d95e96 100644
> --- a/libavdevice/decklink_dec_c.c
> +++ b/libavdevice/decklink_dec_c.c
> @@ -32,8 +32,9 @@
> static const AVOption options[] = {
>     { "list_devices", "list available devices"  , OFFSET(list_devices), AV_OPT_TYPE_INT   , { .i64 = 0   }, 0, 1, DEC },
>     { "list_formats", "list supported formats"  , OFFSET(list_formats), AV_OPT_TYPE_INT   , { .i64 = 0   }, 0, 1, DEC },
> +    { "list_pixelformats", "list supported pixel formats"  , OFFSET(list_pixelformats), AV_OPT_TYPE_INT   , { .i64 = 0   }, 0, 1, DEC },

Uneeded.

>     { "format_code",  "set format by fourcc"    , OFFSET(format_code),  AV_OPT_TYPE_STRING, { .str = NULL}, 0, 0, DEC },
> -    { "bm_v210",      "v210 10 bit per channel" , OFFSET(v210),         AV_OPT_TYPE_INT   , { .i64 = 0   }, 0, 1, DEC },
> +    { "pixelformat_code",  "set pixel format according" , OFFSET(pixel_code),  AV_OPT_TYPE_STRING, { .str = NULL}, 0, 0, DEC },

Since this might be a codec as well later (h264/hevc), maybe better to 
call this something else, like 'raw_format'?

Also I'd rather use option name constants for the various formats, the 
decklink pixel format fourccs are sometimes ugly. The value of the named 
constant can be the DeckLink pixel format fourcc.

>     { "teletext_lines", "teletext lines bitmask", OFFSET(teletext_lines), AV_OPT_TYPE_INT64, { .i64 = 0   }, 0, 0x7ffffffffLL, DEC, "teletext_lines"},
>     { "standard",     NULL,                                           0,  AV_OPT_TYPE_CONST, { .i64 = 0x7fff9fffeLL}, 0, 0,    DEC, "teletext_lines"},
>     { "all",          NULL,                                           0,  AV_OPT_TYPE_CONST, { .i64 = 0x7ffffffffLL}, 0, 0,    DEC, "teletext_lines"},
> --

Regards,
Marton


More information about the ffmpeg-devel mailing list