This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit b9cb948ec158ec451ec79ec86de926914c89ec4c Author: James Almer <[email protected]> AuthorDate: Mon Mar 2 19:49:57 2026 -0300 Commit: James Almer <[email protected]> CommitDate: Sat Mar 7 19:22:42 2026 -0300 avformat/mpegts: add support for LCEVC streams As defined in ITU-T H.222.0 v9, LCEVC streams use the "Byte stream format" defined in Annex B of ISO/IEC 23094-2:2021. Signed-off-by: James Almer <[email protected]> --- Changelog | 1 + libavformat/mpegts.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++--- libavformat/mpegts.h | 5 ++- libavformat/version.h | 4 +-- libavformat/wtvdec.c | 2 +- 5 files changed, 96 insertions(+), 8 deletions(-) diff --git a/Changelog b/Changelog index 6c90b02063..91a2e5fee3 100644 --- a/Changelog +++ b/Changelog @@ -29,6 +29,7 @@ version <next>: - ffprobe: only show refs field in stream section when reading frames - ProRes Vulkan encoder - LCEVC parser +- LCEVC enhancement layer exporting in MPEG-TS version 8.0: diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index a9094ab55b..0ee10f9a77 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -816,6 +816,7 @@ static const StreamType ISO_types[] = { { STREAM_TYPE_VIDEO_JPEG2000, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEG2000 }, { STREAM_TYPE_VIDEO_HEVC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC }, { STREAM_TYPE_VIDEO_JPEGXS, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEGXS }, + { STREAM_TYPE_VIDEO_LCEVC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_LCEVC }, { STREAM_TYPE_VIDEO_VVC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VVC }, { STREAM_TYPE_VIDEO_CAVS, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS }, { STREAM_TYPE_VIDEO_DIRAC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC }, @@ -1834,9 +1835,10 @@ static const uint8_t opus_channel_map[8][8] = { { 0,6,1,2,3,4,5,7 }, }; -static int parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st, +static int parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st, int prg_id, const uint8_t **pp, const uint8_t *desc_end) { + MpegTSContext *ts = fc->priv_data; int ext_tag = get8(pp, desc_end); switch (ext_tag) { @@ -1913,6 +1915,88 @@ static int parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st, st->codecpar->color_space = matrix_coefficients; } break; + case LCEVC_VIDEO_DESCRIPTOR: + { + AVStreamGroup *stg = NULL; + int lcevc_stream_tag = get8(pp, desc_end); + int ret, i; + + if (!get_program(ts, prg_id)) + return 0; + + if (st->codecpar->codec_id != AV_CODEC_ID_LCEVC) + return AVERROR_INVALIDDATA; + + for (i = 0; i < fc->nb_stream_groups; i++) { + stg = fc->stream_groups[i]; + if (stg->type != AV_STREAM_GROUP_PARAMS_LCEVC) + continue; + if (stg->id == lcevc_stream_tag) + break; + } + if (i == fc->nb_stream_groups) + stg = avformat_stream_group_create(fc, AV_STREAM_GROUP_PARAMS_LCEVC, NULL); + if (!stg) + return AVERROR(ENOMEM); + + stg->id = lcevc_stream_tag; + for (i = 0; i < stg->nb_streams; i++) { + if (stg->streams[i]->codecpar->codec_id == AV_CODEC_ID_LCEVC) + break; + } + if (i == stg->nb_streams) { + ret = avformat_stream_group_add_stream(stg, st); + av_assert0(ret != AVERROR(EEXIST)); + if (ret < 0) + return ret; + } else + stg->streams[i] = st; + + av_assert0(i < stg->nb_streams); + stg->params.lcevc->lcevc_index = i; + } + break; + case LCEVC_LINKAGE_DESCRIPTOR: + { + int num_lcevc_stream_tags = get8(pp, desc_end); + + if (!get_program(ts, prg_id)) + return 0; + + if (st->codecpar->codec_id == AV_CODEC_ID_LCEVC) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < num_lcevc_stream_tags; i++) { + AVStreamGroup *stg = NULL; + int lcevc_stream_tag = get8(pp, desc_end);; + int ret, j; + + for (j = 0; j < fc->nb_stream_groups; j++) { + stg = fc->stream_groups[j]; + if (stg->type != AV_STREAM_GROUP_PARAMS_LCEVC) + continue; + if (stg->id == lcevc_stream_tag) + break; + } + if (j == fc->nb_stream_groups) + stg = avformat_stream_group_create(fc, AV_STREAM_GROUP_PARAMS_LCEVC, NULL); + if (!stg) + return AVERROR(ENOMEM); + + stg->id = lcevc_stream_tag; + for (j = 0; j < stg->nb_streams; j++) { + if (stg->streams[j]->index == st->index) + break; + } + if (j == stg->nb_streams) { + ret = avformat_stream_group_add_stream(stg, st); + av_assert0(ret != AVERROR(EEXIST)); + if (ret < 0) + return ret; + } + } + } + break; default: break; } @@ -1920,7 +2004,7 @@ static int parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st, return 0; } -int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, +int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, int prg_id, const uint8_t **pp, const uint8_t *desc_list_end, Mp4Descr *mp4_descr, int mp4_descr_count, int pid, MpegTSContext *ts) @@ -2354,7 +2438,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type break; case EXTENSION_DESCRIPTOR: /* descriptor extension */ { - int ret = parse_mpeg2_extension_descriptor(fc, st, pp, desc_end); + int ret = parse_mpeg2_extension_descriptor(fc, st, prg_id, pp, desc_end); if (ret < 0) return ret; @@ -2643,7 +2727,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (desc_list_end > p_end) goto out; for (;;) { - if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, + if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, h->id, &p, desc_list_end, mp4_descr, mp4_descr_count, pid, ts) < 0) break; diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h index 223962d18e..18f326b8bf 100644 --- a/libavformat/mpegts.h +++ b/libavformat/mpegts.h @@ -146,6 +146,7 @@ #define STREAM_TYPE_VIDEO_HEVC 0x24 #define STREAM_TYPE_VIDEO_JPEGXS 0x32 #define STREAM_TYPE_VIDEO_VVC 0x33 +#define STREAM_TYPE_VIDEO_LCEVC 0x36 #define STREAM_TYPE_VIDEO_CAVS 0x42 #define STREAM_TYPE_VIDEO_AVS2 0xd2 #define STREAM_TYPE_VIDEO_AVS3 0xd4 @@ -208,6 +209,8 @@ https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/ /* ISO/IEC 13818-1 Table 2-109 */ #define JXS_VIDEO_DESCRIPTOR 0x14 /* JPEG-XS descriptor */ +#define LCEVC_VIDEO_DESCRIPTOR 0x17 /* LCEVC video descriptor */ +#define LCEVC_LINKAGE_DESCRIPTOR 0x18 /* LCEVC linkage descriptor */ /* DVB descriptor tag values [0x40, 0x7F] from ETSI EN 300 468 Table 12: Possible locations of descriptors */ @@ -288,7 +291,7 @@ typedef struct DVBAC3Descriptor { * @param desc_list_end End of buffer * @return <0 to stop processing */ -int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, +int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type, int prg_id, const uint8_t **pp, const uint8_t *desc_list_end, Mp4Descr *mp4_descr, int mp4_descr_count, int pid, MpegTSContext *ts); diff --git a/libavformat/version.h b/libavformat/version.h index 787ee8c90b..1055753772 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,8 +31,8 @@ #include "version_major.h" -#define LIBAVFORMAT_VERSION_MINOR 10 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 11 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c index 50d019a03f..088f15f87e 100644 --- a/libavformat/wtvdec.c +++ b/libavformat/wtvdec.c @@ -852,7 +852,7 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p if (ret < 0) return ret; consumed += buf_size; - ff_parse_mpeg2_descriptor(s, st, 0, &pbuf, buf + buf_size, NULL, 0, 0, NULL); + ff_parse_mpeg2_descriptor(s, st, 0, -1, &pbuf, buf + buf_size, NULL, 0, 0, NULL); } } else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) { int stream_index = ff_find_stream_index(s, sid); _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
