#include "isom.h"
#include "libavcodec/mpeg4audio.h"
#include "libavcodec/mpegaudiodata.h"
+#include "libavcodec/get_bits.h"
#if CONFIG_ZLIB
#include <zlib.h>
st->codec->codec_type = CODEC_TYPE_AUDIO;
else if(type == MKTAG('m','1','a',' '))
st->codec->codec_id = CODEC_ID_MP2;
- else if(type == MKTAG('s','u','b','p')) {
+ else if(type == MKTAG('s','u','b','p'))
st->codec->codec_type = CODEC_TYPE_SUBTITLE;
- }
+
get_be32(pb); /* component manufacture */
get_be32(pb); /* component flags */
get_be32(pb); /* component flags mask */
#define MP4DecSpecificDescrTag 0x05
static const AVCodecTag mp4_audio_types[] = {
- { CODEC_ID_MP3ON4, 29 }, /* old mp3on4 draft */
- { CODEC_ID_MP3ON4, 32 }, /* layer 1 */
- { CODEC_ID_MP3ON4, 33 }, /* layer 2 */
- { CODEC_ID_MP3ON4, 34 }, /* layer 3 */
- { CODEC_ID_NONE, 0 },
+ { CODEC_ID_MP3ON4, AOT_PS }, /* old mp3on4 draft */
+ { 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 },
};
static int mov_read_esds(MOVContext *c, ByteIOContext *pb, MOVAtom atom)
color_table = ff_qt_default_palette_256;
for (j = 0; j < color_count; j++) {
- r = color_table[j * 4 + 0];
- g = color_table[j * 4 + 1];
- b = color_table[j * 4 + 2];
+ r = color_table[j * 3 + 0];
+ g = color_table[j * 3 + 1];
+ b = color_table[j * 3 + 2];
st->codec->palctrl->palette[j] =
(r << 16) | (g << 8) | (b);
}
// 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];
{
AVStream *st = c->fc->streams[c->fc->nb_streams-1];
MOVStreamContext *sc = st->priv_data;
- unsigned int i, entries, sample_size;
+ unsigned int i, entries, sample_size, field_size, num_bytes;
+ GetBitContext gb;
+ unsigned char* buf;
get_byte(pb); /* version */
get_be24(pb); /* flags */
- sample_size = get_be32(pb);
- if (!sc->sample_size) /* do not overwrite value computed in stsd */
- sc->sample_size = sample_size;
+ if (atom.type == MKTAG('s','t','s','z')) {
+ sample_size = get_be32(pb);
+ if (!sc->sample_size) /* do not overwrite value computed in stsd */
+ sc->sample_size = sample_size;
+ field_size = 32;
+ } else {
+ sample_size = 0;
+ get_be24(pb); /* reserved */
+ field_size = get_byte(pb);
+ }
entries = get_be32(pb);
dprintf(c->fc, "sample_size = %d sample_count = %d\n", sc->sample_size, entries);
if (sample_size)
return 0;
+ if (field_size != 4 && field_size != 8 && field_size != 16 && field_size != 32) {
+ av_log(c->fc, AV_LOG_ERROR, "Invalid sample field size %d\n", field_size);
+ return -1;
+ }
+
if(entries >= UINT_MAX / sizeof(int))
return -1;
sc->sample_sizes = av_malloc(entries * sizeof(int));
if (!sc->sample_sizes)
return AVERROR(ENOMEM);
+ num_bytes = (entries*field_size+4)>>3;
+
+ buf = av_malloc(num_bytes+FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!buf) {
+ av_freep(&sc->sample_sizes);
+ return AVERROR(ENOMEM);
+ }
+
+ if (get_buffer(pb, buf, num_bytes) < num_bytes) {
+ av_freep(&sc->sample_sizes);
+ av_free(buf);
+ return -1;
+ }
+
+ init_get_bits(&gb, buf, 8*num_bytes);
+
for(i=0; i<entries; i++)
- sc->sample_sizes[i] = get_be32(pb);
+ sc->sample_sizes[i] = get_bits_long(&gb, field_size);
+
+ av_free(buf);
return 0;
}
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 */
if (sc->time_offset) {
+ 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 = - (sc->time_offset / sc->time_rate);
+ 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) {
#if CONFIG_H263_DECODER
case CODEC_ID_H263:
#endif
+#if CONFIG_H264_DECODER
+ case CODEC_ID_H264:
+#endif
#if CONFIG_MPEG4_DECODER
case CODEC_ID_MPEG4:
#endif
av_freep(&sc->sample_sizes);
av_freep(&sc->keyframes);
av_freep(&sc->stts_data);
+ av_freep(&sc->stps_data);
return 0;
}
for(i=0; i<edit_count; i++){
int time;
- get_be32(pb); /* Track duration */
+ int duration = get_be32(pb); /* Track duration */
time = get_be32(pb); /* Media time */
get_be32(pb); /* Media rate */
- if (i == 0 && time != -1) {
- sc->time_offset = time;
- sc->time_rate = av_gcd(sc->time_rate, time);
+ if (i == 0 && time >= -1) {
+ sc->time_offset = time != -1 ? time : -duration;
+ sc->time_rate = av_gcd(sc->time_rate, FFABS(sc->time_offset));
}
}
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 */
{ MKTAG('s','t','s','z'), mov_read_stsz }, /* sample size */
{ MKTAG('s','t','t','s'), mov_read_stts },
+{ MKTAG('s','t','z','2'), mov_read_stsz }, /* compact sample size */
{ MKTAG('t','k','h','d'), mov_read_tkhd }, /* track header */
{ MKTAG('t','f','h','d'), mov_read_tfhd }, /* track fragment header */
{ MKTAG('t','r','a','k'), mov_read_trak },
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 &&