summaryrefslogtreecommitdiffstats
path: root/libavformat/mov.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/mov.c')
-rw-r--r--libavformat/mov.c278
1 files changed, 221 insertions, 57 deletions
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 690cd1e..71b96c1 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -3,20 +3,20 @@
* Copyright (c) 2001 Fabrice Bellard
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -30,6 +30,8 @@
#include "libavutil/mathematics.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
+#include "libavutil/opt.h"
+#include "libavutil/timecode.h"
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
@@ -68,10 +70,11 @@ static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
{
char buf[16];
- short current, total;
+ short current, total = 0;
avio_rb16(pb); // unknown
current = avio_rb16(pb);
- total = avio_rb16(pb);
+ if (len >= 6)
+ total = avio_rb16(pb);
if (!total)
snprintf(buf, sizeof(buf), "%d", current);
else
@@ -181,6 +184,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom)
case MKTAG(0xa9,'w','r','t'): key = "composer"; break;
case MKTAG( 'c','p','r','t'):
case MKTAG(0xa9,'c','p','y'): key = "copyright"; break;
+ case MKTAG(0xa9,'g','r','p'): key = "grouping"; break;
+ case MKTAG(0xa9,'l','y','r'): key = "lyrics"; break;
case MKTAG(0xa9,'c','m','t'):
case MKTAG(0xa9,'i','n','f'): key = "comment"; break;
case MKTAG(0xa9,'a','l','b'): key = "album"; break;
@@ -305,25 +310,23 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (atom.size < 0)
atom.size = INT64_MAX;
- while (total_size + 8 < atom.size && !pb->eof_reached) {
+ while (total_size + 8 <= atom.size && !url_feof(pb)) {
int (*parse)(MOVContext*, AVIOContext*, MOVAtom) = NULL;
a.size = atom.size;
a.type=0;
if (atom.size >= 8) {
a.size = avio_rb32(pb);
a.type = avio_rl32(pb);
+ total_size += 8;
+ if (a.size == 1) { /* 64 bit extended size */
+ a.size = avio_rb64(pb) - 8;
+ total_size += 8;
+ }
}
av_dlog(c->fc, "type: %08x '%.4s' parent:'%.4s' sz: %"PRId64" %"PRId64" %"PRId64"\n",
a.type, (char*)&a.type, (char*)&atom.type, a.size, total_size, atom.size);
- total_size += 8;
- if (a.size == 1) { /* 64 bit extended size */
- a.size = avio_rb64(pb) - 8;
- total_size += 8;
- }
if (a.size == 0) {
- a.size = atom.size - total_size;
- if (a.size <= 8)
- break;
+ a.size = atom.size - total_size + 8;
}
a.size -= 8;
if (a.size < 0)
@@ -430,6 +433,8 @@ static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_skip(pb, 16);
for (type = 0; type != -1 && avio_tell(pb) < next; ) {
+ if(url_feof(pb))
+ return AVERROR_EOF;
type = avio_rb16(pb);
len = avio_rb16(pb);
av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len);
@@ -475,6 +480,8 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
AVStream *st;
uint32_t type;
uint32_t av_unused ctype;
+ int title_size;
+ char *title_str;
if (c->fc->nb_streams < 1) // meta before first trak
return 0;
@@ -504,6 +511,17 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb); /* component flags */
avio_rb32(pb); /* component flags mask */
+ title_size = atom.size - 24;
+ if (title_size > 0) {
+ title_str = av_malloc(title_size + 1); /* Add null terminator */
+ if (!title_str)
+ return AVERROR(ENOMEM);
+ avio_read(pb, title_str, title_size);
+ title_str[title_size] = 0;
+ av_dict_set(&st->metadata, "handler_name", title_str, 0);
+ av_freep(&title_str);
+ }
+
return 0;
}
@@ -579,12 +597,12 @@ static int mov_read_chan(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (atom.size < 16ULL + num_descr * 20ULL)
return 0;
- av_dlog(c->fc, "chan: size=%ld version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n",
+ av_dlog(c->fc, "chan: size=%" PRId64 " version=%u flags=%u layout=%u bitmap=%u num_descr=%u\n",
atom.size, version, flags, layout_tag, bitmap, num_descr);
label_mask = 0;
for (i = 0; i < num_descr; i++) {
- uint32_t label, cflags;
+ uint32_t av_unused label, cflags;
label = avio_rb32(pb); // mChannelLabel
cflags = avio_rb32(pb); // mChannelFlags
avio_rl32(pb); // mCoordinates[0]
@@ -776,6 +794,9 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_dlog(c->fc, "time scale = %i\n", c->time_scale);
c->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */
+ // set the AVCodecContext duration because the duration of individual tracks
+ // may be inaccurate
+ c->fc->duration = av_rescale(c->duration, AV_TIME_BASE, c->time_scale);
avio_rb32(pb); /* preferred scale */
avio_rb16(pb); /* preferred volume */
@@ -791,7 +812,6 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb); /* selection duration */
avio_rb32(pb); /* current time */
avio_rb32(pb); /* next track ID */
-
return 0;
}
@@ -828,7 +848,7 @@ static int mov_read_enda(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
st = c->fc->streams[c->fc->nb_streams-1];
- little_endian = avio_rb16(pb);
+ little_endian = avio_rb16(pb) & 0xFF;
av_dlog(c->fc, "enda %d\n", little_endian);
if (little_endian == 1) {
switch (st->codec->codec_id) {
@@ -886,7 +906,8 @@ static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
/* FIXME modify qdm2/svq3/h264 decoders to take full atom as extradata */
-static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom,
+ enum CodecID codec_id)
{
AVStream *st;
uint64_t size;
@@ -895,6 +916,10 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (c->fc->nb_streams < 1) // will happen with jp2 files
return 0;
st= c->fc->streams[c->fc->nb_streams-1];
+
+ if (st->codec->codec_id != codec_id)
+ return 0; /* unexpected codec_id - don't mess with extradata */
+
size= (uint64_t)st->codec->extradata_size + atom.size + 8 + FF_INPUT_BUFFER_PADDING_SIZE;
if (size > INT_MAX || (uint64_t)atom.size > INT_MAX)
return AVERROR_INVALIDDATA;
@@ -910,6 +935,22 @@ static int mov_read_extradata(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+/* wrapper functions for reading ALAC/AVS/MJPEG/MJPEG2000 extradata atoms only for those codecs */
+static int mov_read_alac(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, CODEC_ID_ALAC);
+}
+
+static int mov_read_avss(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, CODEC_ID_AVS);
+}
+
+static int mov_read_jp2h(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ return mov_read_extradata(c, pb, atom, CODEC_ID_JPEG2000);
+}
+
static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
@@ -1122,6 +1163,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
avio_rb32(pb); /* reserved */
avio_rb16(pb); /* reserved */
dref_id = avio_rb16(pb);
+ }else if (size <= 0){
+ av_log(c->fc, AV_LOG_ERROR, "invalid size %d in stsd\n", size);
+ return -1;
}
if (st->codec->codec_tag &&
@@ -1132,14 +1176,13 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
/* Multiple fourcc, we skip JPEG. This is not correct, we should
* export it as a separate AVStream but this needs a few changes
* in the MOV demuxer, patch welcome. */
- multiple_stsd:
av_log(c->fc, AV_LOG_WARNING, "multiple fourcc not supported\n");
avio_skip(pb, size - (avio_tell(pb) - start_pos));
continue;
}
/* we cannot demux concatenated h264 streams because of different extradata */
if (st->codec->codec_tag && st->codec->codec_tag == AV_RL32("avc1"))
- goto multiple_stsd;
+ av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 might not play corrently.\n");
sc->pseudo_stream_id = st->codec->codec_tag ? -1 : pseudo_stream_id;
sc->dref_id= dref_id;
@@ -1210,7 +1253,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
(color_depth == 8)) {
/* for palette traversal */
unsigned int color_start, color_count, color_end;
- unsigned char r, g, b;
+ unsigned char a, r, g, b;
if (color_greyscale) {
int color_index, color_dec;
@@ -1220,9 +1263,12 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
color_index = 255;
color_dec = 256 / (color_count - 1);
for (j = 0; j < color_count; j++) {
+ if (id == CODEC_ID_CINEPAK){
+ r = g = b = color_count - 1 - color_index;
+ }else
r = g = b = color_index;
sc->palette[j] =
- (r << 16) | (g << 8) | (b);
+ (0xFFU << 24) | (r << 16) | (g << 8) | (b);
color_index -= color_dec;
if (color_index < 0)
color_index = 0;
@@ -1243,7 +1289,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
g = color_table[j * 3 + 1];
b = color_table[j * 3 + 2];
sc->palette[j] =
- (r << 16) | (g << 8) | (b);
+ (0xFFU << 24) | (r << 16) | (g << 8) | (b);
}
} else {
/* load the palette from the file */
@@ -1253,10 +1299,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
if ((color_start <= 255) &&
(color_end <= 255)) {
for (j = color_start; j <= color_end; j++) {
- /* each R, G, or B component is 16 bits;
- * only use the top 8 bits; skip alpha bytes
- * up front */
- avio_r8(pb);
+ /* each A, R, G, or B component is 16 bits;
+ * only use the top 8 bits */
+ a = avio_r8(pb);
avio_r8(pb);
r = avio_r8(pb);
avio_r8(pb);
@@ -1265,7 +1310,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
b = avio_r8(pb);
avio_r8(pb);
sc->palette[j] =
- (r << 16) | (g << 8) | (b);
+ (a << 24 ) | (r << 16) | (g << 8) | (b);
}
}
}
@@ -1361,7 +1406,20 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
st->codec->width = sc->width;
st->codec->height = sc->height;
} else {
- /* other codec type, just skip (rtp, mp4s, tmcd ...) */
+ if (st->codec->codec_tag == MKTAG('t','m','c','d')) {
+ MOVStreamContext *tmcd_ctx = st->priv_data;
+ int val;
+ avio_rb32(pb); /* reserved */
+ val = avio_rb32(pb); /* flags */
+ tmcd_ctx->tmcd_flags = val;
+ if (val & 1)
+ st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
+ avio_rb32(pb); /* time scale */
+ avio_rb32(pb); /* frame duration */
+ st->codec->time_base.den = avio_r8(pb); /* number of frame */
+ st->codec->time_base.num = 1;
+ }
+ /* other codec type, just skip (rtp, mp4s, ...) */
avio_skip(pb, size - (avio_tell(pb) - start_pos));
}
/* this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...) */
@@ -1429,6 +1487,12 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
st->codec->sample_rate = AV_RB32(st->codec->extradata+32);
}
break;
+ case CODEC_ID_AC3:
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ break;
+ case CODEC_ID_MPEG1VIDEO:
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ break;
default:
break;
}
@@ -1637,10 +1701,8 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
av_dlog(c->fc, "track[%i].stts.entries = %i\n",
c->fc->nb_streams-1, entries);
- if (!entries)
- return 0;
if (entries >= UINT_MAX / sizeof(*sc->stts_data))
- return AVERROR(EINVAL);
+ return -1;
sc->stts_data = av_malloc(entries * sizeof(*sc->stts_data));
if (!sc->stts_data)
@@ -1654,6 +1716,11 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sample_count=avio_rb32(pb);
sample_duration = avio_rb32(pb);
+ /* sample_duration < 0 is invalid based on the spec */
+ if (sample_duration < 0) {
+ av_log(c->fc, AV_LOG_ERROR, "Invalid SampleDelta in STTS %d\n", sample_duration);
+ sample_duration = 1;
+ }
sc->stts_data[i].count= sample_count;
sc->stts_data[i].duration= sample_duration;
@@ -1703,7 +1770,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->ctts_data[i].count = count;
sc->ctts_data[i].duration= duration;
- if (duration < 0)
+ if (duration < 0 && i+2<entries)
sc->dts_shift = FFMAX(sc->dts_shift, -duration);
}
@@ -1725,12 +1792,13 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
uint64_t stream_size = 0;
/* adjust first dts according to edit list */
- if (sc->time_offset && mov->time_scale > 0) {
- if (sc->time_offset < 0)
- sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale);
+ if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) {
+ if (sc->empty_duration)
+ sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale);
+ sc->time_offset = sc->start_time - sc->empty_duration;
current_dts = -sc->time_offset;
- if (sc->ctts_data && sc->stts_data && sc->stts_data[0].duration &&
- sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) {
+ if (sc->ctts_data && sc->stts_data &&
+ sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
/* more than 16 frames delay, dts are likely wrong
this happens with files created by iMovie */
sc->wrong_dts = 1;
@@ -1817,7 +1885,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
unsigned count, chunk_count;
chunk_samples = sc->stsc_data[i].count;
- if (sc->samples_per_frame && chunk_samples % sc->samples_per_frame) {
+ if (i != sc->stsc_count - 1 &&
+ sc->samples_per_frame && chunk_samples % sc->samples_per_frame) {
av_log(mov->fc, AV_LOG_ERROR, "error unaligned chunk\n");
return;
}
@@ -1894,14 +1963,14 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
}
}
-static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
- AVIOInterruptCB *int_cb)
+static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref,
+ AVIOInterruptCB *int_cb, int use_absolute_path, AVFormatContext *fc)
{
/* try relative path, we do not try the absolute because it can leak information about our
system to an attacker */
if (ref->nlvl_to > 0 && ref->nlvl_from > 0) {
char filename[1024];
- char *src_path;
+ const char *src_path;
int i, l;
/* find a source dir */
@@ -1933,6 +2002,11 @@ static int mov_open_dref(AVIOContext **pb, char *src, MOVDref *ref,
if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL))
return 0;
}
+ } else if (use_absolute_path) {
+ av_log(fc, AV_LOG_WARNING, "Using absolute path on user request, "
+ "this is a possible security issue\n");
+ if (!avio_open2(pb, ref->path, AVIO_FLAG_READ, int_cb, NULL))
+ return 0;
}
return AVERROR(ENOENT);
@@ -1985,7 +2059,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) {
MOVDref *dref = &sc->drefs[sc->dref_id - 1];
- if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback) < 0)
+ if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback,
+ c->use_absolute_path, c->fc) < 0)
av_log(c->fc, AV_LOG_ERROR,
"stream %d, error opening alias: path='%s', dir='%s', "
"filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n",
@@ -2120,6 +2195,21 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
sc->width = width >> 16;
sc->height = height >> 16;
+ //Assign clockwise rotate values based on transform matrix so that
+ //we can compensate for iPhone orientation during capture.
+
+ if (display_matrix[1][0] == -65536 && display_matrix[0][1] == 65536) {
+ av_dict_set(&st->metadata, "rotate", "90", 0);
+ }
+
+ if (display_matrix[0][0] == -65536 && display_matrix[1][1] == -65536) {
+ av_dict_set(&st->metadata, "rotate", "180", 0);
+ }
+
+ if (display_matrix[1][0] == 65536 && display_matrix[0][1] == -65536) {
+ av_dict_set(&st->metadata, "rotate", "270", 0);
+ }
+
// transform the display width/height according to the matrix
// skip this if the display matrix is the default identity matrix
// or if it is rotating the picture, ex iPhone 3GS
@@ -2194,6 +2284,9 @@ static int mov_read_trex(MOVContext *c, AVIOContext *pb, MOVAtom atom)
trex = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data));
if (!trex)
return AVERROR(ENOMEM);
+
+ c->fc->duration = AV_NOPTS_VALUE; // the duration from mvhd is not representing the whole file when fragments are used.
+
c->trex_data = trex;
trex = &c->trex_data[c->trex_count++];
avio_r8(pb); /* version */
@@ -2371,7 +2464,7 @@ free_and_return:
static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
MOVStreamContext *sc;
- int i, edit_count, version;
+ int i, edit_count, version, edit_start_index = 0;
if (c->fc->nb_streams < 1)
return 0;
@@ -2395,9 +2488,11 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
time = (int32_t)avio_rb32(pb); /* media time */
}
avio_rb32(pb); /* Media rate */
- if (i == 0 && time >= -1) {
- sc->time_offset = time != -1 ? time : -duration;
- }
+ if (i == 0 && time == -1) {
+ sc->empty_duration = duration;
+ edit_start_index = 1;
+ } else if (i == edit_start_index && time >= 0)
+ sc->start_time = time;
}
if (edit_count > 1)
@@ -2408,8 +2503,17 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static int mov_read_chan2(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ if (atom.size < 16)
+ return 0;
+ avio_skip(pb, 4);
+ ff_mov_read_chan(c->fc, atom.size - 4, c->fc->streams[0]->codec);
+ return 0;
+}
+
static const MOVParseTableEntry mov_default_parse_table[] = {
-{ MKTAG('a','v','s','s'), mov_read_extradata },
+{ MKTAG('a','v','s','s'), mov_read_avss },
{ MKTAG('c','h','p','l'), mov_read_chpl },
{ MKTAG('c','o','6','4'), mov_read_stco },
{ MKTAG('c','t','t','s'), mov_read_ctts }, /* composition time to sample */
@@ -2423,7 +2527,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('g','l','b','l'), mov_read_glbl },
{ MKTAG('h','d','l','r'), mov_read_hdlr },
{ MKTAG('i','l','s','t'), mov_read_ilst },
-{ MKTAG('j','p','2','h'), mov_read_extradata },
+{ MKTAG('j','p','2','h'), mov_read_jp2h },
{ MKTAG('m','d','a','t'), mov_read_mdat },
{ MKTAG('m','d','h','d'), mov_read_mdhd },
{ MKTAG('m','d','i','a'), mov_read_default },
@@ -2434,7 +2538,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('m','v','e','x'), mov_read_default },
{ MKTAG('m','v','h','d'), mov_read_mvhd },
{ MKTAG('S','M','I',' '), mov_read_smi }, /* Sorenson extension ??? */
-{ MKTAG('a','l','a','c'), mov_read_extradata }, /* alac specific atom */
+{ MKTAG('a','l','a','c'), mov_read_alac }, /* alac specific atom */
{ MKTAG('a','v','c','C'), mov_read_glbl },
{ MKTAG('p','a','s','p'), mov_read_pasp },
{ MKTAG('s','t','b','l'), mov_read_default },
@@ -2570,7 +2674,7 @@ static void mov_read_chapters(AVFormatContext *s)
if (len == 1 || len == 2)
title[len] = 0;
else
- avio_get_str(sc->pb, len - 2, title + 2, title_len - 2);
+ avio_get_str(sc->pb, INT_MAX, title + 2, len - 1);
}
}
@@ -2581,6 +2685,49 @@ finish:
avio_seek(sc->pb, cur_pos, SEEK_SET);
}
+static int parse_timecode_in_framenum_format(AVFormatContext *s, AVStream *st,
+ uint32_t value, int flags)
+{
+ AVTimecode tc;
+ char buf[AV_TIMECODE_STR_SIZE];
+ AVRational rate = {st->codec->time_base.den,
+ st->codec->time_base.num};
+ int ret = av_timecode_init(&tc, rate, flags, 0, s);
+ if (ret < 0)
+ return ret;
+ av_dict_set(&st->metadata, "timecode",
+ av_timecode_make_string(&tc, buf, value), 0);
+ return 0;
+}
+
+static int mov_read_timecode_track(AVFormatContext *s, AVStream *st)
+{
+ MOVStreamContext *sc = st->priv_data;
+ int flags = 0;
+ int64_t cur_pos = avio_tell(sc->pb);
+ uint32_t value;
+
+ if (!st->nb_index_entries)
+ return -1;
+
+ avio_seek(sc->pb, st->index_entries->pos, SEEK_SET);
+ value = avio_rb32(s->pb);
+
+ if (sc->tmcd_flags & 0x0001) flags |= AV_TIMECODE_FLAG_DROPFRAME;
+ if (sc->tmcd_flags & 0x0002) flags |= AV_TIMECODE_FLAG_24HOURSMAX;
+ if (sc->tmcd_flags & 0x0004) flags |= AV_TIMECODE_FLAG_ALLOWNEGATIVE;
+
+ /* Assume Counter flag is set to 1 in tmcd track (even though it is likely
+ * not the case) and thus assume "frame number format" instead of QT one.
+ * No sample with tmcd track can be found with a QT timecode at the moment,
+ * despite what the tmcd track "suggests" (Counter flag set to 0 means QT
+ * format). */
+ parse_timecode_in_framenum_format(s, st, value, flags);
+
+ avio_seek(sc->pb, cur_pos, SEEK_SET);
+ return 0;
+}
+
static int mov_read_header(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
@@ -2606,8 +2753,14 @@ static int mov_read_header(AVFormatContext *s)
}
av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb));
- if (pb->seekable && mov->chapter_track > 0)
- mov_read_chapters(s);
+ if (pb->seekable) {
+ int i;
+ if (mov->chapter_track > 0)
+ mov_read_chapters(s);
+ for (i = 0; i < s->nb_streams; i++)
+ if (s->streams[i]->codec->codec_tag == AV_RL32("tmcd"))
+ mov_read_timecode_track(s, s->streams[i]);
+ }
if (mov->trex_data) {
int i;
@@ -2655,13 +2808,14 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
AVIndexEntry *sample;
AVStream *st = NULL;
int ret;
+ mov->fc = s;
retry:
sample = mov_find_next_sample(s, &st);
if (!sample) {
mov->found_mdat = 0;
if (s->pb->seekable||
mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 ||
- s->pb->eof_reached)
+ url_feof(s->pb))
return AVERROR_EOF;
av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
goto retry;
@@ -2692,7 +2846,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
}
#if CONFIG_DV_DEMUXER
if (mov->dv_demux && sc->dv_audio_container) {
- avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size);
+ avpriv_dv_produce_packet(mov->dv_demux, pkt, pkt->data, pkt->size, pkt->pos);
av_free(pkt->data);
pkt->size = 0;
ret = avpriv_dv_get_packet(mov->dv_demux, pkt);
@@ -2824,6 +2978,15 @@ static int mov_read_close(AVFormatContext *s)
return 0;
}
+static const AVOption options[] = {
+ {"use_absolute_path",
+ "allow using absolute path when opening alias, this is a possible security issue",
+ offsetof(MOVContext, use_absolute_path), FF_OPT_TYPE_INT, {.dbl = 0},
+ 0, 1, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM},
+ {NULL}
+};
+static const AVClass class = {"mov,mp4,m4a,3gp,3g2,mj2", av_default_item_name, options, LIBAVUTIL_VERSION_INT};
+
AVInputFormat ff_mov_demuxer = {
.name = "mov,mp4,m4a,3gp,3g2,mj2",
.long_name = NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"),
@@ -2833,4 +2996,5 @@ AVInputFormat ff_mov_demuxer = {
.read_packet = mov_read_packet,
.read_close = mov_read_close,
.read_seek = mov_read_seek,
+ .priv_class = &class,
};
OpenPOWER on IntegriCloud