ffmpeg7.0 flv支持hdr

ffmpeg7.0 flv支持hdr

自从ffmpeg6.0应用enhance rtmp支持h265/av1的flv格式后,7.0迎来了flv的hdr能力。本文介绍ffmpeg7.0如何支持hdr in flv。

如果对enhance rtmp如何支持h265不了解,推荐详解Enhanced-RTMP支持H.265

1. enhance rtmp关于hdr

文档enhance-rtmp-v2.md中,metadata-frame章节规定相关支持HDR部分。

定义一个新的VideoPacketType.Metadata,其内容为AMF格式的metadata(AMF是一种简便的描述格式,非常节省内存),具体内部有HDR相关的colorInfo数据(每次hdr参数更新的时候,就发送该metadata)。

type ColorInfo = {
  colorConfig: {
    // number of bits used to record the color channels for each pixel
    bitDepth:                 number, // SHOULD be 8, 10 or 12

    //
    // colorPrimaries, transferCharacteristics and matrixCoefficients are defined 
    // in ISO/IEC 23091-4/ITU-T H.273. The values are an index into 
    // respective tables which are described in “Colour primaries”, 
    // "Transfer characteristics" and "Matrix coefficients" sections. 
    // It is RECOMMENDED to provide these values.
    //

    // indicates the chromaticity coordinates of the source color primaries
    colorPrimaries:           number, // enumeration [0-255]

    // opto-electronic transfer characteristic function (ex. PQ, HLG)
    transferCharacteristics:  number, // enumeration [0-255]

    // matrix coefficients used in deriving luma and chroma signals
    matrixCoefficients:       number, // enumeration [0-255]
  },

  hdrCll: {
    //
    // maximum value of the frame average light level
    // (in 1 cd/m2) of the entire playback sequence
    //
    maxFall:  number,     // [0.0001-10000]

    //
    // maximum light level of any single pixel (in 1 cd/m2)
    // of the entire playback sequence
    //
    maxCLL:   number,     // [0.0001-10000]
  },

  //
  // The hdrMdcv object defines mastering display (i.e., where
  // creative work is done during the mastering process) color volume (a.k.a., mdcv)
  // metadata which describes primaries, white point and min/max luminance. The
  // hdrMdcv object SHOULD be provided.
  //
  // Specification of the metadata along with its ranges adhere to the
  // ST 2086:2018 - SMPTE Standard (except for minLuminance see
  // comments below)
  //
  hdrMdcv: {
    //
    // Mastering display color volume (mdcv) xy Chromaticity Coordinates within CIE
    // 1931 color space.
    //
    // Values SHALL be specified with four decimal places. The x coordinate SHALL
    // be in the range [0.0001, 0.7400]. The y coordinate SHALL be 
    // in the range [0.0001, 0.8400].
    //
    redX:         number,
    redY:         number,
    greenX:       number,
    greenY:       number,
    blueX:        number,
    blueY:        number,
    whitePointX:  number,
    whitePointY:  number,

    //
    // max/min display luminance of the mastering display (in 1 cd/m2 ie. nits)
    //
    // note: ST 2086:2018 - SMPTE Standard specifies minimum display mastering
    // luminance in multiples of 0.0001 cd/m2.
    // 
    // For consistency we specify all values
    // in 1 cd/m2. Given that a hypothetical perfect screen has a peak brightness
    // of 10,000 nits and a black level of .0005 nits we do not need to
    // switch units to 0.0001 cd/m2 to increase resolution on the lower end of the
    // minLuminance property. The ranges (in nits) mentioned below suffice
    // the theoretical limit for Mastering Reference Displays and adhere to the
    // SMPTE ST 2084 standard (a.k.a., PQ) which is capable of representing full gamut
    // of luminance level.
    //
    maxLuminance: number,     // [5-10000]
    minLuminance: number,     // [0.0001-5]
  },
}

2. flv mux

在libavformat/flvenc.c中,新增flv_write_metadata_packet函数,用于添加metadata。
flv的数据结构:


typedef struct FLVContext {
    .....
    int metadata_pkt_written;//0: 还未写过,需要写;1: 写过了,不需要写。
} FLVContext;

在函数flv_write_metadata_packet中实现,见注释:

static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts) {
    FLVContext *flv = s->priv_data;

    //不需要写入,就返回;可以通过设置这个标志变量来使能/去使能更新写metadata
    if (flv->metadata_pkt_written)
        return;
    //支持h265, av1, vp9
    if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
        ......
        //写入tag头,标识其为视频
        avio_w8(pb, FLV_TAG_TYPE_VIDEO); //write video tag type
        metadata_size_pos = avio_tell(pb);
        avio_wb24(pb, 0 + flags_size);
        put_timestamp(pb, ts); //ts = pkt->dts, gen
        avio_wb24(pb, flv->reserved);

        //根据enhance rtmp标志,写入FLV_IS_EX_HEADER标识,和fourCC的字段(hvc1 or av01 or vp09)
        if (par->codec_id == AV_CODEC_ID_HEVC) {
            avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeMetadata| FLV_FRAME_VIDEO_INFO_CMD); // ExVideoTagHeader mode with PacketTypeMetadata
            avio_write(pb, "hvc1", 4);
        } else if (par->codec_id == AV_CODEC_ID_AV1 || par->codec_id == AV_CODEC_ID_VP9) {
            avio_w8(pb, FLV_IS_EX_HEADER | PacketTypeMetadata| FLV_FRAME_VIDEO_INFO_CMD);
            avio_write(pb, par->codec_id == AV_CODEC_ID_AV1 ? "av01" : "vp09", 4);
        }
        //下面为写入AMF格式的hdr相关的colorInfo数据
        avio_w8(pb, AMF_DATA_TYPE_STRING);
        put_amf_string(pb, "colorInfo");

        avio_w8(pb, AMF_DATA_TYPE_OBJECT);

        put_amf_string(pb, "colorConfig");  // colorConfig

        avio_w8(pb, AMF_DATA_TYPE_OBJECT);

        if (par->color_trc != AVCOL_TRC_UNSPECIFIED &&
            par->color_trc < AVCOL_TRC_NB) {
            put_amf_string(pb, "transferCharacteristics");  // color_trc
            put_amf_double(pb, par->color_trc);
        }

        if (par->color_space != AVCOL_SPC_UNSPECIFIED &&
            par->color_space < AVCOL_SPC_NB) {
            put_amf_string(pb, "matrixCoefficients"); // colorspace
            put_amf_double(pb, par->color_space);
        }

        if (par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
            par->color_primaries < AVCOL_PRI_NB) {
            put_amf_string(pb, "colorPrimaries"); // color_primaries
            put_amf_double(pb, par->color_primaries);
        }

        put_amf_string(pb, "");
        avio_w8(pb, AMF_END_OF_OBJECT);

        if (lightMetadata) {
            put_amf_string(pb, "hdrCll");
            avio_w8(pb, AMF_DATA_TYPE_OBJECT);

            put_amf_string(pb, "maxFall");
            put_amf_double(pb, lightMetadata->MaxFALL);

            put_amf_string(pb, "maxCLL");
            put_amf_double(pb, lightMetadata->MaxCLL);

            put_amf_string(pb, "");
            avio_w8(pb, AMF_END_OF_OBJECT);
        }

        if (displayMetadata && (displayMetadata->has_primaries || displayMetadata->has_luminance)) {
            put_amf_string(pb, "hdrMdcv");
            avio_w8(pb, AMF_DATA_TYPE_OBJECT);
            if (displayMetadata->has_primaries) {
                put_amf_string(pb, "redX");
                put_amf_double(pb, av_q2d(displayMetadata->display_primaries[0][0]));

                put_amf_string(pb, "redY");
                put_amf_double(pb, av_q2d(displayMetadata->display_primaries[0][1]));

                put_amf_string(pb, "greenX");
                put_amf_double(pb, av_q2d(displayMetadata->display_primaries[1][0]));

                put_amf_string(pb, "greenY");
                put_amf_double(pb, av_q2d(displayMetadata->display_primaries[1][1]));

                put_amf_string(pb, "blueX");
                put_amf_double(pb, av_q2d(displayMetadata->display_primaries[2][0]));

                put_amf_string(pb, "blueY");
                put_amf_double(pb, av_q2d(displayMetadata->display_primaries[2][1]));

                put_amf_string(pb, "whitePointX");
                put_amf_double(pb, av_q2d(displayMetadata->white_point[0]));

                put_amf_string(pb, "whitePointY");
                put_amf_double(pb, av_q2d(displayMetadata->white_point[1]));
            }
            if (displayMetadata->has_luminance) {
                put_amf_string(pb, "maxLuminance");
                put_amf_double(pb, av_q2d(displayMetadata->max_luminance));

                put_amf_string(pb, "minLuminance");
                put_amf_double(pb, av_q2d(displayMetadata->min_luminance));
            }
            put_amf_string(pb, "");
            avio_w8(pb, AMF_END_OF_OBJECT);
        }
        put_amf_string(pb, "");
        avio_w8(pb, AMF_END_OF_OBJECT);

        flv->metadata_pkt_written = 1;//标识写过了
    }
}

其中HDR的数据来源为AVCodecParameters *par数据结构中的内容:

typedef struct AVCodecParameters {
    ....
    /**
     * Video only. Additional colorspace characteristics.
     */
    enum AVColorRange                  color_range;
    enum AVColorPrimaries              color_primaries;
    enum AVColorTransferCharacteristic color_trc;
    enum AVColorSpace                  color_space;
    enum AVChromaLocation              chroma_location;

    /*
     * 类型: AV_PKT_DATA_CONTENT_LIGHT_LEVEL, 数据: AVContentLightMetadata* lightMetadata
     * 类型: AV_PKT_DATA_MASTERING_DISPLAY_METADATA, 数据: AVMasteringDisplayMetadata *displayMetadata
    */
    AVPacketSideData *coded_side_data;
    ....
}

3. flv demux

解析函数在libavformat/flvdec.c文件中,函数amf_parse_object中。

static int amf_parse_object(AVFormatContext *s, AVStream *astream,
                            AVStream *vstream, const char *key,
                            int64_t max_pos, int depth)
{
    FLVMetaVideoColor *meta_video_color = flv->metaVideoColor;
    ......
    
    if (meta_video_color) {
        if (amf_type == AMF_DATA_TYPE_NUMBER ||
            amf_type == AMF_DATA_TYPE_BOOL) {
            if (!strcmp(key, "colorPrimaries")) {
                meta_video_color->primaries = num_val;
            } else if (!strcmp(key, "transferCharacteristics")) {
                meta_video_color->transfer_characteristics = num_val;
            } else if (!strcmp(key, "matrixCoefficients")) {
                meta_video_color->matrix_coefficients = num_val;
            } else if (!strcmp(key, "maxFall")) {
                meta_video_color->max_fall = num_val;
            } else if (!strcmp(key, "maxCLL")) {
                meta_video_color->max_cll = num_val;
            } else if (!strcmp(key, "redX")) {
                meta_video_color->mastering_meta.r_x = num_val;
            } else if (!strcmp(key, "redY")) {
                meta_video_color->mastering_meta.r_y = num_val;
            } else if (!strcmp(key, "greenX")) {
                meta_video_color->mastering_meta.g_x = num_val;
            } else if (!strcmp(key, "greenY")) {
                meta_video_color->mastering_meta.g_y = num_val;
            } else if (!strcmp(key, "blueX")) {
                meta_video_color->mastering_meta.b_x = num_val;
            } else if (!strcmp(key, "blueY")) {
                meta_video_color->mastering_meta.b_y = num_val;
            } else if (!strcmp(key, "whitePointX")) {
                meta_video_color->mastering_meta.white_x = num_val;
            } else if (!strcmp(key, "whitePointY")) {
                meta_video_color->mastering_meta.white_y = num_val;
            } else if (!strcmp(key, "maxLuminance")) {
                meta_video_color->mastering_meta.max_luminance = num_val;
            } else if (!strcmp(key, "minLuminance")) {
                meta_video_color->mastering_meta.min_luminance = num_val;
            }
        }
    }
    ......
}

4. 感谢Zhu Pengfei的提交

Author: Zhu Pengfei <411294962@qq.com>
Date:   Mon Mar 4 21:52:04 2024 +0800

    avformat/flvenc: support enhanced flv PacketTypeMetadata
    
    Signed-off-by: Zhu Pengfei <411294962@qq.com>
    Signed-off-by: Steven Liu <lq@chinaffmpeg.org>
``

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/596391.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

# 怎么关闭 win10 系统中自带的【文件预览】功能?关闭WIN10【文件预览】功能的方法

怎么关闭 win10 系统中自带的【文件预览】功能&#xff1f;关闭WIN10【文件预览】功能的方法 win10 系统中自带的【文件预览】功能&#xff0c;默认是开启状态的&#xff0c;如果需要关闭它&#xff0c;一步搞定。 1、打开电脑文件浏览器&#xff0c;随便进入有文件的一个文件…

《QT实用小工具·五十五》带有标签、下划线的Material Design风格输入框

1、概述 源码放在文章末尾 该项目实现了一个带有标签动画、焦点动画、正确提示、错误警告的单行输入框控件。下面是demo演示&#xff1a; 项目部分代码如下所示&#xff1a; #ifndef LABELEDEDIT_H #define LABELEDEDIT_H#include <QObject> #include <QWidget>…

截取字符串的3种方法

一、截取字符串的实现 在C语言中&#xff0c;没有直接截取字符串的库函数&#xff0c;但是咱们可以借助其他函数实现这个功能。 1&#xff0e;最简单的方法 如果只是直接输出一个字符串的子串&#xff0c;只需要一个简单的printf函数即可。 #include <stdio.h> int m…

寒武纪及瑞芯微平台调用加速调研

文章目录 1 寒武纪加速平台简介1.1 加速平台简介1.1.1 算力硬件1.1.2 配套软件 1.2 部署流程简介1.3 部署环境搭建1.3.1 安装驱动1.3.2 安装CNToolKit1.3.3 配置模型移植开发环境 1.4 模型部署1.4.1 模型转换旧文件格式1.4.2 量化模型生成1.4.3 验证结果1.4.4 离线模型生成 1 寒…

LIUNX系统编程:进程池的实现

1.什么是进程池 每一个可执行程序&#xff0c;在被执行前都要转化为进程&#xff0c;操作系统都要为其创建PCB&#xff0c;地址空间&#xff0c;页表&#xff0c;构建映射关系&#xff0c;进程池就是创建进程时&#xff0c;创建很多个进程&#xff0c;如果要执行程序&#xff…

HTML_CSS学习:背景、鼠标相关属性

一、背景相关属性 相关代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>背景相关属性</title><style>body{background-color: greenyellow;}div{width: 400px;height: …

C语言-分支和循环语句、函数、数组、操作符、指针、结构体

目录 一、scanf和getchar二、产生随机数函数三、辗转相除法求最大公约数四、函数的参数4.1 实际参数&#xff08;实参&#xff09;4.2 形式参数&#xff08;形参&#xff09;4.3 内存分配 五、函数的调用5.1 传值调用5.1 传址调用 六、函数的声明和定义6.1 函数的声明6.2 函数的…

Day62:单调栈 LeedCode503. 下一个更大元素 II 42. 接雨水

503. 下一个更大元素 II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更大的数…

服务运维问题

2024-05-01&#xff08;docker 部署的 jar包自动关闭&#xff09; 查询运行情况&#xff1a;处于退出状态 docker ps -a 查询日志&#xff1a;看不出问题 docker logs -f --tail1000 demo-java 查询关于java服务日志&#xff1a;Out of memory: Kill process 16236 (java) …

智能BI产品设计

BI概念 目录 BI概念 一&#xff1a;与BI相关的几个重要概念 二&#xff1a;数据仓库 VS 数据库 BI架构 一&#xff1a;数据分析通用流程 二&#xff1a;BI平台基本架构 可视化图形 一&#xff1a;如何选择可视化图形 二&#xff1a;数据展示形式 三&#xff1a;数据…

ComfyUI 基础教程(十三):ComfyUI-Impact-Pack 面部修复

SD的WebUI 中的面部修复神器 ADetailer,无法在ComfyUI 中使用。那么如何在ComfyUI中进行面部处理呢?ComfyUI 中也有几个面部修复功能,比如ComfyUI Impact Pack(FaceDetailer),以及换脸插件Reactor和IPAdapter。 ComfyUI-Impact-Pack 是一个功能强大的插件,专为 ComfyUI …

GiantPandaCV | FasterTransformer Decoding 源码分析(三)-LayerNorm介绍

本文来源公众号“GiantPandaCV”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;FasterTransformer Decoding 源码分析(三)-LayerNorm介绍 作者丨进击的Killua 来源丨https://zhuanlan.zhihu.com/p/669440844 编辑丨GiantPandaC…

LLVM的ThinLTO编译优化技术在Postgresql中的应用

部分内容引用&#xff1a;https://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html LTO是什么&#xff1f; 链接时优化&#xff08;Link-time optimization&#xff0c;简称LTO&#xff09;是编译器在链接时对程序进行的一种优化。它适用于以文件为单位编译…

考研数学|基础跟张宇,强化直接1000题还是先做660?

跟宇哥用1000题的&#xff0c;我愿称之为卷王之王&#xff01;660对基础阶段是绝佳的查漏补缺&#xff0c;必做&#xff01; 自我介绍一下&#xff1a;我21年一战数学83&#xff0c;总分没过线&#xff0c;22年二战143&#xff0c;逆袭上岸211&#xff01;660是我的心头好&…

奶爸预备 |《伯克毕生发展心理学.从0岁到青少年》 / (美) 劳拉·E. 伯克著——读书笔记

目录 引出第一篇 人的发展理论与研究第1章 历史、理论和研究方法 第二篇 发展的基础第2章 生物基础与环境基础第3章 孕期发育、分娩及新生儿 第三篇 婴儿期和学步期&#xff1a;0~2岁第4章 婴儿期和学步期的身体发育第5章 婴儿期和学步期的认知发展第6章 婴儿期和学步期的情绪与…

华为OD机试【垃圾信息拦截】(java)(100分)

1、题目描述 大众对垃圾短信深恶痛绝&#xff0c;希望能对垃圾短信发送者进行识别&#xff0c;为此&#xff0c;很多软件增加 了垃圾短信识别机制。经分析&#xff0c;发现正常用户的短信通常具备交互性&#xff0c;而垃圾短信往 往都是大量单向的短信&#xff0c;按照如下规则…

vue3中标签的ref属性

组合API-ref属性 在vue2.x中&#xff0c;可以通过给元素添加refxxx属性&#xff0c;然后在代码中通过this.$refs.xxx获取到对应的元素 然而在vue3中时没有$refs这个东西的&#xff0c;因此vue3中通过ref属性获取元素就不能按照vue2的方式来获取。 目标&#xff1a;掌握使用re…

Python项目实战,用Python实现2048游戏

目录 写在前言项目介绍项目思路环境搭建项目实现初始化Python类初始化游戏窗口定义游戏棋盘和方块移动和合并游戏主循环 进一步探索 写在前言 hello&#xff0c;大家好&#xff0c;我是一点&#xff0c;专注于Python编程&#xff0c;如果你也对感Python感兴趣&#xff0c;欢迎…

基于JSP的酒店客房管理系统(三)

目录 第四章 系统各模块的实现 4.1客房管理系统首页的实现 4.1.1 客房管理系统首页概述 4.2客房管理系统前台的实现 4.2.1 客房管理系统前台概述 4.2.2 客房管理系统前台实现过程 4.2.3 预定客房信息及客房信息的查询 4.3客房管理系统后台的实现 4.3.1 客房管理系统后…

搜索算法系列之四(斐波那契)

以下算法被验证过&#xff0c;如有什么问题或有补充的欢迎留言。 前言 斐波那契数列&#xff0c;又称黄金分割数列&#xff0c;是由意大利数学家&#xff08;Leonardo Fibonacci&#xff09;在1202年提出的。这个数列的递推关系是F(0)1&#xff0c;F(1)1&#xff0c;F(n)F(n-…
最新文章