You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
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:
committed by
Michael Niedermayer
parent
fd1652b3ba
commit
2114e88432
@@ -42,6 +42,8 @@
|
|||||||
#include "libavutil/time_internal.h"
|
#include "libavutil/time_internal.h"
|
||||||
#include "libavcodec/bytestream.h"
|
#include "libavcodec/bytestream.h"
|
||||||
#include "libavcodec/dnxhddata.h"
|
#include "libavcodec/dnxhddata.h"
|
||||||
|
#include "libavcodec/h264.h"
|
||||||
|
#include "libavcodec/internal.h"
|
||||||
#include "audiointerleave.h"
|
#include "audiointerleave.h"
|
||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
#include "avio_internal.h"
|
#include "avio_internal.h"
|
||||||
@@ -98,6 +100,7 @@ static const struct {
|
|||||||
{ AV_CODEC_ID_DVVIDEO, 15 },
|
{ AV_CODEC_ID_DVVIDEO, 15 },
|
||||||
{ AV_CODEC_ID_DNXHD, 24 },
|
{ AV_CODEC_ID_DNXHD, 24 },
|
||||||
{ AV_CODEC_ID_JPEG2000, 34 },
|
{ AV_CODEC_ID_JPEG2000, 34 },
|
||||||
|
{ AV_CODEC_ID_H264, 35 },
|
||||||
{ AV_CODEC_ID_NONE }
|
{ 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,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 },
|
{ 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 },
|
||||||
mxf_write_cdci_desc },
|
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 },
|
{ 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;
|
MXFStreamContext *sc = st->priv_data;
|
||||||
int profile_and_level = (st->codec->profile<<4) | st->codec->level;
|
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);
|
mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5);
|
||||||
|
|
||||||
// bit rate
|
// bit rate
|
||||||
@@ -1000,6 +1009,9 @@ static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st)
|
|||||||
if (!st->codec->profile)
|
if (!st->codec->profile)
|
||||||
profile_and_level |= 0x80; // escape bit
|
profile_and_level |= 0x80; // escape bit
|
||||||
avio_w8(pb, profile_and_level);
|
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)
|
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;
|
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[] = {
|
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,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
|
{ 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");
|
av_log(s, AV_LOG_ERROR, "could not get dv profile\n");
|
||||||
return -1;
|
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) {
|
if (!mxf->header_written) {
|
||||||
|
Reference in New Issue
Block a user