return 0;
}
- st = avformat_new_stream(c->fc, NULL);
- if (!st)
- return AVERROR(ENOMEM);
sc = av_mallocz(sizeof(*sc));
if (!sc)
return AVERROR(ENOMEM);
- st->priv_data = sc;
-
- ret = av_get_packet(pb, &st->attached_pic, len);
- if (ret < 0)
+ ret = ff_add_attached_pic(c->fc, NULL, pb, NULL, len);
+ if (ret < 0) {
+ av_free(sc);
return ret;
+ }
+ st = c->fc->streams[c->fc->nb_streams - 1];
+ st->priv_data = sc;
if (st->attached_pic.size >= 8 && id != AV_CODEC_ID_BMP) {
if (AV_RB64(st->attached_pic.data) == 0x89504e470d0a1a0a) {
id = AV_CODEC_ID_MJPEG;
}
}
-
- st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
-
- st->attached_pic.stream_index = st->index;
- st->attached_pic.flags |= AV_PKT_FLAG_KEY;
-
- st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
st->codecpar->codec_id = id;
return 0;
return 0;
n_hmmt = avio_rb32(pb);
+ if (n_hmmt > len / 4)
+ return AVERROR_INVALIDDATA;
for (i = 0; i < n_hmmt && !pb->eof_reached; i++) {
int moment_time = avio_rb32(pb);
avpriv_new_chapter(c->fc, i, av_make_q(1, 1000), moment_time, AV_NOPTS_VALUE, NULL);
if (c->itunes_metadata && atom.size > 8) {
int data_size = avio_rb32(pb);
int tag = avio_rl32(pb);
- if (tag == MKTAG('d','a','t','a') && data_size <= atom.size) {
+ if (tag == MKTAG('d','a','t','a') && data_size <= atom.size && data_size >= 16) {
data_type = avio_rb32(pb); // type
avio_rb32(pb); // unknown
str_size = data_size - 16;
entries >= UINT_MAX / sizeof(*sc->drefs))
return AVERROR_INVALIDDATA;
+ for (i = 0; i < sc->drefs_count; i++) {
+ MOVDref *dref = &sc->drefs[i];
+ av_freep(&dref->path);
+ av_freep(&dref->dir);
+ }
av_free(sc->drefs);
sc->drefs_count = 0;
sc->drefs = av_mallocz(entries * sizeof(*sc->drefs));
return ret;
}
+/* This atom overrides any previously set aspect ratio */
static int mov_read_pasp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
const int num = avio_rb32(pb);
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
- if ((st->sample_aspect_ratio.den != 1 || st->sample_aspect_ratio.num) && // default
- (den != st->sample_aspect_ratio.den || num != st->sample_aspect_ratio.num)) {
- av_log(c->fc, AV_LOG_WARNING,
- "sample aspect ratio already set to %d:%d, ignoring 'pasp' atom (%d:%d)\n",
- st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
- num, den);
- } else if (den != 0) {
+ if (den != 0) {
av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den,
num, den, 32767);
}
if (track_id >= 0) {
frag_stream_info = get_frag_stream_info(frag_index, index, track_id);
+ if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE)
+ return frag_stream_info->sidx_pts;
+ if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE)
+ return frag_stream_info->first_tfra_pts;
return frag_stream_info->sidx_pts;
}
c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */
// set the AVFormatContext duration because the duration of individual tracks
// may be inaccurate
- if (c->time_scale > 0 && !c->trex_data)
+ if (!c->trex_data)
c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
avio_rb32(pb); /* preferred scale */
if (!entries)
return 0;
- if (sc->chunk_offsets)
- av_log(c->fc, AV_LOG_WARNING, "Duplicated STCO atom\n");
+ if (sc->chunk_offsets) {
+ av_log(c->fc, AV_LOG_WARNING, "Ignoring duplicated STCO atom\n");
+ return 0;
+ }
av_free(sc->chunk_offsets);
sc->chunk_count = 0;
sc->chunk_offsets = av_malloc_array(entries, sizeof(*sc->chunk_offsets));
uint8_t codec_name[32] = { 0 };
int64_t stsd_start;
unsigned int len;
+ uint32_t id = 0;
/* The first 16 bytes of the video sample description are already
* read in ff_mov_read_stsd_entries() */
avio_rb16(pb); /* version */
avio_rb16(pb); /* revision level */
- avio_rb32(pb); /* vendor */
+ id = avio_rl32(pb); /* vendor */
+ av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0);
avio_rb32(pb); /* temporal quality */
avio_rb32(pb); /* spatial quality */
{
int bits_per_sample, flags;
uint16_t version = avio_rb16(pb);
+ uint32_t id = 0;
AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE);
avio_rb16(pb); /* revision level */
- avio_rb32(pb); /* vendor */
+ id = avio_rl32(pb); /* vendor */
+ av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0);
st->codecpar->channels = avio_rb16(pb); /* channel count */
st->codecpar->bits_per_coded_sample = avio_rb16(pb); /* sample size */
}
bits_per_sample = av_get_bits_per_sample(st->codecpar->codec_id);
- if (bits_per_sample) {
+ if (bits_per_sample && (bits_per_sample >> 3) * (uint64_t)st->codecpar->channels <= INT_MAX) {
st->codecpar->bits_per_coded_sample = bits_per_sample;
sc->sample_size = (bits_per_sample >> 3) * st->codecpar->channels;
}
st->codec->time_base = av_inv_q(st->avg_frame_rate);
FF_ENABLE_DEPRECATION_WARNINGS
#endif
- /* adjust for per frame dur in counter mode */
- if (tmcd_ctx->tmcd_flags & 0x0008) {
- int timescale = AV_RB32(st->codecpar->extradata + 8);
- int framedur = AV_RB32(st->codecpar->extradata + 12);
- st->avg_frame_rate.num *= timescale;
- st->avg_frame_rate.den *= framedur;
-#if FF_API_LAVF_AVCTX
-FF_DISABLE_DEPRECATION_WARNINGS
- st->codec->time_base.den *= timescale;
- st->codec->time_base.num *= framedur;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
- }
if (size > 30) {
uint32_t len = AV_RB32(st->codecpar->extradata + 18); /* name atom length */
uint32_t format = AV_RB32(st->codecpar->extradata + 22);
entries = avio_rb32(pb);
/* Each entry contains a size (4 bytes) and format (4 bytes). */
- if (entries <= 0 || entries > atom.size / 8) {
+ if (entries <= 0 || entries > atom.size / 8 || entries > 1024) {
av_log(c->fc, AV_LOG_ERROR, "invalid STSD entries %d\n", entries);
return AVERROR_INVALIDDATA;
}
if (!entries)
return 0;
- if (sc->stsc_data)
- av_log(c->fc, AV_LOG_WARNING, "Duplicated STSC atom\n");
+ if (sc->stsc_data) {
+ av_log(c->fc, AV_LOG_WARNING, "Ignoring duplicated STSC atom\n");
+ return 0;
+ }
av_free(sc->stsc_data);
sc->stsc_count = 0;
sc->stsc_data = av_malloc_array(entries, sizeof(*sc->stsc_data));
av_freep(&sc->sdtp_data);
sc->sdtp_count = 0;
- sc->sdtp_data = av_mallocz(entries);
+ sc->sdtp_data = av_malloc(entries);
if (!sc->sdtp_data)
return AVERROR(ENOMEM);
static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
- int64_t end = avio_tell(pb) + atom.size;
+ int64_t end = av_sat_add64(avio_tell(pb), atom.size);
uint8_t *key = NULL, *val = NULL, *mean = NULL;
int i;
int ret = 0;
// save the matrix when it is not the default identity
if (!IS_MATRIX_IDENT(res_display_matrix)) {
- double rotate;
-
av_freep(&sc->display_matrix);
sc->display_matrix = av_malloc(sizeof(int32_t) * 9);
if (!sc->display_matrix)
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
sc->display_matrix[i * 3 + j] = res_display_matrix[i][j];
-
-#if FF_API_OLD_ROTATE_API
- rotate = av_display_rotation_get(sc->display_matrix);
- if (!isnan(rotate)) {
- char rotate_buf[64];
- rotate = -rotate;
- if (rotate < 0) // for backward compatibility
- rotate += 360;
- snprintf(rotate_buf, sizeof(rotate_buf), "%g", rotate);
- av_dict_set(&st->metadata, "rotate", rotate_buf, 0);
- }
-#endif
}
// transform the display width/height according to the matrix
disp_transform[i] = hypot(sc->display_matrix[0 + i],
sc->display_matrix[3 + i]);
- if (disp_transform[0] > 0 && disp_transform[1] > 0 &&
+ if (disp_transform[0] > 1 && disp_transform[1] > 1 &&
disp_transform[0] < (1<<24) && disp_transform[1] < (1<<24) &&
fabs((disp_transform[0] / disp_transform[1]) - 1.0) > 0.01)
st->sample_aspect_ratio = av_d2q(
static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
int64_t stream_size = avio_size(pb);
- int64_t offset = avio_tell(pb) + atom.size, pts, timestamp;
+ int64_t offset = av_sat_add64(avio_tell(pb), atom.size), pts, timestamp;
uint8_t version, is_complete;
+ int64_t offadd;
unsigned i, j, track_id, item_count;
AVStream *st = NULL;
AVStream *ref_st = NULL;
if (version == 0) {
pts = avio_rb32(pb);
- offset += avio_rb32(pb);
+ offadd= avio_rb32(pb);
} else {
pts = avio_rb64(pb);
- offset += avio_rb64(pb);
+ offadd= avio_rb64(pb);
}
+ if (av_sat_add64(offset, offadd) != offset + (uint64_t)offadd)
+ return AVERROR_INVALIDDATA;
+
+ offset += (uint64_t)offadd;
avio_rb16(pb); // reserved
if (frag_stream_info)
frag_stream_info->sidx_pts = timestamp;
+ if (av_sat_add64(offset, size) != offset + size ||
+ av_sat_add64(pts, duration) != pts + (uint64_t)duration
+ )
+ return AVERROR_INVALIDDATA;
offset += size;
pts += duration;
}
av_log(c->fc, AV_LOG_ERROR, "Empty stereoscopic video box\n");
return AVERROR_INVALIDDATA;
}
+
+ if (sc->stereo3d)
+ return AVERROR_INVALIDDATA;
+
avio_skip(pb, 4); /* version + flags */
mode = avio_r8(pb);
AVStream *st;
uint8_t *side_data, *extra_data, *old_side_data;
size_t side_data_size;
- int ret = 0, old_side_data_size;
+ buffer_size_t old_side_data_size;
+ int ret = 0;
unsigned int version, kid_count, extra_data_size, alloc_size = 0;
if (c->fc->nb_streams < 1)
uint32_t type;
avio_skip(pb, 4);
type = avio_rl32(pb);
+ if (avio_feof(pb))
+ break;
avio_seek(pb, -8, SEEK_CUR);
if (type == MKTAG('m','v','h','d') ||
type == MKTAG('c','m','o','v')) {
c->atom_depth --;
return err;
}
- if (c->found_moov && c->found_mdat &&
+ if (c->found_moov && c->found_mdat && a.size <= INT64_MAX - start_pos &&
((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) ||
start_pos + a.size == avio_size(pb))) {
if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete)
/* check file header */
offset = 0;
for (;;) {
+ int64_t size;
+ int minsize = 8;
/* ignore invalid offset */
- if ((offset + 8) > (unsigned int)p->buf_size)
+ if ((offset + 8ULL) > (unsigned int)p->buf_size)
break;
+ size = AV_RB32(p->buf + offset);
+ if (size == 1 && offset + 16 <= (unsigned int)p->buf_size) {
+ size = AV_RB64(p->buf+offset + 8);
+ minsize = 16;
+ } else if (size == 0) {
+ size = p->buf_size - offset;
+ }
+ if (size < minsize) {
+ offset += 4;
+ continue;
+ }
tag = AV_RL32(p->buf + offset + 4);
switch(tag) {
/* check for obvious tags */
case MKTAG('p','n','o','t'): /* detect movs with preview pics like ew.mov and april.mov */
case MKTAG('u','d','t','a'): /* Packet Video PVAuthor adds this and a lot of more junk */
case MKTAG('f','t','y','p'):
- if (AV_RB32(p->buf+offset) < 8 &&
- (AV_RB32(p->buf+offset) != 1 ||
- offset + 12 > (unsigned int)p->buf_size ||
- AV_RB64(p->buf+offset + 8) == 0)) {
- score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
- } else if (tag == MKTAG('f','t','y','p') &&
+ if (tag == MKTAG('f','t','y','p') &&
( AV_RL32(p->buf + offset + 8) == MKTAG('j','p','2',' ')
|| AV_RL32(p->buf + offset + 8) == MKTAG('j','p','x',' ')
)) {
} else {
score = AVPROBE_SCORE_MAX;
}
- offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
break;
/* those are more common words, so rate then a bit less */
case MKTAG('e','d','i','w'): /* xdcam files have reverted first tags */
case MKTAG('j','u','n','k'):
case MKTAG('p','i','c','t'):
score = FFMAX(score, AVPROBE_SCORE_MAX - 5);
- offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
break;
case MKTAG(0x82,0x82,0x7f,0x7d):
case MKTAG('s','k','i','p'):
case MKTAG('p','r','f','l'):
/* if we only find those cause probedata is too small at least rate them */
score = FFMAX(score, AVPROBE_SCORE_EXTENSION);
- offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
break;
- default:
- offset = FFMAX(4, AV_RB32(p->buf+offset)) + offset;
}
+ if (size > INT64_MAX - offset)
+ break;
+ offset += size;
}
if (score > AVPROBE_SCORE_MAX - 50 && moov_offset != -1) {
/* moov atom in the header - we should make sure that this is not a
goto finish;
}
- if (av_get_packet(sc->pb, &st->attached_pic, sample->size) < 0)
+ if (ff_add_attached_pic(s, st, sc->pb, NULL, sample->size) < 0)
goto finish;
-
- st->attached_pic.stream_index = st->index;
- st->attached_pic.flags |= AV_PKT_FLAG_KEY;
}
} else {
st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
sc->ffindex, sample->pos);
if (should_retry(sc->pb, ret64)) {
mov_current_sample_dec(sc);
+ } else if (ret64 < 0) {
+ return (int)ret64;
}
return AVERROR_INVALIDDATA;
}
return sample;
}
+static int64_t mov_get_skip_samples(AVStream *st, int sample)
+{
+ MOVStreamContext *sc = st->priv_data;
+ int64_t first_ts = st->internal->index_entries[0].timestamp;
+ int64_t ts = st->internal->index_entries[sample].timestamp;
+ int64_t off;
+
+ if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
+ return 0;
+
+ /* compute skip samples according to stream start_pad, seek ts and first ts */
+ off = av_rescale_q(ts - first_ts, st->time_base,
+ (AVRational){1, st->codecpar->sample_rate});
+ return FFMAX(sc->start_pad - off, 0);
+}
+
static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
{
MOVContext *mc = s->priv_data;
if (mc->seek_individually) {
/* adjust seek timestamp to found sample timestamp */
int64_t seek_timestamp = st->internal->index_entries[sample].timestamp;
+ st->internal->skip_samples = mov_get_skip_samples(st, sample);
for (i = 0; i < s->nb_streams; i++) {
int64_t timestamp;
- MOVStreamContext *sc = s->streams[i]->priv_data;
st = s->streams[i];
- st->internal->skip_samples = (sample_time <= 0) ? sc->start_pad : 0;
if (stream_index == i)
continue;
timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base);
- mov_seek_stream(s, st, timestamp, flags);
+ sample = mov_seek_stream(s, st, timestamp, flags);
+ if (sample >= 0)
+ st->internal->skip_samples = mov_get_skip_samples(st, sample);
}
} else {
for (i = 0; i < s->nb_streams; i++) {