X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmxfenc.c;h=0acd74b3e796d8e83614492bac7047a9a80bd7bc;hb=2fd49019210a9fbe430b1b94ff7a2f98a6d0fed1;hp=c6532a34276f845cc1f8f43f63e47840203b168c;hpb=4b87a088bf5acad2a11e9f9c1dcec8f29bab3ec9;p=ffmpeg diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index c6532a34276..0acd74b3e79 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -35,10 +35,13 @@ #include #include +#include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavcodec/bytestream.h" +#include "libavcodec/timecode.h" #include "audiointerleave.h" #include "avformat.h" +#include "internal.h" #include "mxf.h" static const int NTSC_samples_per_frame[] = { 1602, 1601, 1602, 1601, 1602, 0 }; @@ -170,6 +173,7 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { }; typedef struct MXFContext { + AVClass *av_class; int64_t footer_partition_offset; int essence_container_count; AVRational time_base; @@ -183,10 +187,9 @@ typedef struct MXFContext { unsigned body_partitions_count; int last_key_index; ///< index of last key frame uint64_t duration; + struct ff_timecode tc; AVStream *timecode_track; int timecode_base; ///< rounded time code base (25 or 30) - int timecode_start; ///< frame number computed from mpeg-2 gop header timecode - int timecode_drop_frame; ///< time code use drop frame method frop mpeg-2 essence gop header int edit_unit_byte_count; ///< fixed edit unit byte count uint64_t body_offset; uint32_t instance_number; @@ -664,7 +667,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum // Start Time Code mxf_write_local_tag(pb, 8, 0x1501); - avio_wb64(pb, mxf->timecode_start); + avio_wb64(pb, mxf->tc.start); // Rounded Time Code Base mxf_write_local_tag(pb, 2, 0x1502); @@ -672,7 +675,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum // Drop Frame mxf_write_local_tag(pb, 1, 0x1503); - avio_w8(pb, mxf->timecode_drop_frame); + avio_w8(pb, mxf->tc.drop); } static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) @@ -1308,7 +1311,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt, MXFIndexEntry *e) { MXFStreamContext *sc = st->priv_data; - MXFContext *mxf = s->priv_data; uint32_t c = -1; int i; @@ -1328,21 +1330,6 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, if (e->flags & 0x40) // sequence header present e->flags |= 0x80; // random access } - if (!mxf->header_written) { - unsigned hours = (pkt->data[i+1]>>2) & 0x1f; - unsigned minutes = ((pkt->data[i+1] & 0x03) << 4) | (pkt->data[i+2]>>4); - unsigned seconds = ((pkt->data[i+2] & 0x07) << 3) | (pkt->data[i+3]>>5); - unsigned frames = ((pkt->data[i+3] & 0x1f) << 1) | (pkt->data[i+4]>>7); - mxf->timecode_drop_frame = !!(pkt->data[i+1] & 0x80); - mxf->timecode_start = (hours*3600 + minutes*60 + seconds) * - mxf->timecode_base + frames; - if (mxf->timecode_drop_frame) { - unsigned tminutes = 60 * hours + minutes; - mxf->timecode_start -= 2 * (tminutes - tminutes / 10); - } - av_log(s, AV_LOG_DEBUG, "frame %d %d:%d:%d%c%d\n", mxf->timecode_start, - hours, minutes, seconds, mxf->timecode_drop_frame ? ';':':', frames); - } } else if (c == 0x1b3) { // seq e->flags |= 0x40; switch ((pkt->data[i+4]>>4) & 0xf) { @@ -1407,6 +1394,8 @@ static int mxf_write_header(AVFormatContext *s) int i; uint8_t present[FF_ARRAY_ELEMS(mxf_essence_container_uls)] = {0}; const int *samples_per_frame = NULL; + AVDictionaryEntry *t; + int64_t timestamp = 0; if (!s->nb_streams) return -1; @@ -1436,6 +1425,12 @@ static int mxf_write_header(AVFormatContext *s) return -1; } av_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den); + if (mxf->tc.str) { + mxf->tc.rate.num = mxf->time_base.den; + mxf->tc.rate.den = mxf->time_base.num; + if (ff_init_smtpe_timecode(s, &mxf->tc) < 0) + return -1; + } if (s->oformat == &ff_mxf_d10_muxer) { if (st->codec->bit_rate == 50000000) if (mxf->time_base.den == 25) sc->index = 3; @@ -1512,8 +1507,15 @@ static int mxf_write_header(AVFormatContext *s) sc->order = AV_RB32(sc->track_essence_element_key+12); } +#if FF_API_TIMESTAMP if (s->timestamp) - mxf->timestamp = mxf_parse_timestamp(s->timestamp); + timestamp = s->timestamp; + else +#endif + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + timestamp = ff_iso8601_to_unix_time(t->value); + if (timestamp) + mxf->timestamp = mxf_parse_timestamp(timestamp); mxf->duration = -1; mxf->timecode_track = av_mallocz(sizeof(*mxf->timecode_track)); @@ -1536,24 +1538,6 @@ static int mxf_write_header(AVFormatContext *s) static const uint8_t system_metadata_pack_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x05,0x01,0x01,0x0D,0x01,0x03,0x01,0x04,0x01,0x01,0x00 }; static const uint8_t system_metadata_package_set_key[] = { 0x06,0x0E,0x2B,0x34,0x02,0x43,0x01,0x01,0x0D,0x01,0x03,0x01,0x04,0x01,0x02,0x01 }; -static uint32_t ff_framenum_to_12m_time_code(unsigned frame, int drop, int fps) -{ - return (0 << 31) | // color frame flag - (0 << 30) | // drop frame flag - ( ((frame % fps) / 10) << 28) | // tens of frames - ( ((frame % fps) % 10) << 24) | // units of frames - (0 << 23) | // field phase (NTSC), b0 (PAL) - ((((frame / fps) % 60) / 10) << 20) | // tens of seconds - ((((frame / fps) % 60) % 10) << 16) | // units of seconds - (0 << 15) | // b0 (NTSC), b2 (PAL) - ((((frame / (fps * 60)) % 60) / 10) << 12) | // tens of minutes - ((((frame / (fps * 60)) % 60) % 10) << 8) | // units of minutes - (0 << 7) | // b1 - (0 << 6) | // b2 (NSC), field phase (PAL) - ((((frame / (fps * 3600) % 24)) / 10) << 4) | // tens of hours - ( (frame / (fps * 3600) % 24)) % 10; // units of hours -} - static void mxf_write_system_item(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -1561,7 +1545,7 @@ static void mxf_write_system_item(AVFormatContext *s) unsigned frame; uint32_t time_code; - frame = mxf->timecode_start + mxf->last_indexed_edit_unit + mxf->edit_units_count; + frame = mxf->tc.start + mxf->last_indexed_edit_unit + mxf->edit_units_count; // write system metadata pack avio_write(pb, system_metadata_pack_key, 16); @@ -1582,7 +1566,11 @@ static void mxf_write_system_item(AVFormatContext *s) avio_wb64(pb, 0); // creation date/time stamp avio_w8(pb, 0x81); // SMPTE 12M time code - time_code = ff_framenum_to_12m_time_code(frame, mxf->timecode_drop_frame, mxf->timecode_base); + time_code = frame; + if (mxf->tc.drop) + time_code = ff_framenum_to_drop_timecode(time_code); + time_code = ff_framenum_to_smtpe_timecode(time_code, mxf->timecode_base, + mxf->tc.drop); avio_wb32(pb, time_code); avio_wb32(pb, 0); // binary group data avio_wb64(pb, 0); @@ -1879,34 +1867,43 @@ static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int mxf_interleave_get_packet, mxf_compare_timestamps); } +static const AVClass class = { + .class_name = "mxf", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = (const AVOption[]){ + {TIMECODE_OPT(MXFContext, AV_OPT_FLAG_ENCODING_PARAM)}, + {NULL} + }, +}; + AVOutputFormat ff_mxf_muxer = { - "mxf", - NULL_IF_CONFIG_SMALL("Material eXchange Format"), - "application/mxf", - "mxf", - sizeof(MXFContext), - CODEC_ID_PCM_S16LE, - CODEC_ID_MPEG2VIDEO, - mxf_write_header, - mxf_write_packet, - mxf_write_footer, - AVFMT_NOTIMESTAMPS, - NULL, - mxf_interleave, + .name = "mxf", + .long_name = NULL_IF_CONFIG_SMALL("Material eXchange Format"), + .mime_type = "application/mxf", + .extensions = "mxf", + .priv_data_size = sizeof(MXFContext), + .audio_codec = CODEC_ID_PCM_S16LE, + .video_codec = CODEC_ID_MPEG2VIDEO, + .write_header = mxf_write_header, + .write_packet = mxf_write_packet, + .write_trailer = mxf_write_footer, + .flags = AVFMT_NOTIMESTAMPS, + .interleave_packet = mxf_interleave, + .priv_class = &class, }; AVOutputFormat ff_mxf_d10_muxer = { - "mxf_d10", - NULL_IF_CONFIG_SMALL("Material eXchange Format, D-10 Mapping"), - "application/mxf", - NULL, - sizeof(MXFContext), - CODEC_ID_PCM_S16LE, - CODEC_ID_MPEG2VIDEO, - mxf_write_header, - mxf_write_packet, - mxf_write_footer, - AVFMT_NOTIMESTAMPS, - NULL, - mxf_interleave, + .name = "mxf_d10", + .long_name = NULL_IF_CONFIG_SMALL("Material eXchange Format, D-10 Mapping"), + .mime_type = "application/mxf", + .priv_data_size = sizeof(MXFContext), + .audio_codec = CODEC_ID_PCM_S16LE, + .video_codec = CODEC_ID_MPEG2VIDEO, + .write_header = mxf_write_header, + .write_packet = mxf_write_packet, + .write_trailer = mxf_write_footer, + .flags = AVFMT_NOTIMESTAMPS, + .interleave_packet = mxf_interleave, + .priv_class = &class, };