From 2114e8843256f6c1d5a3c450f8ed19cd8fbdcdd5 Mon Sep 17 00:00:00 2001 From: Thomas Mundt Date: Tue, 28 Oct 2014 22:38:22 +0000 Subject: avformat/mxfenc: AVC Intra support To keep h264 parsing simple and fast, I used the framesize for selecting the right Panasonic codec label. The framesize is fixed for Panasonic AVC Intra. This patch only supports AVCI50/100. But in all flavours, i.e. with no SPS/PPS in header. Reviewed-by: tomas.hardin@codemill.se Signed-off-by: Michael Niedermayer --- libavformat/mxfenc.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) (limited to 'libavformat') diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index ac05677f99..d05b6969b1 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -42,6 +42,8 @@ #include "libavutil/time_internal.h" #include "libavcodec/bytestream.h" #include "libavcodec/dnxhddata.h" +#include "libavcodec/h264.h" +#include "libavcodec/internal.h" #include "audiointerleave.h" #include "avformat.h" #include "avio_internal.h" @@ -98,6 +100,7 @@ static const struct { { AV_CODEC_ID_DVVIDEO, 15 }, { AV_CODEC_ID_DNXHD, 24 }, { AV_CODEC_ID_JPEG2000, 34 }, + { AV_CODEC_ID_H264, 35 }, { AV_CODEC_ID_NONE } }; @@ -274,6 +277,11 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x08,0x00 }, { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, mxf_write_cdci_desc }, + // H.264 + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x10,0x60,0x01 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 }, + mxf_write_mpegvideo_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 }, @@ -989,6 +997,7 @@ static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st) MXFStreamContext *sc = st->priv_data; int profile_and_level = (st->codec->profile<<4) | st->codec->level; + if (st->codec->codec_id != AV_CODEC_ID_H264) { mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5); // bit rate @@ -1000,6 +1009,9 @@ static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st) if (!st->codec->profile) profile_and_level |= 0x80; // escape bit avio_w8(pb, profile_and_level); + } else { + mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 0); + } } static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size) @@ -1572,6 +1584,95 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) return 1; } +static const struct { + UID uid; + int frame_size; + int profile; + uint8_t interlaced; +} mxf_h264_codec_uls[] = { + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 }, 0, 110, 0 }, // AVC High 10 Intra + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960, 0, 1 }, // AVC Intra 50 1080i60 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088, 0, 1 }, // AVC Intra 50 1080i50 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960, 0, 0 }, // AVC Intra 50 1080p30 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, 281088, 0, 0 }, // AVC Intra 50 1080p25 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736, 0, 0 }, // AVC Intra 50 720p60 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, 140800, 0, 0 }, // AVC Intra 50 720p50 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 }, 0, 122, 0 }, // AVC High 422 Intra + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576, 0, 1 }, // AVC Intra 100 1080i60 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832, 0, 1 }, // AVC Intra 100 1080i50 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576, 0, 0 }, // AVC Intra 100 1080p30 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, 568832, 0, 0 }, // AVC Intra 100 1080p25 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544, 0, 0 }, // AVC Intra 100 720p60 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, 284672, 0, 0 }, // AVC Intra 100 720p50 +}; + +static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, + AVPacket *pkt, MXFIndexEntry *e) +{ + MXFContext *mxf = s->priv_data; + MXFStreamContext *sc = st->priv_data; + static const int mxf_h264_num_codec_uls = sizeof(mxf_h264_codec_uls) / sizeof(mxf_h264_codec_uls[0]); + const uint8_t *buf = pkt->data; + const uint8_t *buf_end = pkt->data + pkt->size; + uint32_t state = -1; + int extra_size = 512; // support AVC Intra files without SPS/PPS header + int i, frame_size; + uint8_t uid_found; + + if (pkt->size > extra_size) + buf_end -= pkt->size - extra_size; // no need to parse beyond SPS/PPS header + + for (;;) { + buf = avpriv_find_start_code(buf, buf_end, &state); + if (buf >= buf_end) + break; + --buf; + switch (state & 0x1f) { + case NAL_SPS: + st->codec->profile = buf[1]; + e->flags |= 0x40; + break; + case NAL_PPS: + if (e->flags & 0x40) { // sequence header present + e->flags |= 0x80; // random access + extra_size = 0; + buf = buf_end; + } + break; + default: + break; + } + } + + if (mxf->header_written) + return 1; + + sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD + sc->component_depth = 10; // AVC Intra is always 10 Bit + sc->interlaced = st->codec->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0; + if (sc->interlaced) + sc->field_dominance = 1; // top field first is mandatory for AVC Intra + + uid_found = 0; + frame_size = pkt->size + extra_size; + for (i = 0; i < mxf_h264_num_codec_uls; i++) { + if (frame_size == mxf_h264_codec_uls[i].frame_size && sc->interlaced == mxf_h264_codec_uls[i].interlaced) { + sc->codec_ul = &mxf_h264_codec_uls[i].uid; + return 1; + } else if (st->codec->profile == mxf_h264_codec_uls[i].profile) { + sc->codec_ul = &mxf_h264_codec_uls[i].uid; + uid_found = 1; + } + } + + if (!uid_found) { + av_log(s, AV_LOG_ERROR, "AVC Intra 50/100 supported only\n"); + return 0; + } + + 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 @@ -1978,6 +2079,11 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "could not get dv profile\n"); return -1; } + } else if (st->codec->codec_id == AV_CODEC_ID_H264) { + if (!mxf_parse_h264_frame(s, st, pkt, &ie)) { + av_log(s, AV_LOG_ERROR, "could not get h264 profile\n"); + return -1; + } } if (!mxf->header_written) { -- cgit v1.2.3