aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat/mxfenc.c
diff options
context:
space:
mode:
authorBaptiste Coudurier <baptiste.coudurier@gmail.com>2009-02-11 07:18:00 +0000
committerBaptiste Coudurier <baptiste.coudurier@gmail.com>2009-02-11 07:18:00 +0000
commit7c9668cf8af529976b5275a4f5d8df5489402c75 (patch)
tree4f90e6a8959aabb6da68ae0ac837ccc90c3d056e /libavformat/mxfenc.c
parent898189880bc624e3e1bdfc05fb2d238b3229fe98 (diff)
downloadffmpeg-7c9668cf8af529976b5275a4f5d8df5489402c75.tar.gz
write timecode track
Originally committed as revision 17148 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavformat/mxfenc.c')
-rw-r--r--libavformat/mxfenc.c113
1 files changed, 90 insertions, 23 deletions
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 1a9fe46008..f87d4dd88f 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -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;