mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-27 18:02:11 +00:00
mov: fix decryption with edit list
Retain the ranges of frame indexes when applying edit list in mov_fix_index. The index ranges are then used to keep track of the frame index of the current sample. In case of a discontinuity in frame indexes due to edit, update the auxiliary info position accordingly. Reviewed-by: Sasi Inguva <isasi@google.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
parent
0983e13957
commit
0101d29095
@ -121,6 +121,11 @@ typedef struct MOVFragmentIndex {
|
|||||||
MOVFragmentIndexItem *items;
|
MOVFragmentIndexItem *items;
|
||||||
} MOVFragmentIndex;
|
} MOVFragmentIndex;
|
||||||
|
|
||||||
|
typedef struct MOVIndexRange {
|
||||||
|
int64_t start;
|
||||||
|
int64_t end;
|
||||||
|
} MOVIndexRange;
|
||||||
|
|
||||||
typedef struct MOVStreamContext {
|
typedef struct MOVStreamContext {
|
||||||
AVIOContext *pb;
|
AVIOContext *pb;
|
||||||
int pb_is_copied;
|
int pb_is_copied;
|
||||||
@ -152,6 +157,9 @@ typedef struct MOVStreamContext {
|
|||||||
int time_scale;
|
int time_scale;
|
||||||
int64_t time_offset; ///< time offset of the edit list entries
|
int64_t time_offset; ///< time offset of the edit list entries
|
||||||
int current_sample;
|
int current_sample;
|
||||||
|
int64_t current_index;
|
||||||
|
MOVIndexRange* index_ranges;
|
||||||
|
MOVIndexRange* current_index_range;
|
||||||
unsigned int bytes_per_frame;
|
unsigned int bytes_per_frame;
|
||||||
unsigned int samples_per_frame;
|
unsigned int samples_per_frame;
|
||||||
int dv_audio_container;
|
int dv_audio_container;
|
||||||
@ -198,6 +206,7 @@ typedef struct MOVStreamContext {
|
|||||||
uint8_t auxiliary_info_default_size;
|
uint8_t auxiliary_info_default_size;
|
||||||
uint8_t* auxiliary_info_sizes;
|
uint8_t* auxiliary_info_sizes;
|
||||||
size_t auxiliary_info_sizes_count;
|
size_t auxiliary_info_sizes_count;
|
||||||
|
int64_t auxiliary_info_index;
|
||||||
struct AVAESCTR* aes_ctr;
|
struct AVAESCTR* aes_ctr;
|
||||||
} cenc;
|
} cenc;
|
||||||
} MOVStreamContext;
|
} MOVStreamContext;
|
||||||
|
@ -2947,6 +2947,52 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns
|
|||||||
return *ctts_count;
|
return *ctts_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mov_current_sample_inc(MOVStreamContext *sc)
|
||||||
|
{
|
||||||
|
sc->current_sample++;
|
||||||
|
sc->current_index++;
|
||||||
|
if (sc->index_ranges &&
|
||||||
|
sc->current_index >= sc->current_index_range->end &&
|
||||||
|
sc->current_index_range->end) {
|
||||||
|
sc->current_index_range++;
|
||||||
|
sc->current_index = sc->current_index_range->start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mov_current_sample_dec(MOVStreamContext *sc)
|
||||||
|
{
|
||||||
|
sc->current_sample--;
|
||||||
|
sc->current_index--;
|
||||||
|
if (sc->index_ranges &&
|
||||||
|
sc->current_index < sc->current_index_range->start &&
|
||||||
|
sc->current_index_range > sc->index_ranges) {
|
||||||
|
sc->current_index_range--;
|
||||||
|
sc->current_index = sc->current_index_range->end - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mov_current_sample_set(MOVStreamContext *sc, int current_sample)
|
||||||
|
{
|
||||||
|
int64_t range_size;
|
||||||
|
|
||||||
|
sc->current_sample = current_sample;
|
||||||
|
sc->current_index = current_sample;
|
||||||
|
if (!sc->index_ranges) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (sc->current_index_range = sc->index_ranges;
|
||||||
|
sc->current_index_range->end;
|
||||||
|
sc->current_index_range++) {
|
||||||
|
range_size = sc->current_index_range->end - sc->current_index_range->start;
|
||||||
|
if (range_size > current_sample) {
|
||||||
|
sc->current_index = sc->current_index_range->start + current_sample;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current_sample -= range_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix st->index_entries, so that it contains only the entries (and the entries
|
* Fix st->index_entries, so that it contains only the entries (and the entries
|
||||||
* which are needed to decode them) that fall in the edit list time ranges.
|
* which are needed to decode them) that fall in the edit list time ranges.
|
||||||
@ -2984,10 +3030,21 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
|||||||
int num_discarded_begin = 0;
|
int num_discarded_begin = 0;
|
||||||
int first_non_zero_audio_edit = -1;
|
int first_non_zero_audio_edit = -1;
|
||||||
int packet_skip_samples = 0;
|
int packet_skip_samples = 0;
|
||||||
|
MOVIndexRange *current_index_range;
|
||||||
|
|
||||||
if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) {
|
if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allocate the index ranges array
|
||||||
|
msc->index_ranges = av_malloc((msc->elst_count + 1) * sizeof(msc->index_ranges[0]));
|
||||||
|
if (!msc->index_ranges) {
|
||||||
|
av_log(mov->fc, AV_LOG_ERROR, "Cannot allocate index ranges buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msc->current_index_range = msc->index_ranges;
|
||||||
|
current_index_range = msc->index_ranges - 1;
|
||||||
|
|
||||||
// Clean AVStream from traces of old index
|
// Clean AVStream from traces of old index
|
||||||
st->index_entries = NULL;
|
st->index_entries = NULL;
|
||||||
st->index_entries_allocated_size = 0;
|
st->index_entries_allocated_size = 0;
|
||||||
@ -3182,6 +3239,13 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the index ranges array
|
||||||
|
if (current_index_range < msc->index_ranges || index != current_index_range->end) {
|
||||||
|
current_index_range++;
|
||||||
|
current_index_range->start = index;
|
||||||
|
}
|
||||||
|
current_index_range->end = index + 1;
|
||||||
|
|
||||||
// Only start incrementing DTS in frame_duration amounts, when we encounter a frame in edit list.
|
// Only start incrementing DTS in frame_duration amounts, when we encounter a frame in edit list.
|
||||||
if (edit_list_start_encountered > 0) {
|
if (edit_list_start_encountered > 0) {
|
||||||
edit_list_dts_counter = edit_list_dts_counter + frame_duration;
|
edit_list_dts_counter = edit_list_dts_counter + frame_duration;
|
||||||
@ -3212,6 +3276,12 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
|||||||
// Free the old index and the old CTTS structures
|
// Free the old index and the old CTTS structures
|
||||||
av_free(e_old);
|
av_free(e_old);
|
||||||
av_free(ctts_data_old);
|
av_free(ctts_data_old);
|
||||||
|
|
||||||
|
// Null terminate the index ranges array
|
||||||
|
current_index_range++;
|
||||||
|
current_index_range->start = 0;
|
||||||
|
current_index_range->end = 0;
|
||||||
|
msc->current_index = msc->index_ranges[0].start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mov_build_index(MOVContext *mov, AVStream *st)
|
static void mov_build_index(MOVContext *mov, AVStream *st)
|
||||||
@ -4908,8 +4978,8 @@ static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sc->cenc.auxiliary_info_end = sc->cenc.auxiliary_info + auxiliary_info_size;
|
sc->cenc.auxiliary_info_end = sc->cenc.auxiliary_info + auxiliary_info_size;
|
||||||
|
|
||||||
sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info;
|
sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info;
|
||||||
|
sc->cenc.auxiliary_info_index = 0;
|
||||||
|
|
||||||
if (avio_read(pb, sc->cenc.auxiliary_info, auxiliary_info_size) != auxiliary_info_size) {
|
if (avio_read(pb, sc->cenc.auxiliary_info, auxiliary_info_size) != auxiliary_info_size) {
|
||||||
av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info");
|
av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info");
|
||||||
@ -5018,12 +5088,50 @@ static int mov_read_dfla(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cenc_filter(MOVContext *c, MOVStreamContext *sc, uint8_t *input, int size)
|
static int mov_seek_auxiliary_info(MOVContext *c, MOVStreamContext *sc, int64_t index)
|
||||||
|
{
|
||||||
|
size_t auxiliary_info_seek_offset = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (sc->cenc.auxiliary_info_default_size) {
|
||||||
|
auxiliary_info_seek_offset = (size_t)sc->cenc.auxiliary_info_default_size * index;
|
||||||
|
} else if (sc->cenc.auxiliary_info_sizes) {
|
||||||
|
if (index > sc->cenc.auxiliary_info_sizes_count) {
|
||||||
|
av_log(c, AV_LOG_ERROR, "current sample %"PRId64" greater than the number of auxiliary info sample sizes %"SIZE_SPECIFIER"\n",
|
||||||
|
index, sc->cenc.auxiliary_info_sizes_count);
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < index; i++) {
|
||||||
|
auxiliary_info_seek_offset += sc->cenc.auxiliary_info_sizes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auxiliary_info_seek_offset > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info) {
|
||||||
|
av_log(c, AV_LOG_ERROR, "auxiliary info offset %"SIZE_SPECIFIER" greater than auxiliary info size %"SIZE_SPECIFIER"\n",
|
||||||
|
auxiliary_info_seek_offset, (size_t)(sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info));
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info + auxiliary_info_seek_offset;
|
||||||
|
sc->cenc.auxiliary_info_index = index;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cenc_filter(MOVContext *c, MOVStreamContext *sc, int64_t index, uint8_t *input, int size)
|
||||||
{
|
{
|
||||||
uint32_t encrypted_bytes;
|
uint32_t encrypted_bytes;
|
||||||
uint16_t subsample_count;
|
uint16_t subsample_count;
|
||||||
uint16_t clear_bytes;
|
uint16_t clear_bytes;
|
||||||
uint8_t* input_end = input + size;
|
uint8_t* input_end = input + size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (index != sc->cenc.auxiliary_info_index) {
|
||||||
|
ret = mov_seek_auxiliary_info(c, sc, index);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* read the iv */
|
/* read the iv */
|
||||||
if (AES_CTR_IV_SIZE > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
|
if (AES_CTR_IV_SIZE > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
|
||||||
@ -5081,36 +5189,7 @@ static int cenc_filter(MOVContext *c, MOVStreamContext *sc, uint8_t *input, int
|
|||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
sc->cenc.auxiliary_info_index++;
|
||||||
}
|
|
||||||
|
|
||||||
static int mov_seek_auxiliary_info(AVFormatContext *s, MOVStreamContext *sc)
|
|
||||||
{
|
|
||||||
size_t auxiliary_info_seek_offset = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sc->cenc.auxiliary_info_default_size) {
|
|
||||||
auxiliary_info_seek_offset = (size_t)sc->cenc.auxiliary_info_default_size * sc->current_sample;
|
|
||||||
} else if (sc->cenc.auxiliary_info_sizes) {
|
|
||||||
if (sc->current_sample > sc->cenc.auxiliary_info_sizes_count) {
|
|
||||||
av_log(s, AV_LOG_ERROR, "current sample %d greater than the number of auxiliary info sample sizes %"SIZE_SPECIFIER"\n",
|
|
||||||
sc->current_sample, sc->cenc.auxiliary_info_sizes_count);
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < sc->current_sample; i++) {
|
|
||||||
auxiliary_info_seek_offset += sc->cenc.auxiliary_info_sizes[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auxiliary_info_seek_offset > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info) {
|
|
||||||
av_log(s, AV_LOG_ERROR, "auxiliary info offset %"SIZE_SPECIFIER" greater than auxiliary info size %"SIZE_SPECIFIER"\n",
|
|
||||||
auxiliary_info_seek_offset, (size_t)(sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info));
|
|
||||||
return AVERROR_INVALIDDATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info + auxiliary_info_seek_offset;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5605,6 +5684,7 @@ static int mov_read_close(AVFormatContext *s)
|
|||||||
av_freep(&sc->elst_data);
|
av_freep(&sc->elst_data);
|
||||||
av_freep(&sc->rap_group);
|
av_freep(&sc->rap_group);
|
||||||
av_freep(&sc->display_matrix);
|
av_freep(&sc->display_matrix);
|
||||||
|
av_freep(&sc->index_ranges);
|
||||||
|
|
||||||
if (sc->extradata)
|
if (sc->extradata)
|
||||||
for (j = 0; j < sc->stsd_count; j++)
|
for (j = 0; j < sc->stsd_count; j++)
|
||||||
@ -6083,6 +6163,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
MOVStreamContext *sc;
|
MOVStreamContext *sc;
|
||||||
AVIndexEntry *sample;
|
AVIndexEntry *sample;
|
||||||
AVStream *st = NULL;
|
AVStream *st = NULL;
|
||||||
|
int64_t current_index;
|
||||||
int ret;
|
int ret;
|
||||||
mov->fc = s;
|
mov->fc = s;
|
||||||
retry:
|
retry:
|
||||||
@ -6096,7 +6177,8 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
}
|
}
|
||||||
sc = st->priv_data;
|
sc = st->priv_data;
|
||||||
/* must be done just before reading, to avoid infinite loop on sample */
|
/* must be done just before reading, to avoid infinite loop on sample */
|
||||||
sc->current_sample++;
|
current_index = sc->current_index;
|
||||||
|
mov_current_sample_inc(sc);
|
||||||
|
|
||||||
if (mov->next_root_atom) {
|
if (mov->next_root_atom) {
|
||||||
sample->pos = FFMIN(sample->pos, mov->next_root_atom);
|
sample->pos = FFMIN(sample->pos, mov->next_root_atom);
|
||||||
@ -6108,7 +6190,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
if (ret64 != sample->pos) {
|
if (ret64 != sample->pos) {
|
||||||
av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n",
|
av_log(mov->fc, AV_LOG_ERROR, "stream %d, offset 0x%"PRIx64": partial file\n",
|
||||||
sc->ffindex, sample->pos);
|
sc->ffindex, sample->pos);
|
||||||
sc->current_sample -= should_retry(sc->pb, ret64);
|
if (should_retry(sc->pb, ret64)) {
|
||||||
|
mov_current_sample_dec(sc);
|
||||||
|
}
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6119,7 +6203,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
|
|
||||||
ret = av_get_packet(sc->pb, pkt, sample->size);
|
ret = av_get_packet(sc->pb, pkt, sample->size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
sc->current_sample -= should_retry(sc->pb, ret);
|
if (should_retry(sc->pb, ret)) {
|
||||||
|
mov_current_sample_dec(sc);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (sc->has_palette) {
|
if (sc->has_palette) {
|
||||||
@ -6197,7 +6283,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
|||||||
aax_filter(pkt->data, pkt->size, mov);
|
aax_filter(pkt->data, pkt->size, mov);
|
||||||
|
|
||||||
if (sc->cenc.aes_ctr) {
|
if (sc->cenc.aes_ctr) {
|
||||||
ret = cenc_filter(mov, sc, pkt->data, pkt->size);
|
ret = cenc_filter(mov, sc, current_index, pkt->data, pkt->size);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -6248,7 +6334,7 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
|
|||||||
sample = 0;
|
sample = 0;
|
||||||
if (sample < 0) /* not sure what to do */
|
if (sample < 0) /* not sure what to do */
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
sc->current_sample = sample;
|
mov_current_sample_set(sc, sample);
|
||||||
av_log(s, AV_LOG_TRACE, "stream %d, found sample %d\n", st->index, sc->current_sample);
|
av_log(s, AV_LOG_TRACE, "stream %d, found sample %d\n", st->index, sc->current_sample);
|
||||||
/* adjust ctts index */
|
/* adjust ctts index */
|
||||||
if (sc->ctts_data) {
|
if (sc->ctts_data) {
|
||||||
@ -6276,11 +6362,6 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
|
|||||||
time_sample = next;
|
time_sample = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = mov_seek_auxiliary_info(s, sc);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sample;
|
return sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6320,7 +6401,7 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
|
|||||||
MOVStreamContext *sc;
|
MOVStreamContext *sc;
|
||||||
st = s->streams[i];
|
st = s->streams[i];
|
||||||
sc = st->priv_data;
|
sc = st->priv_data;
|
||||||
sc->current_sample = 0;
|
mov_current_sample_set(sc, 0);
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
MOVStreamContext *sc;
|
MOVStreamContext *sc;
|
||||||
@ -6330,7 +6411,7 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
|
|||||||
sc = st->priv_data;
|
sc = st->priv_data;
|
||||||
if (sc->ffindex == stream_index && sc->current_sample == sample)
|
if (sc->ffindex == stream_index && sc->current_sample == sample)
|
||||||
break;
|
break;
|
||||||
sc->current_sample++;
|
mov_current_sample_inc(sc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user