mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
Merge commit '76729970049fe95659346503f7401a5d869f9959'
* commit '76729970049fe95659346503f7401a5d869f9959': mov: Implement support for multiple sample description tables Notes: * The sc->stsc_data[index].id checks have been moved from the mov_read_stsc to mov_read_packet before the value is used in mov_change_extradata to not break playback of samples with broken stsc entries (see sample of ticket #1918). * sc->stsc_index is now checked against sc->stsc_count - 1 before it is incremented so it remains lesser than sc->stsc_count. Fixes a crash with: ./ffmpeg -i matrixbench_mpeg2.mpg -t 1 -frag_duration 200k test.mov ./ffprobe -show_packets test.mov Merged-by: Matthieu Bouron <matthieu.bouron@stupeflix.com>
This commit is contained in:
commit
3c058f5701
@ -128,6 +128,8 @@ typedef struct MOVStreamContext {
|
|||||||
MOVStts *ctts_data;
|
MOVStts *ctts_data;
|
||||||
unsigned int stsc_count;
|
unsigned int stsc_count;
|
||||||
MOVStsc *stsc_data;
|
MOVStsc *stsc_data;
|
||||||
|
int stsc_index;
|
||||||
|
int stsc_sample;
|
||||||
unsigned int stps_count;
|
unsigned int stps_count;
|
||||||
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
|
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
|
||||||
MOVElst *elst_data;
|
MOVElst *elst_data;
|
||||||
@ -169,6 +171,12 @@ typedef struct MOVStreamContext {
|
|||||||
int nb_frames_for_fps;
|
int nb_frames_for_fps;
|
||||||
int64_t duration_for_fps;
|
int64_t duration_for_fps;
|
||||||
|
|
||||||
|
/** extradata array (and size) for multiple stsd */
|
||||||
|
uint8_t **extradata;
|
||||||
|
int *extradata_size;
|
||||||
|
int last_stsd_index;
|
||||||
|
int stsd_count;
|
||||||
|
|
||||||
int32_t *display_matrix;
|
int32_t *display_matrix;
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
|
|
||||||
|
@ -2215,8 +2215,7 @@ static int mov_skip_multiple_stsd(MOVContext *c, AVIOContext *pb,
|
|||||||
avio_skip(pb, size);
|
avio_skip(pb, size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ( codec_tag == AV_RL32("avc1") ||
|
if ( codec_tag == AV_RL32("hvc1") ||
|
||||||
codec_tag == AV_RL32("hvc1") ||
|
|
||||||
codec_tag == AV_RL32("hev1")
|
codec_tag == AV_RL32("hev1")
|
||||||
)
|
)
|
||||||
av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n");
|
av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n");
|
||||||
@ -2294,6 +2293,19 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
|
|||||||
return ret;
|
return ret;
|
||||||
} else if (a.size > 0)
|
} else if (a.size > 0)
|
||||||
avio_skip(pb, a.size);
|
avio_skip(pb, a.size);
|
||||||
|
|
||||||
|
if (sc->extradata) {
|
||||||
|
int extra_size = st->codecpar->extradata_size;
|
||||||
|
|
||||||
|
/* Move the current stream extradata to the stream context one. */
|
||||||
|
sc->extradata_size[pseudo_stream_id] = extra_size;
|
||||||
|
sc->extradata[pseudo_stream_id] = av_malloc(extra_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if (!sc->extradata[pseudo_stream_id])
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, extra_size);
|
||||||
|
av_freep(&st->codecpar->extradata);
|
||||||
|
st->codecpar->extradata_size = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pb->eof_reached)
|
if (pb->eof_reached)
|
||||||
@ -2304,13 +2316,41 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
|
|||||||
|
|
||||||
static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
{
|
{
|
||||||
int entries;
|
AVStream *st;
|
||||||
|
MOVStreamContext *sc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (c->fc->nb_streams < 1)
|
||||||
|
return 0;
|
||||||
|
st = c->fc->streams[c->fc->nb_streams - 1];
|
||||||
|
sc = st->priv_data;
|
||||||
|
|
||||||
avio_r8(pb); /* version */
|
avio_r8(pb); /* version */
|
||||||
avio_rb24(pb); /* flags */
|
avio_rb24(pb); /* flags */
|
||||||
entries = avio_rb32(pb);
|
sc->stsd_count = avio_rb32(pb); /* entries */
|
||||||
|
|
||||||
return ff_mov_read_stsd_entries(c, pb, entries);
|
/* Prepare space for hosting multiple extradata. */
|
||||||
|
sc->extradata = av_mallocz_array(sc->stsd_count, sizeof(*sc->extradata));
|
||||||
|
if (!sc->extradata)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
sc->extradata_size = av_mallocz_array(sc->stsd_count, sizeof(sc->extradata_size));
|
||||||
|
if (!sc->extradata_size)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
ret = ff_mov_read_stsd_entries(c, pb, sc->stsd_count);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Restore back the primary extradata. */
|
||||||
|
av_free(st->codecpar->extradata);
|
||||||
|
st->codecpar->extradata_size = sc->extradata_size[0];
|
||||||
|
st->codecpar->extradata = av_mallocz(sc->extradata_size[0] + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if (!st->codecpar->extradata)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
memcpy(st->codecpar->extradata, sc->extradata[0], sc->extradata_size[0]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
@ -2355,6 +2395,19 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute the samples value for the stsc entry at the given index. */
|
||||||
|
static inline int mov_get_stsc_samples(MOVStreamContext *sc, int index)
|
||||||
|
{
|
||||||
|
int chunk_count;
|
||||||
|
|
||||||
|
if (index < sc->stsc_count - 1)
|
||||||
|
chunk_count = sc->stsc_data[index + 1].first - sc->stsc_data[index].first;
|
||||||
|
else
|
||||||
|
chunk_count = sc->chunk_count - (sc->stsc_data[index].first - 1);
|
||||||
|
|
||||||
|
return sc->stsc_data[index].count * chunk_count;
|
||||||
|
}
|
||||||
|
|
||||||
static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
{
|
{
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
@ -3212,7 +3265,6 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
|||||||
}
|
}
|
||||||
/* Do not need those anymore. */
|
/* Do not need those anymore. */
|
||||||
av_freep(&sc->chunk_offsets);
|
av_freep(&sc->chunk_offsets);
|
||||||
av_freep(&sc->stsc_data);
|
|
||||||
av_freep(&sc->sample_sizes);
|
av_freep(&sc->sample_sizes);
|
||||||
av_freep(&sc->keyframes);
|
av_freep(&sc->keyframes);
|
||||||
av_freep(&sc->stts_data);
|
av_freep(&sc->stts_data);
|
||||||
@ -4773,6 +4825,11 @@ static int mov_read_close(AVFormatContext *s)
|
|||||||
av_freep(&sc->rap_group);
|
av_freep(&sc->rap_group);
|
||||||
av_freep(&sc->display_matrix);
|
av_freep(&sc->display_matrix);
|
||||||
|
|
||||||
|
for (j = 0; j < sc->stsd_count; j++)
|
||||||
|
av_free(sc->extradata[j]);
|
||||||
|
av_freep(&sc->extradata);
|
||||||
|
av_freep(&sc->extradata_size);
|
||||||
|
|
||||||
av_freep(&sc->cenc.auxiliary_info);
|
av_freep(&sc->cenc.auxiliary_info);
|
||||||
av_freep(&sc->cenc.auxiliary_info_sizes);
|
av_freep(&sc->cenc.auxiliary_info_sizes);
|
||||||
av_aes_ctr_free(sc->cenc.aes_ctr);
|
av_aes_ctr_free(sc->cenc.aes_ctr);
|
||||||
@ -5190,6 +5247,29 @@ static int mov_switch_root(AVFormatContext *s, int64_t target)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt)
|
||||||
|
{
|
||||||
|
uint8_t *side, *extradata;
|
||||||
|
int extradata_size;
|
||||||
|
|
||||||
|
/* Save the current index. */
|
||||||
|
sc->last_stsd_index = sc->stsc_data[sc->stsc_index].id - 1;
|
||||||
|
|
||||||
|
/* Notify the decoder that extradata changed. */
|
||||||
|
extradata_size = sc->extradata_size[sc->last_stsd_index];
|
||||||
|
extradata = sc->extradata[sc->last_stsd_index];
|
||||||
|
if (extradata_size > 0 && extradata) {
|
||||||
|
side = av_packet_new_side_data(pkt,
|
||||||
|
AV_PKT_DATA_NEW_EXTRADATA,
|
||||||
|
extradata_size);
|
||||||
|
if (!side)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
memcpy(side, extradata, extradata_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
{
|
{
|
||||||
MOVContext *mov = s->priv_data;
|
MOVContext *mov = s->priv_data;
|
||||||
@ -5282,6 +5362,25 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
|
pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
|
||||||
pkt->pos = sample->pos;
|
pkt->pos = sample->pos;
|
||||||
|
|
||||||
|
/* Multiple stsd handling. */
|
||||||
|
if (sc->stsc_data) {
|
||||||
|
/* Keep track of the stsc index for the given sample, then check
|
||||||
|
* if the stsd index is different from the last used one. */
|
||||||
|
sc->stsc_sample++;
|
||||||
|
if (sc->stsc_index < sc->stsc_count - 1 &&
|
||||||
|
mov_get_stsc_samples(sc, sc->stsc_index) == sc->stsc_sample) {
|
||||||
|
sc->stsc_index++;
|
||||||
|
sc->stsc_sample = 0;
|
||||||
|
/* Do not check indexes after a switch. */
|
||||||
|
} else if (sc->stsc_data[sc->stsc_index].id > 0 &&
|
||||||
|
sc->stsc_data[sc->stsc_index].id - 1 < sc->stsd_count &&
|
||||||
|
sc->stsc_data[sc->stsc_index].id - 1 != sc->last_stsd_index) {
|
||||||
|
ret = mov_change_extradata(sc, pkt);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mov->aax_mode)
|
if (mov->aax_mode)
|
||||||
aax_filter(pkt->data, pkt->size, mov);
|
aax_filter(pkt->data, pkt->size, mov);
|
||||||
|
|
||||||
@ -5352,6 +5451,18 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* adjust stsd index */
|
||||||
|
time_sample = 0;
|
||||||
|
for (i = 0; i < sc->stsc_count; i++) {
|
||||||
|
int next = time_sample + mov_get_stsc_samples(sc, i);
|
||||||
|
if (next > sc->current_sample) {
|
||||||
|
sc->stsc_index = i;
|
||||||
|
sc->stsc_sample = sc->current_sample - time_sample;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
time_sample = next;
|
||||||
|
}
|
||||||
|
|
||||||
ret = mov_seek_auxiliary_info(s, sc);
|
ret = mov_seek_auxiliary_info(s, sc);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user