diff options
author | Matthieu Bouron <matthieu.bouron@gmail.com> | 2012-05-26 20:09:47 +0400 |
---|---|---|
committer | Matthieu Bouron <matthieu.bouron@gmail.com> | 2012-07-05 15:34:43 +0400 |
commit | 135e6843114a06f8dde4d8ad0ea39a3b77b5a795 (patch) | |
tree | 8db698b70ec457c55c037bb626f7fbf960813047 /libavformat/mxfenc.c | |
parent | 325fb246f257547b56c39c545fc193e40fe5b590 (diff) |
mxfenc: support smpte dv codec
After some internal talks it seems the code is similar to what is in FFmbc
by Baptiste Coudurier; Baptiste accepted to relicense the similiar chunks
from GPL to LGPL.
Diffstat (limited to 'libavformat/mxfenc.c')
-rw-r--r-- | libavformat/mxfenc.c | 131 |
1 files changed, 128 insertions, 3 deletions
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 5597dd2c33..2d255ff006 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -43,6 +43,7 @@ #include "avformat.h" #include "internal.h" #include "mxf.h" +#include "config.h" static const int NTSC_samples_per_frame[] = { 1602, 1601, 1602, 1601, 1602, 0 }; static const int NTSC_60_samples_per_frame[] = { 801, 801, 801, 801, 800, 0 }; @@ -93,6 +94,7 @@ static const struct { { CODEC_ID_MPEG2VIDEO, 0 }, { CODEC_ID_PCM_S24LE, 1 }, { CODEC_ID_PCM_S16LE, 1 }, + { CODEC_ID_DVVIDEO, 15 }, { CODEC_ID_NONE } }; @@ -169,6 +171,51 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x06,0x01,0x10,0x00 }, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, mxf_write_generic_sound_desc }, + // DV Unknwon + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x7F,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x00,0x00,0x00 }, + mxf_write_cdci_desc }, + // DV25 525/60 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x40,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x01,0x00 }, + mxf_write_cdci_desc }, + // DV25 625/50 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x02,0x00 }, + mxf_write_cdci_desc }, + // DV50 525/60 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x50,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x03,0x00 }, + mxf_write_cdci_desc }, + // DV50 625/50 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x51,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x04,0x00 }, + mxf_write_cdci_desc }, + // DV100 1080/60 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x60,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x05,0x00 }, + mxf_write_cdci_desc }, + // DV100 1080/50 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x61,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x06,0x00 }, + mxf_write_cdci_desc }, + // DV100 720/60 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x62,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x07,0x00 }, + mxf_write_cdci_desc }, + // DV100 720/50 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x02,0x63,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x08,0x00 }, + mxf_write_cdci_desc }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, @@ -830,9 +877,9 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke // video line map switch (st->codec->height) { - case 576: f1 = 23; f2 = 336; break; + case 576: f1 = 23; f2 = st->codec->codec_id == CODEC_ID_DVVIDEO ? 335 : 336; break; case 608: f1 = 7; f2 = 320; break; - case 480: f1 = 20; f2 = 283; break; + case 480: f1 = 20; f2 = st->codec->codec_id == CODEC_ID_DVVIDEO ? 285 : 283; break; case 512: f1 = 7; f2 = 270; break; case 720: f1 = 26; f2 = 0; break; // progressive case 1080: f1 = 21; f2 = 584; break; @@ -1291,6 +1338,76 @@ static void mxf_write_partition(AVFormatContext *s, int bodysid, avio_flush(pb); } +static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + MXFContext *mxf = s->priv_data; + MXFStreamContext *sc = st->priv_data; + uint8_t *vs_pack, *vsc_pack; + int i, ul_index, frame_size, stype, pal; + + if (mxf->header_written) + return 1; + + // Check for minimal frame size + if (pkt->size < 120000) + return -1; + + vs_pack = pkt->data + 80*5 + 48; + vsc_pack = pkt->data + 80*5 + 53; + stype = vs_pack[3] & 0x1f; + pal = (vs_pack[3] >> 5) & 0x1; + + if ((vs_pack[2] & 0x07) == 0x02) + sc->aspect_ratio = (AVRational){ 16, 9 }; + else + sc->aspect_ratio = (AVRational){ 4, 3 }; + + sc->interlaced = (vsc_pack[3] >> 4) & 0x01; + // TODO: fix dv encoder to set proper FF/FS value in VSC pack + // and set field dominance accordingly + // av_log(s, AV_LOG_DEBUG, "DV vsc pack ff/ss = %x\n", vsc_pack[2] >> 6); + + switch (stype) { + case 0x18: // DV100 720p + ul_index = 6 + pal; + frame_size = pal ? 288000 : 240000; + if (sc->interlaced) { + av_log(s, AV_LOG_ERROR, "source marked as interlaced but codec profile is progressive"); + sc->interlaced = 0; + } + break; + case 0x14: // DV100 1080i + ul_index = 4 + pal; + frame_size = pal ? 576000 : 480000; + break; + case 0x04: // DV50 + ul_index = 2 + pal; + frame_size = pal ? 288000 : 240000; + break; + default: // DV25 + ul_index = 0 + pal; + frame_size = pal ? 144000 : 120000; + } + + sc->index = ul_index + 16; + sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul; + + mxf->edit_unit_byte_count = KAG_SIZE; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + MXFStreamContext *sc = st->priv_data; + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size; + mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); + } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + mxf->edit_unit_byte_count += 16 + 4 + frame_size; + mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); + } + } + + return 1; +} + static const UID mxf_mpeg2_codec_uls[] = { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x10,0x00 }, // MP-ML I-Frame { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x03,0x04,0x01,0x02,0x02,0x01,0x01,0x11,0x00 }, // MP-ML Long GOP @@ -1537,7 +1654,10 @@ static int mxf_write_header(AVFormatContext *s) MXFStreamContext *sc = s->streams[i]->priv_data; // update element count sc->track_essence_element_key[13] = present[sc->index]; - sc->order = AV_RB32(sc->track_essence_element_key+12); + if (!memcmp(sc->track_essence_element_key, mxf_essence_container_uls[15].element_ul, 13)) // DV + sc->order = (0x15 << 24) | AV_RB32(sc->track_essence_element_key+13); + else + sc->order = AV_RB32(sc->track_essence_element_key+12); } if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) @@ -1691,6 +1811,11 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "could not get mpeg2 profile and level\n"); return -1; } + } else if (st->codec->codec_id == CODEC_ID_DVVIDEO) { + if (!mxf_parse_dv_frame(s, st, pkt)) { + av_log(s, AV_LOG_ERROR, "could not get dv profile\n"); + return -1; + } } if (!mxf->header_written) { |