#include "isom.h"
#include "libavcodec/mpeg4audio.h"
#include "libavcodec/mpegaudiodata.h"
-#include "libavcodec/bitstream.h"
+#include "libavcodec/get_bits.h"
#if CONFIG_ZLIB
#include <zlib.h>
{ CODEC_ID_MP3ON4, AOT_L1 }, /* layer 1 */
{ CODEC_ID_MP3ON4, AOT_L2 }, /* layer 2 */
{ CODEC_ID_MP3ON4, AOT_L3 }, /* layer 3 */
+ { CODEC_ID_MP4ALS, AOT_ALS }, /* MPEG-4 ALS */
{ CODEC_ID_NONE, AOT_NULL },
};
// ttxt stsd contains display flags, justification, background
// color, fonts, and default styles, so fake an atom to read it
MOVAtom fake_atom = { .size = size - (url_ftell(pb) - start_pos) };
- mov_read_glbl(c, pb, fake_atom);
+ if (format != AV_RL32("mp4s")) // mp4s contains a regular esds atom
+ mov_read_glbl(c, pb, fake_atom);
st->codec->codec_id= id;
st->codec->width = sc->width;
st->codec->height = sc->height;
#endif
/* no ifdef since parameters are always those */
case CODEC_ID_QCELP:
+ // force sample rate for qcelp when not stored in mov
+ if (st->codec->codec_tag != MKTAG('Q','c','l','p'))
+ st->codec->sample_rate = 8000;
st->codec->frame_size= 160;
st->codec->channels= 1; /* really needed */
break;
return 0;
}
+static int mov_read_stps(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ MOVStreamContext *sc;
+ unsigned i, entries;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+ sc = st->priv_data;
+
+ get_be32(pb); // version + flags
+
+ entries = get_be32(pb);
+ if (entries >= UINT_MAX / sizeof(*sc->stps_data))
+ return -1;
+ sc->stps_data = av_malloc(entries * sizeof(*sc->stps_data));
+ if (!sc->stps_data)
+ return AVERROR(ENOMEM);
+ sc->stps_count = entries;
+
+ for (i = 0; i < entries; i++) {
+ sc->stps_data[i] = get_be32(pb);
+ //dprintf(c->fc, "stps %d\n", sc->stps_data[i]);
+ }
+
+ return 0;
+}
+
static int mov_read_stss(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
AVStream *st = c->fc->streams[c->fc->nb_streams-1];
return 0;
}
+static int mov_read_cslg(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ MOVStreamContext *sc;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+ sc = st->priv_data;
+
+ get_be32(pb); // version + flags
+
+ sc->dts_shift = get_be32(pb);
+ dprintf(c->fc, "dts shift %d\n", sc->dts_shift);
+
+ sc->time_rate= av_gcd(sc->time_rate, FFABS(sc->dts_shift));
+
+ get_be32(pb); // least dts to pts delta
+ get_be32(pb); // greatest dts to pts delta
+ get_be32(pb); // pts start
+ get_be32(pb); // pts end
+
+ return 0;
+}
+
static int mov_read_ctts(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
{
AVStream *st = c->fc->streams[c->fc->nb_streams-1];
int count =get_be32(pb);
int duration =get_be32(pb);
- if (duration < 0) {
- sc->wrong_dts = 1;
- st->codec->has_b_frames = 1;
- }
sc->ctts_data[i].count = count;
sc->ctts_data[i].duration= duration;
unsigned int stts_index = 0;
unsigned int stsc_index = 0;
unsigned int stss_index = 0;
+ unsigned int stps_index = 0;
unsigned int i, j;
/* adjust first dts according to edit list */
int rescaled = sc->time_offset < 0 ? av_rescale(sc->time_offset, sc->time_scale, mov->time_scale) : sc->time_offset;
assert(sc->time_offset % sc->time_rate == 0);
current_dts = - (rescaled / sc->time_rate);
+ if (sc->ctts_data && sc->ctts_data[0].duration / sc->stts_data[0].duration > 16) {
+ /* more than 16 frames delay, dts are likely wrong
+ this happens with files created by iMovie */
+ sc->wrong_dts = 1;
+ st->codec->has_b_frames = 1;
+ }
}
/* only use old uncompressed audio chunk demuxing when stts specifies it */
sc->stts_count == 1 && sc->stts_data[0].duration == 1)) {
unsigned int current_sample = 0;
unsigned int stts_sample = 0;
- unsigned int keyframe, sample_size;
+ unsigned int sample_size;
unsigned int distance = 0;
int key_off = sc->keyframes && sc->keyframes[0] == 1;
+ sc->dts_shift /= sc->time_rate;
+ current_dts -= sc->dts_shift;
+
st->nb_frames = sc->sample_count;
for (i = 0; i < sc->chunk_count; i++) {
current_offset = sc->chunk_offsets[i];
i + 1 == sc->stsc_data[stsc_index + 1].first)
stsc_index++;
for (j = 0; j < sc->stsc_data[stsc_index].count; j++) {
+ int keyframe = 0;
if (current_sample >= sc->sample_count) {
av_log(mov->fc, AV_LOG_ERROR, "wrong sample count\n");
return;
}
- keyframe = !sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index];
- if (keyframe) {
- distance = 0;
+
+ if (!sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index]) {
+ keyframe = 1;
if (stss_index + 1 < sc->keyframe_count)
stss_index++;
+ } else if (sc->stps_count && current_sample+key_off == sc->stps_data[stps_index]) {
+ keyframe = 1;
+ if (stps_index + 1 < sc->stps_count)
+ stps_index++;
}
+ if (keyframe)
+ distance = 0;
sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample];
if(sc->pseudo_stream_id == -1 ||
sc->stsc_data[stsc_index].id - 1 == sc->pseudo_stream_id) {
av_freep(&sc->sample_sizes);
av_freep(&sc->keyframes);
av_freep(&sc->stts_data);
+ av_freep(&sc->stps_data);
return 0;
}
static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('a','v','s','s'), mov_read_extradata },
{ MKTAG('c','o','6','4'), mov_read_stco },
+{ MKTAG('c','s','l','g'), mov_read_cslg },
{ MKTAG('c','t','t','s'), mov_read_ctts }, /* composition time to sample */
{ MKTAG('d','i','n','f'), mov_read_default },
{ MKTAG('d','r','e','f'), mov_read_dref },
{ MKTAG('p','a','s','p'), mov_read_pasp },
{ MKTAG('s','t','b','l'), mov_read_default },
{ MKTAG('s','t','c','o'), mov_read_stco },
+{ MKTAG('s','t','p','s'), mov_read_stps },
{ MKTAG('s','t','s','c'), mov_read_stsc },
{ MKTAG('s','t','s','d'), mov_read_stsd }, /* sample description */
{ MKTAG('s','t','s','s'), mov_read_stss }, /* sync sample */
pkt->dts = sample->timestamp;
if (sc->ctts_data) {
assert(sc->ctts_data[sc->ctts_index].duration % sc->time_rate == 0);
- pkt->pts = pkt->dts + sc->ctts_data[sc->ctts_index].duration / sc->time_rate;
+ pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration / sc->time_rate;
/* update ctts context */
sc->ctts_sample++;
if (sc->ctts_index < sc->ctts_count &&