avformat/movenc: add support for writing srat box

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
James Almer
2025-11-21 23:06:25 -03:00
committed by Zhao Zhili
parent 148cf61585
commit 6f4a3be9dc
4 changed files with 56 additions and 18 deletions

View File

@@ -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)

View File

@@ -86,6 +86,7 @@ typedef struct MOVFragmentInfo {
typedef struct MOVTrack {
int mode;
int entry_version;
int entry, entry_written;
unsigned timescale;
uint64_t time;

View File

@@ -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) \

View File

@@ -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