From 8071dca3d595a4fc5f9b3ee9f667e2c3e4a35517 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Fri, 14 Sep 2012 22:26:14 +0200 Subject: [PATCH 1/2] matroska: implement support for ALAC Support Matroska native formatting. On demuxing reconstruct the 36-bytes QuickTime atom that the ALAC decoder expects by prepending the "atom size", "tag" and "tag version" fields missing from the Matroska's CodecPrivate element. On muxing remove the initial 12 bytes Sample files are available: http://www.bunkus.org/videotools/mkvtoolnix/samples/alac/alac-in-matroska.mka and the CoreAudio file it was created from with today's mkvmerge: http://www.bunkus.org/videotools/mkvtoolnix/samples/alac/alac-in-matroska-source.caf Signed-off-by: Luca Barbato --- libavformat/matroska.c | 1 + libavformat/matroskadec.c | 13 +++++++++++++ libavformat/matroskaenc.c | 10 ++++++++++ 3 files changed, 24 insertions(+) diff --git a/libavformat/matroska.c b/libavformat/matroska.c index d2d07a8eca..652e4d0b03 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -24,6 +24,7 @@ const CodecTags ff_mkv_codec_tags[]={ {"A_AAC" , AV_CODEC_ID_AAC}, {"A_AC3" , AV_CODEC_ID_AC3}, + {"A_ALAC" , AV_CODEC_ID_ALAC}, {"A_DTS" , AV_CODEC_ID_DTS}, {"A_EAC3" , AV_CODEC_ID_EAC3}, {"A_FLAC" , AV_CODEC_ID_FLAC}, diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index ff2a6c29dc..69a8c7f06e 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1528,6 +1528,19 @@ static int matroska_read_header(AVFormatContext *s) extradata_size = 5; } else extradata_size = 2; + } else if (codec_id == AV_CODEC_ID_ALAC && track->codec_priv.size) { + /* Only ALAC's magic cookie is stored in Matroska's track headers. + Create the "atom size", "tag", and "tag version" fields the + decoder expects manually. */ + extradata_size = 12 + track->codec_priv.size; + extradata = av_mallocz(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + if (extradata == NULL) + return AVERROR(ENOMEM); + AV_WB32(extradata, extradata_size); + memcpy(&extradata[4], "alac", 4); + AV_WB32(&extradata[8], 0); + memcpy(&extradata[12], track->codec_priv.data, + track->codec_priv.size); } else if (codec_id == AV_CODEC_ID_TTA) { extradata_size = 30; extradata = av_mallocz(extradata_size); diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 9d9c223dbb..521f6b5c1a 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -475,6 +475,16 @@ static int mkv_write_codecprivate(AVFormatContext *s, AVIOContext *pb, AVCodecCo ret = ff_flac_write_header(dyn_cp, codec, 1); else if (codec->codec_id == AV_CODEC_ID_H264) ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); + else if (codec->codec_id == AV_CODEC_ID_ALAC) { + if (codec->extradata_size < 36) { + av_log(s, AV_LOG_ERROR, + "Invalid extradata found, ALAC expects a 36-byte " + "QuickTime atom."); + ret = AVERROR_INVALIDDATA; + } else + avio_write(dyn_cp, codec->extradata + 12, + codec->extradata_size - 12); + } else if (codec->extradata_size) avio_write(dyn_cp, codec->extradata, codec->extradata_size); } else if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { From 117d8c6d1f1c187ffc6098d9618457e00534e013 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Sat, 15 Sep 2012 00:59:05 +0200 Subject: [PATCH 2/2] matroska: implement support for ProRes Support Matroska native formatting. On demuxing prepend a Frame container atom (32bit big endian encoded frame size and 'icpf' string). On muxing remove it. --- libavformat/matroska.c | 1 + libavformat/matroskadec.c | 15 +++++++++++++-- libavformat/matroskaenc.c | 12 ++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/libavformat/matroska.c b/libavformat/matroska.c index 652e4d0b03..edb7ab7910 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -71,6 +71,7 @@ const CodecTags ff_mkv_codec_tags[]={ {"V_MPEG4/ISO/SP" , AV_CODEC_ID_MPEG4}, {"V_MPEG4/ISO/AVC" , AV_CODEC_ID_H264}, {"V_MPEG4/MS/V3" , AV_CODEC_ID_MSMPEG4V3}, + {"V_PRORES" , AV_CODEC_ID_PRORES}, {"V_REAL/RV10" , AV_CODEC_ID_RV10}, {"V_REAL/RV20" , AV_CODEC_ID_RV20}, {"V_REAL/RV30" , AV_CODEC_ID_RV30}, diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 69a8c7f06e..c00ebaac8e 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -37,6 +37,7 @@ #include "isom.h" #include "rm.h" #include "matroska.h" +#include "libavcodec/bytestream.h" #include "libavcodec/mpeg4audio.h" #include "libavutil/intfloat.h" #include "libavutil/intreadwrite.h" @@ -1966,6 +1967,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, MatroskaTrackEncoding *encodings = track->encodings.elem; uint32_t pkt_size = lace_size[n]; uint8_t *pkt_data = data; + int offset = 0; if (encodings && encodings->scope & 1) { res = matroska_decode_buffer(&pkt_data, &pkt_size, track); @@ -1973,15 +1975,24 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, break; } + if (st->codec->codec_id == AV_CODEC_ID_PRORES) + offset = 8; + pkt = av_mallocz(sizeof(AVPacket)); /* XXX: prevent data copy... */ - if (av_new_packet(pkt, pkt_size) < 0) { + if (av_new_packet(pkt, pkt_size + offset) < 0) { av_free(pkt); res = AVERROR(ENOMEM); break; } - memcpy(pkt->data, pkt_data, pkt_size); + if (st->codec->codec_id == AV_CODEC_ID_PRORES) { + uint8_t *buf = pkt->data; + bytestream_put_be32(&buf, pkt_size); + bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f')); + } + + memcpy(pkt->data + offset, pkt_data, pkt_size); if (pkt_data != data) av_free(pkt_data); diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 521f6b5c1a..3e32943153 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1050,7 +1050,7 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, MatroskaMuxContext *mkv = s->priv_data; AVCodecContext *codec = s->streams[pkt->stream_index]->codec; uint8_t *data = NULL; - int size = pkt->size; + int offset = 0, size = pkt->size; int64_t ts = mkv->tracks[pkt->stream_index].write_dts ? pkt->dts : pkt->pts; av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " @@ -1061,12 +1061,20 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, ff_avc_parse_nal_units_buf(pkt->data, &data, &size); else data = pkt->data; + + if (codec->codec_id == AV_CODEC_ID_PRORES) { + /* Matroska specification requires to remove the first QuickTime atom + */ + size -= 8; + offset = 8; + } + put_ebml_id(pb, blockid); put_ebml_num(pb, size+4, 0); avio_w8(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126 avio_wb16(pb, ts - mkv->cluster_pts); avio_w8(pb, flags); - avio_write(pb, data, size); + avio_write(pb, data + offset, size); if (data != pkt->data) av_free(data); }