📄 mov.c
字号:
ctx.buf_end = ctx.buffer + moov_len; atom.type = MKTAG( 'm', 'o', 'o', 'v' ); atom.offset = 0; atom.size = moov_len;#ifdef DEBUG// { int fd = open("/tmp/uncompheader.mov", O_WRONLY | O_CREAT); write(fd, moov_data, moov_len); close(fd); }#endif ret = mov_read_default(c, &ctx, atom); av_free(moov_data); av_free(cmov_data); return ret;}#endif/* edit list atom */static int mov_read_elst(MOVContext *c, ByteIOContext *pb, MOV_atom_t atom){ int i, edit_count; get_byte(pb); /* version */ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ edit_count= c->streams[c->fc->nb_streams-1]->edit_count = get_be32(pb); /* entries */ for(i=0; i<edit_count; i++){ get_be32(pb); /* Track duration */ get_be32(pb); /* Media time */ get_be32(pb); /* Media rate */ } dprintf("track[%i].edit_count = %i\n", c->fc->nb_streams-1, c->streams[c->fc->nb_streams-1]->edit_count); return 0;}static const MOVParseTableEntry mov_default_parse_table[] = {/* mp4 atoms */{ MKTAG( 'c', 'o', '6', '4' ), mov_read_stco },{ MKTAG( 'c', 'p', 'r', 't' ), mov_read_default },{ MKTAG( 'c', 'r', 'h', 'd' ), mov_read_default },{ MKTAG( 'c', 't', 't', 's' ), mov_read_ctts }, /* composition time to sample */{ MKTAG( 'd', 'i', 'n', 'f' ), mov_read_default }, /* data information */{ MKTAG( 'd', 'p', 'n', 'd' ), mov_read_leaf },{ MKTAG( 'd', 'r', 'e', 'f' ), mov_read_leaf },{ MKTAG( 'e', 'd', 't', 's' ), mov_read_default },{ MKTAG( 'e', 'l', 's', 't' ), mov_read_elst },{ MKTAG( 'e', 'n', 'd', 'a' ), mov_read_enda },{ MKTAG( 'f', 'r', 'e', 'e' ), mov_read_leaf },{ MKTAG( 'f', 't', 'y', 'p' ), mov_read_ftyp },{ MKTAG( 'h', 'd', 'l', 'r' ), mov_read_hdlr },{ MKTAG( 'h', 'i', 'n', 't' ), mov_read_leaf },{ MKTAG( 'h', 'm', 'h', 'd' ), mov_read_leaf },{ MKTAG( 'i', 'o', 'd', 's' ), mov_read_leaf },{ MKTAG( 'j', 'p', '2', 'h' ), mov_read_jp2h },{ MKTAG( 'm', 'd', 'a', 't' ), mov_read_mdat },{ MKTAG( 'm', 'd', 'h', 'd' ), mov_read_mdhd },{ MKTAG( 'm', 'd', 'i', 'a' ), mov_read_default },{ MKTAG( 'm', 'i', 'n', 'f' ), mov_read_default },{ MKTAG( 'm', 'o', 'o', 'v' ), mov_read_moov },{ MKTAG( 'm', 'p', '4', 'a' ), mov_read_default },{ MKTAG( 'm', 'p', '4', 's' ), mov_read_default },{ MKTAG( 'm', 'p', '4', 'v' ), mov_read_default },{ MKTAG( 'm', 'p', 'o', 'd' ), mov_read_leaf },{ MKTAG( 'm', 'v', 'h', 'd' ), mov_read_mvhd },{ MKTAG( 'n', 'm', 'h', 'd' ), mov_read_leaf },{ MKTAG( 'o', 'd', 'h', 'd' ), mov_read_default },{ MKTAG( 's', 'd', 'h', 'd' ), mov_read_default },{ MKTAG( 's', 'k', 'i', 'p' ), mov_read_leaf },{ MKTAG( 's', 'm', 'h', 'd' ), mov_read_leaf }, /* sound media info header */{ MKTAG( 'S', 'M', 'I', ' ' ), mov_read_smi }, /* Sorenson extension ??? */{ MKTAG( 'a', 'l', 'a', 'c' ), mov_read_alac }, /* alac specific atom */{ MKTAG( 'a', 'v', 'c', 'C' ), mov_read_avcC },{ MKTAG( 's', 't', 'b', 'l' ), mov_read_default },{ MKTAG( 's', 't', 'c', 'o' ), mov_read_stco },{ MKTAG( 's', 't', 'd', 'p' ), mov_read_default },{ MKTAG( 's', 't', 's', 'c' ), mov_read_stsc },{ MKTAG( 's', 't', 's', 'd' ), mov_read_stsd }, /* sample description */{ MKTAG( 's', 't', 's', 'h' ), mov_read_default },{ 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( 't', 'k', 'h', 'd' ), mov_read_tkhd }, /* track header */{ MKTAG( 't', 'r', 'a', 'k' ), mov_read_trak },{ MKTAG( 't', 'r', 'e', 'f' ), mov_read_default }, /* not really */{ MKTAG( 'u', 'd', 't', 'a' ), mov_read_leaf },{ MKTAG( 'u', 'r', 'l', ' ' ), mov_read_leaf },{ MKTAG( 'u', 'r', 'n', ' ' ), mov_read_leaf },{ MKTAG( 'u', 'u', 'i', 'd' ), mov_read_leaf },{ MKTAG( 'v', 'm', 'h', 'd' ), mov_read_leaf }, /* video media info header */{ MKTAG( 'w', 'a', 'v', 'e' ), mov_read_wave },/* extra mp4 */{ MKTAG( 'M', 'D', 'E', 'S' ), mov_read_leaf },/* QT atoms */{ MKTAG( 'c', 'h', 'a', 'p' ), mov_read_leaf },{ MKTAG( 'c', 'l', 'i', 'p' ), mov_read_default },{ MKTAG( 'c', 'r', 'g', 'n' ), mov_read_leaf },{ MKTAG( 'c', 't', 'a', 'b' ), mov_read_ctab },{ MKTAG( 'e', 's', 'd', 's' ), mov_read_esds },{ MKTAG( 'k', 'm', 'a', 't' ), mov_read_leaf },{ MKTAG( 'm', 'a', 't', 't' ), mov_read_default },{ MKTAG( 'r', 'd', 'r', 'f' ), mov_read_leaf },{ MKTAG( 'r', 'm', 'd', 'a' ), mov_read_default },{ MKTAG( 'r', 'm', 'd', 'r' ), mov_read_leaf },{ MKTAG( 'r', 'm', 'r', 'a' ), mov_read_default },{ MKTAG( 's', 'c', 'p', 't' ), mov_read_leaf },{ MKTAG( 's', 's', 'r', 'c' ), mov_read_leaf },{ MKTAG( 's', 'y', 'n', 'c' ), mov_read_leaf },{ MKTAG( 't', 'c', 'm', 'd' ), mov_read_leaf },{ MKTAG( 'w', 'i', 'd', 'e' ), mov_read_wide }, /* place holder *///{ MKTAG( 'r', 'm', 'q', 'u' ), mov_read_leaf },#ifdef CONFIG_ZLIB{ MKTAG( 'c', 'm', 'o', 'v' ), mov_read_cmov },#else{ MKTAG( 'c', 'm', 'o', 'v' ), mov_read_leaf },#endif{ 0L, mov_read_leaf }};static void mov_free_stream_context(MOVStreamContext *sc){ if(sc) { 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); av_freep(&sc->ctts_data); av_freep(&sc); }}static inline uint32_t mov_to_tag(uint8_t *buf){ return MKTAG(buf[0], buf[1], buf[2], buf[3]);}static inline uint32_t to_be32(uint8_t *buf){ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];}/* XXX: is it sufficient ? */static int mov_probe(AVProbeData *p){ unsigned int offset; uint32_t tag; int score = 0; /* check file header */ if (p->buf_size <= 12) return 0; offset = 0; for(;;) { /* ignore invalid offset */ if ((offset + 8) > (unsigned int)p->buf_size) return score; tag = mov_to_tag(p->buf + offset + 4); switch(tag) { /* check for obvious tags */ case MKTAG( 'j', 'P', ' ', ' ' ): /* jpeg 2000 signature */ case MKTAG( 'm', 'o', 'o', 'v' ): case MKTAG( 'm', 'd', 'a', 't' ): case MKTAG( 'p', 'n', 'o', 't' ): /* detect movs with preview pics like ew.mov and april.mov */ case MKTAG( 'u', 'd', 't', 'a' ): /* Packet Video PVAuthor adds this and a lot of more junk */ return AVPROBE_SCORE_MAX; /* those are more common words, so rate then a bit less */ case MKTAG( 'w', 'i', 'd', 'e' ): case MKTAG( 'f', 'r', 'e', 'e' ): case MKTAG( 'j', 'u', 'n', 'k' ): case MKTAG( 'p', 'i', 'c', 't' ): return AVPROBE_SCORE_MAX - 5; case MKTAG( 'f', 't', 'y', 'p' ): case MKTAG( 's', 'k', 'i', 'p' ): case MKTAG( 'u', 'u', 'i', 'd' ): offset = to_be32(p->buf+offset) + offset; /* if we only find those cause probedata is too small at least rate them */ score = AVPROBE_SCORE_MAX - 50; break; default: /* unrecognized tag */ return score; } } return score;}static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap){ MOVContext *mov = (MOVContext *) s->priv_data; ByteIOContext *pb = &s->pb; int i, j, nb, err; MOV_atom_t atom = { 0, 0, 0 }; mov->fc = s; mov->parse_table = mov_default_parse_table; if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ atom.size = url_fsize(pb); else atom.size = 0x7FFFFFFFFFFFFFFFLL; /* check MOV header */ err = mov_read_default(mov, pb, atom); if (err<0 || (!mov->found_moov && !mov->found_mdat)) { av_log(s, AV_LOG_ERROR, "mov: header not found !!! (err:%d, moov:%d, mdat:%d) pos:%"PRId64"\n", err, mov->found_moov, mov->found_mdat, url_ftell(pb)); return -1; } dprintf("on_parse_exit_offset=%d\n", (int) url_ftell(pb)); /* some cleanup : make sure we are on the mdat atom */ if(!url_is_streamed(pb) && (url_ftell(pb) != mov->mdat_offset)) url_fseek(pb, mov->mdat_offset, SEEK_SET); mov->next_chunk_offset = mov->mdat_offset; /* initialise reading */ mov->total_streams = nb = s->nb_streams;#if 1 for(i=0; i<s->nb_streams;) { if(s->streams[i]->codec->codec_type == CODEC_TYPE_MOV_OTHER) {/* not audio, not video, delete */ av_free(s->streams[i]); for(j=i+1; j<s->nb_streams; j++) s->streams[j-1] = s->streams[j]; s->nb_streams--; } else i++; } for(i=0; i<s->nb_streams;i++) { MOVStreamContext *sc = (MOVStreamContext *)s->streams[i]->priv_data; if(!sc->time_rate) sc->time_rate=1; if(!sc->time_scale) sc->time_scale= mov->time_scale; av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale); if(s->streams[i]->duration != AV_NOPTS_VALUE){ assert(s->streams[i]->duration % sc->time_rate == 0); s->streams[i]->duration /= sc->time_rate; } sc->ffindex = i; sc->is_ff_stream = 1; }#endif return 0;}/* Yes, this is ugly... I didn't write the specs of QT :p *//* XXX:remove useless commented code sometime */static int mov_read_packet(AVFormatContext *s, AVPacket *pkt){ MOVContext *mov = (MOVContext *) s->priv_data; MOVStreamContext *sc; AVStream *st; int64_t offset = INT64_MAX; int64_t best_dts = INT64_MAX; int i, a, b, m; int next_sample= -99; int size; int idx; size = 0x0FFFFFFF; if (mov->partial) { sc = mov->partial; idx = sc->sample_to_chunk_index; if (idx < 0) return 0; dprintf("sc[ffid %d]->sample_size = %ld\n", sc->ffindex, sc->sample_size); //size = sc->sample_sizes[sc->current_sample]; // that ain't working... //size = (sc->sample_size)?sc->sample_size:sc->sample_sizes[sc->current_sample]; size = (sc->sample_size > 1)?sc->sample_size:sc->sample_sizes[sc->current_sample]; next_sample= sc->current_sample+1; sc->left_in_chunk--; if (sc->left_in_chunk <= 0) mov->partial = 0; offset = mov->next_chunk_offset; /* extract the sample */ goto readchunk; }again: sc = 0; if(offset == INT64_MAX) best_dts= INT64_MAX; for(i=0; i<mov->total_streams; i++) { MOVStreamContext *msc = mov->streams[i]; if ((msc->next_chunk < msc->chunk_count) && msc->next_chunk >= 0){ if (msc->sample_to_time_index < msc->stts_count && mov->ni) { int64_t dts; int index= msc->sample_to_time_index; int sample= msc->sample_to_time_sample; int time= msc->sample_to_time_time; int duration = msc->stts_data[index].duration; int count = msc->stts_data[index].count; if (sample + count <= msc->current_sample) { sample += count; time += count*duration; index ++; duration = msc->stts_data[index].duration; } dts = time + (msc->current_sample - sample) * (int64_t)duration; dts = av_rescale(dts, AV_TIME_BASE, msc->time_scale); dprintf("stream: %d dts: %"PRId64" best_dts: %"PRId64" offset: %"PRId64"\n", i, dts, best_dts, offset); if(dts < best_dts){ best_dts= dts; sc = msc; offset = msc->chunk_offsets[msc->next_chunk]; } }else{ if ((msc->chunk_offsets[msc->next_chunk] < offset)) { sc = msc; offset = msc->chunk_offsets[msc->next_chunk]; } } } } if (!sc || offset==INT64_MAX) return -1; sc->next_chunk++; if(mov->next_chunk_offset < offset) { /* some meta data */ url_fskip(&s->pb, (offset - mov->next_chunk_offset)); mov->next_chunk_offset = offset; } if(!sc->is_ff_stream || (s->streams[sc->ffindex]->discard >= AVDISCARD_ALL)) { url_fskip(&s->pb, (offset - mov->next_chunk_offset)); mov->next_chunk_offset = offset; offset = INT64_MAX; goto again; } /* now get the chunk size... */ for(i=0; i<mov->total_streams; i++) { MOVStreamContext *msc = mov->streams[i]; if ((msc->next_chunk < msc->chunk_count) && msc->chunk_offsets[msc->next_chunk] - offset < size && msc->chunk_offsets[msc->next_chunk] > offset) size = msc->chunk_offsets[msc->next_chunk] - offset; }#ifdef MOV_MINOLTA_FIX //Make sure that size is according to sample_size (Needed by .mov files //created on a Minolta Dimage Xi where audio chunks contains waste data in the end) //Maybe we should really not only check sc->sample_size, but also sc->sample_sizes //but I have no such movies if (sc->sample_size > 0) { int foundsize=0; for(i=0; i<(sc->sample_to_chunk_sz); i++) { if( (sc->sample_to_chunk[i].first)<=(sc->next_chunk) ) { foundsize=sc->sample_to_chunk[i].count*sc->sample_size; } dprintf("sample_to_chunk first=%ld count=%ld, id=%ld\n", sc->sample_to_chunk[i].first, sc->sample_to_chunk[i].count, sc->sample_to_chunk[i].id); } if( (foundsize>0) && (foundsize<size) ) { size=foundsize; } }#endif //MOV_MINOLTA_FIX idx = sc->sample_to_chunk_index; if (idx + 1 < sc->sample_to_chunk_sz && sc->next_chunk >= sc->sample_to_chunk[idx + 1].first)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -