Skip to content

Commit 7dc4200

Browse files
kinetiknzjamrial
authored andcommitted
Add experimental muxing support for FLAC in ISO BMFF (MP4).
Based on the draft spec at https://git.xiph.org/?p=flac.git;a=blob;f=doc/isoflac.txt '-strict experimental' is required to create files in this format. Signed-off-by: Matthew Gregan <kinetik@flim.org> Signed-off-by: James Almer <jamrial@gmail.com>
1 parent 5f4e555 commit 7dc4200

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

libavformat/isom.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const AVCodecTag ff_mp4_obj_type[] = {
6060
{ AV_CODEC_ID_EAC3 , 0xA6 },
6161
{ AV_CODEC_ID_DTS , 0xA9 }, /* mp4ra.org */
6262
{ AV_CODEC_ID_VP9 , 0xC0 }, /* nonstandard, update when there is a standard value */
63+
{ AV_CODEC_ID_FLAC , 0xC1 }, /* nonstandard, update when there is a standard value */
6364
{ AV_CODEC_ID_TSCC2 , 0xD0 }, /* nonstandard, camtasia uses it */
6465
{ AV_CODEC_ID_VORBIS , 0xDD }, /* nonstandard, gpac uses it */
6566
{ AV_CODEC_ID_DVD_SUBTITLE, 0xE0 }, /* nonstandard, see unsupported-embedded-subs-2.mp4 */
@@ -345,6 +346,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = {
345346
{ AV_CODEC_ID_WMAV2, MKTAG('W', 'M', 'A', '2') },
346347
{ AV_CODEC_ID_EVRC, MKTAG('s', 'e', 'v', 'c') }, /* 3GPP2 */
347348
{ AV_CODEC_ID_SMV, MKTAG('s', 's', 'm', 'v') }, /* 3GPP2 */
349+
{ AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') }, /* nonstandard */
348350
{ AV_CODEC_ID_NONE, 0 },
349351
};
350352

libavformat/movenc.c

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "avc.h"
3434
#include "libavcodec/ac3_parser.h"
3535
#include "libavcodec/dnxhddata.h"
36+
#include "libavcodec/flac.h"
3637
#include "libavcodec/get_bits.h"
3738
#include "libavcodec/put_bits.h"
3839
#include "libavcodec/vc1_common.h"
@@ -655,6 +656,26 @@ static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
655656
return update_size(pb, pos);
656657
}
657658

659+
static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
660+
{
661+
int64_t pos = avio_tell(pb);
662+
avio_wb32(pb, 0);
663+
ffio_wfourcc(pb, "dfLa");
664+
avio_w8(pb, 0); /* version */
665+
avio_wb24(pb, 0); /* flags */
666+
667+
/* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
668+
if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
669+
return AVERROR_INVALIDDATA;
670+
671+
/* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
672+
avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
673+
avio_wb24(pb, track->par->extradata_size); /* Length */
674+
avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
675+
676+
return update_size(pb, pos);
677+
}
678+
658679
static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
659680
{
660681
uint32_t layout_tag, bitmap;
@@ -964,8 +985,13 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
964985
avio_wb16(pb, 16);
965986
avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
966987
} else { /* reserved for mp4/3gp */
967-
avio_wb16(pb, 2);
968-
avio_wb16(pb, 16);
988+
if (track->par->codec_id == AV_CODEC_ID_FLAC) {
989+
avio_wb16(pb, track->par->channels);
990+
avio_wb16(pb, track->par->bits_per_raw_sample);
991+
} else {
992+
avio_wb16(pb, 2);
993+
avio_wb16(pb, 16);
994+
}
969995
avio_wb16(pb, 0);
970996
}
971997

@@ -1010,6 +1036,8 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex
10101036
mov_write_extradata_tag(pb, track);
10111037
else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
10121038
mov_write_wfex_tag(s, pb, track);
1039+
else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1040+
mov_write_dfla_tag(pb, track);
10131041
else if (track->vos_len > 0)
10141042
mov_write_glbl_tag(pb, track);
10151043

@@ -1178,6 +1206,7 @@ static int mp4_get_codec_tag(AVFormatContext *s, MOVTrack *track)
11781206
else if (track->par->codec_id == AV_CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c');
11791207
else if (track->par->codec_id == AV_CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g');
11801208
else if (track->par->codec_id == AV_CODEC_ID_VC1) tag = MKTAG('v','c','-','1');
1209+
else if (track->par->codec_id == AV_CODEC_ID_FLAC) tag = MKTAG('f','L','a','C');
11811210
else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) tag = MKTAG('m','p','4','v');
11821211
else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) tag = MKTAG('m','p','4','a');
11831212
else if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE) tag = MKTAG('m','p','4','s');
@@ -5043,7 +5072,8 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
50435072
trk->start_cts = 0;
50445073
}
50455074

5046-
if (trk->par->codec_id == AV_CODEC_ID_MP4ALS) {
5075+
if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
5076+
trk->par->codec_id == AV_CODEC_ID_FLAC) {
50475077
int side_size = 0;
50485078
uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
50495079
if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
@@ -5757,6 +5787,19 @@ static int mov_init(AVFormatContext *s)
57575787
i, track->par->sample_rate);
57585788
}
57595789
}
5790+
if (track->par->codec_id == AV_CODEC_ID_FLAC) {
5791+
if (track->mode != MODE_MP4) {
5792+
av_log(s, AV_LOG_ERROR, "FLAC only supported in MP4.\n");
5793+
return AVERROR(EINVAL);
5794+
}
5795+
if (s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
5796+
av_log(s, AV_LOG_ERROR,
5797+
"FLAC in MP4 support is experimental, add "
5798+
"'-strict %d' if you want to use it.\n",
5799+
FF_COMPLIANCE_EXPERIMENTAL);
5800+
return AVERROR_EXPERIMENTAL;
5801+
}
5802+
}
57605803
} else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
57615804
track->timescale = st->time_base.den;
57625805
} else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {

0 commit comments

Comments
 (0)