mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 21:00:41 +08:00
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 <jamrial@gmail.com>
This commit is contained in:
@@ -29,6 +29,7 @@ version <next>:
|
|||||||
- ffprobe: only show refs field in stream section when reading frames
|
- ffprobe: only show refs field in stream section when reading frames
|
||||||
- ProRes Vulkan encoder
|
- ProRes Vulkan encoder
|
||||||
- LCEVC parser
|
- LCEVC parser
|
||||||
|
- LCEVC enhancement layer exporting in MPEG-TS
|
||||||
|
|
||||||
|
|
||||||
version 8.0:
|
version 8.0:
|
||||||
|
|||||||
@@ -816,6 +816,7 @@ static const StreamType ISO_types[] = {
|
|||||||
{ STREAM_TYPE_VIDEO_JPEG2000, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEG2000 },
|
{ 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_HEVC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
|
||||||
{ STREAM_TYPE_VIDEO_JPEGXS, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEGXS },
|
{ 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_VVC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_VVC },
|
||||||
{ STREAM_TYPE_VIDEO_CAVS, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
|
{ STREAM_TYPE_VIDEO_CAVS, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
|
||||||
{ STREAM_TYPE_VIDEO_DIRAC, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_DIRAC },
|
{ 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 },
|
{ 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)
|
const uint8_t **pp, const uint8_t *desc_end)
|
||||||
{
|
{
|
||||||
|
MpegTSContext *ts = fc->priv_data;
|
||||||
int ext_tag = get8(pp, desc_end);
|
int ext_tag = get8(pp, desc_end);
|
||||||
|
|
||||||
switch (ext_tag) {
|
switch (ext_tag) {
|
||||||
@@ -1913,6 +1915,88 @@ static int parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st,
|
|||||||
st->codecpar->color_space = matrix_coefficients;
|
st->codecpar->color_space = matrix_coefficients;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1920,7 +2004,7 @@ static int parse_mpeg2_extension_descriptor(AVFormatContext *fc, AVStream *st,
|
|||||||
return 0;
|
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,
|
const uint8_t **pp, const uint8_t *desc_list_end,
|
||||||
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
|
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
|
||||||
MpegTSContext *ts)
|
MpegTSContext *ts)
|
||||||
@@ -2354,7 +2438,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type
|
|||||||
break;
|
break;
|
||||||
case EXTENSION_DESCRIPTOR: /* descriptor extension */
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
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)
|
if (desc_list_end > p_end)
|
||||||
goto out;
|
goto out;
|
||||||
for (;;) {
|
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,
|
desc_list_end, mp4_descr,
|
||||||
mp4_descr_count, pid, ts) < 0)
|
mp4_descr_count, pid, ts) < 0)
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -146,6 +146,7 @@
|
|||||||
#define STREAM_TYPE_VIDEO_HEVC 0x24
|
#define STREAM_TYPE_VIDEO_HEVC 0x24
|
||||||
#define STREAM_TYPE_VIDEO_JPEGXS 0x32
|
#define STREAM_TYPE_VIDEO_JPEGXS 0x32
|
||||||
#define STREAM_TYPE_VIDEO_VVC 0x33
|
#define STREAM_TYPE_VIDEO_VVC 0x33
|
||||||
|
#define STREAM_TYPE_VIDEO_LCEVC 0x36
|
||||||
#define STREAM_TYPE_VIDEO_CAVS 0x42
|
#define STREAM_TYPE_VIDEO_CAVS 0x42
|
||||||
#define STREAM_TYPE_VIDEO_AVS2 0xd2
|
#define STREAM_TYPE_VIDEO_AVS2 0xd2
|
||||||
#define STREAM_TYPE_VIDEO_AVS3 0xd4
|
#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 */
|
/* ISO/IEC 13818-1 Table 2-109 */
|
||||||
#define JXS_VIDEO_DESCRIPTOR 0x14 /* JPEG-XS descriptor */
|
#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
|
/* DVB descriptor tag values [0x40, 0x7F] from
|
||||||
ETSI EN 300 468 Table 12: Possible locations of descriptors */
|
ETSI EN 300 468 Table 12: Possible locations of descriptors */
|
||||||
@@ -288,7 +291,7 @@ typedef struct DVBAC3Descriptor {
|
|||||||
* @param desc_list_end End of buffer
|
* @param desc_list_end End of buffer
|
||||||
* @return <0 to stop processing
|
* @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,
|
const uint8_t **pp, const uint8_t *desc_list_end,
|
||||||
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
|
Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
|
||||||
MpegTSContext *ts);
|
MpegTSContext *ts);
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
|
|
||||||
#include "version_major.h"
|
#include "version_major.h"
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_MINOR 10
|
#define LIBAVFORMAT_VERSION_MINOR 11
|
||||||
#define LIBAVFORMAT_VERSION_MICRO 101
|
#define LIBAVFORMAT_VERSION_MICRO 100
|
||||||
|
|
||||||
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
|
||||||
LIBAVFORMAT_VERSION_MINOR, \
|
LIBAVFORMAT_VERSION_MINOR, \
|
||||||
|
|||||||
@@ -852,7 +852,7 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
consumed += buf_size;
|
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)) {
|
} else if (!ff_guidcmp(g, EVENTID_AudioTypeSpanningEvent)) {
|
||||||
int stream_index = ff_find_stream_index(s, sid);
|
int stream_index = ff_find_stream_index(s, sid);
|
||||||
|
|||||||
Reference in New Issue
Block a user