diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 42c8771496..afbb1151af 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -161,6 +161,18 @@ static int64_t update_size(AVIOContext *pb, int64_t pos) return curpos - pos; } +static int64_t update_size_and_version(AVIOContext *pb, int64_t pos, int version) +{ + int64_t curpos = avio_tell(pb); + avio_seek(pb, pos, SEEK_SET); + avio_wb32(pb, curpos - pos); /* rewrite size */ + avio_skip(pb, 4); + avio_w8(pb, version); /* rewrite version */ + avio_seek(pb, curpos, SEEK_SET); + + return curpos - pos; +} + static int co64_required(const MOVTrack *track) { if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX) @@ -1344,6 +1356,18 @@ static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra return update_size(pb, pos); } +static int mov_write_srat_tag(AVIOContext *pb, MOVTrack *track) +{ + int64_t pos = avio_tell(pb); + avio_wb32(pb, 0); /* size */ + ffio_wfourcc(pb, "srat"); + avio_wb32(pb, 0); /* version & flags */ + + avio_wb32(pb, track->par->sample_rate); + + return update_size(pb, pos); +} + static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) { int64_t pos = avio_tell(pb); @@ -1363,6 +1387,10 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex track->par->codec_id == AV_CODEC_ID_QDM2) { version = 1; } + } else if (track->mode == MODE_MP4) { + if (track->par->sample_rate > UINT16_MAX && + (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG)) + version = 1; } avio_wb32(pb, 0); /* size */ @@ -1395,6 +1423,8 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex avio_wb32(pb, track->sample_size); avio_wb32(pb, get_samples_per_packet(track)); } else { + unsigned sample_rate = track->par->sample_rate; + if (track->mode == MODE_MOV) { avio_wb16(pb, track->par->ch_layout.nb_channels); if (track->par->codec_id == AV_CODEC_ID_PCM_U8 || @@ -1415,6 +1445,9 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex avio_wb16(pb, 16); } avio_wb16(pb, 0); + + while (sample_rate > UINT16_MAX) + sample_rate >>= 1; } avio_wb16(pb, 0); /* packet size (= 0) */ @@ -1425,14 +1458,13 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex else if (track->par->codec_id == AV_CODEC_ID_TRUEHD) avio_wb32(pb, track->par->sample_rate); else - avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ? - track->par->sample_rate : 0); + avio_wb16(pb, sample_rate); if (track->par->codec_id != AV_CODEC_ID_TRUEHD) avio_wb16(pb, 0); /* Reserved */ } - if (version == 1) { /* SoundDescription V1 extended info */ + if (track->mode == MODE_MOV && version == 1) { /* SoundDescription V1 extended info */ if (mov_pcm_le_gt16(track->par->codec_id) || mov_pcm_be_gt16(track->par->codec_id)) avio_wb32(pb, 1); /* must be 1 for uncompressed formats */ @@ -1478,6 +1510,8 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex else if (track->par->codec_id == AV_CODEC_ID_TRUEHD) ret = mov_write_dmlp_tag(s, pb, track); else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) { + if (track->par->sample_rate > UINT16_MAX) + mov_write_srat_tag(pb, track); if (track->par->ch_layout.nb_channels > 1) ret = mov_write_chnl_tag(s, pb, track); if (ret < 0) @@ -1508,6 +1542,9 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex ((ret = mov_write_btrt_tag(pb, track)) < 0)) return ret; + if (track->mode == MODE_MP4) + track->entry_version = version; + ret = update_size(pb, pos); return ret; } @@ -3122,7 +3159,7 @@ static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext track->last_stsd_index = stsd_index_back; - return update_size(pb, pos); + return update_size_and_version(pb, pos, track->entry_version); } static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) diff --git a/libavformat/movenc.h b/libavformat/movenc.h index 942ad905f7..eb12551ee5 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -86,6 +86,7 @@ typedef struct MOVFragmentInfo { typedef struct MOVTrack { int mode; + int entry_version; int entry, entry_written; unsigned timescale; uint64_t time; diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index 1f2f589beb..15417a215d 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -251,8 +251,8 @@ fate-mov-channel-description: CMD = transcode wav $(TARGET_PATH)/tests/data/asyn # Test PCM in mp4 and channel layout FATE_MOV_FFMPEG-$(call TRANSCODE, PCM_S16LE, MP4 MOV, WAV_DEMUXER PAN_FILTER) \ += fate-mov-mp4-pcm -fate-mov-mp4-pcm: tests/data/asynth-44100-1.wav tests/data/filtergraphs/mov-mp4-pcm -fate-mov-mp4-pcm: CMD = transcode wav $(TARGET_PATH)/tests/data/asynth-44100-1.wav mp4 "-/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/mov-mp4-pcm -map [mono] -map [stereo] -map [2.1] -map [5.1] -map [7.1] -c:a pcm_s16le" "-map 0 -c copy -frames:a 0" +fate-mov-mp4-pcm: tests/data/asynth-96000-1.wav tests/data/filtergraphs/mov-mp4-pcm +fate-mov-mp4-pcm: CMD = transcode wav $(TARGET_PATH)/tests/data/asynth-96000-1.wav mp4 "-/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/mov-mp4-pcm -map [mono] -map [stereo] -map [2.1] -map [5.1] -map [7.1] -c:a pcm_s16le" "-map 0 -c copy -frames:a 0" # Test floating sample format PCM in mp4 and unusual channel layout FATE_MOV_FFMPEG-$(call TRANSCODE, PCM_F32LE, MP4 MOV, WAV_DEMUXER PAN_FILTER) \ diff --git a/tests/ref/fate/mov-mp4-pcm b/tests/ref/fate/mov-mp4-pcm index 7cdca8629f..77c1584dcb 100644 --- a/tests/ref/fate/mov-mp4-pcm +++ b/tests/ref/fate/mov-mp4-pcm @@ -1,27 +1,27 @@ -0c6802135e9eb442201c0c1b001259d6 *tests/data/fate/mov-mp4-pcm.mp4 -10587977 tests/data/fate/mov-mp4-pcm.mp4 -#tb 0: 1/44100 +531c4a3389a66d305fb247691f4b14ab *tests/data/fate/mov-mp4-pcm.mp4 +23044177 tests/data/fate/mov-mp4-pcm.mp4 +#tb 0: 1/96000 #media_type 0: audio #codec_id 0: pcm_s16le -#sample_rate 0: 44100 +#sample_rate 0: 96000 #channel_layout_name 0: mono -#tb 1: 1/44100 +#tb 1: 1/96000 #media_type 1: audio #codec_id 1: pcm_s16le -#sample_rate 1: 44100 +#sample_rate 1: 96000 #channel_layout_name 1: stereo -#tb 2: 1/44100 +#tb 2: 1/96000 #media_type 2: audio #codec_id 2: pcm_s16le -#sample_rate 2: 44100 +#sample_rate 2: 96000 #channel_layout_name 2: 2.1 -#tb 3: 1/44100 +#tb 3: 1/96000 #media_type 3: audio #codec_id 3: pcm_s16le -#sample_rate 3: 44100 +#sample_rate 3: 96000 #channel_layout_name 3: 5.1 -#tb 4: 1/44100 +#tb 4: 1/96000 #media_type 4: audio #codec_id 4: pcm_s16le -#sample_rate 4: 44100 +#sample_rate 4: 96000 #channel_layout_name 4: 7.1