lavf/mxfdec: demux s436m as eia608 subtitle track
This commit is contained in:
@@ -52,6 +52,7 @@
|
|||||||
#include "libavutil/intreadwrite.h"
|
#include "libavutil/intreadwrite.h"
|
||||||
#include "libavutil/parseutils.h"
|
#include "libavutil/parseutils.h"
|
||||||
#include "libavutil/timecode.h"
|
#include "libavutil/timecode.h"
|
||||||
|
#include "libavutil/opt.h"
|
||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "mxf.h"
|
#include "mxf.h"
|
||||||
@@ -265,6 +266,7 @@ typedef struct MXFIndexTable {
|
|||||||
} MXFIndexTable;
|
} MXFIndexTable;
|
||||||
|
|
||||||
typedef struct MXFContext {
|
typedef struct MXFContext {
|
||||||
|
const AVClass *class; /**< Class for private options. */
|
||||||
MXFPartition *partitions;
|
MXFPartition *partitions;
|
||||||
unsigned partitions_count;
|
unsigned partitions_count;
|
||||||
MXFOP op;
|
MXFOP op;
|
||||||
@@ -287,6 +289,7 @@ typedef struct MXFContext {
|
|||||||
int last_forward_partition;
|
int last_forward_partition;
|
||||||
int nb_index_tables;
|
int nb_index_tables;
|
||||||
MXFIndexTable *index_tables;
|
MXFIndexTable *index_tables;
|
||||||
|
int eia608_extract;
|
||||||
} MXFContext;
|
} MXFContext;
|
||||||
|
|
||||||
/* NOTE: klv_offset is not set (-1) for local keys */
|
/* NOTE: klv_offset is not set (-1) for local keys */
|
||||||
@@ -449,6 +452,81 @@ static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset)
|
|||||||
return mxf->partitions[a].body_sid;
|
return mxf->partitions[a].body_sid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mxf_get_eia608_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt, int64_t length)
|
||||||
|
{
|
||||||
|
int count = avio_rb16(s->pb);
|
||||||
|
int cdp_identifier, cdp_length, cdp_footer_id, ccdata_id, cc_count;
|
||||||
|
int line_num, sample_coding, sample_count;
|
||||||
|
int did, sdid, data_length;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
if (count != 1)
|
||||||
|
av_log(s, AV_LOG_WARNING, "unsupported multiple ANC packets (%d) per KLV packet\n", count);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (length < 6) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "error reading s436m packet %"PRId64"\n", length);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
line_num = avio_rb16(s->pb);
|
||||||
|
avio_r8(s->pb); // wrapping type
|
||||||
|
sample_coding = avio_r8(s->pb);
|
||||||
|
sample_count = avio_rb16(s->pb);
|
||||||
|
length -= 6 + 8 + sample_count;
|
||||||
|
if (line_num != 9 && line_num != 11)
|
||||||
|
continue;
|
||||||
|
if (sample_coding == 7 || sample_coding == 8 || sample_coding == 9) {
|
||||||
|
av_log(s, AV_LOG_WARNING, "unsupported s436m 10 bit sample coding\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (length < 0)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
|
||||||
|
avio_rb32(s->pb); // array count
|
||||||
|
avio_rb32(s->pb); // array elem size
|
||||||
|
did = avio_r8(s->pb);
|
||||||
|
sdid = avio_r8(s->pb);
|
||||||
|
data_length = avio_r8(s->pb);
|
||||||
|
if (did != 0x61 || sdid != 1) {
|
||||||
|
av_log(s, AV_LOG_WARNING, "unsupported did or sdid: %x %x\n", did, sdid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cdp_identifier = avio_rb16(s->pb); // cdp id
|
||||||
|
if (cdp_identifier != 0x9669) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "wrong cdp identifier %x\n", cdp_identifier);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
cdp_length = avio_r8(s->pb);
|
||||||
|
avio_r8(s->pb); // cdp_frame_rate
|
||||||
|
avio_r8(s->pb); // cdp_flags
|
||||||
|
avio_rb16(s->pb); // cdp_hdr_sequence_cntr
|
||||||
|
ccdata_id = avio_r8(s->pb); // ccdata_id
|
||||||
|
if (ccdata_id != 0x72) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "wrong cdp data section %x\n", ccdata_id);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
cc_count = avio_r8(s->pb) & 0x1f;
|
||||||
|
ret = av_get_packet(s->pb, pkt, cc_count * 3);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (cdp_length - 9 - 4 < cc_count * 3) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "wrong cdp size %d cc count %d\n", cdp_length, cc_count);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
avio_skip(s->pb, data_length - 9 - 4 - cc_count * 3);
|
||||||
|
cdp_footer_id = avio_r8(s->pb);
|
||||||
|
if (cdp_footer_id != 0x74) {
|
||||||
|
av_log(s, AV_LOG_ERROR, "wrong cdp footer section %x\n", cdp_footer_id);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
avio_rb16(s->pb); // cdp_ftr_sequence_cntr
|
||||||
|
avio_r8(s->pb); // packet_checksum
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: use AVBitStreamFilter */
|
/* XXX: use AVBitStreamFilter */
|
||||||
static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
|
static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length)
|
||||||
{
|
{
|
||||||
@@ -2433,6 +2511,11 @@ static int mxf_parse_structural_metadata(MXFContext *mxf)
|
|||||||
st->codecpar->codec_type = type;
|
st->codecpar->codec_type = type;
|
||||||
if (container_ul->desc)
|
if (container_ul->desc)
|
||||||
av_dict_set(&st->metadata, "data_type", container_ul->desc, 0);
|
av_dict_set(&st->metadata, "data_type", container_ul->desc, 0);
|
||||||
|
if (mxf->eia608_extract &&
|
||||||
|
!strcmp(container_ul->desc, "vbi_vanc_smpte_436M")) {
|
||||||
|
st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
|
||||||
|
st->codecpar->codec_id = AV_CODEC_ID_EIA_608;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (descriptor->extradata) {
|
if (descriptor->extradata) {
|
||||||
if (!ff_alloc_extradata(st->codecpar, descriptor->extradata_size)) {
|
if (!ff_alloc_extradata(st->codecpar, descriptor->extradata_size)) {
|
||||||
@@ -3409,6 +3492,13 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
mxf->current_klv_data = (KLVPacket){{0}};
|
mxf->current_klv_data = (KLVPacket){{0}};
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
} else if (mxf->eia608_extract &&
|
||||||
|
s->streams[index]->codecpar->codec_id == AV_CODEC_ID_EIA_608) {
|
||||||
|
ret = mxf_get_eia608_packet(s, s->streams[index], pkt, klv.length);
|
||||||
|
if (ret < 0) {
|
||||||
|
mxf->current_klv_data = (KLVPacket){{0}};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = av_get_packet(s->pb, pkt, klv.length);
|
ret = av_get_packet(s->pb, pkt, klv.length);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -3607,6 +3697,21 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const AVOption options[] = {
|
||||||
|
{ "eia608_extract", "extract eia 608 captions from s436m track",
|
||||||
|
offsetof(MXFContext, eia608_extract), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1,
|
||||||
|
AV_OPT_FLAG_DECODING_PARAM },
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AVClass demuxer_class = {
|
||||||
|
.class_name = "mxf",
|
||||||
|
.item_name = av_default_item_name,
|
||||||
|
.option = options,
|
||||||
|
.version = LIBAVUTIL_VERSION_INT,
|
||||||
|
.category = AV_CLASS_CATEGORY_DEMUXER,
|
||||||
|
};
|
||||||
|
|
||||||
AVInputFormat ff_mxf_demuxer = {
|
AVInputFormat ff_mxf_demuxer = {
|
||||||
.name = "mxf",
|
.name = "mxf",
|
||||||
.long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"),
|
.long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"),
|
||||||
@@ -3617,4 +3722,5 @@ AVInputFormat ff_mxf_demuxer = {
|
|||||||
.read_packet = mxf_read_packet,
|
.read_packet = mxf_read_packet,
|
||||||
.read_close = mxf_read_close,
|
.read_close = mxf_read_close,
|
||||||
.read_seek = mxf_read_seek,
|
.read_seek = mxf_read_seek,
|
||||||
|
.priv_class = &demuxer_class,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user