📄 mov.c
字号:
for(i=0; i<entries; i++) { sc->sample_sizes[i] = get_be32(pb);#ifdef DEBUG/* printf("sample_sizes[]=%ld\n", sc->sample_sizes[i]); */#endif } return 0;}static int parse_stts(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param){ MOVContext *c; int entries, i; AVStream *st; MOVStreamContext *sc;#ifdef DEBUG print_atom("stts", atom_type, atom_offset, atom_size);#endif c = (MOVContext *)param; st = c->fc->streams[c->fc->nb_streams-1]; sc = (MOVStreamContext *)st->priv_data; get_byte(pb); /* version */ get_byte(pb); get_byte(pb); get_byte(pb); /* flags */ entries = get_be32(pb);#ifdef DEBUGprintf("track[%i].stts.entries = %i\n", c->fc->nb_streams-1, entries);#endif for(i=0; i<entries; i++) { int sample_duration; get_be32(pb); sample_duration = get_be32(pb); if (!i && st->codec.codec_type==CODEC_TYPE_VIDEO) { st->codec.frame_rate = FRAME_RATE_BASE * c->streams[c->total_streams]->time_scale; if (sample_duration) st->codec.frame_rate /= sample_duration;#ifdef DEBUG printf("VIDEO FRAME RATE= %i (sd= %i)\n", st->codec.frame_rate, sample_duration);#endif } } return 0;}#ifdef CONFIG_ZLIBstatic int null_read_packet(void *opaque, UINT8 *buf, int buf_size){ return -1;}static int parse_cmov(const MOVParseTableEntry *parse_table, ByteIOContext *pb, UINT32 atom_type, INT64 atom_offset, INT64 atom_size, void *param){ MOVContext *c; ByteIOContext ctx; char *cmov_data; unsigned char *moov_data; /* uncompressed data */ long cmov_len, moov_len; int ret;#ifdef DEBUG print_atom("cmov", atom_type, atom_offset, atom_size);#endif c = (MOVContext *)param; get_be32(pb); /* dcom atom */ if (get_le32(pb) != MKTAG( 'd', 'c', 'o', 'm' )) return -1; if (get_le32(pb) != MKTAG( 'z', 'l', 'i', 'b' )) { puts("unknown compression for cmov atom !"); return -1; } get_be32(pb); /* cmvd atom */ if (get_le32(pb) != MKTAG( 'c', 'm', 'v', 'd' )) return -1; moov_len = get_be32(pb); /* uncompressed size */ cmov_len = atom_size - 6 * 4; cmov_data = av_malloc(cmov_len); if (!cmov_data) return -1; moov_data = av_malloc(moov_len); if (!moov_data) { av_free(cmov_data); return -1; } get_buffer(pb, cmov_data, cmov_len); if(uncompress (moov_data, &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) return -1; if(init_put_byte(&ctx, moov_data, moov_len, 0, NULL, null_read_packet, NULL, NULL) != 0) return -1; ctx.buf_end = ctx.buffer + moov_len; ret = parse_default(parse_table, &ctx, MKTAG( 'm', 'o', 'o', 'v' ), 0, moov_len, param); av_free(moov_data); av_free(cmov_data); return ret;}#endifstatic const MOVParseTableEntry mov_default_parse_table[] = {/* mp4 atoms */{ MKTAG( 'm', 'p', '4', 'a' ), parse_default },{ MKTAG( 'c', 'o', '6', '4' ), parse_stco },{ MKTAG( 's', 't', 'c', 'o' ), parse_stco },{ MKTAG( 'c', 'r', 'h', 'd' ), parse_default },{ MKTAG( 'c', 't', 't', 's' ), parse_leaf },{ MKTAG( 'c', 'p', 'r', 't' ), parse_default },{ MKTAG( 'u', 'r', 'l', ' ' ), parse_leaf },{ MKTAG( 'u', 'r', 'n', ' ' ), parse_leaf },{ MKTAG( 'd', 'i', 'n', 'f' ), parse_default },{ MKTAG( 'd', 'r', 'e', 'f' ), parse_leaf },{ MKTAG( 's', 't', 'd', 'p' ), parse_default },{ MKTAG( 'e', 's', 'd', 's' ), parse_default },{ MKTAG( 'e', 'd', 't', 's' ), parse_default },{ MKTAG( 'e', 'l', 's', 't' ), parse_leaf },{ MKTAG( 'u', 'u', 'i', 'd' ), parse_default },{ MKTAG( 'f', 'r', 'e', 'e' ), parse_leaf },{ MKTAG( 'h', 'd', 'l', 'r' ), parse_hdlr },{ MKTAG( 'h', 'm', 'h', 'd' ), parse_leaf },{ MKTAG( 'h', 'i', 'n', 't' ), parse_leaf },{ MKTAG( 'n', 'm', 'h', 'd' ), parse_leaf },{ MKTAG( 'm', 'p', '4', 's' ), parse_default },{ MKTAG( 'm', 'd', 'i', 'a' ), parse_default },{ MKTAG( 'm', 'd', 'a', 't' ), parse_mdat },{ MKTAG( 'm', 'd', 'h', 'd' ), parse_mdhd },{ MKTAG( 'm', 'i', 'n', 'f' ), parse_default },{ MKTAG( 'm', 'o', 'o', 'v' ), parse_moov },{ MKTAG( 'm', 'v', 'h', 'd' ), parse_mvhd },{ MKTAG( 'i', 'o', 'd', 's' ), parse_leaf },{ MKTAG( 'o', 'd', 'h', 'd' ), parse_default },{ MKTAG( 'm', 'p', 'o', 'd' ), parse_leaf },{ MKTAG( 's', 't', 's', 'd' ), parse_stsd },{ MKTAG( 's', 't', 's', 'z' ), parse_stsz },{ MKTAG( 's', 't', 'b', 'l' ), parse_default },{ MKTAG( 's', 't', 's', 'c' ), parse_stsc },{ MKTAG( 's', 'd', 'h', 'd' ), parse_default },{ MKTAG( 's', 't', 's', 'h' ), parse_default },{ MKTAG( 's', 'k', 'i', 'p' ), parse_default },{ MKTAG( 's', 'm', 'h', 'd' ), parse_leaf },{ MKTAG( 'd', 'p', 'n', 'd' ), parse_leaf },{ MKTAG( 's', 't', 's', 's' ), parse_leaf },{ MKTAG( 's', 't', 't', 's' ), parse_stts },{ MKTAG( 't', 'r', 'a', 'k' ), parse_trak },{ MKTAG( 't', 'k', 'h', 'd' ), parse_tkhd },{ MKTAG( 't', 'r', 'e', 'f' ), parse_default }, /* not really */{ MKTAG( 'u', 'd', 't', 'a' ), parse_leaf },{ MKTAG( 'v', 'm', 'h', 'd' ), parse_leaf },{ MKTAG( 'm', 'p', '4', 'v' ), parse_default },/* extra mp4 */{ MKTAG( 'M', 'D', 'E', 'S' ), parse_leaf },/* QT atoms */{ MKTAG( 'c', 'h', 'a', 'p' ), parse_leaf },{ MKTAG( 'c', 'l', 'i', 'p' ), parse_default },{ MKTAG( 'c', 'r', 'g', 'n' ), parse_leaf },{ MKTAG( 'k', 'm', 'a', 't' ), parse_leaf },{ MKTAG( 'm', 'a', 't', 't' ), parse_default },{ MKTAG( 'r', 'd', 'r', 'f' ), parse_leaf },{ MKTAG( 'r', 'm', 'd', 'a' ), parse_default },{ MKTAG( 'r', 'm', 'd', 'r' ), parse_leaf },//{ MKTAG( 'r', 'm', 'q', 'u' ), parse_leaf },{ MKTAG( 'r', 'm', 'r', 'a' ), parse_default },{ MKTAG( 's', 'c', 'p', 't' ), parse_leaf },{ MKTAG( 's', 'y', 'n', 'c' ), parse_leaf },{ MKTAG( 's', 's', 'r', 'c' ), parse_leaf },{ MKTAG( 't', 'c', 'm', 'd' ), parse_leaf },{ MKTAG( 'w', 'i', 'd', 'e' ), parse_wide }, /* place holder */#ifdef CONFIG_ZLIB{ MKTAG( 'c', 'm', 'o', 'v' ), parse_cmov },#else{ MKTAG( 'c', 'm', 'o', 'v' ), parse_leaf },#endif{ 0L, parse_leaf }};static void mov_free_stream_context(MOVStreamContext *sc){ if(sc) { av_free(sc->chunk_offsets); av_free(sc->sample_to_chunk); av_free(sc->header_data); av_free(sc); }}static uint32_t to_tag(uint8_t *buf){ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);}static uint32_t to_be32(uint8_t *buf){ return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];}/* XXX: is it suffisant ? */static int mov_probe(AVProbeData *p){ unsigned int offset; uint32_t tag; /* 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 0; tag = to_tag(p->buf + offset + 4); switch(tag) { case MKTAG( 'm', 'o', 'o', 'v' ): case MKTAG( 'w', 'i', 'd', 'e' ): case MKTAG( 'f', 'r', 'e', 'e' ): case MKTAG( 'm', 'd', 'a', 't'): return AVPROBE_SCORE_MAX; case MKTAG( 'f', 't', 'y', 'p' ): case MKTAG( 's', 'k', 'i', 'p' ): offset = to_be32(p->buf) + offset; break; default: /* unrecognized tag */ return 0; } } return 0;}static int mov_read_header(AVFormatContext *s, AVFormatParameters *ap){ MOVContext *mov = s->priv_data; ByteIOContext *pb = &s->pb; int i, j, nb, err; INT64 size; mov->fc = s;#if 0 /* XXX: I think we should auto detect */ if(s->iformat->name[1] == 'p') mov->mp4 = 1;#endif if(!url_is_streamed(pb)) /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ size = url_filesize(url_fileno(pb)); else size = 0x7FFFFFFFFFFFFFFF;#ifdef DEBUG printf("filesz=%Ld\n", size);#endif /* check MOV header */ err = parse_default(mov_default_parse_table, pb, 0L, 0LL, size, mov); if(err<0 || (!mov->found_moov || !mov->found_mdat)) { puts("header not found !!!"); exit(1); }#ifdef DEBUG printf("on_parse_exit_offset=%d\n", (int) url_ftell(pb));#endif /* 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 */#ifdef DEBUG printf("mdat_reset_offset=%d\n", (int) url_ftell(pb));#endif#ifdef DEBUG printf("streams= %d\n", s->nb_streams);#endif 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; sc = (MOVStreamContext *)s->streams[i]->priv_data; sc->ffindex = i; sc->is_ff_stream = 1; }#endif#ifdef DEBUG printf("real streams= %d\n", s->nb_streams);#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 = s->priv_data; MOVStreamContext *sc; INT64 offset = 0x0FFFFFFFFFFFFFFF; int i; int st_id = 0, size; size = 0x0FFFFFFF; #ifdef MOV_SPLIT_CHUNKS if (mov->partial) { int idx; st_id = mov->partial - 1; idx = mov->streams[st_id]->sample_to_chunk_index; if (idx < 0) return 0; size = mov->streams[st_id]->sample_sizes[mov->streams[st_id]->current_sample]; mov->streams[st_id]->current_sample++; mov->streams[st_id]->left_in_chunk--; if(mov->streams[st_id]->left_in_chunk <= 0) mov->partial = 0; offset = mov->next_chunk_offset; /* extract the sample */ goto readchunk; }#endifagain: for(i=0; i<mov->total_streams; i++) { if((mov->streams[i]->next_chunk < mov->streams[i]->chunk_count) && (mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk] < offset)) { st_id = i; offset = mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk]; } } mov->streams[st_id]->next_chunk++; if(offset==0x0FFFFFFFFFFFFFFF) return -1; if(mov->next_chunk_offset < offset) { /* some meta data */ url_fskip(&s->pb, (offset - mov->next_chunk_offset)); mov->next_chunk_offset = offset; }//printf("chunk: [%i] %lli -> %lli\n", st_id, mov->next_chunk_offset, offset); if(!mov->streams[st_id]->is_ff_stream) { url_fskip(&s->pb, (offset - mov->next_chunk_offset)); mov->next_chunk_offset = offset; offset = 0x0FFFFFFFFFFFFFFF; goto again; } /* now get the chunk size... */ for(i=0; i<mov->total_streams; i++) { if((mov->streams[i]->next_chunk < mov->streams[i]->chunk_count) && ((mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk] - offset) < size)) { size = mov->streams[i]->chunk_offsets[mov->streams[i]->next_chunk] - offset; } }#ifdef MOV_SPLIT_CHUNKS /* split chunks into samples */ if(mov->streams[st_id]->sample_size == 0) { int idx; idx = mov->streams[st_id]->sample_to_chunk_index; if ((idx + 1 < mov->streams[st_id]->sample_to_chunk_sz) && (mov->streams[st_id]->next_chunk >= mov->streams[st_id]->sample_to_chunk[idx + 1].first)) idx++; mov->streams[st_id]->sample_to_chunk_index = idx; if(idx >= 0 && mov->streams[st_id]->sample_to_chunk[idx].count != 1) { mov->partial = st_id+1; /* we'll have to get those samples before next chunk */ mov->streams[st_id]->left_in_chunk = (mov->streams[st_id]->sample_to_chunk[idx].count) - 1; size = mov->streams[st_id]->sample_sizes[mov->streams[st_id]->current_sample]; } mov->streams[st_id]->current_sample++; }#endifreadchunk://printf("chunk: [%i] %lli -> %lli (%i)\n", st_id, offset, offset + size, size); if(size == 0x0FFFFFFF) size = mov->mdat_size + mov->mdat_offset - offset; if(size < 0) return -1; if(size == 0) return -1; url_fseek(&s->pb, offset, SEEK_SET); sc = mov->streams[st_id]; if (sc->header_len > 0) { av_new_packet(pkt, size + sc->header_len); memcpy(pkt->data, sc->header_data, sc->header_len); get_buffer(&s->pb, pkt->data + sc->header_len, size); /* free header */ av_freep(&sc->header_data); sc->header_len = 0; } else { av_new_packet(pkt, size); get_buffer(&s->pb, pkt->data, pkt->size); } pkt->stream_index = sc->ffindex;#ifdef DEBUG/* printf("Packet (%d, %d, %ld) ", pkt->stream_index, st_id, pkt->size); for(i=0; i<8; i++) printf("%02x ", pkt->data[i]); for(i=0; i<8; i++) printf("%c ", (pkt->data[i]) & 0x7F); puts("");*/#endif mov->next_chunk_offset = offset + size; return 0;}static int mov_read_close(AVFormatContext *s){ int i; MOVContext *mov = s->priv_data; for(i=0; i<mov->total_streams; i++) mov_free_stream_context(mov->streams[i]); for(i=0; i<s->nb_streams; i++) av_freep(&s->streams[i]); return 0;}static AVInputFormat mov_iformat = { "mov", "QuickTime/MPEG4 format", sizeof(MOVContext), mov_probe, mov_read_header, mov_read_packet, mov_read_close,};int mov_init(void){ av_register_input_format(&mov_iformat); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -