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 <michaelni@gmx.at>
This commit is contained in:
parent
fd1652b3ba
commit
2114e88432
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user