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

Showing the changes to libavformat (2 of 2 files). Show all

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
247/* Sample to chunk atom */247/* Sample to chunk atom */
248static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)248static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
249{249{
250 int index = 0, oldval = -1, i;250 int index = 0, oldidx = -1, oldval = -1, i;
251 int64_t entryPos, curpos;251 int64_t entryPos, curpos;
252 252
253 int64_t pos = avio_tell(pb);253 int64_t pos = avio_tell(pb);
@@ -257,11 +257,13 @@ static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track) · 3 unmodified lines
257 entryPos = avio_tell(pb);257 entryPos = avio_tell(pb);
258 avio_wb32(pb, track->chunkCount); // entry count258 avio_wb32(pb, track->chunkCount); // entry count
259 for (i = 0; i < track->entry; i++) {259 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) {
261 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk262 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
262 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk263 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
263 avio_wb32(pb, 0x1); // sample description index264 avio_wb32(pb, track->cluster[i].stsd_index + 1); // sample description index
264 oldval = track->cluster[i].samples_in_chunk;265 oldval = track->cluster[i].samples_in_chunk;
266 oldidx = track->cluster[i].stsd_index;
265 index++;267 index++;
266 }268 }
267 }269 }
@@ -3053,8 +3055,12 @@ static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext · 2785 unmodified lines
3053 avio_wb32(pb, 0); /* size */3055 avio_wb32(pb, 0); /* size */
3054 ffio_wfourcc(pb, "stsd");3056 ffio_wfourcc(pb, "stsd");
3055 avio_wb32(pb, 0); /* version & flags */3057 avio_wb32(pb, 0); /* version & flags */
3056 avio_wb32(pb, 1); /* entry count */3058 avio_wb32(pb, track->stsd_count);
3057 3059
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++) {
3058 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)3064 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3059 ret = mov_write_video_tag(s, pb, mov, track);3065 ret = mov_write_video_tag(s, pb, mov, track);
3060 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)3066 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
3070 3076
3071 if (ret < 0)3077 if (ret < 0)
3072 return ret;3078 return ret;
3079 }
3080
3081 track->last_stsd_index = stsd_index_back;
3073 3082
3074 return update_size(pb, pos);3083 return update_size(pb, pos);
3075}3084}
@@ -5040,6 +5049,7 @@ static void build_chunks(MOVTrack *trk) · 1964 unmodified lines
5040 trk->chunkCount = 1;5049 trk->chunkCount = 1;
5041 for (i = 1; i<trk->entry; i++){5050 for (i = 1; i<trk->entry; i++){
5042 if (chunk->pos + chunkSize == trk->cluster[i].pos &&5051 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
5052 chunk->stsd_index == trk->cluster[i].stsd_index &&
5043 chunkSize + trk->cluster[i].size < (1<<20)){5053 chunkSize + trk->cluster[i].size < (1<<20)){
5044 chunkSize += trk->cluster[i].size;5054 chunkSize += trk->cluster[i].size;
5045 chunk->samples_in_chunk += trk->cluster[i].entries;5055 chunk->samples_in_chunk += trk->cluster[i].entries;
@@ -6761,6 +6771,39 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) · 1715 unmodified lines
6761 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);6771 memset(trk->extradata[0] + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6762 }6772 }
6763 6773
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
6764 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&6807 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6765 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {6808 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6766 if (!trk->st->nb_frames) {6809 if (!trk->st->nb_frames) {
@@ -6912,6 +6955,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) · 145 unmodified lines
6912 }6955 }
6913 6956
6914 trk->cluster[trk->entry].pos = avio_tell(pb) - size;6957 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6958 trk->cluster[trk->entry].stsd_index = trk->last_stsd_index;
6915 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;6959 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6916 trk->cluster[trk->entry].chunkNum = 0;6960 trk->cluster[trk->entry].chunkNum = 0;
6917 trk->cluster[trk->entry].size = size;6961 trk->cluster[trk->entry].size = size;
@@ -7594,6 +7638,7 @@ static void mov_free(AVFormatContext *s) · 676 unmodified lines
7594 for (int j = 0; j < track->stsd_count; j++)7638 for (int j = 0; j < track->stsd_count; j++)
7595 av_freep(&track->extradata[j]);7639 av_freep(&track->extradata[j]);
7596 av_freep(&track->extradata);7640 av_freep(&track->extradata);
7641 av_freep(&track->extradata_size);
7597 7642
7598 ff_mov_cenc_free(&track->cenc);7643 ff_mov_cenc_free(&track->cenc);
7599 ffio_free_dyn_buf(&track->mdat_buf);7644 ffio_free_dyn_buf(&track->mdat_buf);
libavformat/movenc.h+1−0
@@ -50,6 +50,7 @@ typedef struct MOVIentry { · 49 unmodified lines
50 int64_t dts;50 int64_t dts;
51 int64_t pts;51 int64_t pts;
52 unsigned int size;52 unsigned int size;
53 unsigned int stsd_index;
53 unsigned int samples_in_chunk;54 unsigned int samples_in_chunk;
54 unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 055 unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 0
55 unsigned int entries;56 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