📄 mov.c
字号:
return -1; dprintf(c->fc, "track[%i].ctts.entries = %i\n", c->fc->nb_streams-1, entries); for(i=0; i<entries; i++) { int count =get_be32(pb); int duration =get_be32(pb); if (duration < 0) { av_log(c->fc, AV_LOG_ERROR, "negative ctts, ignoring\n"); sc->ctts_count = 0; url_fskip(pb, 8 * (entries - i - 1)); break; } sc->ctts_data[i].count = count; sc->ctts_data[i].duration= duration; sc->time_rate= ff_gcd(sc->time_rate, duration); } return 0;}static void mov_build_index(MOVContext *mov, AVStream *st){ MOVStreamContext *sc = st->priv_data; offset_t current_offset; int64_t current_dts = 0; unsigned int stts_index = 0; unsigned int stsc_index = 0; unsigned int stss_index = 0; unsigned int i, j; /* only use old uncompressed audio chunk demuxing when stts specifies it */ if (!(st->codec->codec_type == CODEC_TYPE_AUDIO && 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 distance = 0; int key_off = sc->keyframes && sc->keyframes[0] == 1; st->nb_frames = sc->sample_count; for (i = 0; i < sc->chunk_count; i++) { current_offset = sc->chunk_offsets[i]; if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) stsc_index++; for (j = 0; j < sc->sample_to_chunk[stsc_index].count; j++) { if (current_sample >= sc->sample_count) { av_log(mov->fc, AV_LOG_ERROR, "wrong sample count\n"); goto out; } keyframe = !sc->keyframe_count || current_sample+key_off == sc->keyframes[stss_index]; if (keyframe) { distance = 0; if (stss_index + 1 < sc->keyframe_count) stss_index++; } sample_size = sc->sample_size > 0 ? sc->sample_size : sc->sample_sizes[current_sample]; if(sc->pseudo_stream_id == -1 || sc->sample_to_chunk[stsc_index].id - 1 == sc->pseudo_stream_id) { av_add_index_entry(st, current_offset, current_dts, sample_size, distance, keyframe ? AVINDEX_KEYFRAME : 0); dprintf(mov->fc, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " "size %d, distance %d, keyframe %d\n", st->index, current_sample, current_offset, current_dts, sample_size, distance, keyframe); } current_offset += sample_size; assert(sc->stts_data[stts_index].duration % sc->time_rate == 0); current_dts += sc->stts_data[stts_index].duration / sc->time_rate; distance++; stts_sample++; current_sample++; if (stts_index + 1 < sc->stts_count && stts_sample == sc->stts_data[stts_index].count) { stts_sample = 0; stts_index++; } } } } else { /* read whole chunk */ unsigned int chunk_samples, chunk_size, chunk_duration; unsigned int frames = 1; for (i = 0; i < sc->chunk_count; i++) { current_offset = sc->chunk_offsets[i]; if (stsc_index + 1 < sc->sample_to_chunk_sz && i + 1 == sc->sample_to_chunk[stsc_index + 1].first) stsc_index++; chunk_samples = sc->sample_to_chunk[stsc_index].count; /* get chunk size, beware of alaw/ulaw/mace */ if (sc->samples_per_frame > 0 && (chunk_samples * sc->bytes_per_frame % sc->samples_per_frame == 0)) { if (sc->samples_per_frame < 160) chunk_size = chunk_samples * sc->bytes_per_frame / sc->samples_per_frame; else { chunk_size = sc->bytes_per_frame; frames = chunk_samples / sc->samples_per_frame; chunk_samples = sc->samples_per_frame; } } else chunk_size = chunk_samples * sc->sample_size; for (j = 0; j < frames; j++) { av_add_index_entry(st, current_offset, current_dts, chunk_size, 0, AVINDEX_KEYFRAME); /* get chunk duration */ chunk_duration = 0; while (chunk_samples > 0) { if (chunk_samples < sc->stts_data[stts_index].count) { chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; sc->stts_data[stts_index].count -= chunk_samples; break; } else { chunk_duration += sc->stts_data[stts_index].duration * chunk_samples; chunk_samples -= sc->stts_data[stts_index].count; if (stts_index + 1 < sc->stts_count) stts_index++; } } current_offset += sc->bytes_per_frame; dprintf(mov->fc, "AVIndex stream %d, chunk %d, offset %"PRIx64", dts %"PRId64", " "size %d, duration %d\n", st->index, i, current_offset, current_dts, chunk_size, chunk_duration); assert(chunk_duration % sc->time_rate == 0); current_dts += chunk_duration / sc->time_rate; } } } out: /* adjust sample count to avindex entries */ sc->sample_count = st->nb_index_entries;}static int mov_read_trak(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ AVStream *st; MOVStreamContext *sc; int ret; st = av_new_stream(c->fc, c->fc->nb_streams); if (!st) return AVERROR(ENOMEM); sc = av_mallocz(sizeof(MOVStreamContext)); if (!sc) return AVERROR(ENOMEM); st->priv_data = sc; st->codec->codec_type = CODEC_TYPE_DATA; st->start_time = 0; /* XXX: check */ if ((ret = mov_read_default(c, pb, atom)) < 0) return ret; /* sanity checks */ if(sc->chunk_count && (!sc->stts_count || !sc->sample_to_chunk_sz || (!sc->sample_size && !sc->sample_count))){ av_log(c->fc, AV_LOG_ERROR, "stream %d, missing mandatory atoms, broken header\n", st->index); sc->sample_count = 0; //ignore track return 0; } if(!sc->time_rate) sc->time_rate=1; if(!sc->time_scale) sc->time_scale= c->time_scale; av_set_pts_info(st, 64, sc->time_rate, sc->time_scale); if (st->codec->codec_type == CODEC_TYPE_AUDIO && !st->codec->frame_size && sc->stts_count == 1) st->codec->frame_size = av_rescale(sc->time_rate, st->codec->sample_rate, sc->time_scale); if(st->duration != AV_NOPTS_VALUE){ assert(st->duration % sc->time_rate == 0); st->duration /= sc->time_rate; } sc->ffindex = st->index; mov_build_index(c, st); if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { if (url_fopen(&sc->pb, sc->drefs[sc->dref_id-1].path, URL_RDONLY) < 0) av_log(c->fc, AV_LOG_ERROR, "stream %d, error opening file %s: %s\n", st->index, sc->drefs[sc->dref_id-1].path, strerror(errno)); } else sc->pb = c->fc->pb; switch (st->codec->codec_id) {#ifdef CONFIG_H261_DECODER case CODEC_ID_H261:#endif#ifdef CONFIG_H263_DECODER case CODEC_ID_H263:#endif#ifdef CONFIG_MPEG4_DECODER case CODEC_ID_MPEG4:#endif st->codec->width= 0; /* let decoder init width/height */ st->codec->height= 0; break;#ifdef CONFIG_VORBIS_DECODER case CODEC_ID_VORBIS:#endif st->codec->sample_rate= 0; /* let decoder init parameters properly */ break; } /* Do not need those anymore. */ av_freep(&sc->chunk_offsets); av_freep(&sc->sample_to_chunk); av_freep(&sc->sample_sizes); av_freep(&sc->keyframes); av_freep(&sc->stts_data); return 0;}static void mov_parse_udta_string(ByteIOContext *pb, char *str, int size){ uint16_t str_size = get_be16(pb); /* string length */; get_be16(pb); /* skip language */ get_buffer(pb, str, FFMIN(size, str_size));}static int mov_read_udta(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ uint64_t end = url_ftell(pb) + atom.size; while (url_ftell(pb) + 8 < end) { uint32_t tag_size = get_be32(pb); uint32_t tag = get_le32(pb); uint64_t next = url_ftell(pb) + tag_size - 8; if (next > end) // stop if tag_size is wrong break; switch (tag) { case MKTAG(0xa9,'n','a','m'): mov_parse_udta_string(pb, c->fc->title, sizeof(c->fc->title)); break; case MKTAG(0xa9,'w','r','t'): mov_parse_udta_string(pb, c->fc->author, sizeof(c->fc->author)); break; case MKTAG(0xa9,'c','p','y'): mov_parse_udta_string(pb, c->fc->copyright, sizeof(c->fc->copyright)); break; case MKTAG(0xa9,'i','n','f'): mov_parse_udta_string(pb, c->fc->comment, sizeof(c->fc->comment)); break; default: break; } url_fseek(pb, next, SEEK_SET); } return 0;}static int mov_read_tkhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ AVStream *st = c->fc->streams[c->fc->nb_streams-1]; int version = get_byte(pb); get_be24(pb); /* flags */ /* MOV_TRACK_ENABLED 0x0001 MOV_TRACK_IN_MOVIE 0x0002 MOV_TRACK_IN_PREVIEW 0x0004 MOV_TRACK_IN_POSTER 0x0008 */ if (version == 1) { get_be64(pb); get_be64(pb); } else { get_be32(pb); /* creation time */ get_be32(pb); /* modification time */ } st->id = (int)get_be32(pb); /* track id (NOT 0 !)*/ get_be32(pb); /* reserved */ st->start_time = 0; /* check */ /* highlevel (considering edits) duration in movie timebase */ (version == 1) ? get_be64(pb) : get_be32(pb); get_be32(pb); /* reserved */ get_be32(pb); /* reserved */ get_be16(pb); /* layer */ get_be16(pb); /* alternate group */ get_be16(pb); /* volume */ get_be16(pb); /* reserved */ url_fskip(pb, 36); /* display matrix */ /* those are fixed-point */ get_be32(pb); /* track width */ get_be32(pb); /* track height */ return 0;}static int mov_read_tfhd(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ MOVFragment *frag = &c->fragment; MOVTrackExt *trex = NULL; int flags, track_id, i; get_byte(pb); /* version */ flags = get_be24(pb); track_id = get_be32(pb); if (!track_id || track_id > c->fc->nb_streams) return -1; frag->track_id = track_id; for (i = 0; i < c->trex_count; i++) if (c->trex_data[i].track_id == frag->track_id) { trex = &c->trex_data[i]; break; } if (!trex) { av_log(c->fc, AV_LOG_ERROR, "could not find corresponding trex\n"); return -1; } if (flags & 0x01) frag->base_data_offset = get_be64(pb); else frag->base_data_offset = frag->moof_offset; if (flags & 0x02) frag->stsd_id = get_be32(pb); else frag->stsd_id = trex->stsd_id; frag->duration = flags & 0x08 ? get_be32(pb) : trex->duration; frag->size = flags & 0x10 ? get_be32(pb) : trex->size; frag->flags = flags & 0x20 ? get_be32(pb) : trex->flags; dprintf(c->fc, "frag flags 0x%x\n", frag->flags); return 0;}static int mov_read_trex(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ MOVTrackExt *trex; if ((uint64_t)c->trex_count+1 >= UINT_MAX / sizeof(*c->trex_data)) return -1; c->trex_data = av_realloc(c->trex_data, (c->trex_count+1)*sizeof(*c->trex_data)); if (!c->trex_data) return AVERROR(ENOMEM); trex = &c->trex_data[c->trex_count++]; get_byte(pb); /* version */ get_be24(pb); /* flags */ trex->track_id = get_be32(pb); trex->stsd_id = get_be32(pb); trex->duration = get_be32(pb); trex->size = get_be32(pb); trex->flags = get_be32(pb); return 0;}static int mov_read_trun(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ MOVFragment *frag = &c->fragment; AVStream *st; MOVStreamContext *sc; uint64_t offset; int64_t dts; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; int flags, distance, i; if (!frag->track_id || frag->track_id > c->fc->nb_streams) return -1; st = c->fc->streams[frag->track_id-1]; sc = st->priv_data; if (sc->pseudo_stream_id+1 != frag->stsd_id) return 0; get_byte(pb); /* version */ flags = get_be24(pb); entries = get_be32(pb); dprintf(c->fc, "flags 0x%x entries %d\n", flags, entries); if (flags & 0x001) data_offset = get_be32(pb); if (flags & 0x004) first_sample_flags = get_be32(pb); if (flags & 0x800) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -