|
|
|
@ -63,7 +63,6 @@ typedef struct { |
|
|
|
|
UID track_essence_element_key; |
|
|
|
|
int index; ///< index in mxf_essence_container_uls table
|
|
|
|
|
const UID *codec_ul; |
|
|
|
|
int64_t duration; |
|
|
|
|
int order; ///< interleaving order if dts are equal
|
|
|
|
|
int interlaced; ///< wether picture is interlaced
|
|
|
|
|
int temporal_reordering; |
|
|
|
@ -124,6 +123,11 @@ typedef struct MXFContext { |
|
|
|
|
uint64_t *body_partition_offset; |
|
|
|
|
unsigned body_partitions_count; |
|
|
|
|
int last_key_index; ///< index of last key frame
|
|
|
|
|
uint64_t duration; |
|
|
|
|
AVStream *timecode_track; |
|
|
|
|
int timecode_base; ///< rounded time code base (25 or 30)
|
|
|
|
|
int timecode_start; ///< value from mpeg-2 essence gop header
|
|
|
|
|
int timecode_drop_frame; ///< time code use drop frame method frop mpeg-2 essence gop header
|
|
|
|
|
} MXFContext; |
|
|
|
|
|
|
|
|
|
static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; |
|
|
|
@ -194,6 +198,10 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { |
|
|
|
|
{ 0x1201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x03,0x01,0x04,0x00,0x00}}, /* Start position */ |
|
|
|
|
{ 0x1101, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x03,0x01,0x00,0x00,0x00}}, /* SourcePackageID */ |
|
|
|
|
{ 0x1102, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x03,0x02,0x00,0x00,0x00}}, /* SourceTrackID */ |
|
|
|
|
// Timecode Component
|
|
|
|
|
{ 0x1501, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x03,0x01,0x05,0x00,0x00}}, /* Start Time Code */ |
|
|
|
|
{ 0x1502, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x04,0x01,0x01,0x02,0x06,0x00,0x00}}, /* Rounded Time Code Base */ |
|
|
|
|
{ 0x1503, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x04,0x01,0x01,0x05,0x00,0x00,0x00}}, /* Drop Frame */ |
|
|
|
|
// File Descriptor
|
|
|
|
|
{ 0x3F01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x06,0x01,0x01,0x04,0x06,0x0B,0x00,0x00}}, /* Sub Descriptors reference array */ |
|
|
|
|
{ 0x3006, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x06,0x01,0x01,0x03,0x05,0x00,0x00,0x00}}, /* Linked Track ID */ |
|
|
|
@ -522,23 +530,32 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe |
|
|
|
|
mxf_write_uuid(pb, type == MaterialPackage ? Sequence: Sequence + TypeBottom, st->index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void mxf_write_common_fields(ByteIOContext *pb, AVStream *st) |
|
|
|
|
static const uint8_t smpte_12m_timecode_track_data_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x01,0x01,0x00,0x00,0x00 }; |
|
|
|
|
|
|
|
|
|
static void mxf_write_common_fields(AVFormatContext *s, AVStream *st) |
|
|
|
|
{ |
|
|
|
|
const MXFCodecUL *data_def_ul = mxf_get_data_definition_ul(st->codec->codec_type); |
|
|
|
|
MXFStreamContext *sc = st->priv_data; |
|
|
|
|
MXFContext *mxf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
|
|
|
|
|
// find data define uls
|
|
|
|
|
mxf_write_local_tag(pb, 16, 0x0201); |
|
|
|
|
put_buffer(pb, data_def_ul->uid, 16); |
|
|
|
|
if (st == mxf->timecode_track) |
|
|
|
|
put_buffer(pb, smpte_12m_timecode_track_data_ul, 16); |
|
|
|
|
else { |
|
|
|
|
const MXFCodecUL *data_def_ul = mxf_get_data_definition_ul(st->codec->codec_type); |
|
|
|
|
put_buffer(pb, data_def_ul->uid, 16); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// write duration
|
|
|
|
|
mxf_write_local_tag(pb, 8, 0x0202); |
|
|
|
|
put_be64(pb, sc->duration); |
|
|
|
|
put_be64(pb, mxf->duration); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) |
|
|
|
|
{ |
|
|
|
|
MXFContext *mxf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
enum MXFMetadataSetType component; |
|
|
|
|
|
|
|
|
|
mxf_write_metadata_key(pb, 0x010f00); |
|
|
|
|
PRINT_KEY(s, "sequence key", pb->buf_ptr - 16); |
|
|
|
@ -548,12 +565,45 @@ static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadat |
|
|
|
|
mxf_write_uuid(pb, type == MaterialPackage ? Sequence: Sequence + TypeBottom, st->index); |
|
|
|
|
|
|
|
|
|
PRINT_KEY(s, "sequence uid", pb->buf_ptr - 16); |
|
|
|
|
mxf_write_common_fields(pb, st); |
|
|
|
|
mxf_write_common_fields(s, st); |
|
|
|
|
|
|
|
|
|
// write structural component
|
|
|
|
|
mxf_write_local_tag(pb, 16 + 8, 0x1001); |
|
|
|
|
mxf_write_refs_count(pb, 1); |
|
|
|
|
mxf_write_uuid(pb, type == MaterialPackage ? SourceClip: SourceClip + TypeBottom, st->index); |
|
|
|
|
if (st == mxf->timecode_track) |
|
|
|
|
component = TimecodeComponent; |
|
|
|
|
else if (type == MaterialPackage) |
|
|
|
|
component = SourceClip; |
|
|
|
|
else |
|
|
|
|
component = SourceClip+TypeBottom; |
|
|
|
|
mxf_write_uuid(pb, component, st->index); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st) |
|
|
|
|
{ |
|
|
|
|
MXFContext *mxf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
|
|
|
|
|
mxf_write_metadata_key(pb, 0x011400); |
|
|
|
|
klv_encode_ber_length(pb, 75); |
|
|
|
|
|
|
|
|
|
// UID
|
|
|
|
|
mxf_write_local_tag(pb, 16, 0x3C0A); |
|
|
|
|
mxf_write_uuid(pb, TimecodeComponent, st->index); |
|
|
|
|
|
|
|
|
|
mxf_write_common_fields(s, st); |
|
|
|
|
|
|
|
|
|
// Start Time Code
|
|
|
|
|
mxf_write_local_tag(pb, 8, 0x1501); |
|
|
|
|
put_be64(pb, mxf->timecode_start); |
|
|
|
|
|
|
|
|
|
// Rounded Time Code Base
|
|
|
|
|
mxf_write_local_tag(pb, 2, 0x1502); |
|
|
|
|
put_be16(pb, mxf->timecode_base); |
|
|
|
|
|
|
|
|
|
// Drop Frame
|
|
|
|
|
mxf_write_local_tag(pb, 1, 0x1503); |
|
|
|
|
put_byte(pb, mxf->timecode_drop_frame); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) |
|
|
|
@ -570,7 +620,7 @@ static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enu |
|
|
|
|
mxf_write_uuid(pb, type == MaterialPackage ? SourceClip: SourceClip + TypeBottom, st->index); |
|
|
|
|
|
|
|
|
|
PRINT_KEY(s, "structural component uid", pb->buf_ptr - 16); |
|
|
|
|
mxf_write_common_fields(pb, st); |
|
|
|
|
mxf_write_common_fields(s, st); |
|
|
|
|
|
|
|
|
|
// write start_position
|
|
|
|
|
mxf_write_local_tag(pb, 8, 0x1201); |
|
|
|
@ -773,16 +823,18 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type) |
|
|
|
|
{ |
|
|
|
|
MXFContext *mxf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
int i; |
|
|
|
|
int i, track_count; |
|
|
|
|
|
|
|
|
|
if (type == MaterialPackage) { |
|
|
|
|
track_count = s->nb_streams + 1; // add timecode track
|
|
|
|
|
mxf_write_metadata_key(pb, 0x013600); |
|
|
|
|
PRINT_KEY(s, "Material Package key", pb->buf_ptr - 16); |
|
|
|
|
klv_encode_ber_length(pb, 92 + 16 * s->nb_streams); |
|
|
|
|
klv_encode_ber_length(pb, 92 + 16*track_count); |
|
|
|
|
} else { |
|
|
|
|
track_count = s->nb_streams; |
|
|
|
|
mxf_write_metadata_key(pb, 0x013700); |
|
|
|
|
PRINT_KEY(s, "Source Package key", pb->buf_ptr - 16); |
|
|
|
|
klv_encode_ber_length(pb, 112 + 16 * s->nb_streams); // 20 bytes length for descriptor reference
|
|
|
|
|
klv_encode_ber_length(pb, 112 + 16*track_count); // 20 bytes length for descriptor reference
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// write uid
|
|
|
|
@ -805,10 +857,12 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type) |
|
|
|
|
put_be64(pb, mxf->timestamp); |
|
|
|
|
|
|
|
|
|
// write track refs
|
|
|
|
|
mxf_write_local_tag(pb, s->nb_streams * 16 + 8, 0x4403); |
|
|
|
|
mxf_write_refs_count(pb, s->nb_streams); |
|
|
|
|
mxf_write_local_tag(pb, track_count*16 + 8, 0x4403); |
|
|
|
|
mxf_write_refs_count(pb, track_count); |
|
|
|
|
for (i = 0; i < s->nb_streams; i++) |
|
|
|
|
mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, i); |
|
|
|
|
if (type == MaterialPackage) |
|
|
|
|
mxf_write_uuid(pb, Track, s->nb_streams); // timecode track
|
|
|
|
|
|
|
|
|
|
// write multiple descriptor reference
|
|
|
|
|
if (type == SourcePackage) { |
|
|
|
@ -818,6 +872,11 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type) |
|
|
|
|
mxf_write_multi_descriptor(s); |
|
|
|
|
} else |
|
|
|
|
mxf_write_uuid(pb, SubDescriptor, 0); |
|
|
|
|
} else { |
|
|
|
|
// write timecode track
|
|
|
|
|
mxf_write_track(s, mxf->timecode_track, type); |
|
|
|
|
mxf_write_sequence(s, mxf->timecode_track, type); |
|
|
|
|
mxf_write_timecode_component(s, mxf->timecode_track); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (i = 0; i < s->nb_streams; i++) { |
|
|
|
@ -1220,9 +1279,11 @@ static int mxf_write_header(AVFormatContext *s) |
|
|
|
|
if (fabs(av_q2d(st->codec->time_base) - 1/25.0) < 0.0001) { |
|
|
|
|
samples_per_frame = PAL_samples_per_frame; |
|
|
|
|
mxf->time_base = (AVRational){ 1, 25 }; |
|
|
|
|
mxf->timecode_base = 25; |
|
|
|
|
} else if (fabs(av_q2d(st->codec->time_base) - 1001/30000.0) < 0.0001) { |
|
|
|
|
samples_per_frame = NTSC_samples_per_frame; |
|
|
|
|
mxf->time_base = (AVRational){ 1001, 30000 }; |
|
|
|
|
mxf->timecode_base = 30; |
|
|
|
|
} else { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "unsupported video frame rate\n"); |
|
|
|
|
return -1; |
|
|
|
@ -1236,7 +1297,6 @@ static int mxf_write_header(AVFormatContext *s) |
|
|
|
|
av_set_pts_info(st, 64, 1, st->codec->sample_rate); |
|
|
|
|
mxf->slice_count = 1; |
|
|
|
|
} |
|
|
|
|
sc->duration = -1; |
|
|
|
|
|
|
|
|
|
sc->index = mxf_get_essence_container_ul_index(st->codec->codec_id); |
|
|
|
|
if (sc->index == -1) { |
|
|
|
@ -1265,6 +1325,15 @@ static int mxf_write_header(AVFormatContext *s) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
mxf->timestamp = mxf_parse_timestamp(s->timestamp); |
|
|
|
|
mxf->duration = -1; |
|
|
|
|
|
|
|
|
|
mxf->timecode_track = av_mallocz(sizeof(*mxf->timecode_track)); |
|
|
|
|
if (!mxf->timecode_track) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
mxf->timecode_track->priv_data = av_mallocz(sizeof(MXFStreamContext)); |
|
|
|
|
if (!mxf->timecode_track->priv_data) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
mxf->timecode_track->index = s->nb_streams; |
|
|
|
|
|
|
|
|
|
if (!samples_per_frame) |
|
|
|
|
samples_per_frame = PAL_samples_per_frame; |
|
|
|
@ -1300,7 +1369,7 @@ static void mxf_write_system_item(AVFormatContext *s) |
|
|
|
|
{ |
|
|
|
|
MXFContext *mxf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
unsigned fps, frame; |
|
|
|
|
unsigned frame; |
|
|
|
|
uint32_t time_code; |
|
|
|
|
|
|
|
|
|
frame = mxf->last_indexed_edit_unit + mxf->edit_units_count; |
|
|
|
@ -1321,12 +1390,8 @@ static void mxf_write_system_item(AVFormatContext *s) |
|
|
|
|
put_be64(pb, 0); |
|
|
|
|
put_be64(pb, 0); // creation date/time stamp
|
|
|
|
|
|
|
|
|
|
// XXX drop frame
|
|
|
|
|
if (mxf->time_base.den == 30000) fps = 30; |
|
|
|
|
else fps = 25; |
|
|
|
|
|
|
|
|
|
put_byte(pb, 0x81); // SMPTE 12M time code
|
|
|
|
|
time_code = ff_framenum_to_12m_time_code(frame, 0, fps); |
|
|
|
|
time_code = ff_framenum_to_12m_time_code(frame, mxf->timecode_drop_frame, mxf->timecode_base); |
|
|
|
|
put_be32(pb, time_code); |
|
|
|
|
put_be32(pb, 0); // binary group data
|
|
|
|
|
put_be64(pb, 0); |
|
|
|
@ -1396,8 +1461,6 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
klv_encode_ber_length(pb, pkt->size); // write length
|
|
|
|
|
put_buffer(pb, pkt->data, pkt->size); // write value
|
|
|
|
|
|
|
|
|
|
sc->duration = FFMAX(pkt->pts + pkt->duration, sc->duration); |
|
|
|
|
|
|
|
|
|
put_flush_packet(pb); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
@ -1431,6 +1494,8 @@ static int mxf_write_footer(AVFormatContext *s) |
|
|
|
|
MXFContext *mxf = s->priv_data; |
|
|
|
|
ByteIOContext *pb = s->pb; |
|
|
|
|
|
|
|
|
|
mxf->duration = mxf->last_indexed_edit_unit + mxf->edit_units_count; |
|
|
|
|
|
|
|
|
|
mxf_write_klv_fill(s); |
|
|
|
|
mxf->footer_partition_offset = url_ftell(pb); |
|
|
|
|
mxf_write_partition(s, 0, 2, footer_partition_key, 0); |
|
|
|
@ -1450,6 +1515,8 @@ static int mxf_write_footer(AVFormatContext *s) |
|
|
|
|
|
|
|
|
|
av_freep(&mxf->index_entries); |
|
|
|
|
av_freep(&mxf->body_partition_offset); |
|
|
|
|
av_freep(&mxf->timecode_track->priv_data); |
|
|
|
|
av_freep(&mxf->timecode_track); |
|
|
|
|
|
|
|
|
|
mxf_free(s); |
|
|
|
|
return 0; |
|
|
|
|