/*
* First version by Francois Revol revol@free.fr
* Seek function by Gael Chardon gael.dev@4now.net
- *
- * Features and limitations:
- * - reads most of the QT files I have (at least the structure),
- * Sample QuickTime files with mp3 audio can be found at: http://www.3ivx.com/showcase.html
- * - the code is quite ugly... maybe I won't do it recursive next time :-)
- *
- * Funny I didn't know about http://sourceforge.net/projects/qt-ffmpeg/
- * when coding this :) (it's a writer anyway)
- *
- * Reference documents:
- * http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
- * Apple:
- * http://developer.apple.com/documentation/QuickTime/QTFF/
- * http://developer.apple.com/documentation/QuickTime/QTFF/qtff.pdf
- * QuickTime is a trademark of Apple (AFAIK :))
*/
#include "qtpalette.h"
#undef NDEBUG
#include <assert.h>
-/* XXX: it's the first time I make a recursive parser I think... sorry if it's ugly :P */
-
/* those functions parse an atom */
-/* return code:
- 0: continue to parse next atom
- <0: error occurred, exit
-*/
/* links atom IDs to parse functions */
typedef struct MOVParseTableEntry {
uint32_t type;
{
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
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;
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;
}
st->codec->flags2 |= CODEC_FLAG2_DROP_FRAME_TIMECODE;
avio_rb32(pb);
avio_rb32(pb);
- st->codec->time_base.den = get_byte(pb);
+ st->codec->time_base.den = avio_r8(pb);
st->codec->time_base.num = 1;
}
/* other codec type, just skip (rtp, mp4s, ...) */
st->codec->channels= 1; /* really needed */
break;
case CODEC_ID_AMR_NB:
- case CODEC_ID_AMR_WB:
- st->codec->frame_size= sc->samples_per_frame;
st->codec->channels= 1; /* really needed */
/* force sample rate for amr, stsd in 3gp does not store sample rate */
- if (st->codec->codec_id == CODEC_ID_AMR_NB)
- st->codec->sample_rate = 8000;
- else if (st->codec->codec_id == CODEC_ID_AMR_WB)
- st->codec->sample_rate = 16000;
+ st->codec->sample_rate = 8000;
+ /* force frame_size, too, samples_per_frame isn't always set properly */
+ st->codec->frame_size = 160;
+ break;
+ case CODEC_ID_AMR_WB:
+ st->codec->channels = 1;
+ st->codec->sample_rate = 16000;
+ st->codec->frame_size = 320;
break;
case CODEC_ID_MP2:
case CODEC_ID_MP3:
case CODEC_ID_AC3:
st->need_parsing = AVSTREAM_PARSE_FULL;
break;
+ case CODEC_ID_MPEG1VIDEO:
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ break;
default:
break;
}
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->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
}
}
-static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref)
+static int mov_open_dref(AVIOContext **pb, const char *src, MOVDref *ref,
+ AVIOInterruptCB *int_cb)
{
/* try relative path, we do not try the absolute because it can leak information about our
system to an attacker */
av_strlcat(filename, ref->path + l + 1, 1024);
- if (!avio_open(pb, filename, AVIO_FLAG_READ))
+ if (!avio_open2(pb, filename, AVIO_FLAG_READ, int_cb, NULL))
return 0;
}
}
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) < 0)
+ if (mov_open_dref(&sc->pb, c->fc->filename, dref, &c->fc->interrupt_callback) < 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",
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;
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)