* Re: [FFmpeg-devel] [PATCH 2/2] avformat/flvdec: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
@ 2023-12-13 13:41 ` 朱鹏飞 via ffmpeg-devel
2023-12-17 16:24 ` [FFmpeg-devel] [PATCH v2 1/2] avformat/flvenc: " zhupengfei via ffmpeg-devel
` (7 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: 朱鹏飞 via ffmpeg-devel @ 2023-12-13 13:41 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Cc: 朱鹏飞, jamrial
> 2023年12月5日 05:32,James Almer <jamrial@gmail.com> 写道:
>
> On 11/15/2023 11:40 AM, zhupengfei via ffmpeg-devel wrote:
>> From: Zhu Pengfei <411294962@qq.com>
>> Signed-off-by: Zhu Pengfei <411294962@qq.com>
>> ---
>> libavformat/flvdec.c | 171 ++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 170 insertions(+), 1 deletion(-)
>> diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
>> index e25b5bd163..46bb0825ca 100644
>> --- a/libavformat/flvdec.c
>> +++ b/libavformat/flvdec.c
>> @@ -34,6 +34,7 @@
>> #include "libavutil/intfloat.h"
>> #include "libavutil/intreadwrite.h"
>> #include "libavutil/mathematics.h"
>> +#include "libavutil/mastering_display_metadata.h"
>> #include "avformat.h"
>> #include "demux.h"
>> #include "internal.h"
>> @@ -45,6 +46,28 @@
>> #define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
>> +typedef struct FLVMasteringMeta {
>> + double r_x;
>> + double r_y;
>> + double g_x;
>> + double g_y;
>> + double b_x;
>> + double b_y;
>> + double white_x;
>> + double white_y;
>> + double max_luminance;
>> + double min_luminance;
>> +} FLVMasteringMeta;
>> +
>> +typedef struct FLVMetaVideoColor {
>> + uint64_t matrix_coefficients;
>> + uint64_t transfer_characteristics;
>> + uint64_t primaries;
>> + uint64_t max_cll;
>> + uint64_t max_fall;
>> + FLVMasteringMeta mastering_meta;
>> +} FLVMetaVideoColor;
>> +
>> typedef struct FLVContext {
>> const AVClass *class; ///< Class for private options.
>> int trust_metadata; ///< configure streams according onMetaData
>> @@ -80,6 +103,8 @@ typedef struct FLVContext {
>> int64_t time_offset;
>> int64_t time_pos;
>> + FLVMetaVideoColor *metaVideoColor;
>> + int meta_color_info_flag;
>> } FLVContext;
>> /* AMF date type */
>> @@ -524,6 +549,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
>> FLVContext *flv = s->priv_data;
>> AVIOContext *ioc;
>> AMFDataType amf_type;
>> + FLVMetaVideoColor *meta_video_color = flv->metaVideoColor;
>> char str_val[1024];
>> double num_val;
>> amf_date date;
>> @@ -655,6 +681,36 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
>> } else if (!strcmp(key, "height") && vpar) {
>> vpar->height = num_val;
>> }
>> + } else if (!strcmp(key, "colorPrimaries") && meta_video_color) {
>
> You should put this inside an "else if (meta_video_color)" block, instead of checking for meta_video_color with every single string.
>
> See how it's done for flv->trust_metadata above.
>
>> + meta_video_color->primaries = num_val;
>> + } else if (!strcmp(key, "transferCharacteristics") && meta_video_color) {
>> + meta_video_color->transfer_characteristics = num_val;
>> + } else if (!strcmp(key, "matrixCoefficients") && meta_video_color) {
>> + meta_video_color->matrix_coefficients = num_val;
>> + } else if (!strcmp(key, "maxFall") && meta_video_color) {
>> + meta_video_color->max_fall = num_val;
>> + } else if (!strcmp(key, "maxCLL") && meta_video_color) {
>> + meta_video_color->max_cll = num_val;
>> + } else if (!strcmp(key, "redX") && meta_video_color) {
>> + meta_video_color->mastering_meta.r_x = num_val;
>> + } else if (!strcmp(key, "redY") && meta_video_color) {
>> + meta_video_color->mastering_meta.r_y = num_val;
>> + } else if (!strcmp(key, "greenX") && meta_video_color) {
>> + meta_video_color->mastering_meta.g_x = num_val;
>> + } else if (!strcmp(key, "greenY") && meta_video_color) {
>> + meta_video_color->mastering_meta.g_y = num_val;
>> + } else if (!strcmp(key, "blueX") && meta_video_color) {
>> + meta_video_color->mastering_meta.b_x = num_val;
>> + } else if (!strcmp(key, "blueY") && meta_video_color) {
>> + meta_video_color->mastering_meta.b_y = num_val;
>> + } else if (!strcmp(key, "whitePointX") && meta_video_color) {
>> + meta_video_color->mastering_meta.white_x = num_val;
>> + } else if (!strcmp(key, "whitePointY") && meta_video_color) {
>> + meta_video_color->mastering_meta.white_y = num_val;
>> + } else if (!strcmp(key, "maxLuminance") && meta_video_color) {
>> + meta_video_color->mastering_meta.max_luminance = num_val;
>> + } else if (!strcmp(key, "minLuminance") && meta_video_color) {
>> + meta_video_color->mastering_meta.min_luminance = num_val;
>> }
>> }
>> if (amf_type == AMF_DATA_TYPE_STRING) {
>> @@ -824,6 +880,7 @@ static int flv_read_close(AVFormatContext *s)
>> av_freep(&flv->new_extradata[i]);
>> av_freep(&flv->keyframe_times);
>> av_freep(&flv->keyframe_filepositions);
>> + av_freep(&flv->metaVideoColor);
>> return 0;
>> }
>> @@ -1028,6 +1085,104 @@ static int resync(AVFormatContext *s)
>> return AVERROR_EOF;
>> }
>> +static int flv_parse_video_color_info(AVFormatContext *s, AVStream *st, int64_t next_pos)
>> +{
>> + FLVContext *flv = s->priv_data;
>> + AMFDataType type;
>> + AVIOContext *ioc;
>> + char buffer[32];
>> + ioc = s->pb;
>> +
>> + // first object needs to be "colorInfo" string
>> + type = avio_r8(ioc);
>> + if (type != AMF_DATA_TYPE_STRING ||
>> + amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
>> + return TYPE_UNKNOWN;
>> +
>> + if (strcmp(buffer, "colorInfo")) {
>> + av_log(s, AV_LOG_DEBUG, "Unknown type %s\n", buffer);
>> + return TYPE_UNKNOWN;
>> + }
>> +
>> + flv->metaVideoColor = av_mallocz(sizeof(FLVMetaVideoColor));
>> + if (!flv->metaVideoColor) {
>> + return AVERROR(ENOMEM);
>> + }
>> + flv->meta_color_info_flag = 1;
>> + amf_parse_object(s, NULL, NULL, buffer, next_pos, 0); // parse metadata
>> + return 0;
>> +}
>> +
>> +static int flv_update_video_color_info(AVFormatContext *s, AVStream *st)
>> +{
>> + FLVContext *flv = s->priv_data;
>> + const FLVMetaVideoColor* meta_video_color = flv->metaVideoColor;
>> + const FLVMasteringMeta *mastering_meta = &meta_video_color->mastering_meta;
>> +
>> + int has_mastering_primaries, has_mastering_luminance;
>> + // Mastering primaries are CIE 1931 coords, and must be > 0.
>> + has_mastering_primaries =
>> + mastering_meta->r_x > 0 && mastering_meta->r_y > 0 &&
>> + mastering_meta->g_x > 0 && mastering_meta->g_y > 0 &&
>> + mastering_meta->b_x > 0 && mastering_meta->b_y > 0 &&
>> + mastering_meta->white_x > 0 && mastering_meta->white_y > 0;
>> + has_mastering_luminance = mastering_meta->max_luminance >= 0 && mastering_meta->min_luminance >= 0;
>> +
>> + if (meta_video_color->matrix_coefficients != AVCOL_SPC_RESERVED)
>> + st->codecpar->color_space = meta_video_color->matrix_coefficients;
>> + if (meta_video_color->primaries != AVCOL_PRI_RESERVED &&
>> + meta_video_color->primaries != AVCOL_PRI_RESERVED0)
>> + st->codecpar->color_primaries = meta_video_color->primaries;
>> + if (meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED &&
>> + meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED0)
>> + st->codecpar->color_trc = meta_video_color->transfer_characteristics;
>> +
>> + if (meta_video_color->max_cll && meta_video_color->max_fall) {
>> + size_t size = 0;
>> + AVContentLightMetadata *metadata = av_content_light_metadata_alloc(&size);
>> + if (!metadata)
>> + return AVERROR(ENOMEM);
>> + if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data,
>> + AV_PKT_DATA_CONTENT_LIGHT_LEVEL, metadata, size, 0)) {
>> + av_freep(&metadata);
>> + return AVERROR(ENOMEM);
>> + }
>> + metadata->MaxCLL = meta_video_color->max_cll;
>> + metadata->MaxFALL = meta_video_color->max_fall;
>> + }
>> +
>> + if (has_mastering_primaries || has_mastering_luminance) {
>> + AVMasteringDisplayMetadata *metadata;
>> + AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data,
>> + &st->codecpar->nb_coded_side_data,
>> + AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
>> + sizeof(AVMasteringDisplayMetadata), 0);
>> + if (!sd)
>> + return AVERROR(ENOMEM);
>> + metadata = (AVMasteringDisplayMetadata*)sd->data;
>> + memset(metadata, 0, sizeof(AVMasteringDisplayMetadata));
>> + // hdrCll
>> + if (has_mastering_luminance) {
>> + metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX);
>> + metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX);
>> + metadata->has_luminance = 1;
>> + }
>> + // hdrMdcv
>> + if (has_mastering_primaries) {
>> + metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX);
>> + metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX);
>> + metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX);
>> + metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX);
>> + metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX);
>> + metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX);
>> + metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX);
>> + metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX);
>> + metadata->has_primaries = 1;
>> + }
>> + }
>> + return 0;
>> +}
>> +
>> static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
>> {
>> FLVContext *flv = s->priv_data;
>> @@ -1100,8 +1255,17 @@ retry:
>> video_codec_id = avio_rb32(s->pb);
>> size -= 4;
>> }
>> - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
>> +
>> + if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
>> + type = flags & 0x0F;
>> + if (type == PacketTypeMetadata) {
>> + int ret = flv_parse_video_color_info(s, st, next);
>> + av_log(s, AV_LOG_INFO, "enhanced flv parse metadata ret %d and skip\n", ret);
>> + }
>> + goto skip;
>> + } else if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
>> goto skip;
>> + }
>> } else if (type == FLV_TAG_TYPE_META) {
>> stream_type=FLV_STREAM_TYPE_SUBTITLE;
>> if (size > 13 + 1 + 4) { // Header-type metadata stuff
>> @@ -1287,6 +1451,11 @@ retry_duration:
>> goto leave;
>> }
>> + if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && flv->meta_color_info_flag) {
>> + flv_update_video_color_info(s, st); // update av packet side data
>> + flv->meta_color_info_flag = 0;
>> + }
>> +
>> if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
>> (st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
>> // sign extension
>
> A test for this would be nice. Can be one that creates a file and then demuxes it.
> See the fate-lavf-fate-* tests to remux an existing sample.
Thank you very much for your suggestion. All other comments have been modified as per your suggestions locally.
But about fate test, I have some questions that would like to ask for advice:
1. During the development stage, can I use ffmpeg with the mov/mkv muxer to write side data to construct an hdr flv file (ffmpeg -i *** -metadata:s:v **.mkv)
2. Referring to fate-lavf-fate-* tests, I did not find sample file with metadata in the official fate suite. If test-fate uses codec copy, it cannot obtain sidedata and therefore cannot be constructed flv file.
3. Do you have any suggestions? Besides creating a new fate suite file, are there any other methods?
Thanks
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org <mailto:ffmpeg-devel@ffmpeg.org>
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org <mailto: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
* [FFmpeg-devel] [PATCH v2 1/2] avformat/flvenc: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
2023-12-13 13:41 ` 朱鹏飞 via ffmpeg-devel
@ 2023-12-17 16:24 ` zhupengfei via ffmpeg-devel
2023-12-17 18:22 ` James Almer
2023-12-17 16:24 ` [FFmpeg-devel] [PATCH v2 2/2] avformat/flvdec: " zhupengfei via ffmpeg-devel
` (6 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2023-12-17 16:24 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvenc.c | 155 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index f6d10f331c..7268394b93 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -24,6 +24,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "libavcodec/codec_desc.h"
#include "libavcodec/mpeg4audio.h"
#include "avio.h"
@@ -124,6 +125,7 @@ typedef struct FLVContext {
int flags;
int64_t last_ts[FLV_STREAM_TYPE_NB];
+ int write_metadata_pkt;
} FLVContext;
static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
@@ -478,6 +480,158 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
avio_wb32(pb, flv->metadata_totalsize + 11);
}
+static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
+{
+ AVIOContext *pb = s->pb;
+ FLVContext *flv = s->priv_data;
+ AVContentLightMetadata *lightMetadata = NULL;
+ AVMasteringDisplayMetadata *displayMetadata = NULL;
+ const int flags_size = 5;
+ int64_t metadata_size_pos = 0;
+ int64_t total_size = 0;
+ const AVPacketSideData *side_data = NULL;
+
+ if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
+ par->codec_id == AV_CODEC_ID_VP9) {
+ if (flv->write_metadata_pkt) return;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
+ if (side_data)
+ lightMetadata = (AVContentLightMetadata *)side_data->data;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
+ if (side_data)
+ displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
+
+ if (!lightMetadata && !displayMetadata) return;
+
+ /*
+ * Reference Enhancing FLV
+ * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
+ * */
+ 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);
+
+ 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);
+ }
+
+ 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
+
+ /* mixed array (hash) with size and string/type/data tuples */
+ avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
+
+ avio_wb32(pb, 0); // write array count
+
+ 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); // array end of object
+
+ if (lightMetadata) {
+ put_amf_string(pb, "hdrCll");
+
+ /* mixed array (hash) with size and string/type/data tuples */
+ avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
+
+ avio_wb32(pb, 0); // write array count
+
+ put_amf_string(pb, "maxFall");
+ put_amf_double(pb, lightMetadata->MaxFALL);
+
+ put_amf_string(pb, "maxCLL");
+ put_amf_double(pb, lightMetadata->MaxCLL);
+
+ // array end of object
+ put_amf_string(pb, "");
+ avio_w8(pb, AMF_END_OF_OBJECT);
+ }
+
+ if (displayMetadata && (displayMetadata->has_primaries || displayMetadata->has_luminance)) {
+ put_amf_string(pb, "hdrMdcv");
+
+ /* mixed array (hash) with size and string/type/data tuples */
+ avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
+ avio_wb32(pb, 0); // write array count
+
+ 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);
+ }
+ avio_w8(pb, AMF_DATA_TYPE_OBJECT_END);
+
+ total_size = avio_tell(pb) - metadata_size_pos - 10;
+ avio_seek(pb, metadata_size_pos, SEEK_SET);
+ avio_wb24(pb, total_size);
+ avio_tell(pb);
+ avio_skip(pb, total_size + 10 - 3);
+ avio_tell(pb);
+ avio_wb32(pb, total_size + 11); // previous tag size
+ flv->write_metadata_pkt = 1;
+ }
+}
+
static int unsupported_codec(AVFormatContext *s,
const char* type, int codec_id)
{
@@ -878,6 +1032,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(par->extradata, side, side_size);
flv_write_codec_header(s, par, pkt->dts);
}
+ flv_write_metadata_packet(s, par, pkt->dts);
}
if (flv->delay == AV_NOPTS_VALUE)
--
2.42.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 v2 1/2] avformat/flvenc: support enhanced flv PacketTypeMetadata
2023-12-17 16:24 ` [FFmpeg-devel] [PATCH v2 1/2] avformat/flvenc: " zhupengfei via ffmpeg-devel
@ 2023-12-17 18:22 ` James Almer
2023-12-21 13:46 ` zhupengfei via ffmpeg-devel
0 siblings, 1 reply; 17+ messages in thread
From: James Almer @ 2023-12-17 18:22 UTC (permalink / raw)
To: ffmpeg-devel
On 12/17/2023 1:24 PM, zhupengfei via ffmpeg-devel wrote:
> From: Zhu Pengfei <411294962@qq.com>
>
> Signed-off-by: Zhu Pengfei <411294962@qq.com>
> ---
> libavformat/flvenc.c | 155 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 155 insertions(+)
>
> diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
> index f6d10f331c..7268394b93 100644
> --- a/libavformat/flvenc.c
> +++ b/libavformat/flvenc.c
> @@ -24,6 +24,7 @@
> #include "libavutil/intfloat.h"
> #include "libavutil/avassert.h"
> #include "libavutil/mathematics.h"
> +#include "libavutil/mastering_display_metadata.h"
> #include "libavcodec/codec_desc.h"
> #include "libavcodec/mpeg4audio.h"
> #include "avio.h"
> @@ -124,6 +125,7 @@ typedef struct FLVContext {
>
> int flags;
> int64_t last_ts[FLV_STREAM_TYPE_NB];
> + int write_metadata_pkt;
> } FLVContext;
>
> static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
> @@ -478,6 +480,158 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
> avio_wb32(pb, flv->metadata_totalsize + 11);
> }
>
> +static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
> +{
> + AVIOContext *pb = s->pb;
> + FLVContext *flv = s->priv_data;
> + AVContentLightMetadata *lightMetadata = NULL;
> + AVMasteringDisplayMetadata *displayMetadata = NULL;
> + const int flags_size = 5;
> + int64_t metadata_size_pos = 0;
> + int64_t total_size = 0;
> + const AVPacketSideData *side_data = NULL;
> +
> + if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
> + par->codec_id == AV_CODEC_ID_VP9) {
> + if (flv->write_metadata_pkt) return;
> +
> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
> + AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
> + if (side_data)
> + lightMetadata = (AVContentLightMetadata *)side_data->data;
> +
> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
> + AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
> + if (side_data)
> + displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
> +
> + if (!lightMetadata && !displayMetadata) return;
Again, why are you not writing anything when there's no static HDR metadata?
transferCharacteristics, matrixCoefficients and colorPrimaries don't
depend on those, and can be written on their own. Similarly, you can
write lightMetadata when there's no displayMetadata, and vice versa.
> +
> + /*
> + * Reference Enhancing FLV
> + * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
> + * */
> + 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);
> +
> + 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);
> + }
> +
> + 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
> +
> + /* mixed array (hash) with size and string/type/data tuples */
> + avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
> +
> + avio_wb32(pb, 0); // write array count
> +
> + 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); // array end of object
> +
> + if (lightMetadata) {
> + put_amf_string(pb, "hdrCll");
> +
> + /* mixed array (hash) with size and string/type/data tuples */
> + avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
> +
> + avio_wb32(pb, 0); // write array count
> +
> + put_amf_string(pb, "maxFall");
> + put_amf_double(pb, lightMetadata->MaxFALL);
> +
> + put_amf_string(pb, "maxCLL");
> + put_amf_double(pb, lightMetadata->MaxCLL);
> +
> + // array end of object
> + put_amf_string(pb, "");
> + avio_w8(pb, AMF_END_OF_OBJECT);
> + }
> +
> + if (displayMetadata && (displayMetadata->has_primaries || displayMetadata->has_luminance)) {
> + put_amf_string(pb, "hdrMdcv");
> +
> + /* mixed array (hash) with size and string/type/data tuples */
> + avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
> + avio_wb32(pb, 0); // write array count
> +
> + 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);
> + }
> + avio_w8(pb, AMF_DATA_TYPE_OBJECT_END);
> +
> + total_size = avio_tell(pb) - metadata_size_pos - 10;
> + avio_seek(pb, metadata_size_pos, SEEK_SET);
> + avio_wb24(pb, total_size);
> + avio_tell(pb);
> + avio_skip(pb, total_size + 10 - 3);
> + avio_tell(pb);
> + avio_wb32(pb, total_size + 11); // previous tag size
> + flv->write_metadata_pkt = 1;
> + }
> +}
> +
> static int unsupported_codec(AVFormatContext *s,
> const char* type, int codec_id)
> {
> @@ -878,6 +1032,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
> memcpy(par->extradata, side, side_size);
> flv_write_codec_header(s, par, pkt->dts);
> }
> + flv_write_metadata_packet(s, par, pkt->dts);
> }
>
> if (flv->delay == AV_NOPTS_VALUE)
_______________________________________________
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 v2 1/2] avformat/flvenc: support enhanced flv PacketTypeMetadata
2023-12-17 18:22 ` James Almer
@ 2023-12-21 13:46 ` zhupengfei via ffmpeg-devel
0 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2023-12-21 13:46 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: zhupengfei
> 2023年12月18日 02:22,James Almer <jamrial@gmail.com> 写道:
>
> On 12/17/2023 1:24 PM, zhupengfei via ffmpeg-devel wrote:
>> From: Zhu Pengfei <411294962@qq.com>
>> Signed-off-by: Zhu Pengfei <411294962@qq.com>
>> ---
>> libavformat/flvenc.c | 155 +++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 155 insertions(+)
>> diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
>> index f6d10f331c..7268394b93 100644
>> --- a/libavformat/flvenc.c
>> +++ b/libavformat/flvenc.c
>> @@ -24,6 +24,7 @@
>> #include "libavutil/intfloat.h"
>> #include "libavutil/avassert.h"
>> #include "libavutil/mathematics.h"
>> +#include "libavutil/mastering_display_metadata.h"
>> #include "libavcodec/codec_desc.h"
>> #include "libavcodec/mpeg4audio.h"
>> #include "avio.h"
>> @@ -124,6 +125,7 @@ typedef struct FLVContext {
>> int flags;
>> int64_t last_ts[FLV_STREAM_TYPE_NB];
>> + int write_metadata_pkt;
>> } FLVContext;
>> static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
>> @@ -478,6 +480,158 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
>> avio_wb32(pb, flv->metadata_totalsize + 11);
>> }
>> +static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
>> +{
>> + AVIOContext *pb = s->pb;
>> + FLVContext *flv = s->priv_data;
>> + AVContentLightMetadata *lightMetadata = NULL;
>> + AVMasteringDisplayMetadata *displayMetadata = NULL;
>> + const int flags_size = 5;
>> + int64_t metadata_size_pos = 0;
>> + int64_t total_size = 0;
>> + const AVPacketSideData *side_data = NULL;
>> +
>> + if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
>> + par->codec_id == AV_CODEC_ID_VP9) {
>> + if (flv->write_metadata_pkt) return;
>> +
>> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
>> + AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
>> + if (side_data)
>> + lightMetadata = (AVContentLightMetadata *)side_data->data;
>> +
>> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
>> + AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
>> + if (side_data)
>> + displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
>> +
>> + if (!lightMetadata && !displayMetadata) return;
>
> Again, why are you not writing anything when there's no static HDR metadata?
> transferCharacteristics, matrixCoefficients and colorPrimaries don't depend on those, and can be written on their own. Similarly, you can write lightMetadata when there's no displayMetadata, and vice versa.
This is a mistake, I ignored this comment and will fix in the next patch.
>
>> +
>> + /*
>> + * Reference Enhancing FLV
>> + * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
>> + * */
>> + 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);
>> +
>> + 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);
>> + }
>> +
>> + 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
>> +
>> + /* mixed array (hash) with size and string/type/data tuples */
>> + avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
>> +
>> + avio_wb32(pb, 0); // write array count
>> +
>> + 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); // array end of object
>> +
>> + if (lightMetadata) {
>> + put_amf_string(pb, "hdrCll");
>> +
>> + /* mixed array (hash) with size and string/type/data tuples */
>> + avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
>> +
>> + avio_wb32(pb, 0); // write array count
>> +
>> + put_amf_string(pb, "maxFall");
>> + put_amf_double(pb, lightMetadata->MaxFALL);
>> +
>> + put_amf_string(pb, "maxCLL");
>> + put_amf_double(pb, lightMetadata->MaxCLL);
>> +
>> + // array end of object
>> + put_amf_string(pb, "");
>> + avio_w8(pb, AMF_END_OF_OBJECT);
>> + }
>> +
>> + if (displayMetadata && (displayMetadata->has_primaries || displayMetadata->has_luminance)) {
>> + put_amf_string(pb, "hdrMdcv");
>> +
>> + /* mixed array (hash) with size and string/type/data tuples */
>> + avio_w8(pb, AMF_DATA_TYPE_MIXEDARRAY);
>> + avio_wb32(pb, 0); // write array count
>> +
>> + 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);
>> + }
>> + avio_w8(pb, AMF_DATA_TYPE_OBJECT_END);
>> +
>> + total_size = avio_tell(pb) - metadata_size_pos - 10;
>> + avio_seek(pb, metadata_size_pos, SEEK_SET);
>> + avio_wb24(pb, total_size);
>> + avio_tell(pb);
>> + avio_skip(pb, total_size + 10 - 3);
>> + avio_tell(pb);
>> + avio_wb32(pb, total_size + 11); // previous tag size
>> + flv->write_metadata_pkt = 1;
>> + }
>> +}
>> +
>> static int unsupported_codec(AVFormatContext *s,
>> const char* type, int codec_id)
>> {
>> @@ -878,6 +1032,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
>> memcpy(par->extradata, side, side_size);
>> flv_write_codec_header(s, par, pkt->dts);
>> }
>> + flv_write_metadata_packet(s, par, pkt->dts);
>> }
>> if (flv->delay == AV_NOPTS_VALUE)
> _______________________________________________
> 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
* [FFmpeg-devel] [PATCH v2 2/2] avformat/flvdec: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
2023-12-13 13:41 ` 朱鹏飞 via ffmpeg-devel
2023-12-17 16:24 ` [FFmpeg-devel] [PATCH v2 1/2] avformat/flvenc: " zhupengfei via ffmpeg-devel
@ 2023-12-17 16:24 ` zhupengfei via ffmpeg-devel
2024-01-11 16:15 ` [FFmpeg-devel] [PATCH v3 1/2] " zhupengfei via ffmpeg-devel
` (5 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2023-12-17 16:24 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvdec.c | 178 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 1 deletion(-)
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index e25b5bd163..6d40b4c7d5 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -34,6 +34,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "avformat.h"
#include "demux.h"
#include "internal.h"
@@ -45,6 +46,28 @@
#define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
+typedef struct FLVMasteringMeta {
+ double r_x;
+ double r_y;
+ double g_x;
+ double g_y;
+ double b_x;
+ double b_y;
+ double white_x;
+ double white_y;
+ double max_luminance;
+ double min_luminance;
+} FLVMasteringMeta;
+
+typedef struct FLVMetaVideoColor {
+ uint64_t matrix_coefficients;
+ uint64_t transfer_characteristics;
+ uint64_t primaries;
+ uint64_t max_cll;
+ uint64_t max_fall;
+ FLVMasteringMeta mastering_meta;
+} FLVMetaVideoColor;
+
typedef struct FLVContext {
const AVClass *class; ///< Class for private options.
int trust_metadata; ///< configure streams according onMetaData
@@ -80,6 +103,8 @@ typedef struct FLVContext {
int64_t time_offset;
int64_t time_pos;
+ FLVMetaVideoColor *metaVideoColor;
+ int meta_color_info_flag;
} FLVContext;
/* AMF date type */
@@ -524,6 +549,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
FLVContext *flv = s->priv_data;
AVIOContext *ioc;
AMFDataType amf_type;
+ FLVMetaVideoColor *meta_video_color = flv->metaVideoColor;
char str_val[1024];
double num_val;
amf_date date;
@@ -672,6 +698,43 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
}
}
+ 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;
+ }
+ }
+ }
+
if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
((!apar && !strcmp(key, "audiocodecid")) ||
(!vpar && !strcmp(key, "videocodecid"))))
@@ -824,6 +887,7 @@ static int flv_read_close(AVFormatContext *s)
av_freep(&flv->new_extradata[i]);
av_freep(&flv->keyframe_times);
av_freep(&flv->keyframe_filepositions);
+ av_freep(&flv->metaVideoColor);
return 0;
}
@@ -1028,6 +1092,104 @@ static int resync(AVFormatContext *s)
return AVERROR_EOF;
}
+static int flv_parse_video_color_info(AVFormatContext *s, AVStream *st, int64_t next_pos)
+{
+ FLVContext *flv = s->priv_data;
+ AMFDataType type;
+ AVIOContext *ioc;
+ char buffer[32];
+ ioc = s->pb;
+
+ // first object needs to be "colorInfo" string
+ type = avio_r8(ioc);
+ if (type != AMF_DATA_TYPE_STRING ||
+ amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
+ return TYPE_UNKNOWN;
+
+ if (strcmp(buffer, "colorInfo")) {
+ av_log(s, AV_LOG_DEBUG, "Unknown type %s\n", buffer);
+ return TYPE_UNKNOWN;
+ }
+
+ flv->metaVideoColor = av_mallocz(sizeof(FLVMetaVideoColor));
+ if (!flv->metaVideoColor) {
+ return AVERROR(ENOMEM);
+ }
+ flv->meta_color_info_flag = 1;
+ amf_parse_object(s, NULL, NULL, buffer, next_pos, 0); // parse metadata
+ return 0;
+}
+
+static int flv_update_video_color_info(AVFormatContext *s, AVStream *st)
+{
+ FLVContext *flv = s->priv_data;
+ const FLVMetaVideoColor* meta_video_color = flv->metaVideoColor;
+ const FLVMasteringMeta *mastering_meta = &meta_video_color->mastering_meta;
+
+ int has_mastering_primaries, has_mastering_luminance;
+ // Mastering primaries are CIE 1931 coords, and must be > 0.
+ has_mastering_primaries =
+ mastering_meta->r_x > 0 && mastering_meta->r_y > 0 &&
+ mastering_meta->g_x > 0 && mastering_meta->g_y > 0 &&
+ mastering_meta->b_x > 0 && mastering_meta->b_y > 0 &&
+ mastering_meta->white_x > 0 && mastering_meta->white_y > 0;
+ has_mastering_luminance = mastering_meta->max_luminance >= 0 && mastering_meta->min_luminance >= 0;
+
+ if (meta_video_color->matrix_coefficients != AVCOL_SPC_RESERVED)
+ st->codecpar->color_space = meta_video_color->matrix_coefficients;
+ if (meta_video_color->primaries != AVCOL_PRI_RESERVED &&
+ meta_video_color->primaries != AVCOL_PRI_RESERVED0)
+ st->codecpar->color_primaries = meta_video_color->primaries;
+ if (meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED &&
+ meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED0)
+ st->codecpar->color_trc = meta_video_color->transfer_characteristics;
+
+ if (meta_video_color->max_cll && meta_video_color->max_fall) {
+ size_t size = 0;
+ AVContentLightMetadata *metadata = av_content_light_metadata_alloc(&size);
+ if (!metadata)
+ return AVERROR(ENOMEM);
+ if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL, metadata, size, 0)) {
+ av_freep(&metadata);
+ return AVERROR(ENOMEM);
+ }
+ metadata->MaxCLL = meta_video_color->max_cll;
+ metadata->MaxFALL = meta_video_color->max_fall;
+ }
+
+ if (has_mastering_primaries || has_mastering_luminance) {
+ AVMasteringDisplayMetadata *metadata;
+ AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data,
+ &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
+ sizeof(AVMasteringDisplayMetadata), 0);
+ if (!sd)
+ return AVERROR(ENOMEM);
+ metadata = (AVMasteringDisplayMetadata*)sd->data;
+ memset(metadata, 0, sizeof(AVMasteringDisplayMetadata));
+ // hdrCll
+ if (has_mastering_luminance) {
+ metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX);
+ metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX);
+ metadata->has_luminance = 1;
+ }
+ // hdrMdcv
+ if (has_mastering_primaries) {
+ metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX);
+ metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX);
+ metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX);
+ metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX);
+ metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX);
+ metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX);
+ metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX);
+ metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX);
+ metadata->has_primaries = 1;
+ }
+ }
+ return 0;
+}
+
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
@@ -1100,8 +1262,17 @@ retry:
video_codec_id = avio_rb32(s->pb);
size -= 4;
}
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
+
+ if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
+ type = flags & 0x0F;
+ if (type == PacketTypeMetadata) {
+ int ret = flv_parse_video_color_info(s, st, next);
+ av_log(s, AV_LOG_INFO, "enhanced flv parse metadata ret %d and skip\n", ret);
+ }
+ goto skip;
+ } else if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
goto skip;
+ }
} else if (type == FLV_TAG_TYPE_META) {
stream_type=FLV_STREAM_TYPE_SUBTITLE;
if (size > 13 + 1 + 4) { // Header-type metadata stuff
@@ -1287,6 +1458,11 @@ retry_duration:
goto leave;
}
+ if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && flv->meta_color_info_flag) {
+ flv_update_video_color_info(s, st); // update av packet side data
+ flv->meta_color_info_flag = 0;
+ }
+
if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
(st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
// sign extension
--
2.42.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 v3 1/2] avformat/flvdec: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
` (2 preceding siblings ...)
2023-12-17 16:24 ` [FFmpeg-devel] [PATCH v2 2/2] avformat/flvdec: " zhupengfei via ffmpeg-devel
@ 2024-01-11 16:15 ` zhupengfei via ffmpeg-devel
2024-01-11 16:17 ` [FFmpeg-devel] [PATCH v3 2/2] avformat/flvenc: " zhupengfei via ffmpeg-devel
` (4 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-01-11 16:15 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvdec.c | 178 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 1 deletion(-)
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index e25b5bd163..65815e51f9 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -34,6 +34,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "avformat.h"
#include "demux.h"
#include "internal.h"
@@ -45,6 +46,28 @@
#define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
+typedef struct FLVMasteringMeta {
+ double r_x;
+ double r_y;
+ double g_x;
+ double g_y;
+ double b_x;
+ double b_y;
+ double white_x;
+ double white_y;
+ double max_luminance;
+ double min_luminance;
+} FLVMasteringMeta;
+
+typedef struct FLVMetaVideoColor {
+ uint64_t matrix_coefficients;
+ uint64_t transfer_characteristics;
+ uint64_t primaries;
+ uint64_t max_cll;
+ uint64_t max_fall;
+ FLVMasteringMeta mastering_meta;
+} FLVMetaVideoColor;
+
typedef struct FLVContext {
const AVClass *class; ///< Class for private options.
int trust_metadata; ///< configure streams according onMetaData
@@ -80,6 +103,8 @@ typedef struct FLVContext {
int64_t time_offset;
int64_t time_pos;
+ FLVMetaVideoColor *metaVideoColor;
+ int meta_color_info_flag;
} FLVContext;
/* AMF date type */
@@ -524,6 +549,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
FLVContext *flv = s->priv_data;
AVIOContext *ioc;
AMFDataType amf_type;
+ FLVMetaVideoColor *meta_video_color = flv->metaVideoColor;
char str_val[1024];
double num_val;
amf_date date;
@@ -672,6 +698,43 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
}
}
+ 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;
+ }
+ }
+ }
+
if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
((!apar && !strcmp(key, "audiocodecid")) ||
(!vpar && !strcmp(key, "videocodecid"))))
@@ -824,6 +887,7 @@ static int flv_read_close(AVFormatContext *s)
av_freep(&flv->new_extradata[i]);
av_freep(&flv->keyframe_times);
av_freep(&flv->keyframe_filepositions);
+ av_freep(&flv->metaVideoColor);
return 0;
}
@@ -1028,6 +1092,104 @@ static int resync(AVFormatContext *s)
return AVERROR_EOF;
}
+static int flv_parse_video_color_info(AVFormatContext *s, AVStream *st, int64_t next_pos)
+{
+ FLVContext *flv = s->priv_data;
+ AMFDataType type;
+ AVIOContext *ioc;
+ char buffer[32];
+ ioc = s->pb;
+
+ // first object needs to be "colorInfo" string
+ type = avio_r8(ioc);
+ if (type != AMF_DATA_TYPE_STRING ||
+ amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
+ return TYPE_UNKNOWN;
+
+ if (strcmp(buffer, "colorInfo")) {
+ av_log(s, AV_LOG_DEBUG, "Unknown type %s\n", buffer);
+ return TYPE_UNKNOWN;
+ }
+
+ flv->metaVideoColor = av_mallocz(sizeof(FLVMetaVideoColor));
+ if (!flv->metaVideoColor) {
+ return AVERROR(ENOMEM);
+ }
+ flv->meta_color_info_flag = 1;
+ amf_parse_object(s, NULL, NULL, buffer, next_pos, 0); // parse metadata
+ return 0;
+}
+
+static int flv_update_video_color_info(AVFormatContext *s, AVStream *st)
+{
+ FLVContext *flv = s->priv_data;
+ const FLVMetaVideoColor* meta_video_color = flv->metaVideoColor;
+ const FLVMasteringMeta *mastering_meta = &meta_video_color->mastering_meta;
+
+ int has_mastering_primaries, has_mastering_luminance;
+ // Mastering primaries are CIE 1931 coords, and must be > 0.
+ has_mastering_primaries =
+ mastering_meta->r_x > 0 && mastering_meta->r_y > 0 &&
+ mastering_meta->g_x > 0 && mastering_meta->g_y > 0 &&
+ mastering_meta->b_x > 0 && mastering_meta->b_y > 0 &&
+ mastering_meta->white_x > 0 && mastering_meta->white_y > 0;
+ has_mastering_luminance = mastering_meta->max_luminance >= 0 && mastering_meta->min_luminance >= 0;
+
+ if (meta_video_color->matrix_coefficients != AVCOL_SPC_RESERVED)
+ st->codecpar->color_space = meta_video_color->matrix_coefficients;
+ if (meta_video_color->primaries != AVCOL_PRI_RESERVED &&
+ meta_video_color->primaries != AVCOL_PRI_RESERVED0)
+ st->codecpar->color_primaries = meta_video_color->primaries;
+ if (meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED &&
+ meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED0)
+ st->codecpar->color_trc = meta_video_color->transfer_characteristics;
+
+ if (meta_video_color->max_cll && meta_video_color->max_fall) {
+ size_t size = 0;
+ AVContentLightMetadata *metadata = av_content_light_metadata_alloc(&size);
+ if (!metadata)
+ return AVERROR(ENOMEM);
+ if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL, metadata, size, 0)) {
+ av_freep(&metadata);
+ return AVERROR(ENOMEM);
+ }
+ metadata->MaxCLL = meta_video_color->max_cll;
+ metadata->MaxFALL = meta_video_color->max_fall;
+ }
+
+ if (has_mastering_primaries || has_mastering_luminance) {
+ AVMasteringDisplayMetadata *metadata;
+ AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data,
+ &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
+ sizeof(AVMasteringDisplayMetadata), 0);
+ if (!sd)
+ return AVERROR(ENOMEM);
+ metadata = (AVMasteringDisplayMetadata*)sd->data;
+ memset(metadata, 0, sizeof(AVMasteringDisplayMetadata));
+ // hdrCll
+ if (has_mastering_luminance) {
+ metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX);
+ metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX);
+ metadata->has_luminance = 1;
+ }
+ // hdrMdcv
+ if (has_mastering_primaries) {
+ metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX);
+ metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX);
+ metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX);
+ metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX);
+ metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX);
+ metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX);
+ metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX);
+ metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX);
+ metadata->has_primaries = 1;
+ }
+ }
+ return 0;
+}
+
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
@@ -1100,8 +1262,17 @@ retry:
video_codec_id = avio_rb32(s->pb);
size -= 4;
}
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
+
+ if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
+ type = flags & 0x0F;
+ if (type == PacketTypeMetadata) {
+ int ret = flv_parse_video_color_info(s, st, next);
+ av_log(s, AV_LOG_DEBUG, "enhanced flv parse metadata ret %d and skip\n", ret);
+ }
+ goto skip;
+ } else if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
goto skip;
+ }
} else if (type == FLV_TAG_TYPE_META) {
stream_type=FLV_STREAM_TYPE_SUBTITLE;
if (size > 13 + 1 + 4) { // Header-type metadata stuff
@@ -1287,6 +1458,11 @@ retry_duration:
goto leave;
}
+ if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && flv->meta_color_info_flag) {
+ flv_update_video_color_info(s, st); // update av packet side data
+ flv->meta_color_info_flag = 0;
+ }
+
if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
(st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
// sign extension
--
2.42.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 v3 2/2] avformat/flvenc: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
` (3 preceding siblings ...)
2024-01-11 16:15 ` [FFmpeg-devel] [PATCH v3 1/2] " zhupengfei via ffmpeg-devel
@ 2024-01-11 16:17 ` zhupengfei via ffmpeg-devel
2024-01-11 16:37 ` zhupengfei via ffmpeg-devel
` (3 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-01-11 16:17 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvenc.c | 133 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index f6d10f331c..4485aba03c 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -24,6 +24,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "libavcodec/codec_desc.h"
#include "libavcodec/mpeg4audio.h"
#include "avio.h"
@@ -124,6 +125,7 @@ typedef struct FLVContext {
int flags;
int64_t last_ts[FLV_STREAM_TYPE_NB];
+ int write_metadata_pkt;
} FLVContext;
static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
@@ -478,6 +480,136 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
avio_wb32(pb, flv->metadata_totalsize + 11);
}
+static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
+{
+ AVIOContext *pb = s->pb;
+ FLVContext *flv = s->priv_data;
+ AVContentLightMetadata *lightMetadata = NULL;
+ AVMasteringDisplayMetadata *displayMetadata = NULL;
+ const int flags_size = 5;
+ int64_t metadata_size_pos = 0;
+ int64_t total_size = 0;
+ const AVPacketSideData *side_data = NULL;
+
+ if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
+ par->codec_id == AV_CODEC_ID_VP9) {
+ if (flv->write_metadata_pkt) return;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
+ if (side_data)
+ lightMetadata = (AVContentLightMetadata *)side_data->data;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
+ if (side_data)
+ displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
+
+ /*
+ * Reference Enhancing FLV
+ * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
+ * */
+ 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);
+
+ 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);
+ }
+
+ 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);
+
+ put_amf_string(pb, "transferCharacteristics"); // color_trc
+ put_amf_double(pb, par->color_trc);
+
+ put_amf_string(pb, "matrixCoefficients"); // colorspace
+ put_amf_double(pb, par->color_space);
+
+ 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);
+
+ total_size = avio_tell(pb) - metadata_size_pos - 10;
+ avio_seek(pb, metadata_size_pos, SEEK_SET);
+ avio_wb24(pb, total_size);
+ avio_tell(pb);
+ avio_skip(pb, total_size + 10 - 3);
+ avio_tell(pb);
+ avio_wb32(pb, total_size + 11); // previous tag size
+ flv->write_metadata_pkt = 1;
+ }
+}
+
static int unsupported_codec(AVFormatContext *s,
const char* type, int codec_id)
{
@@ -878,6 +1010,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(par->extradata, side, side_size);
flv_write_codec_header(s, par, pkt->dts);
}
+ flv_write_metadata_packet(s, par, pkt->dts);
}
if (flv->delay == AV_NOPTS_VALUE)
--
2.42.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 v3 2/2] avformat/flvenc: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
` (4 preceding siblings ...)
2024-01-11 16:17 ` [FFmpeg-devel] [PATCH v3 2/2] avformat/flvenc: " zhupengfei via ffmpeg-devel
@ 2024-01-11 16:37 ` zhupengfei via ffmpeg-devel
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 1/3] avformat/flvdec: " zhupengfei via ffmpeg-devel
` (2 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-01-11 16:37 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvenc.c | 133 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index f6d10f331c..4485aba03c 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -24,6 +24,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "libavcodec/codec_desc.h"
#include "libavcodec/mpeg4audio.h"
#include "avio.h"
@@ -124,6 +125,7 @@ typedef struct FLVContext {
int flags;
int64_t last_ts[FLV_STREAM_TYPE_NB];
+ int write_metadata_pkt;
} FLVContext;
static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
@@ -478,6 +480,136 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
avio_wb32(pb, flv->metadata_totalsize + 11);
}
+static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
+{
+ AVIOContext *pb = s->pb;
+ FLVContext *flv = s->priv_data;
+ AVContentLightMetadata *lightMetadata = NULL;
+ AVMasteringDisplayMetadata *displayMetadata = NULL;
+ const int flags_size = 5;
+ int64_t metadata_size_pos = 0;
+ int64_t total_size = 0;
+ const AVPacketSideData *side_data = NULL;
+
+ if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
+ par->codec_id == AV_CODEC_ID_VP9) {
+ if (flv->write_metadata_pkt) return;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
+ if (side_data)
+ lightMetadata = (AVContentLightMetadata *)side_data->data;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
+ if (side_data)
+ displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
+
+ /*
+ * Reference Enhancing FLV
+ * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
+ * */
+ 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);
+
+ 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);
+ }
+
+ 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);
+
+ put_amf_string(pb, "transferCharacteristics"); // color_trc
+ put_amf_double(pb, par->color_trc);
+
+ put_amf_string(pb, "matrixCoefficients"); // colorspace
+ put_amf_double(pb, par->color_space);
+
+ 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);
+
+ total_size = avio_tell(pb) - metadata_size_pos - 10;
+ avio_seek(pb, metadata_size_pos, SEEK_SET);
+ avio_wb24(pb, total_size);
+ avio_tell(pb);
+ avio_skip(pb, total_size + 10 - 3);
+ avio_tell(pb);
+ avio_wb32(pb, total_size + 11); // previous tag size
+ flv->write_metadata_pkt = 1;
+ }
+}
+
static int unsupported_codec(AVFormatContext *s,
const char* type, int codec_id)
{
@@ -878,6 +1010,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(par->extradata, side, side_size);
flv_write_codec_header(s, par, pkt->dts);
}
+ flv_write_metadata_packet(s, par, pkt->dts);
}
if (flv->delay == AV_NOPTS_VALUE)
--
2.42.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 v4 1/3] avformat/flvdec: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
` (5 preceding siblings ...)
2024-01-11 16:37 ` zhupengfei via ffmpeg-devel
@ 2024-03-02 8:51 ` zhupengfei via ffmpeg-devel
2024-03-02 14:25 ` James Almer
2024-03-02 15:05 ` Andreas Rheinhardt
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 2/3] avformat/flvenc: " zhupengfei via ffmpeg-devel
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 3/3] fate/flvenc: " zhupengfei via ffmpeg-devel
8 siblings, 2 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-03-02 8:51 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvdec.c | 178 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 1 deletion(-)
diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
index e25b5bd163..d0806c5338 100644
--- a/libavformat/flvdec.c
+++ b/libavformat/flvdec.c
@@ -34,6 +34,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "avformat.h"
#include "demux.h"
#include "internal.h"
@@ -45,6 +46,28 @@
#define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
+typedef struct FLVMasteringMeta {
+ double r_x;
+ double r_y;
+ double g_x;
+ double g_y;
+ double b_x;
+ double b_y;
+ double white_x;
+ double white_y;
+ double max_luminance;
+ double min_luminance;
+} FLVMasteringMeta;
+
+typedef struct FLVMetaVideoColor {
+ uint64_t matrix_coefficients;
+ uint64_t transfer_characteristics;
+ uint64_t primaries;
+ uint64_t max_cll;
+ uint64_t max_fall;
+ FLVMasteringMeta mastering_meta;
+} FLVMetaVideoColor;
+
typedef struct FLVContext {
const AVClass *class; ///< Class for private options.
int trust_metadata; ///< configure streams according onMetaData
@@ -80,6 +103,8 @@ typedef struct FLVContext {
int64_t time_offset;
int64_t time_pos;
+ FLVMetaVideoColor *metaVideoColor;
+ int meta_color_info_flag;
} FLVContext;
/* AMF date type */
@@ -524,6 +549,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
FLVContext *flv = s->priv_data;
AVIOContext *ioc;
AMFDataType amf_type;
+ FLVMetaVideoColor *meta_video_color = flv->metaVideoColor;
char str_val[1024];
double num_val;
amf_date date;
@@ -672,6 +698,43 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
}
}
+ 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;
+ }
+ }
+ }
+
if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
((!apar && !strcmp(key, "audiocodecid")) ||
(!vpar && !strcmp(key, "videocodecid"))))
@@ -824,6 +887,7 @@ static int flv_read_close(AVFormatContext *s)
av_freep(&flv->new_extradata[i]);
av_freep(&flv->keyframe_times);
av_freep(&flv->keyframe_filepositions);
+ av_freep(&flv->metaVideoColor);
return 0;
}
@@ -1028,6 +1092,104 @@ static int resync(AVFormatContext *s)
return AVERROR_EOF;
}
+static int flv_parse_video_color_info(AVFormatContext *s, AVStream *st, int64_t next_pos)
+{
+ FLVContext *flv = s->priv_data;
+ AMFDataType type;
+ AVIOContext *ioc;
+ char buffer[32];
+ ioc = s->pb;
+
+ // first object needs to be "colorInfo" string
+ type = avio_r8(ioc);
+ if (type != AMF_DATA_TYPE_STRING ||
+ amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
+ return TYPE_UNKNOWN;
+
+ if (strcmp(buffer, "colorInfo")) {
+ av_log(s, AV_LOG_DEBUG, "Unknown type %s\n", buffer);
+ return TYPE_UNKNOWN;
+ }
+
+ flv->metaVideoColor = av_mallocz(sizeof(FLVMetaVideoColor));
+ if (!flv->metaVideoColor) {
+ return AVERROR(ENOMEM);
+ }
+ flv->meta_color_info_flag = 1;
+ amf_parse_object(s, NULL, NULL, buffer, next_pos, 0); // parse metadata
+ return 0;
+}
+
+static int flv_update_video_color_info(AVFormatContext *s, AVStream *st)
+{
+ FLVContext *flv = s->priv_data;
+ const FLVMetaVideoColor* meta_video_color = flv->metaVideoColor;
+ const FLVMasteringMeta *mastering_meta = &meta_video_color->mastering_meta;
+
+ int has_mastering_primaries, has_mastering_luminance;
+ // Mastering primaries are CIE 1931 coords, and must be > 0.
+ has_mastering_primaries =
+ mastering_meta->r_x > 0 && mastering_meta->r_y > 0 &&
+ mastering_meta->g_x > 0 && mastering_meta->g_y > 0 &&
+ mastering_meta->b_x > 0 && mastering_meta->b_y > 0 &&
+ mastering_meta->white_x > 0 && mastering_meta->white_y > 0;
+ has_mastering_luminance = mastering_meta->max_luminance > 0 && mastering_meta->min_luminance > 0;
+
+ if (meta_video_color->matrix_coefficients != AVCOL_SPC_RESERVED)
+ st->codecpar->color_space = meta_video_color->matrix_coefficients;
+ if (meta_video_color->primaries != AVCOL_PRI_RESERVED &&
+ meta_video_color->primaries != AVCOL_PRI_RESERVED0)
+ st->codecpar->color_primaries = meta_video_color->primaries;
+ if (meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED &&
+ meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED0)
+ st->codecpar->color_trc = meta_video_color->transfer_characteristics;
+
+ if (meta_video_color->max_cll && meta_video_color->max_fall) {
+ size_t size = 0;
+ AVContentLightMetadata *metadata = av_content_light_metadata_alloc(&size);
+ if (!metadata)
+ return AVERROR(ENOMEM);
+ if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL, metadata, size, 0)) {
+ av_freep(&metadata);
+ return AVERROR(ENOMEM);
+ }
+ metadata->MaxCLL = meta_video_color->max_cll;
+ metadata->MaxFALL = meta_video_color->max_fall;
+ }
+
+ if (has_mastering_primaries || has_mastering_luminance) {
+ AVMasteringDisplayMetadata *metadata;
+ AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data,
+ &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
+ sizeof(AVMasteringDisplayMetadata), 0);
+ if (!sd)
+ return AVERROR(ENOMEM);
+ metadata = (AVMasteringDisplayMetadata*)sd->data;
+ memset(metadata, 0, sizeof(AVMasteringDisplayMetadata));
+ // hdrCll
+ if (has_mastering_luminance) {
+ metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX);
+ metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX);
+ metadata->has_luminance = 1;
+ }
+ // hdrMdcv
+ if (has_mastering_primaries) {
+ metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX);
+ metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX);
+ metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX);
+ metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX);
+ metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX);
+ metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX);
+ metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX);
+ metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX);
+ metadata->has_primaries = 1;
+ }
+ }
+ return 0;
+}
+
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
@@ -1100,8 +1262,17 @@ retry:
video_codec_id = avio_rb32(s->pb);
size -= 4;
}
- if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
+
+ if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
+ type = flags & 0x0F;
+ if (type == PacketTypeMetadata) {
+ int ret = flv_parse_video_color_info(s, st, next);
+ av_log(s, AV_LOG_DEBUG, "enhanced flv parse metadata ret %d and skip\n", ret);
+ }
+ goto skip;
+ } else if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
goto skip;
+ }
} else if (type == FLV_TAG_TYPE_META) {
stream_type=FLV_STREAM_TYPE_SUBTITLE;
if (size > 13 + 1 + 4) { // Header-type metadata stuff
@@ -1287,6 +1458,11 @@ retry_duration:
goto leave;
}
+ if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && flv->meta_color_info_flag) {
+ flv_update_video_color_info(s, st); // update av packet side data
+ flv->meta_color_info_flag = 0;
+ }
+
if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
(st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
// sign extension
--
2.44.0
_______________________________________________
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 v4 1/3] avformat/flvdec: support enhanced flv PacketTypeMetadata
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 1/3] avformat/flvdec: " zhupengfei via ffmpeg-devel
@ 2024-03-02 14:25 ` James Almer
2024-03-02 15:05 ` Andreas Rheinhardt
1 sibling, 0 replies; 17+ messages in thread
From: James Almer @ 2024-03-02 14:25 UTC (permalink / raw)
To: ffmpeg-devel
On 3/2/2024 5:51 AM, zhupengfei via ffmpeg-devel wrote:
> @@ -1100,8 +1262,17 @@ retry:
> video_codec_id = avio_rb32(s->pb);
> size -= 4;
> }
> - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
> +
> + if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
> + type = flags & 0x0F;
> + if (type == PacketTypeMetadata) {
warning: comparison between 'enum FlvTagType' and 'enum <anonymous>'
[-Wenum-compare]
I changed it locally to use a new packet_type variable in this scope.
Will apply the set soon if no one objects.
> + int ret = flv_parse_video_color_info(s, st, next);
> + av_log(s, AV_LOG_DEBUG, "enhanced flv parse metadata ret %d and skip\n", ret);
> + }
> + goto skip;
> + } else if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
> goto skip;
> + }
> } else if (type == FLV_TAG_TYPE_META) {
> stream_type=FLV_STREAM_TYPE_SUBTITLE;
> if (size > 13 + 1 + 4) { // Header-type metadata stuff
> @@ -1287,6 +1458,11 @@ retry_duration:
> goto leave;
> }
>
> + if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && flv->meta_color_info_flag) {
> + flv_update_video_color_info(s, st); // update av packet side data
> + flv->meta_color_info_flag = 0;
> + }
> +
> if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
> (st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
> // sign extension
_______________________________________________
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 v4 1/3] avformat/flvdec: support enhanced flv PacketTypeMetadata
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 1/3] avformat/flvdec: " zhupengfei via ffmpeg-devel
2024-03-02 14:25 ` James Almer
@ 2024-03-02 15:05 ` Andreas Rheinhardt
1 sibling, 0 replies; 17+ messages in thread
From: Andreas Rheinhardt @ 2024-03-02 15:05 UTC (permalink / raw)
To: ffmpeg-devel
zhupengfei via ffmpeg-devel:
> From: Zhu Pengfei <411294962@qq.com>
>
> Signed-off-by: Zhu Pengfei <411294962@qq.com>
> ---
> libavformat/flvdec.c | 178 ++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 177 insertions(+), 1 deletion(-)
>
> diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c
> index e25b5bd163..d0806c5338 100644
> --- a/libavformat/flvdec.c
> +++ b/libavformat/flvdec.c
> @@ -34,6 +34,7 @@
> #include "libavutil/intfloat.h"
> #include "libavutil/intreadwrite.h"
> #include "libavutil/mathematics.h"
> +#include "libavutil/mastering_display_metadata.h"
Order it alphabetically (for the muxer, too).
> #include "avformat.h"
> #include "demux.h"
> #include "internal.h"
> @@ -45,6 +46,28 @@
>
> #define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
>
> +typedef struct FLVMasteringMeta {
> + double r_x;
> + double r_y;
> + double g_x;
> + double g_y;
> + double b_x;
> + double b_y;
> + double white_x;
> + double white_y;
> + double max_luminance;
> + double min_luminance;
> +} FLVMasteringMeta;
> +
> +typedef struct FLVMetaVideoColor {
> + uint64_t matrix_coefficients;
> + uint64_t transfer_characteristics;
> + uint64_t primaries;
> + uint64_t max_cll;
> + uint64_t max_fall;
> + FLVMasteringMeta mastering_meta;
> +} FLVMetaVideoColor;
> +
> typedef struct FLVContext {
> const AVClass *class; ///< Class for private options.
> int trust_metadata; ///< configure streams according onMetaData
> @@ -80,6 +103,8 @@ typedef struct FLVContext {
> int64_t time_offset;
> int64_t time_pos;
>
> + FLVMetaVideoColor *metaVideoColor;
> + int meta_color_info_flag;
> } FLVContext;
>
> /* AMF date type */
> @@ -524,6 +549,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
> FLVContext *flv = s->priv_data;
> AVIOContext *ioc;
> AMFDataType amf_type;
> + FLVMetaVideoColor *meta_video_color = flv->metaVideoColor;
> char str_val[1024];
> double num_val;
> amf_date date;
> @@ -672,6 +698,43 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream,
> }
> }
>
> + 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;
> + }
> + }
> + }
> +
> if (amf_type == AMF_DATA_TYPE_OBJECT && s->nb_streams == 1 &&
> ((!apar && !strcmp(key, "audiocodecid")) ||
> (!vpar && !strcmp(key, "videocodecid"))))
> @@ -824,6 +887,7 @@ static int flv_read_close(AVFormatContext *s)
> av_freep(&flv->new_extradata[i]);
> av_freep(&flv->keyframe_times);
> av_freep(&flv->keyframe_filepositions);
> + av_freep(&flv->metaVideoColor);
> return 0;
> }
>
> @@ -1028,6 +1092,104 @@ static int resync(AVFormatContext *s)
> return AVERROR_EOF;
> }
>
> +static int flv_parse_video_color_info(AVFormatContext *s, AVStream *st, int64_t next_pos)
> +{
> + FLVContext *flv = s->priv_data;
> + AMFDataType type;
> + AVIOContext *ioc;
> + char buffer[32];
> + ioc = s->pb;
> +
> + // first object needs to be "colorInfo" string
> + type = avio_r8(ioc);
> + if (type != AMF_DATA_TYPE_STRING ||
> + amf_get_string(ioc, buffer, sizeof(buffer)) < 0)
> + return TYPE_UNKNOWN;
> +
> + if (strcmp(buffer, "colorInfo")) {
> + av_log(s, AV_LOG_DEBUG, "Unknown type %s\n", buffer);
> + return TYPE_UNKNOWN;
> + }
> +
> + flv->metaVideoColor = av_mallocz(sizeof(FLVMetaVideoColor));
Why is this thing separately allocated?
> + if (!flv->metaVideoColor) {
> + return AVERROR(ENOMEM);
> + }
> + flv->meta_color_info_flag = 1;
> + amf_parse_object(s, NULL, NULL, buffer, next_pos, 0); // parse metadata
> + return 0;
> +}
> +
> +static int flv_update_video_color_info(AVFormatContext *s, AVStream *st)
> +{
> + FLVContext *flv = s->priv_data;
> + const FLVMetaVideoColor* meta_video_color = flv->metaVideoColor;
> + const FLVMasteringMeta *mastering_meta = &meta_video_color->mastering_meta;
> +
> + int has_mastering_primaries, has_mastering_luminance;
> + // Mastering primaries are CIE 1931 coords, and must be > 0.
> + has_mastering_primaries =
> + mastering_meta->r_x > 0 && mastering_meta->r_y > 0 &&
> + mastering_meta->g_x > 0 && mastering_meta->g_y > 0 &&
> + mastering_meta->b_x > 0 && mastering_meta->b_y > 0 &&
> + mastering_meta->white_x > 0 && mastering_meta->white_y > 0;
> + has_mastering_luminance = mastering_meta->max_luminance > 0 && mastering_meta->min_luminance > 0;
> +
> + if (meta_video_color->matrix_coefficients != AVCOL_SPC_RESERVED)
> + st->codecpar->color_space = meta_video_color->matrix_coefficients;
> + if (meta_video_color->primaries != AVCOL_PRI_RESERVED &&
> + meta_video_color->primaries != AVCOL_PRI_RESERVED0)
> + st->codecpar->color_primaries = meta_video_color->primaries;
> + if (meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED &&
> + meta_video_color->transfer_characteristics != AVCOL_TRC_RESERVED0)
> + st->codecpar->color_trc = meta_video_color->transfer_characteristics;
> +
> + if (meta_video_color->max_cll && meta_video_color->max_fall) {
> + size_t size = 0;
> + AVContentLightMetadata *metadata = av_content_light_metadata_alloc(&size);
> + if (!metadata)
> + return AVERROR(ENOMEM);
> + if (!av_packet_side_data_add(&st->codecpar->coded_side_data, &st->codecpar->nb_coded_side_data,
> + AV_PKT_DATA_CONTENT_LIGHT_LEVEL, metadata, size, 0)) {
> + av_freep(&metadata);
> + return AVERROR(ENOMEM);
> + }
> + metadata->MaxCLL = meta_video_color->max_cll;
> + metadata->MaxFALL = meta_video_color->max_fall;
> + }
> +
> + if (has_mastering_primaries || has_mastering_luminance) {
> + AVMasteringDisplayMetadata *metadata;
> + AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data,
> + &st->codecpar->nb_coded_side_data,
> + AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
> + sizeof(AVMasteringDisplayMetadata), 0);
> + if (!sd)
> + return AVERROR(ENOMEM);
> + metadata = (AVMasteringDisplayMetadata*)sd->data;
> + memset(metadata, 0, sizeof(AVMasteringDisplayMetadata));
> + // hdrCll
> + if (has_mastering_luminance) {
> + metadata->max_luminance = av_d2q(mastering_meta->max_luminance, INT_MAX);
> + metadata->min_luminance = av_d2q(mastering_meta->min_luminance, INT_MAX);
> + metadata->has_luminance = 1;
> + }
> + // hdrMdcv
> + if (has_mastering_primaries) {
> + metadata->display_primaries[0][0] = av_d2q(mastering_meta->r_x, INT_MAX);
> + metadata->display_primaries[0][1] = av_d2q(mastering_meta->r_y, INT_MAX);
> + metadata->display_primaries[1][0] = av_d2q(mastering_meta->g_x, INT_MAX);
> + metadata->display_primaries[1][1] = av_d2q(mastering_meta->g_y, INT_MAX);
> + metadata->display_primaries[2][0] = av_d2q(mastering_meta->b_x, INT_MAX);
> + metadata->display_primaries[2][1] = av_d2q(mastering_meta->b_y, INT_MAX);
> + metadata->white_point[0] = av_d2q(mastering_meta->white_x, INT_MAX);
> + metadata->white_point[1] = av_d2q(mastering_meta->white_y, INT_MAX);
> + metadata->has_primaries = 1;
> + }
> + }
> + return 0;
> +}
> +
> static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
> {
> FLVContext *flv = s->priv_data;
> @@ -1100,8 +1262,17 @@ retry:
> video_codec_id = avio_rb32(s->pb);
> size -= 4;
> }
> - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD)
> +
> + if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && (flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
> + type = flags & 0x0F;
> + if (type == PacketTypeMetadata) {
> + int ret = flv_parse_video_color_info(s, st, next);
> + av_log(s, AV_LOG_DEBUG, "enhanced flv parse metadata ret %d and skip\n", ret);
> + }
> + goto skip;
> + } else if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) {
> goto skip;
> + }
> } else if (type == FLV_TAG_TYPE_META) {
> stream_type=FLV_STREAM_TYPE_SUBTITLE;
> if (size > 13 + 1 + 4) { // Header-type metadata stuff
> @@ -1287,6 +1458,11 @@ retry_duration:
> goto leave;
> }
>
> + if (enhanced_flv && stream_type == FLV_STREAM_TYPE_VIDEO && flv->meta_color_info_flag) {
> + flv_update_video_color_info(s, st); // update av packet side data
> + flv->meta_color_info_flag = 0;
> + }
> +
> if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 ||
> (st->codecpar->codec_id == AV_CODEC_ID_HEVC && type == PacketTypeCodedFrames)) {
> // sign extension
_______________________________________________
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 v4 2/3] avformat/flvenc: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
` (6 preceding siblings ...)
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 1/3] avformat/flvdec: " zhupengfei via ffmpeg-devel
@ 2024-03-02 8:51 ` zhupengfei via ffmpeg-devel
2024-03-02 14:59 ` Andreas Rheinhardt
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 3/3] fate/flvenc: " zhupengfei via ffmpeg-devel
8 siblings, 1 reply; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-03-02 8:51 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
libavformat/flvenc.c | 142 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 142 insertions(+)
diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
index f6d10f331c..ae7ea84bad 100644
--- a/libavformat/flvenc.c
+++ b/libavformat/flvenc.c
@@ -24,6 +24,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
+#include "libavutil/mastering_display_metadata.h"
#include "libavcodec/codec_desc.h"
#include "libavcodec/mpeg4audio.h"
#include "avio.h"
@@ -124,6 +125,7 @@ typedef struct FLVContext {
int flags;
int64_t last_ts[FLV_STREAM_TYPE_NB];
+ int write_metadata_pkt;
} FLVContext;
static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
@@ -478,6 +480,145 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
avio_wb32(pb, flv->metadata_totalsize + 11);
}
+static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
+{
+ AVIOContext *pb = s->pb;
+ FLVContext *flv = s->priv_data;
+ AVContentLightMetadata *lightMetadata = NULL;
+ AVMasteringDisplayMetadata *displayMetadata = NULL;
+ const int flags_size = 5;
+ int64_t metadata_size_pos = 0;
+ int64_t total_size = 0;
+ const AVPacketSideData *side_data = NULL;
+
+ if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
+ par->codec_id == AV_CODEC_ID_VP9) {
+ if (flv->write_metadata_pkt) return;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
+ if (side_data)
+ lightMetadata = (AVContentLightMetadata *)side_data->data;
+
+ side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
+ AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
+ if (side_data)
+ displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
+
+ /*
+ * Reference Enhancing FLV
+ * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
+ * */
+ 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);
+
+ 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);
+ }
+
+ 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);
+
+ total_size = avio_tell(pb) - metadata_size_pos - 10;
+ avio_seek(pb, metadata_size_pos, SEEK_SET);
+ avio_wb24(pb, total_size);
+ avio_tell(pb);
+ avio_skip(pb, total_size + 10 - 3);
+ avio_tell(pb);
+ avio_wb32(pb, total_size + 11); // previous tag size
+ flv->write_metadata_pkt = 1;
+ }
+}
+
static int unsupported_codec(AVFormatContext *s,
const char* type, int codec_id)
{
@@ -878,6 +1019,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
memcpy(par->extradata, side, side_size);
flv_write_codec_header(s, par, pkt->dts);
}
+ flv_write_metadata_packet(s, par, pkt->dts);
}
if (flv->delay == AV_NOPTS_VALUE)
--
2.44.0
_______________________________________________
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 v4 2/3] avformat/flvenc: support enhanced flv PacketTypeMetadata
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 2/3] avformat/flvenc: " zhupengfei via ffmpeg-devel
@ 2024-03-02 14:59 ` Andreas Rheinhardt
2024-03-03 3:33 ` zhupengfei via ffmpeg-devel
0 siblings, 1 reply; 17+ messages in thread
From: Andreas Rheinhardt @ 2024-03-02 14:59 UTC (permalink / raw)
To: ffmpeg-devel
zhupengfei via ffmpeg-devel:
> From: Zhu Pengfei <411294962@qq.com>
>
> Signed-off-by: Zhu Pengfei <411294962@qq.com>
> ---
> libavformat/flvenc.c | 142 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 142 insertions(+)
>
> diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
> index f6d10f331c..ae7ea84bad 100644
> --- a/libavformat/flvenc.c
> +++ b/libavformat/flvenc.c
> @@ -24,6 +24,7 @@
> #include "libavutil/intfloat.h"
> #include "libavutil/avassert.h"
> #include "libavutil/mathematics.h"
> +#include "libavutil/mastering_display_metadata.h"
> #include "libavcodec/codec_desc.h"
> #include "libavcodec/mpeg4audio.h"
> #include "avio.h"
> @@ -124,6 +125,7 @@ typedef struct FLVContext {
>
> int flags;
> int64_t last_ts[FLV_STREAM_TYPE_NB];
> + int write_metadata_pkt;
Should be metadata_pkt_written to be consistent with its semantics.
> } FLVContext;
>
> static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
> @@ -478,6 +480,145 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
> avio_wb32(pb, flv->metadata_totalsize + 11);
> }
>
> +static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
> +{
> + AVIOContext *pb = s->pb;
> + FLVContext *flv = s->priv_data;
> + AVContentLightMetadata *lightMetadata = NULL;
> + AVMasteringDisplayMetadata *displayMetadata = NULL;
Can be constified.
> + const int flags_size = 5;
> + int64_t metadata_size_pos = 0;
> + int64_t total_size = 0;
> + const AVPacketSideData *side_data = NULL;
> +
> + if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
> + par->codec_id == AV_CODEC_ID_VP9) {
You can avoid one level of indentation by returning early here.
> + if (flv->write_metadata_pkt) return;
> +
> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
> + AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
> + if (side_data)
> + lightMetadata = (AVContentLightMetadata *)side_data->data;
> +
> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
> + AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
> + if (side_data)
> + displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
> +
> + /*
> + * Reference Enhancing FLV
> + * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
> + * */
> + 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);
> +
> + 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);
> + }
> +
> + 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);
> +
> + total_size = avio_tell(pb) - metadata_size_pos - 10;
> + avio_seek(pb, metadata_size_pos, SEEK_SET);
I see nothing that guarantees that this seek will succeed. In fact, this
whole muxer seems to presume that the output is seekable, without
checking so. Even worse: flv_write_header() clears the AVIOContext's
seekability field in case the FLV_NO_METADATA flag is set.
> + avio_wb24(pb, total_size);
> + avio_tell(pb);
> + avio_skip(pb, total_size + 10 - 3);
> + avio_tell(pb);
These two avio_tell() are useless.
> + avio_wb32(pb, total_size + 11); // previous tag size
> + flv->write_metadata_pkt = 1;
> + }
> +}
> +
> static int unsupported_codec(AVFormatContext *s,
> const char* type, int codec_id)
> {
> @@ -878,6 +1019,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
> memcpy(par->extradata, side, side_size);
> flv_write_codec_header(s, par, pkt->dts);
> }
> + flv_write_metadata_packet(s, par, pkt->dts);
> }
>
> if (flv->delay == AV_NOPTS_VALUE)
_______________________________________________
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 v4 2/3] avformat/flvenc: support enhanced flv PacketTypeMetadata
2024-03-02 14:59 ` Andreas Rheinhardt
@ 2024-03-03 3:33 ` zhupengfei via ffmpeg-devel
0 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-03-03 3:33 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: zhupengfei, andreas.rheinhardt
> 2024年3月2日 22:59,Andreas Rheinhardt <andreas.rheinhardt@outlook.com> 写道:
>
> zhupengfei via ffmpeg-devel:
>> From: Zhu Pengfei <411294962@qq.com>
>>
>> Signed-off-by: Zhu Pengfei <411294962@qq.com>
>> ---
>> libavformat/flvenc.c | 142 +++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 142 insertions(+)
>>
>> diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c
>> index f6d10f331c..ae7ea84bad 100644
>> --- a/libavformat/flvenc.c
>> +++ b/libavformat/flvenc.c
>> @@ -24,6 +24,7 @@
>> #include "libavutil/intfloat.h"
>> #include "libavutil/avassert.h"
>> #include "libavutil/mathematics.h"
>> +#include "libavutil/mastering_display_metadata.h"
>> #include "libavcodec/codec_desc.h"
>> #include "libavcodec/mpeg4audio.h"
>> #include "avio.h"
>> @@ -124,6 +125,7 @@ typedef struct FLVContext {
>>
>> int flags;
>> int64_t last_ts[FLV_STREAM_TYPE_NB];
>> + int write_metadata_pkt;
>
> Should be metadata_pkt_written to be consistent with its semantics.
>
>> } FLVContext;
>>
>> static int get_audio_flags(AVFormatContext *s, AVCodecParameters *par)
>> @@ -478,6 +480,145 @@ static void write_metadata(AVFormatContext *s, unsigned int ts)
>> avio_wb32(pb, flv->metadata_totalsize + 11);
>> }
>>
>> +static void flv_write_metadata_packet(AVFormatContext *s, AVCodecParameters *par, unsigned int ts)
>> +{
>> + AVIOContext *pb = s->pb;
>> + FLVContext *flv = s->priv_data;
>> + AVContentLightMetadata *lightMetadata = NULL;
>> + AVMasteringDisplayMetadata *displayMetadata = NULL;
>
> Can be constified.
>
>> + const int flags_size = 5;
>> + int64_t metadata_size_pos = 0;
>> + int64_t total_size = 0;
>> + const AVPacketSideData *side_data = NULL;
>> +
>> + if (par->codec_id == AV_CODEC_ID_HEVC || par->codec_id == AV_CODEC_ID_AV1 ||
>> + par->codec_id == AV_CODEC_ID_VP9) {
>
> You can avoid one level of indentation by returning early here.
>
>> + if (flv->write_metadata_pkt) return;
>> +
>> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
>> + AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
>> + if (side_data)
>> + lightMetadata = (AVContentLightMetadata *)side_data->data;
>> +
>> + side_data = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data,
>> + AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
>> + if (side_data)
>> + displayMetadata = (AVMasteringDisplayMetadata *)side_data->data;
>> +
>> + /*
>> + * Reference Enhancing FLV
>> + * https://github.com/veovera/enhanced-rtmp/blob/main/enhanced-rtmp.pdf
>> + * */
>> + 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);
>> +
>> + 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);
>> + }
>> +
>> + 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);
>> +
>> + total_size = avio_tell(pb) - metadata_size_pos - 10;
>> + avio_seek(pb, metadata_size_pos, SEEK_SET);
>
> I see nothing that guarantees that this seek will succeed. In fact, this
> whole muxer seems to presume that the output is seekable, without
> checking so. Even worse: flv_write_header() clears the AVIOContext's
> seekability field in case the FLV_NO_METADATA flag is set.
>
Hi Andreas: Thank you very much for your suggestion. The other comments have been modified.
1. "I see nothing that guarantees that this seek will succeed"
As you mentioned, most of the other muxer scenarios where avio_seek is used have no guarantees. In my thougth, it is relatively safe to use SEEK_SET to find the corresponding offset in this scenario.
2. "flv_write_header() clears the AVIOContext's seekability field in case the FLV_NO_METADATA flag is set"
I checked the corresponding commit log and it was submitted by Steven Liu, which looks more like an expected feature.
"avformat/flvenc: add no_metadata to flvflags some flv have no metadata, ffmpeg will same with the source flv stream."
>> + avio_wb24(pb, total_size);
>> + avio_tell(pb);
>> + avio_skip(pb, total_size + 10 - 3);
>> + avio_tell(pb);
>
> These two avio_tell() are useless.
>
>> + avio_wb32(pb, total_size + 11); // previous tag size
>> + flv->write_metadata_pkt = 1;
>> + }
>> +}
>> +
>> static int unsupported_codec(AVFormatContext *s,
>> const char* type, int codec_id)
>> {
>> @@ -878,6 +1019,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt)
>> memcpy(par->extradata, side, side_size);
>> flv_write_codec_header(s, par, pkt->dts);
>> }
>> + flv_write_metadata_packet(s, par, pkt->dts);
>> }
>>
>> if (flv->delay == AV_NOPTS_VALUE)
>
> _______________________________________________
> 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
* [FFmpeg-devel] [PATCH v4 3/3] fate/flvenc: support enhanced flv PacketTypeMetadata
2023-12-04 21:32 ` James Almer
` (7 preceding siblings ...)
2024-03-02 8:51 ` [FFmpeg-devel] [PATCH v4 2/3] avformat/flvenc: " zhupengfei via ffmpeg-devel
@ 2024-03-02 8:51 ` zhupengfei via ffmpeg-devel
8 siblings, 0 replies; 17+ messages in thread
From: zhupengfei via ffmpeg-devel @ 2024-03-02 8:51 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 411294962
From: Zhu Pengfei <411294962@qq.com>
Signed-off-by: Zhu Pengfei <411294962@qq.com>
---
tests/fate/lavf-container.mak | 2 ++
tests/ref/fate/enhanced-flv-hevc | 4 ++--
tests/ref/fate/enhanced-flv-vp9 | 4 ++--
tests/ref/lavf-fate/hevc.flv | 3 +++
4 files changed, 9 insertions(+), 4 deletions(-)
create mode 100644 tests/ref/lavf-fate/hevc.flv
diff --git a/tests/fate/lavf-container.mak b/tests/fate/lavf-container.mak
index fa7ecd2cb5..efef00d5b3 100644
--- a/tests/fate/lavf-container.mak
+++ b/tests/fate/lavf-container.mak
@@ -80,6 +80,7 @@ FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MOV_DEMUXER LATM_MUXER) +
FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MP3_DEMUXER MP3_MUXER) += mp3
FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MOV_DEMUXER MOV_MUXER) += qtrle_mace6.mov
FATE_LAVF_CONTAINER_FATE-$(call ALLYES, AVI_DEMUXER AVI_MUXER) += cram.avi
+FATE_LAVF_CONTAINER_FATE-$(call ALLYES, AVI_DEMUXER FLV_MUXER) += hevc.flv
FATE_LAVF_CONTAINER_FATE = $(FATE_LAVF_CONTAINER_FATE-yes:%=fate-lavf-fate-%)
@@ -96,6 +97,7 @@ fate-lavf-fate-latm: CMD = lavf_container_fate "aac/al04_44.mp4" "" "-acodec cop
fate-lavf-fate-mp3: CMD = lavf_container_fate "mp3-conformance/he_32khz.bit" "" "-acodec copy"
fate-lavf-fate-qtrle_mace6.mov: CMD = lavf_container_fate "qtrle/Animation-16Greys.mov" "-idct auto"
fate-lavf-fate-cram.avi: CMD = lavf_container_fate "cram/toon.avi" "-idct auto"
+fate-lavf-fate-hevc.flv: CMD = lavf_container_fate "mkv/hdr10tags-both.mkv" "" "-c:v copy"
FATE_SAMPLES_FFMPEG += $(FATE_LAVF_CONTAINER_FATE)
fate-lavf-fate fate-lavf: $(FATE_LAVF_CONTAINER_FATE)
diff --git a/tests/ref/fate/enhanced-flv-hevc b/tests/ref/fate/enhanced-flv-hevc
index 90b81fcc0f..f011d38a30 100644
--- a/tests/ref/fate/enhanced-flv-hevc
+++ b/tests/ref/fate/enhanced-flv-hevc
@@ -1,5 +1,5 @@
-25fb1fcdcfde498ab86a3387f1a7f833 *tests/data/fate/enhanced-flv-hevc.flv
-3602897 tests/data/fate/enhanced-flv-hevc.flv
+0da54607064548fa1aae5695751f189c *tests/data/fate/enhanced-flv-hevc.flv
+3603038 tests/data/fate/enhanced-flv-hevc.flv
#extradata 0: 551, 0xa18acf66
#extradata 1: 2, 0x00340022
#tb 0: 1/1000
diff --git a/tests/ref/fate/enhanced-flv-vp9 b/tests/ref/fate/enhanced-flv-vp9
index c9bcaa8029..1c70b52e6a 100644
--- a/tests/ref/fate/enhanced-flv-vp9
+++ b/tests/ref/fate/enhanced-flv-vp9
@@ -1,5 +1,5 @@
-f5cd49123111202ff220850e60f17ac4 *tests/data/fate/enhanced-flv-vp9.flv
-9388 tests/data/fate/enhanced-flv-vp9.flv
+7dae331e8e7a73e2e2288a31fe51104c *tests/data/fate/enhanced-flv-vp9.flv
+9441 tests/data/fate/enhanced-flv-vp9.flv
#extradata 0: 12, 0x03bc009d
#tb 0: 1/1000
#media_type 0: video
diff --git a/tests/ref/lavf-fate/hevc.flv b/tests/ref/lavf-fate/hevc.flv
new file mode 100644
index 0000000000..5f47c352fd
--- /dev/null
+++ b/tests/ref/lavf-fate/hevc.flv
@@ -0,0 +1,3 @@
+eca3b99e846e509c6957260b1ce4d82d *tests/data/lavf-fate/lavf.hevc.flv
+11784 tests/data/lavf-fate/lavf.hevc.flv
+tests/data/lavf-fate/lavf.hevc.flv CRC=0xd29da885
--
2.44.0
_______________________________________________
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