//#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);
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_dvc1(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ uint8_t profile_level;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+
+ if (atom.size >= (1<<28) || atom.size < 7)
+ return AVERROR_INVALIDDATA;
+
+ profile_level = avio_r8(pb);
+ if (profile_level & 0xf0 != 0xc0)
+ return 0;
+
+ av_free(st->codec->extradata);
+ st->codec->extradata = av_mallocz(atom.size - 7 + FF_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codec->extradata)
+ return AVERROR(ENOMEM);
+ st->codec->extradata_size = atom.size - 7;
+ avio_seek(pb, 6, SEEK_CUR);
+ avio_read(pb, st->codec->extradata, st->codec->extradata_size);
+ return 0;
+}
+
/**
* An strf atom is a BITMAPINFOHEADER struct. This struct is 40 bytes itself,
* but can have extradata appended at the end after the 40 bytes belonging
if (st->codec->codec_tag &&
st->codec->codec_tag != format &&
- (c->fc->video_codec_id ? ff_codec_get_id(codec_movvideo_tags, format) != c->fc->video_codec_id
+ (c->fc->video_codec_id ? ff_codec_get_id(ff_codec_movvideo_tags, format) != c->fc->video_codec_id
: st->codec->codec_tag != MKTAG('j','p','e','g'))
){
/* Multiple fourcc, we skip JPEG. This is not correct, we should
sc->dref_id= dref_id;
st->codec->codec_tag = format;
- id = ff_codec_get_id(codec_movaudio_tags, format);
+ id = ff_codec_get_id(ff_codec_movaudio_tags, format);
if (id<=0 && ((format&0xFFFF) == 'm'+('s'<<8) || (format&0xFFFF) == 'T'+('S'<<8)))
id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format)&0xFFFF);
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
} else if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO && /* do not overwrite codec type */
format && format != MKTAG('m','p','4','s')) { /* skip old asf mpeg4 tag */
- id = ff_codec_get_id(codec_movvideo_tags, format);
+ id = ff_codec_get_id(ff_codec_movvideo_tags, format);
if (id <= 0)
id = ff_codec_get_id(ff_codec_bmp_tags, format);
if (id > 0)
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)
+ return 0;
if (entries >= UINT_MAX / sizeof(int))
return AVERROR_INVALIDDATA;
sc->keyframes = av_malloc(entries * sizeof(int));
st->nb_frames= total_sample_count;
if (duration)
st->duration= duration;
+ sc->track_end = duration;
return 0;
}
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;
}
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) {
return AVERROR_INVALIDDATA;
}
- if (flags & 0x01) frag->base_data_offset = avio_rb64(pb);
- else frag->base_data_offset = frag->moof_offset;
- if (flags & 0x02) frag->stsd_id = avio_rb32(pb);
- else frag->stsd_id = trex->stsd_id;
+ frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ?
+ avio_rb64(pb) : frag->moof_offset;
+ frag->stsd_id = flags & MOV_TFHD_STSD_ID ? avio_rb32(pb) : trex->stsd_id;
- frag->duration = flags & 0x08 ? avio_rb32(pb) : trex->duration;
- frag->size = flags & 0x10 ? avio_rb32(pb) : trex->size;
- frag->flags = flags & 0x20 ? avio_rb32(pb) : trex->flags;
+ frag->duration = flags & MOV_TFHD_DEFAULT_DURATION ?
+ avio_rb32(pb) : trex->duration;
+ frag->size = flags & MOV_TFHD_DEFAULT_SIZE ?
+ avio_rb32(pb) : trex->size;
+ frag->flags = flags & MOV_TFHD_DEFAULT_FLAGS ?
+ avio_rb32(pb) : trex->flags;
av_dlog(c->fc, "frag flags 0x%x\n", frag->flags);
return 0;
}
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);
- dts = st->duration - sc->time_offset;
+ 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;
av_dlog(c->fc, "first sample flags 0x%x\n", first_sample_flags);
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) || 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);
sc->data_size += sample_size;
}
frag->moof_offset = offset;
- st->duration = dts + sc->time_offset;
+ st->duration = sc->track_end = dts + sc->time_offset;
return 0;
}
{ MKTAG('w','f','e','x'), mov_read_wfex },
{ MKTAG('c','m','o','v'), mov_read_cmov },
{ MKTAG('c','h','a','n'), mov_read_chan }, /* channel layout */
+{ MKTAG('d','v','c','1'), mov_read_dvc1 },
{ 0, NULL }
};
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));