//#define DEBUG
//#define MOV_EXPORT_ALL_METADATA
+#include "libavutil/audioconvert.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/intfloat.h"
#include "libavutil/mathematics.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
+#include "libavcodec/ac3tab.h"
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
if (err < 0)
return err;
if (c->found_moov && c->found_mdat &&
- (!pb->seekable || start_pos + a.size == avio_size(pb)))
+ ((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX) ||
+ start_pos + a.size == avio_size(pb))) {
+ if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX)
+ c->next_root_atom = start_pos + a.size;
return 0;
+ }
left = a.size - avio_tell(pb) + start_pos;
if (left > 0) /* skip garbage at atom end */
avio_skip(pb, left);
entries = avio_rb32(pb);
if (entries >= UINT_MAX / sizeof(*sc->drefs))
return AVERROR_INVALIDDATA;
+ av_free(sc->drefs);
sc->drefs = av_mallocz(entries * sizeof(*sc->drefs));
if (!sc->drefs)
return AVERROR(ENOMEM);
acmod = (ac3info >> 11) & 0x7;
lfeon = (ac3info >> 10) & 0x1;
st->codec->channels = ((int[]){2,1,2,3,3,4,4,5})[acmod] + lfeon;
+ st->codec->channel_layout = avpriv_ac3_channel_layout_tab[acmod];
+ if (lfeon)
+ st->codec->channel_layout |= AV_CH_LOW_FREQUENCY;
+ st->codec->audio_service_type = bsmod;
+ if (st->codec->channels > 1 && bsmod == 0x7)
+ st->codec->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE;
+
+ return 0;
+}
+
+static int mov_read_dec3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ int eac3info, acmod, lfeon, bsmod;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+
+ /* No need to parse fields for additional independent substreams and its
+ * associated dependent substreams since libavcodec's E-AC-3 decoder
+ * does not support them yet. */
+ avio_rb16(pb); /* data_rate and num_ind_sub */
+ eac3info = avio_rb24(pb);
+ bsmod = (eac3info >> 12) & 0x1f;
+ acmod = (eac3info >> 9) & 0x7;
+ lfeon = (eac3info >> 8) & 0x1;
+ st->codec->channel_layout = avpriv_ac3_channel_layout_tab[acmod];
+ if (lfeon)
+ st->codec->channel_layout |= AV_CH_LOW_FREQUENCY;
+ st->codec->channels = av_get_channel_layout_nb_channels(st->codec->channel_layout);
st->codec->audio_service_type = bsmod;
if (st->codec->channels > 1 && bsmod == 0x7)
st->codec->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE;
if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
unsigned int color_depth, len;
int color_greyscale;
+ int color_table_id;
st->codec->codec_id = id;
avio_rb16(pb); /* version */
st->codec->codec_tag=MKTAG('I', '4', '2', '0');
st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */
- st->codec->color_table_id = avio_rb16(pb); /* colortable id */
+ color_table_id = avio_rb16(pb); /* colortable id */
av_dlog(c->fc, "depth %d, ctab id %d\n",
- st->codec->bits_per_coded_sample, st->codec->color_table_id);
+ st->codec->bits_per_coded_sample, color_table_id);
/* figure out the palette situation */
color_depth = st->codec->bits_per_coded_sample & 0x1F;
color_greyscale = st->codec->bits_per_coded_sample & 0x20;
if (color_index < 0)
color_index = 0;
}
- } else if (st->codec->color_table_id) {
+ } else if (color_table_id) {
const uint8_t *color_table;
/* if flag bit 3 is set, use the default palette */
color_count = 1 << color_depth;
// 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;
case CODEC_ID_AMR_NB:
st->codec->channels= 1; /* really needed */
/* force sample rate for amr, stsd in 3gp does not store sample rate */
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_GSM:
case CODEC_ID_ADPCM_MS:
case CODEC_ID_ADPCM_IMA_WAV:
- st->codec->frame_size = sc->samples_per_frame;
st->codec->block_align = sc->bytes_per_frame;
break;
case CODEC_ID_ALAC:
if (st->codec->extradata_size == 36) {
- st->codec->frame_size = AV_RB32(st->codec->extradata+12);
st->codec->channels = AV_RB8 (st->codec->extradata+21);
st->codec->sample_rate = AV_RB32(st->codec->extradata+32);
}
av_dlog(c->fc, "keyframe_count = %d\n", entries);
if (!entries)
+ {
+ sc->keyframe_absent = 1;
return 0;
+ }
if (entries >= UINT_MAX / sizeof(int))
return AVERROR_INVALIDDATA;
sc->keyframes = av_malloc(entries * sizeof(int));
unsigned int stps_index = 0;
unsigned int i, j;
uint64_t stream_size = 0;
+ AVIndexEntry *mem;
/* adjust first dts according to edit list */
if (sc->time_offset && mov->time_scale > 0) {
unsigned int stts_sample = 0;
unsigned int sample_size;
unsigned int distance = 0;
- int key_off = sc->keyframes && sc->keyframes[0] == 1;
+ int key_off = (sc->keyframes && sc->keyframes[0] > 0) || (sc->stps_data && sc->stps_data[0] > 0);
current_dts -= sc->dts_shift;
if (!sc->sample_count)
return;
- if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries))
+ if (sc->sample_count >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
return;
- st->index_entries = av_malloc(sc->sample_count*sizeof(*st->index_entries));
- if (!st->index_entries)
+ mem = av_realloc(st->index_entries, (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries));
+ if (!mem)
return;
- st->index_entries_allocated_size = sc->sample_count*sizeof(*st->index_entries);
+ st->index_entries = mem;
+ st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries);
for (i = 0; i < sc->chunk_count; i++) {
current_offset = sc->chunk_offsets[i];
return;
}
- if (!sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index]) {
+ if (!sc->keyframe_absent && (!sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index])) {
keyframe = 1;
if (stss_index + 1 < sc->keyframe_count)
stss_index++;
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;
}
}
av_dlog(mov->fc, "chunk count %d\n", total);
- if (total >= UINT_MAX / sizeof(*st->index_entries))
+ if (total >= UINT_MAX / sizeof(*st->index_entries) - st->nb_index_entries)
return;
- st->index_entries = av_malloc(total*sizeof(*st->index_entries));
- if (!st->index_entries)
+ mem = av_realloc(st->index_entries, (st->nb_index_entries + total) * sizeof(*st->index_entries));
+ if (!mem)
return;
- st->index_entries_allocated_size = total*sizeof(*st->index_entries);
+ st->index_entries = mem;
+ st->index_entries_allocated_size = (st->nb_index_entries + total) * sizeof(*st->index_entries);
// populate index
for (i = 0; i < sc->chunk_count; i++) {
avpriv_set_pts_info(st, 64, 1, sc->time_scale);
- if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
- !st->codec->frame_size && sc->stts_count == 1) {
- st->codec->frame_size = av_rescale(sc->stts_data[0].duration,
- st->codec->sample_rate, sc->time_scale);
- av_dlog(c->fc, "frame size %d\n", st->codec->frame_size);
- }
-
mov_build_index(c, st);
if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) {
int64_t dts;
int data_offset = 0;
unsigned entries, first_sample_flags = frag->flags;
- int flags, distance, i;
+ int flags, distance, i, found_keyframe = 0;
for (i = 0; i < c->fc->nb_streams; i++) {
if (c->fc->streams[i]->id == frag->track_id) {
return AVERROR(ENOMEM);
sc->ctts_data = ctts_data;
- if (flags & 0x001) data_offset = avio_rb32(pb);
- if (flags & 0x004) first_sample_flags = avio_rb32(pb);
+ if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb);
+ if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);
dts = sc->track_end - sc->time_offset;
offset = frag->base_data_offset + data_offset;
distance = 0;
unsigned sample_size = frag->size;
int sample_flags = i ? frag->flags : first_sample_flags;
unsigned sample_duration = frag->duration;
- int keyframe;
+ int keyframe = 0;
- if (flags & 0x100) sample_duration = avio_rb32(pb);
- if (flags & 0x200) sample_size = avio_rb32(pb);
- if (flags & 0x400) sample_flags = avio_rb32(pb);
+ if (flags & MOV_TRUN_SAMPLE_DURATION) sample_duration = avio_rb32(pb);
+ if (flags & MOV_TRUN_SAMPLE_SIZE) sample_size = avio_rb32(pb);
+ if (flags & MOV_TRUN_SAMPLE_FLAGS) sample_flags = avio_rb32(pb);
sc->ctts_data[sc->ctts_count].count = 1;
- sc->ctts_data[sc->ctts_count].duration = (flags & 0x800) ? avio_rb32(pb) : 0;
+ sc->ctts_data[sc->ctts_count].duration = (flags & MOV_TRUN_SAMPLE_CTS) ?
+ avio_rb32(pb) : 0;
sc->ctts_count++;
- if ((keyframe = st->codec->codec_type == AVMEDIA_TYPE_AUDIO ||
- (flags & 0x004 && !i && !(sample_flags & 0xffff0000)) || sample_flags & 0x2000000))
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
+ keyframe = 1;
+ else if (!found_keyframe)
+ keyframe = found_keyframe =
+ !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC |
+ MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES));
+ if (keyframe)
distance = 0;
av_add_index_entry(st, offset, dts, sample_size, distance,
keyframe ? AVINDEX_KEYFRAME : 0);
{ MKTAG('w','a','v','e'), mov_read_wave },
{ MKTAG('e','s','d','s'), mov_read_esds },
{ MKTAG('d','a','c','3'), mov_read_dac3 }, /* AC-3 info */
+{ MKTAG('d','e','c','3'), mov_read_dec3 }, /* EAC-3 info */
{ MKTAG('w','i','d','e'), mov_read_wide }, /* place holder */
{ MKTAG('w','f','e','x'), mov_read_wfex },
{ MKTAG('c','m','o','v'), mov_read_cmov },
avio_seek(sc->pb, cur_pos, SEEK_SET);
}
+static int mov_read_close(AVFormatContext *s)
+{
+ MOVContext *mov = s->priv_data;
+ int i, j;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ MOVStreamContext *sc = st->priv_data;
+
+ av_freep(&sc->ctts_data);
+ for (j = 0; j < sc->drefs_count; j++) {
+ av_freep(&sc->drefs[j].path);
+ av_freep(&sc->drefs[j].dir);
+ }
+ av_freep(&sc->drefs);
+ if (sc->pb && sc->pb != s->pb)
+ avio_close(sc->pb);
+ }
+
+ if (mov->dv_demux) {
+ for (i = 0; i < mov->dv_fctx->nb_streams; i++) {
+ av_freep(&mov->dv_fctx->streams[i]->codec);
+ av_freep(&mov->dv_fctx->streams[i]);
+ }
+ av_freep(&mov->dv_fctx);
+ av_freep(&mov->dv_demux);
+ }
+
+ av_freep(&mov->trex_data);
+
+ return 0;
+}
+
static int mov_read_header(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
/* check MOV header */
if ((err = mov_read_default(mov, pb, atom)) < 0) {
av_log(s, AV_LOG_ERROR, "error reading header: %d\n", err);
+ mov_read_close(s);
return err;
}
if (!mov->found_moov) {
av_log(s, AV_LOG_ERROR, "moov atom not found\n");
+ mov_read_close(s);
return AVERROR_INVALIDDATA;
}
av_dlog(mov->fc, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb));
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 ||
+ if (!mov->next_root_atom)
+ return AVERROR_EOF;
+ avio_seek(s->pb, mov->next_root_atom, SEEK_SET);
+ mov->next_root_atom = 0;
+ if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 ||
s->pb->eof_reached)
return AVERROR_EOF;
av_dlog(s, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));
pkt->stream_index = sc->ffindex;
pkt->dts = sample->timestamp;
- if (sc->ctts_data) {
+ if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration;
/* update ctts context */
sc->ctts_sample++;
return 0;
}
-static int mov_read_close(AVFormatContext *s)
-{
- MOVContext *mov = s->priv_data;
- int i, j;
-
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- MOVStreamContext *sc = st->priv_data;
-
- av_freep(&sc->ctts_data);
- for (j = 0; j < sc->drefs_count; j++) {
- av_freep(&sc->drefs[j].path);
- av_freep(&sc->drefs[j].dir);
- }
- av_freep(&sc->drefs);
- if (sc->pb && sc->pb != s->pb)
- avio_close(sc->pb);
- }
-
- if (mov->dv_demux) {
- for (i = 0; i < mov->dv_fctx->nb_streams; i++) {
- av_freep(&mov->dv_fctx->streams[i]->codec);
- av_freep(&mov->dv_fctx->streams[i]);
- }
- av_freep(&mov->dv_fctx);
- av_freep(&mov->dv_demux);
- }
-
- av_freep(&mov->trex_data);
-
- return 0;
-}
-
AVInputFormat ff_mov_demuxer = {
.name = "mov,mp4,m4a,3gp,3g2,mj2",
.long_name = NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"),