📄 demux_mov.c
字号:
// QuickTime MOV file parser by A'rpi// additional work by Atmos// based on TOOLS/movinfo.c by A'rpi & Al3x// compressed header support from moov.c of the openquicktime lib.// References: http://openquicktime.sf.net/, http://www.heroinewarrior.com/// http://www.geocities.com/SiliconValley/Lakes/2160/fformats/files/mov.pdf// (above url no longer works, file mirrored somewhere? ::atmos)// The QuickTime File Format PDF from Apple:// http://developer.apple.com/techpubs/quicktime/qtdevdocs/PDF/QTFileFormat.pdf// (Complete list of documentation at http://developer.apple.com/quicktime/)// MP4-Lib sources from http://mpeg4ip.sf.net/ might be usefull fot .mp4// aswell as .mov specific stuff.// All sort of Stuff about MPEG4:// http://www.cmlab.csie.ntu.edu.tw/~pkhsiao/thesis.html// I really recommend N4270-1.doc and N4270-2.doc which are exact specs// of the MP4-File Format and the MPEG4 Specific extensions. ::atmos#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream.h"#include "demuxer.h"#include "stheader.h"#include "bswap.h"#include "qtpalette.h"#include "parse_mp4.h" // .MP4 specific stuff#ifdef MACOSX#include <QuickTime/QuickTime.h>#else#include "../loader/qtx/qtxsdk/components.h"#endif#ifdef HAVE_ZLIB#include <zlib.h>#endif#ifndef _FCNTL_H#include <fcntl.h>#endif#define BE_16(x) (((unsigned char *)(x))[0] << 8 | \ ((unsigned char *)(x))[1])#define BE_32(x) (((unsigned char *)(x))[0] << 24 | \ ((unsigned char *)(x))[1] << 16 | \ ((unsigned char *)(x))[2] << 8 | \ ((unsigned char *)(x))[3])#define char2short(x,y) BE_16(&(x)[(y)])#define char2int(x,y) BE_32(&(x)[(y)])typedef struct { unsigned int pts; // duration unsigned int size; off_t pos;} mov_sample_t;typedef struct { unsigned int sample; // number of the first sample in the chunk unsigned int size; // number of samples in the chunk int desc; // for multiple codecs mode - not used off_t pos;} mov_chunk_t;typedef struct { unsigned int first; unsigned int spc; unsigned int sdid;} mov_chunkmap_t;typedef struct { unsigned int num; unsigned int dur;} mov_durmap_t;typedef struct { unsigned int dur; unsigned int pos; int speed; // int frames; int start_sample; int start_frame; int pts_offset;} mov_editlist_t;#define MOV_TRAK_UNKNOWN 0#define MOV_TRAK_VIDEO 1#define MOV_TRAK_AUDIO 2#define MOV_TRAK_FLASH 3#define MOV_TRAK_GENERIC 4#define MOV_TRAK_CODE 5typedef struct { int id; int type; off_t pos; // unsigned int media_handler; unsigned int data_handler; // int timescale; unsigned int length; int samplesize; // 0 = variable int duration; // 0 = variable int width,height; // for video unsigned int fourcc; unsigned int nchannels; unsigned int samplebytes; // int tkdata_len; // track data unsigned char* tkdata; int stdata_len; // stream data unsigned char* stdata; // unsigned char* stream_header; int stream_header_len; // if >0, this header should be sent before the 1st frame // int samples_size; mov_sample_t* samples; int chunks_size; mov_chunk_t* chunks; int chunkmap_size; mov_chunkmap_t* chunkmap; int durmap_size; mov_durmap_t* durmap; int keyframes_size; unsigned int* keyframes; int editlist_size; mov_editlist_t* editlist; int editlist_pos; // void* desc; // image/sound/etc description (pointer to ImageDescription etc)} mov_track_t;void mov_build_index(mov_track_t* trak,int timescale){ int i,j,s; int last=trak->chunks_size; unsigned int pts=0;#if 0 if (trak->chunks_size <= 0) { mp_msg(MSGT_DEMUX, MSGL_WARN, "No chunk offset table, trying to build one!\n"); trak->chunks_size = trak->samples_size; /* XXX: FIXME ! */ trak->chunks = realloc(trak->chunks, sizeof(mov_chunk_t)*trak->chunks_size); for (i=0; i < trak->chunks_size; i++) trak->chunks[i].pos = -1; }#endif mp_msg(MSGT_DEMUX, MSGL_INFO, "MOV track #%d: %d chunks, %d samples\n",trak->id,trak->chunks_size,trak->samples_size); mp_msg(MSGT_DEMUX, MSGL_V, "pts=%d scale=%d time=%5.3f\n",trak->length,trak->timescale,(float)trak->length/(float)trak->timescale); // process chunkmap: i=trak->chunkmap_size; while(i>0){ --i; for(j=trak->chunkmap[i].first;j<last;j++){ trak->chunks[j].desc=trak->chunkmap[i].sdid; trak->chunks[j].size=trak->chunkmap[i].spc; } last=trak->chunkmap[i].first; }#if 0 for (i=0; i < trak->chunks_size; i++) { /* fixup position */ if (trak->chunks[i].pos == -1) if (i > 0) trak->chunks[i].pos = trak->chunks[i-1].pos + trak->chunks[i-1].size; else trak->chunks[i].pos = 0; /* FIXME: set initial pos */#endif // calc pts of chunks: s=0; for(j=0;j<trak->chunks_size;j++){ trak->chunks[j].sample=s; s+=trak->chunks[j].size; } // workaround for fixed-size video frames (dv and uncompressed) if(!trak->samples_size && trak->type!=MOV_TRAK_AUDIO){ trak->samples_size=s; trak->samples=malloc(sizeof(mov_sample_t)*s); for(i=0;i<s;i++) trak->samples[i].size=trak->samplesize; trak->samplesize=0; } if(!trak->samples_size){ // constant sampesize if(trak->durmap_size==1 || (trak->durmap_size==2 && trak->durmap[1].num==1)){ trak->duration=trak->durmap[0].dur; } else mp_msg(MSGT_DEMUX, MSGL_ERR, "*** constant samplesize & variable duration not yet supported! ***\nContact the author if you have such sample file!\n"); return; } // calc pts: s=0; for(j=0;j<trak->durmap_size;j++){ for(i=0;i<trak->durmap[j].num;i++){ trak->samples[s].pts=pts; ++s; pts+=trak->durmap[j].dur; } } // calc sample offsets s=0; for(j=0;j<trak->chunks_size;j++){ off_t pos=trak->chunks[j].pos; for(i=0;i<trak->chunks[j].size;i++){ trak->samples[s].pos=pos; mp_msg(MSGT_DEMUX, MSGL_DBG3, "Sample %5d: pts=%8d off=0x%08X size=%d\n",s, trak->samples[s].pts, (int)trak->samples[s].pos, trak->samples[s].size); pos+=trak->samples[s].size; ++s; } } // precalc editlist entries if(trak->editlist_size>0){ int frame=0; int e_pts=0; for(i=0;i<trak->editlist_size;i++){ mov_editlist_t* el=&trak->editlist[i]; int sample=0; int pts=el->pos; el->start_frame=frame; if(pts<0){ // skip! el->frames=0; continue; } // find start sample for(;sample<trak->samples_size;sample++){ if(pts<=trak->samples[sample].pts) break; } el->start_sample=sample; el->pts_offset=((long long)e_pts*(long long)trak->timescale)/(long long)timescale-trak->samples[sample].pts; pts+=((long long)el->dur*(long long)trak->timescale)/(long long)timescale; e_pts+=el->dur; // find end sample for(;sample<trak->samples_size;sample++){ if(pts<=trak->samples[sample].pts) break; } el->frames=sample-el->start_sample; frame+=el->frames; mp_msg(MSGT_DEMUX,MSGL_V,"EL#%d: pts=%d 1st_sample=%d frames=%d (%5.3fs) pts_offs=%d\n",i, el->pos,el->start_sample, el->frames, (float)(el->dur)/(float)timescale, el->pts_offset); } }}#define MOV_MAX_TRACKS 256typedef struct { off_t moov_start; off_t moov_end; off_t mdat_start; off_t mdat_end; int track_db; mov_track_t* tracks[MOV_MAX_TRACKS]; int timescale; // movie timescale int duration; // movie duration (in movie timescale units)} mov_priv_t;#define MOV_FOURCC(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|(d))int mov_check_file(demuxer_t* demuxer){ int flags=0; int no=0; mov_priv_t* priv=malloc(sizeof(mov_priv_t)); mp_msg(MSGT_DEMUX,MSGL_V,"Checking for MOV\n"); memset(priv,0,sizeof(mov_priv_t)); while(1){ int i; int skipped=8; off_t len=stream_read_dword(demuxer->stream); unsigned int id=stream_read_dword(demuxer->stream); if(stream_eof(demuxer->stream)) break; // EOF if (len == 1) /* real size is 64bits - cjb */ {#ifndef _LARGEFILE_SOURCE if (stream_read_dword(demuxer->stream) != 0) mp_msg(MSGT_DEMUX, MSGL_WARN, "64bit file, but you've compiled MPlayer without LARGEFILE support!\n"); len = stream_read_dword(demuxer->stream);#else len = stream_read_qword(demuxer->stream);#endif skipped += 8; }#if 0 else if (len == 0) /* deleted chunk */ { /* XXX: CJB! is this right? - alex */ goto skip_chunk; }#endif else if(len<8) break; // invalid chunk switch(id){ case MOV_FOURCC('f','t','y','p'): { unsigned int tmp; // File Type Box (ftyp): // char[4] major_brand (eg. 'isom') // int minor_version (eg. 0x00000000) // char[4] compatible_brands[] (eg. 'mp41') // compatible_brands list spans to the end of box#if 1 tmp = stream_read_dword(demuxer->stream); switch(tmp) { case MOV_FOURCC('i','s','o','m'): mp_msg(MSGT_DEMUX,MSGL_V,"ISO: File Type Major Brand: ISO Base Media\n"); break; case MOV_FOURCC('m','p','4','1'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: ISO/IEC 14496-1 (MPEG-4 system) v1\n"); break; case MOV_FOURCC('m','p','4','2'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: ISO/IEC 14496-1 (MPEG-4 system) v2\n"); break; case MOV_FOURCC('M','4','A',' '): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: Apple iTunes AAC-LC Audio\n"); break; case MOV_FOURCC('M','4','P',' '): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: Apple iTunes AAC-LC Protected Audio\n"); break; case MOV_FOURCC('q','t',' ',' '): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: Original QuickTime\n"); break; case MOV_FOURCC('3','g','p','1'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: 3GPP Profile 1\n"); break; case MOV_FOURCC('3','g','p','2'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: 3GPP Profile 2\n"); break; case MOV_FOURCC('3','g','p','3'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: 3GPP Profile 3\n"); break; case MOV_FOURCC('3','g','p','4'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: 3GPP Profile 4\n"); break; case MOV_FOURCC('3','g','p','5'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: 3GPP Profile 5\n"); break; case MOV_FOURCC('m','m','p','4'): mp_msg(MSGT_DEMUX,MSGL_INFO,"ISO: File Type Major Brand: Mobile ISO/IEC 14496-1 (MPEG-4 system)\n"); break; default: tmp = be2me_32(tmp); mp_msg(MSGT_DEMUX,MSGL_WARN,"ISO: Unknown File Type Major Brand: %.4s\n",&tmp); } mp_msg(MSGT_DEMUX,MSGL_V,"ISO: File Type Minor Version: %d\n", stream_read_dword(demuxer->stream)); skipped += 8; // List all compatible brands for(i = 0; i < ((len-16)/4); i++) { tmp = be2me_32(stream_read_dword(demuxer->stream)); mp_msg(MSGT_DEMUX,MSGL_V,"ISO: File Type Compatible Brand #%d: %.4s\n",i,&tmp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -