[FFmpeg-devel] [PATCH] mxf : allow using codecs RAWVIDEO and V210
Michael Krebs
michael.krebs at hemeria-group.com
Wed Aug 4 14:51:57 EEST 2021
---
libavformat/mxf.c | 17 ++++
libavformat/mxf.h | 1 +
libavformat/mxfenc.c | 181 +++++++++++++++++++++++++++++++++----------
3 files changed, 156 insertions(+), 43 deletions(-)
diff --git a/libavformat/mxf.c b/libavformat/mxf.c
index 36d662b58c..677d69e3ab 100644
--- a/libavformat/mxf.c
+++ b/libavformat/mxf.c
@@ -81,6 +81,8 @@ const MXFCodecUL ff_mxf_codec_uls[] = {
const MXFCodecUL ff_mxf_pixel_format_uls[] = {
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x01,0x01 }, 16, AV_PIX_FMT_UYVY422 },
{ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x01,0x02 }, 16, AV_PIX_FMT_YUYV422 },
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x01,0x03 }, 16, AV_PIX_FMT_YUV422P },
+ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x03,0x01,0x02 }, 16, AV_PIX_FMT_YUV420P },
{ { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_PIX_FMT_NONE },
};
@@ -183,6 +185,21 @@ int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *
return -1;
}
+int ff_mxf_find_pixel_layout(const char** pixel_layout, const enum AVPixelFormat pix_fmt)
+{
+ int x;
+ *pixel_layout = NULL;
+
+ for(x = 0; x < num_pixel_layouts; x++) {
+ if(ff_mxf_pixel_layouts[x].pix_fmt == pix_fmt) {
+ *pixel_layout = ff_mxf_pixel_layouts[x].data;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
/**
* See SMPTE 326M-2000 Section 7.2 Content package rate
* MXFContentPackageRate->rate is bits b5..b0.
diff --git a/libavformat/mxf.h b/libavformat/mxf.h
index fe9c52732c..fa4a4eb0d2 100644
--- a/libavformat/mxf.h
+++ b/libavformat/mxf.h
@@ -114,6 +114,7 @@ extern const MXFCodecUL ff_mxf_color_trc_uls[];
extern const MXFCodecUL ff_mxf_color_space_uls[];
int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *pix_fmt);
+int ff_mxf_find_pixel_layout(const char** pixel_layout, const enum AVPixelFormat pix_fmt);
int ff_mxf_get_content_package_rate(AVRational time_base);
diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c
index 5ec619675b..a2ec7b89d7 100644
--- a/libavformat/mxfenc.c
+++ b/libavformat/mxfenc.c
@@ -127,6 +127,8 @@ enum ULIndex {
INDEX_H264,
INDEX_S436M,
INDEX_PRORES,
+ INDEX_RAWVIDEO,
+ INDEX_V210
};
static const struct {
@@ -141,6 +143,8 @@ static const struct {
{ AV_CODEC_ID_JPEG2000, INDEX_JPEG2000 },
{ AV_CODEC_ID_H264, INDEX_H264 },
{ AV_CODEC_ID_PRORES, INDEX_PRORES },
+ { AV_CODEC_ID_RAWVIDEO, INDEX_RAWVIDEO },
+ { AV_CODEC_ID_V210, INDEX_V210 },
{ AV_CODEC_ID_NONE }
};
@@ -148,6 +152,7 @@ static void mxf_write_wav_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_aes3_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st);
+static void mxf_write_cdci_or_rgba_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st);
static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st);
@@ -205,6 +210,16 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = {
{ 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x17,0x00 },
{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x03,0x00 },
mxf_write_cdci_desc },
+ // RawVideo
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, // MXF-GC Uncompressed Pictures
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, // GC Picture Essence
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x01,0x7F,0x00,0x00,0x00 }, // Uncompressed
+ mxf_write_cdci_or_rgba_desc },
+ // V210
+ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, // MXF-GC Uncompressed Pictures
+ { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, // GC Picture Essence
+ { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x02,0x01 }, // V210
+ 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 },
@@ -346,6 +361,8 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = {
{ 0x3304, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x03,0x03,0x00,0x00,0x00}}, /* Black Ref level */
{ 0x3305, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x03,0x04,0x00,0x00,0x00}}, /* White Ref level */
{ 0x3306, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x03,0x05,0x00,0x00,0x00}}, /* Color Range */
+ // RGBA Picture Essence Descriptor
+ { 0x3401, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x03,0x06,0x00,0x00,0x00}}, /* Pixel Layout */
// Generic Sound Essence Descriptor
{ 0x3D02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x04,0x02,0x03,0x01,0x04,0x00,0x00,0x00}}, /* Locked/Unlocked */
{ 0x3D03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x01,0x01,0x01,0x00,0x00}}, /* Audio sampling rate */
@@ -1047,7 +1064,7 @@ static void mxf_write_multi_descriptor(AVFormatContext *s)
mxf_write_uuid(pb, SubDescriptor, i);
}
-static int64_t mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID key)
+static int64_t mxf_write_file_desc(AVFormatContext *s, AVStream *st, const UID key)
{
MXFContext *mxf = s->priv_data;
MXFStreamContext *sc = st->priv_data;
@@ -1090,6 +1107,7 @@ static const UID mxf_mpegvideo_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,
static const UID mxf_wav_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 };
static const UID mxf_aes3_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 };
static const UID mxf_cdci_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x28,0x00 };
+static const UID mxf_rgba_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x29,0x00 };
static const UID mxf_generic_sound_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x42,0x00 };
static const UID mxf_avc_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6E,0x00 };
@@ -1104,7 +1122,7 @@ static inline uint32_t rescale_mastering_luma(AVRational q)
return av_rescale(q.num, FF_MXF_MASTERING_LUMA_DEN, q.den);
}
-static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key)
+static int64_t mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID key)
{
MXFStreamContext *sc = st->priv_data;
AVIOContext *pb = s->pb;
@@ -1115,7 +1133,7 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
const MXFCodecUL *color_primaries_ul;
const MXFCodecUL *color_trc_ul;
const MXFCodecUL *color_space_ul;
- int64_t pos = mxf_write_generic_desc(s, st, key);
+ int64_t pos = mxf_write_file_desc(s, st, key);
uint8_t *side_data;
color_primaries_ul = mxf_get_codec_ul_by_id(ff_mxf_color_primaries_uls, st->codecpar->color_primaries);
@@ -1131,6 +1149,8 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
if (!stored_width)
stored_width = (st->codecpar->width+15)/16*16;
+ // TODO: V210 ==> Stored Width shall be a multiple of 48.
+
mxf_write_local_tag(s, 4, 0x3203);
avio_wb32(pb, stored_width);
@@ -1194,43 +1214,6 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
avio_wb32(pb, -((st->codecpar->height - display_height)&1));
}
- // component depth
- mxf_write_local_tag(s, 4, 0x3301);
- avio_wb32(pb, sc->component_depth);
-
- // horizontal subsampling
- mxf_write_local_tag(s, 4, 0x3302);
- avio_wb32(pb, sc->h_chroma_sub_sample);
-
- // vertical subsampling
- mxf_write_local_tag(s, 4, 0x3308);
- avio_wb32(pb, sc->v_chroma_sub_sample);
-
- // color siting
- mxf_write_local_tag(s, 1, 0x3303);
- avio_w8(pb, sc->color_siting);
-
- // Padding Bits
- mxf_write_local_tag(s, 2, 0x3307);
- avio_wb16(pb, 0);
-
- if (st->codecpar->color_range != AVCOL_RANGE_UNSPECIFIED) {
- int black = 0,
- white = (1<<sc->component_depth) - 1,
- color = (1<<sc->component_depth);
- if (st->codecpar->color_range == AVCOL_RANGE_MPEG) {
- black = 1 << (sc->component_depth - 4);
- white = 235 << (sc->component_depth - 8);
- color = (14 << (sc->component_depth - 4)) + 1;
- }
- mxf_write_local_tag(s, 4, 0x3304);
- avio_wb32(pb, black);
- mxf_write_local_tag(s, 4, 0x3305);
- avio_wb32(pb, white);
- mxf_write_local_tag(s, 4, 0x3306);
- avio_wb32(pb, color);
- }
-
if (sc->signal_standard) {
mxf_write_local_tag(s, 1, 0x3215);
avio_w8(pb, sc->signal_standard);
@@ -1256,7 +1239,6 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
f1 *= 2;
}
-
mxf_write_local_tag(s, 16, 0x320D);
avio_wb32(pb, 2);
avio_wb32(pb, 4);
@@ -1328,6 +1310,52 @@ static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID
return pos;
}
+static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key)
+{
+ MXFStreamContext *sc = st->priv_data;
+ AVIOContext *pb = s->pb;
+ int64_t pos = mxf_write_generic_desc(s, st, key);
+
+ // component depth
+ mxf_write_local_tag(s, 4, 0x3301);
+ avio_wb32(pb, sc->component_depth);
+
+ // horizontal subsampling
+ mxf_write_local_tag(s, 4, 0x3302);
+ avio_wb32(pb, sc->h_chroma_sub_sample);
+
+ // vertical subsampling
+ mxf_write_local_tag(s, 4, 0x3308);
+ avio_wb32(pb, sc->v_chroma_sub_sample);
+
+ // color siting
+ mxf_write_local_tag(s, 1, 0x3303);
+ avio_w8(pb, sc->color_siting);
+
+ // Padding Bits
+ mxf_write_local_tag(s, 2, 0x3307);
+ avio_wb16(pb, 0);
+
+ if (st->codecpar->color_range != AVCOL_RANGE_UNSPECIFIED) {
+ int black = 0,
+ white = (1<<sc->component_depth) - 1,
+ color = (1<<sc->component_depth);
+ if (st->codecpar->color_range == AVCOL_RANGE_MPEG) {
+ black = 1 << (sc->component_depth - 4);
+ white = 235 << (sc->component_depth - 8);
+ color = (14 << (sc->component_depth - 4)) + 1;
+ }
+ mxf_write_local_tag(s, 4, 0x3304);
+ avio_wb32(pb, black);
+ mxf_write_local_tag(s, 4, 0x3305);
+ avio_wb32(pb, white);
+ mxf_write_local_tag(s, 4, 0x3306);
+ avio_wb32(pb, color);
+ }
+
+ return pos;
+}
+
static void mxf_update_klv_size(AVIOContext *pb, int64_t pos)
{
int64_t cur_pos = avio_tell(pb);
@@ -1361,6 +1389,32 @@ static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st)
mxf_update_klv_size(s->pb, pos);
}
+static void mxf_write_cdci_or_rgba_desc(AVFormatContext *s, AVStream *st)
+{
+ AVIOContext *pb = s->pb;
+ const char* pixelLayoutData = NULL;
+ int64_t pos;
+
+ if(ff_mxf_find_pixel_layout(&pixelLayoutData, st->codecpar->format) >= 0)
+ {
+ pos = mxf_write_generic_desc(s, st, mxf_rgba_descriptor_key);
+
+ // pixel layout
+ mxf_write_local_tag(s, 16, 0x3401);
+ avio_write(pb, pixelLayoutData, 16);
+
+ mxf_update_klv_size(s->pb, pos);
+ return;
+ }
+
+ pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
+ mxf_update_klv_size(s->pb, pos);
+
+ if (st->codecpar->codec_id == AV_CODEC_ID_H264) {
+ mxf_write_avc_subdesc(s, st);
+ }
+}
+
static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st)
{
int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key);
@@ -1385,7 +1439,7 @@ static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st)
static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st)
{
- int64_t pos = mxf_write_generic_desc(s, st, mxf_s436m_anc_descriptor_key);
+ int64_t pos = mxf_write_file_desc(s, st, mxf_s436m_anc_descriptor_key);
mxf_update_klv_size(s->pb, pos);
}
@@ -1432,7 +1486,7 @@ static int64_t mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st,
AVIOContext *pb = s->pb;
MXFContext *mxf = s->priv_data;
int show_warnings = !mxf->footer_partition_offset;
- int64_t pos = mxf_write_generic_desc(s, st, key);
+ int64_t pos = mxf_write_file_desc(s, st, key);
if (s->oformat == &ff_mxf_opatom_muxer) {
mxf_write_local_tag(s, 8, 0x3002);
@@ -2348,6 +2402,42 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st,
return 1;
}
+static int mxf_parse_raw_frame(AVFormatContext *s, AVStream *st,
+ AVPacket *pkt, MXFIndexEntry *e)
+{
+ MXFContext *mxf = s->priv_data;
+ MXFStreamContext *sc = st->priv_data;
+ const MXFCodecUL* uls = ff_mxf_pixel_format_uls;
+ const char* pixelLayoutData = NULL;
+ int format;
+
+ if (mxf->header_written)
+ return 1;
+
+ format = st->codecpar->format;
+
+ if(ff_mxf_find_pixel_layout(&pixelLayoutData, format) < 0)
+ {
+ while (uls->uid[0]) {
+ if (format == uls->id) {
+ sc->codec_ul = &uls->uid;
+ break;
+ }
+ uls++;
+ }
+
+ if (!uls->uid[0])
+ {
+ av_log(s, AV_LOG_ERROR, "no codec ul available for pixel format %s\n", av_get_pix_fmt_name(format));
+ return 0;
+ }
+ }
+
+ sc->frame_size = pkt->size;
+
+ 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
@@ -2929,6 +3019,11 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt)
av_log(s, AV_LOG_ERROR, "could not get h264 profile\n");
return -1;
}
+ } else if (st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) {
+ if (!mxf_parse_raw_frame(s, st, pkt, &ie)) {
+ av_log(s, AV_LOG_ERROR, "could not get raw profile\n");
+ return -1;
+ }
}
if (mxf->cbr_index) {
--
2.20.1
More information about the ffmpeg-devel
mailing list