History

avformat/movenc: support writing more than one STSD entry per track

If a packet contains new extradata within a side data entry, save for specific cases it means the coded stream changed. If ignored, upon demuxing every packet from then onwards may be undecodable.

James Almer committed 1 year ago

Commit 4eca8df1 parent 30644872 files · +50 −4Browse files

Unified · Split

2 files
  1. libavformat/movenc.c +49 −4
  2. libavformat/movenc.h +1 −0
libavformat/movenc.c+49−4
@@ -247,7 +247,7 @@ static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track) · 246 unmodified lines
247247 /* Sample to chunk atom */
248248 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
249249 {
250− int index = 0, oldval = -1, i;
250+ int index = 0, oldidx = -1, oldval = -1, i;
251251 int64_t entryPos, curpos;
252252
253253 int64_t pos = avio_tell(pb);
@@ -257,11 +257,13 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) · 3 unmodified lines
257257 entryPos = avio_tell(pb);
258258 avio_wb32(pb, track->chunkCount); // entry count
259259 for (i = 0; i < track->entry; i++) {
260− if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
260+ if ((oldval != track->cluster[i].samples_in_chunk ||
261+ oldidx != track->cluster[i].stsd_index) && track->cluster[i].chunkNum) {
261262 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
262263 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
263− avio_wb32(pb, 0x1); // sample description index
264+ avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
264265 oldval = track->cluster[i].samples_in_chunk;
266+ oldidx = track->cluster[i].stsd_index;
265267 index++;
266268 }
267269 }
@@ -3053,8 +3055,12 @@ static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext · 2785 unmodified lines
30533055 avio_wb32(pb, 0); /* size */
30543056 ffio_wfourcc(pb, "stsd");
30553057 avio_wb32(pb, 0); /* version & flags */
3056− avio_wb32(pb, 1); /* entry count */
3058+ avio_wb32(pb, track->stsd_count);
30573059
3060+ int stsd_index_back = track->last_stsd_index;
3061+ for (track->last_stsd_index = 0;
3062+ track->last_stsd_index < track->stsd_count;
3063+ track->last_stsd_index++) {
30583064 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
30593065 ret = mov_write_video_tag(s, pb, mov, track);
30603066 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
@@ -3070,6 +3076,9 @@ static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext · 9 unmodified lines
30703076
30713077 if (ret < 0)
30723078 return ret;
3079+ }
3080+
3081+ track->last_stsd_index = stsd_index_back;
30733082
30743083 return update_size(pb, pos);
30753084 }
@@ -5040,6 +5049,7 @@ static void build_chunks(MOVTrack *trk) · 1964 unmodified lines
50405049 trk->chunkCount = 1;
50415050 for (i = 1; i<trk->entry; i++){
50425051 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5052+ chunk->stsd_index == trk->cluster[i].stsd_index &&
50435053 chunkSize + trk->cluster[i].size < (1<<20)){
50445054 chunkSize += trk->cluster[i].size;
50455055 chunk->samples_in_chunk += trk->cluster[i].entries;
@@ -6761,6 +6771,39 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) · 1715 unmodified lines
67616771 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
67626772 }
67636773
6774+ const AVPacketSideData *sd = av_packet_side_data_get(pkt->side_data, pkt->side_data_elems, AV_PKT_DATA_NEW_EXTRADATA);
6775+ if (pkt->size && sd && sd->size > 0) {
6776+ int i;
6777+ for (i = 0; i < trk->stsd_count; i++) {
6778+ if (trk->extradata_size[i] == sd->size && !memcmp(trk->extradata[i], sd->data, sd->size))
6779+ break;
6780+ }
6781+
6782+ if (i < trk->stsd_count)
6783+ trk->last_stsd_index = i;
6784+ else if (trk->stsd_count <= INT_MAX - 1) {
6785+ int new_count = trk->stsd_count + 1;
6786+ uint8_t **extradata = av_realloc_array(trk->extradata, new_count, sizeof(*trk->extradata));
6787+ if (!extradata)
6788+ return AVERROR(ENOMEM);
6789+ trk->extradata = extradata;
6790+
6791+ int *extradata_size = av_realloc_array(trk->extradata_size, new_count, sizeof(*trk->extradata_size));
6792+ if (!extradata_size)
6793+ return AVERROR(ENOMEM);
6794+ trk->extradata_size = extradata_size;
6795+
6796+ trk->extradata[trk->stsd_count] = av_memdup(sd->data, sd->size);
6797+ if (!trk->extradata[trk->stsd_count])
6798+ return AVERROR(ENOMEM);
6799+
6800+ trk->extradata_size[trk->stsd_count] = sd->size;
6801+ trk->last_stsd_index = trk->stsd_count;
6802+ trk->stsd_count = new_count;
6803+ } else
6804+ return AVERROR(ENOMEM);
6805+ }
6806+
67646807 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
67656808 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
67666809 if (!trk->st->nb_frames) {
@@ -6912,6 +6955,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) · 145 unmodified lines
69126955 }
69136956
69146957 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6958+ trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
69156959 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
69166960 trk->cluster[trk->entry].chunkNum = 0;
69176961 trk->cluster[trk->entry].size = size;
@@ -7594,6 +7638,7 @@ static void mov_free(AVFormatContext *s) · 676 unmodified lines
75947638 for (int j = 0; j < track->stsd_count; j++)
75957639 av_freep(&track->extradata[j]);
75967640 av_freep(&track->extradata);
7641+ av_freep(&track->extradata_size);
75977642
75987643 ff_mov_cenc_free(&track->cenc);
75997644 ffio_free_dyn_buf(&track->mdat_buf);
libavformat/movenc.h+1−0
@@ -50,6 +50,7 @@ typedef struct MOVIentry { · 49 unmodified lines
5050 int64_t dts;
5151 int64_t pts;
5252 unsigned int size;
53+ unsigned int stsd_index;
5354 unsigned int samples_in_chunk;
5455 unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 0
5556 unsigned int entries;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t