summaryrefslogtreecommitdiffstats
path: root/libmpdemux/demux_mov.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmpdemux/demux_mov.c')
-rw-r--r--libmpdemux/demux_mov.c2350
1 files changed, 0 insertions, 2350 deletions
diff --git a/libmpdemux/demux_mov.c b/libmpdemux/demux_mov.c
deleted file mode 100644
index 96fb1a2d86..0000000000
--- a/libmpdemux/demux_mov.c
+++ /dev/null
@@ -1,2350 +0,0 @@
-/*
- * QuickTime MOV file parser
- * copyright(c) 2001 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 useful for .mp4
- * as well 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
- * TSGS#15(02)0088
- * http://www.3gpp.org/ftp/tsg_sa/TSG_SA/TSGS_15/Docs/pdf/SP-020088.pdf
- * http://www.3gpp2.org/Public_html/specs/C.S0050-0_v1.0_121503.pdf
- *
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#include <libavutil/common.h>
-#include <libavutil/intreadwrite.h>
-
-#include "config.h"
-
-#ifdef CONFIG_QUICKTIME
-#include <QuickTime/QuickTime.h>
-#include <QuickTime/ImageCompression.h>
-#include <QuickTime/ImageCodec.h>
-#else
-#include "loader/qtx/qtxsdk/components.h"
-#endif
-
-#if CONFIG_ZLIB
-#include <zlib.h>
-#endif
-
-#ifndef _FCNTL_H
-#include <fcntl.h>
-#endif
-
-#include "mp_msg.h"
-
-#include "stream/stream.h"
-#include "demuxer.h"
-#include "stheader.h"
-
-#include "libmpcodecs/img_format.h"
-
-#include "sub/sub.h"
-
-#include "demux_mov.h"
-#include "qtpalette.h"
-#include "parse_mp4.h" // .MP4 specific stuff
-
-#define char2short(x,y) AV_RB16(&(x)[(y)])
-#define char2int(x,y) AV_RB32(&(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 5
-
-typedef 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;
-
-static 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 ! */
- // audit: this code will be vulnerable if it is reenabled (currently #if 0)
- 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_V, "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;
- j=trak->chunkmap[i].first;
- for(;j>=0 && j<last;j++){
- trak->chunks[j].desc=trak->chunkmap[i].sdid;
- trak->chunks[j].size=trak->chunkmap[i].spc;
- }
- last=FFMIN(trak->chunkmap[i].first, trak->chunks_size);
- }
-
-#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;
- }
- i = 0;
- for (j = 0; j < trak->durmap_size; j++)
- i += trak->durmap[j].num;
- if (i != s) {
- mp_msg(MSGT_DEMUX, MSGL_WARN,
- "MOV: durmap and chunkmap sample count differ (%i vs %i)\n", i, s);
- if (i > s) s = i;
- }
-
- // workaround for fixed-size video frames (dv and uncompressed)
- if(!trak->samples_size && trak->type!=MOV_TRAK_AUDIO){
- trak->samples=calloc(s, sizeof(mov_sample_t));
- trak->samples_size=trak->samples ? s : 0;
- for(i=0;i<trak->samples_size;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;
- }
-
- if (trak->samples_size < s) {
- mp_msg(MSGT_DEMUX, MSGL_WARN,
- "MOV: durmap or chunkmap bigger than sample count (%i vs %i)\n",
- s, trak->samples_size);
- free(trak->samples);
- trak->samples = calloc(s, sizeof(mov_sample_t));
- trak->samples_size = trak->samples ? s : 0;
- }
-
- // calc pts:
- s=0;
- for(j=0;j<trak->durmap_size;j++){
- for(i=0;i<trak->durmap[j].num;i++){
- if (s >= trak->samples_size)
- break;
- 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++){
- if (s >= trak->samples_size)
- break;
- 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 256
-#define MOV_MAX_SUBLEN 1024
-
-typedef 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)
- subtitle subs;
- char subtext[MOV_MAX_SUBLEN + 1];
- int current_sub;
-} mov_priv_t;
-
-#define MOV_FOURCC(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|(d))
-
-static int mov_check_file(demuxer_t* demuxer){
- int flags=0;
- int no=0;
- mov_priv_t* priv=calloc(1, sizeof(mov_priv_t));
-
- mp_msg(MSGT_DEMUX,MSGL_V,"Checking for MOV\n");
-
- priv->current_sub = -1;
-
- 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
- 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'):
- case MOV_FOURCC('3','g','2','a'):
- 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",(char *)&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,(char *)&tmp);
- skipped += 4;
- }
-#endif
- } break;
- case MOV_FOURCC('m','o','o','v'):
-// case MOV_FOURCC('c','m','o','v'):
- mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Movie header found!\n");
- priv->moov_start=(off_t)stream_tell(demuxer->stream);
- priv->moov_end=(off_t)priv->moov_start+len-skipped;
- mp_msg(MSGT_DEMUX,MSGL_DBG2,"MOV: Movie header: start: %"PRIx64" end: %"PRIx64"\n",
- (int64_t)priv->moov_start, (int64_t)priv->moov_end);
- skipped+=8;
- i = stream_read_dword(demuxer->stream)-8;
- if(stream_read_dword(demuxer->stream)==MOV_FOURCC('r','m','r','a')){
- skipped+=i;
- mp_msg(MSGT_DEMUX,MSGL_INFO,"MOV: Reference Media file!!!\n");
- //set demuxer type to playlist ...
- demuxer->type=DEMUXER_TYPE_PLAYLIST;
- while(i>0){
- int len=stream_read_dword(demuxer->stream)-8;
- int fcc=stream_read_dword(demuxer->stream);
- if(len<0) break; // EOF!?
- i-=8;
-// printf("i=%d len=%d\n",i,len);
- switch(fcc){
- case MOV_FOURCC('r','m','d','a'):
- continue;
- case MOV_FOURCC('r','d','r','f'): {
- av_unused int tmp=stream_read_dword(demuxer->stream);
- av_unused int type=stream_read_dword_le(demuxer->stream);
- int slen=stream_read_dword(demuxer->stream);
- //char* s=malloc(slen+1);
- //stream_read(demuxer->stream,s,slen);
-
- //FIXME: also store type & data_rate ?
- ds_read_packet(demuxer->video,
- demuxer->stream,
- slen,
- 0,
- stream_tell(demuxer->stream),
- 0 // no flags
- );
- flags|=4;
- mp_msg(MSGT_DEMUX,MSGL_V,"Added reference to playlist\n");
- //s[slen]=0;
- //mp_msg(MSGT_DEMUX,MSGL_INFO,"REF: [%.4s] %s\n",&type,s);
- len-=12+slen;i-=12+slen; break;
- }
- case MOV_FOURCC('r','m','d','r'): {
- av_unused int flags=stream_read_dword(demuxer->stream);
- int rate=stream_read_dword(demuxer->stream);
- mp_msg(MSGT_DEMUX,MSGL_V," min. data rate: %d bits/sec\n",rate);
- len-=8; i-=8; break;
- }
- case MOV_FOURCC('r','m','q','u'): {
- int q=stream_read_dword(demuxer->stream);
- mp_msg(MSGT_DEMUX,MSGL_V," quality index: %d\n",q);
- len-=4; i-=4; break;
- }
- }
- i-=len;stream_skip(demuxer->stream,len);
- }
- }
- flags|=1;
- break;
- case MOV_FOURCC('w','i','d','e'):
- mp_msg(MSGT_DEMUX,MSGL_V,"MOV: 'WIDE' chunk found!\n");
- if(flags&2) break;
- case MOV_FOURCC('m','d','a','t'):
- mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Movie DATA found!\n");
- priv->mdat_start=stream_tell(demuxer->stream);
- priv->mdat_end=priv->mdat_start+len-skipped;
- mp_msg(MSGT_DEMUX,MSGL_DBG2,"MOV: Movie data: start: %"PRIx64" end: %"PRIx64"\n",
- (int64_t)priv->mdat_start, (int64_t)priv->mdat_end);
- flags|=2;
- if(flags==3){
- // if we're over the headers, then we can stop parsing here!
- demuxer->priv=priv;
- return DEMUXER_TYPE_MOV;
- }
- break;
- case MOV_FOURCC('f','r','e','e'):
- case MOV_FOURCC('s','k','i','p'):
- case MOV_FOURCC('j','u','n','k'):
- mp_msg(MSGT_DEMUX,MSGL_DBG2,"MOV: free space (len: %"PRId64")\n", (int64_t)len);
- /* unused, if you edit a mov, you can use space provided by free atoms (redefining it) */
- break;
- case MOV_FOURCC('p','n','o','t'):
- case MOV_FOURCC('P','I','C','T'):
- /* dunno what, but we shoudl ignore it */
- break;
- default:
- if(no==0){ free(priv); return 0;} // first chunk is bad!
- id = be2me_32(id);
- mp_msg(MSGT_DEMUX,MSGL_V,"MOV: unknown chunk: %.4s %d\n",(char *)&id,(int)len);
- }
-//skip_chunk:
- if(!stream_skip(demuxer->stream,len-skipped)) break;
- ++no;
- }
-
- if(flags==3){
- demuxer->priv=priv;
- return DEMUXER_TYPE_MOV;
- }
- free(priv);
-
- if ((flags==5) || (flags==7)) // reference & header sent
- return DEMUXER_TYPE_PLAYLIST;
-
- if(flags==1)
- mp_msg(MSGT_DEMUX,MSGL_WARN,"MOV: missing data (mdat) chunk! Maybe broken file...\n");
- else if(flags==2)
- mp_msg(MSGT_DEMUX,MSGL_WARN,"MOV: missing header (moov/cmov) chunk! Maybe broken file...\n");
-
- return 0;
-}
-
-static void demux_close_mov(demuxer_t *demuxer) {
- mov_priv_t* priv = demuxer->priv;
- int i;
- if (!priv)
- return;
- for (i = 0; i < MOV_MAX_TRACKS; i++) {
- mov_track_t *track = priv->tracks[i];
- if (track) {
- free(track->tkdata);
- free(track->stdata);
- free(track->stream_header);
- free(track->samples);
- free(track->chunks);
- free(track->chunkmap);
- free(track->durmap);
- free(track->keyframes);
- free(track->editlist);
- free(track->desc);
- free(track);
- }
- }
- free(priv);
-}
-
-unsigned int store_ughvlc(unsigned char *s, unsigned int v){
- unsigned int n = 0;
-
- while(v >= 0xff) {
- *s++ = 0xff;
- v -= 0xff;
- n++;
- }
- *s = v;
- n++;
-
- return n;
-}
-
-static void init_vobsub(sh_sub_t *sh, mov_track_t *trak) {
- sh->type = 'v';
- if (trak->stdata_len < 106)
- return;
- sh->extradata_len = 16*4;
- sh->extradata = malloc(sh->extradata_len);
- memcpy(sh->extradata, trak->stdata + 42, sh->extradata_len);
-}
-
-static int lschunks_intrak(demuxer_t* demuxer, int level, unsigned int id,
- off_t pos, off_t len, mov_track_t* trak);
-
-static int gen_sh_audio(sh_audio_t* sh, mov_track_t* trak, int timescale) {
-#if 0
- struct {
- int16_t version; // 0 or 1 (version 1 is qt3.0+)
- int16_t revision; // 0
- int32_t vendor_id; // 0
- int16_t channels; // 1 or 2 (Mono/Stereo)
- int16_t samplesize; // 8 or 16 (8Bit/16Bit)
- int16_t compression_id; // if version 0 then 0
- // if version 1 and vbr then -2 else 0
- int16_t packet_size; // 0
- uint16_t sample_rate; // samplerate (Hz)
- // qt3.0+ (version == 1)
- uint32_t samples_per_packet; // 0 or num uncompressed samples in a packet
- // if 0 below three values are also 0
- uint32_t bytes_per_packet; // 0 or num compressed bytes for one channel
- uint32_t bytes_per_frame; // 0 or num compressed bytes for all channels
- // (channels * bytes_per_packet)
- uint32_t bytes_per_sample; // 0 or size of uncompressed sample
- // if samples_per_packet and bytes_per_packet are constant (CBR)
- // then bytes_per_frame and bytes_per_sample must be 0 (else is VBR)
- // ---
- // optional additional atom-based fields
- // ([int32_t size,int32_t type,some data ],repeat)
- } my_stdata;
-#endif
- int version = -1, adjust;
- int is_vorbis = 0;
- sh->format=trak->fourcc;
-
- // crude audio delay from editlist0 hack ::atm
- if(trak->editlist_size>=1) {
- if(trak->editlist[0].pos == -1) {
- sh->stream_delay = (float)trak->editlist[0].dur/(float)timescale;
- mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Initial Audio-Delay: %.3f sec\n", sh->stream_delay);
- }
- }
-
-
- switch( sh->format ) {
- case 0x726D6173: /* samr */
- /* amr narrowband */
- trak->samplebytes=sh->samplesize=1;
- trak->nchannels=sh->channels=1;
- sh->samplerate=8000;
- break;
-
- case 0x62776173: /* sawb */
- /* amr wideband */
- trak->samplebytes=sh->samplesize=1;
- trak->nchannels=sh->channels=1;
- sh->samplerate=16000;
- break;
-
- default:
-
-// assumptions for below table: short is 16bit, int is 32bit, intfp is 16bit
-// XXX: 32bit fixed point numbers (intfp) are only 2 Byte!
-// short values are usually one byte leftpadded by zero
-// int values are usually two byte leftpadded by zero
-// stdata[]:
-// 8 short version
-// 10 short revision
-// 12 int vendor_id
-// 16 short channels
-// 18 short samplesize
-// 20 short compression_id
-// 22 short packet_size (==0)
-// 24 intfp sample_rate
-// (26 short) unknown (==0)
-// ---- qt3.0+ (version>=1)
-// 28 int samples_per_packet
-// 32 int bytes_per_packet
-// 36 int bytes_per_frame
-// 40 int bytes_per_sample
-// there may be additional atoms following at 28 (version 0)
-// or 44 (version 1), eg. esds atom of .MP4 files
-// esds atom:
-// 28 int atom size (bytes of int size, int type and data)
-// 32 char[4] atom type (fourc charater code -> esds)
-// 36 char[] atom data (len=size-8)
-
-// TODO: fix parsing for files using version 2.
- if (trak->stdata_len < 26) {
- mp_msg(MSGT_DEMUX, MSGL_WARN, "MOV: broken (too small) sound atom!\n");
- return 0;
- }
- version=char2short(trak->stdata,8);
- if (version > 1)
- mp_msg(MSGT_DEMUX, MSGL_WARN, "MOV: version %d sound atom may not parse correctly!\n", version);
- trak->samplebytes=sh->samplesize=char2short(trak->stdata,18)/8;
-
- /* I can't find documentation, but so far this is the case. -Corey */
- switch (char2short(trak->stdata,16)) {
- case 1:
- trak->nchannels = 1; break;
- case 2:
- trak->nchannels = 2; break;
- case 3:
- trak->nchannels = 6; break;
- default:
- mp_msg(MSGT_DEMUX, MSGL_WARN,
- "MOV: unable to determine audio channels, assuming 2 (got %d)\n",
- char2short(trak->stdata,16));
- trak->nchannels = 2;
- }
- sh->channels = trak->nchannels;
-
- /*printf("MOV: timescale: %d samplerate: %d durmap: %d (%d) -> %d (%d)\n",
- trak->timescale, char2short(trak->stdata,24), trak->durmap[0].dur,
- trak->durmap[0].num, trak->timescale/trak->durmap[0].dur,
- char2short(trak->stdata,24)/trak->durmap[0].dur);*/
- sh->samplerate=char2short(trak->stdata,24);
- if((sh->samplerate < 7000) && trak->durmap && trak->durmap[0].dur > 1) {
- switch(char2short(trak->stdata,24)/trak->durmap[0].dur) {
- // TODO: add more cases.
- case 31:
- sh->samplerate = 32000; break;
- case 43:
- sh->samplerate = 44100; break;
- case 47:
- sh->samplerate = 48000; break;
- default:
- mp_msg(MSGT_DEMUX, MSGL_WARN,
- "MOV: unable to determine audio samplerate, "
- "assuming 44.1kHz (got %d)\n",
- char2short(trak->stdata,24)/trak->durmap[0].dur);
- sh->samplerate = 44100;
- }
- }
- }
- mp_msg(MSGT_DEMUX, MSGL_V, "Audio bits: %d chans: %d rate: %d\n",
- sh->samplesize*8,sh->channels,sh->samplerate);
-
- if(trak->stdata_len >= 44 && trak->stdata[9]>=1){
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio header: samp/pack=%d bytes/pack=%d bytes/frame=%d bytes/samp=%d \n",
- char2int(trak->stdata,28),
- char2int(trak->stdata,32),
- char2int(trak->stdata,36),
- char2int(trak->stdata,40));
- if(trak->stdata_len>=44+8){
- int len=char2int(trak->stdata,44);
- int fcc=char2int(trak->stdata,48);
- // we have extra audio headers!!!
- mp_msg(MSGT_DEMUX,MSGL_V,"Audio extra header: len=%d fcc=0x%X\n",len,fcc);
- if((len >= 4) &&
- (char2int(trak->stdata,52) >= 12) &&
- (char2int(trak->stdata,52+4) == MOV_FOURCC('f','r','m','a'))) {
- switch(char2int(trak->stdata,52+8)) {
- case MOV_FOURCC('a','l','a','c'):
- if (len >= 36 + char2int(trak->stdata,52)) {
- sh->codecdata_len = char2int(trak->stdata,52+char2int(trak->stdata,52));
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Found alac atom (%d)!\n", sh->codecdata_len);
- sh->codecdata = malloc(sh->codecdata_len);
- memcpy(sh->codecdata, &trak->stdata[52+char2int(trak->stdata,52)], sh->codecdata_len);
- }
- break;
- case MOV_FOURCC('i','n','2','4'):
- case MOV_FOURCC('i','n','3','2'):
- case MOV_FOURCC('f','l','3','2'):
- case MOV_FOURCC('f','l','6','4'):
- if ((len >= 22) &&
- (char2int(trak->stdata,52+16)==MOV_FOURCC('e','n','d','a')) &&
- (char2short(trak->stdata,52+20))) {
- sh->format=char2int(trak->stdata,52+8);
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Found little endian PCM data, reversed fourcc:%04x\n", sh->format);
- }
- break;
- default:
- if (len > 8 && len + 44 <= trak->stdata_len) {
- sh->codecdata_len = len-8;
- sh->codecdata = malloc(sh->codecdata_len);
- memcpy(sh->codecdata, trak->stdata+44+8, sh->codecdata_len);
- }
- }
- } else {
- if (len > 8 && len + 44 <= trak->stdata_len) {
- sh->codecdata_len = len-8;
- sh->codecdata = malloc(sh->codecdata_len);
- memcpy(sh->codecdata, trak->stdata+44+8, sh->codecdata_len);
- }
- }
- }
- }
-
- switch (version) {
- case 0:
- adjust = 0; break;
- case 1:
- adjust = 48; break;
- case 2:
- adjust = 68; break;
- default:
- mp_msg(MSGT_DEMUX, MSGL_WARN, "MOV: unknown sound atom version (%d); may not work!\n", version);
- adjust = 68;
- }
- if (trak->stdata_len >= 36 + adjust) {
- int atom_len = char2int(trak->stdata,28+adjust);
- if (atom_len < 0 || atom_len > trak->stdata_len - 28 - adjust) atom_len = trak->stdata_len - 28 - adjust;
- switch(char2int(trak->stdata,32+adjust)) { // atom type
- case MOV_FOURCC('e','s','d','s'): {
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Found MPEG4 audio Elementary Stream Descriptor atom (%d)!\n", atom_len);
- if(atom_len > 8) {
- esds_t esds;
- if(!mp4_parse_esds(&trak->stdata[36+adjust], atom_len-8, &esds)) {
- /* 0xdd is a "user private" id, not an official allocated id (see http://www.mp4ra.org/object.html),
- so perform some extra checks to be sure that this is really vorbis audio */
- if(esds.objectTypeId==0xdd && esds.streamType==0x15 && sh->format==0x6134706D && esds.decoderConfigLen > 8)
- {
- //vorbis audio
- unsigned char *buf[3];
- unsigned short sizes[3];
- int offset, len, k;
- unsigned char *ptr = esds.decoderConfig;
-
- if(ptr[0] != 0 || ptr[1] != 30) goto quit_vorbis_block; //wrong extradata layout
-
- offset = len = 0;
- for(k = 0; k < 3; k++)
- {
- sizes[k] = (ptr[offset]<<8) | ptr[offset+1];
- len += sizes[k];
- offset += 2;
- if(offset + sizes[k] > esds.decoderConfigLen)
- {
- mp_msg(MSGT_DEMUX, MSGL_FATAL, "MOV: ERROR!, not enough vorbis extradata to read: offset = %d, k=%d, size=%d, len: %d\n", offset, k, sizes[k], esds.decoderConfigLen);
- goto quit_vorbis_block;
- }
- buf[k] = malloc(sizes[k]);
- if(!buf[k]) goto quit_vorbis_block;
- memcpy(buf[k], &ptr[offset], sizes[k]);
- offset += sizes[k];
- }
-
- sh->codecdata_len = len + len/255 + 64;
- sh->codecdata = malloc(sh->codecdata_len);
- ptr = sh->codecdata;
-
- ptr[0] = 2;
- offset = 1;
- offset += store_ughvlc(&ptr[offset], sizes[0]);
- offset += store_ughvlc(&ptr[offset], sizes[1]);
- for(k = 0; k < 3; k++)
- {
- memcpy(&ptr[offset], buf[k], sizes[k]);
- offset += sizes[k];
- }
-
- sh->codecdata_len = offset;
- sh->codecdata = realloc(sh->codecdata, offset);
- mp_msg(MSGT_DEMUX,MSGL_V, "demux_mov, vorbis extradata size: %d\n", offset);
- is_vorbis = 1;
-quit_vorbis_block:
- sh->format = mmioFOURCC('v', 'r', 'b', 's');
- }
- sh->i_bps = esds.avgBitrate/8;
-
-// printf("######## audio format = %d ########\n",esds.objectTypeId);
- if(esds.objectTypeId==MP4OTI_MPEG1Audio || esds.objectTypeId==MP4OTI_MPEG2AudioPart3)
- sh->format=0x55; // .mp3
-
- if(esds.objectTypeId==MP4OTI_13kVoice) { // 13K Voice, defined by 3GPP2
- sh->format=mmioFOURCC('Q', 'c', 'l', 'p');
- trak->nchannels=sh->channels=1;
- trak->samplebytes=sh->samplesize=1;
- }
-
- // dump away the codec specific configuration for the AAC decoder
- if(esds.decoderConfigLen){
- if( (esds.decoderConfig[0]>>3) == 29 )
- sh->format = 0x1d61346d; // request multi-channel mp3 decoder
- if(!is_vorbis)
- {
- sh->codecdata_len = esds.decoderConfigLen;
- sh->codecdata = malloc(sh->codecdata_len);
- memcpy(sh->codecdata, esds.decoderConfig, sh->codecdata_len);
- }
- }
- }
- mp4_free_esds(&esds); // freeup esds mem
-#if 0
- { FILE* f=fopen("esds.dat","wb");
- fwrite(&trak->stdata[36],atom_len-8,1,f);
- fclose(f); }
-#endif
- }
- } break;
- case MOV_FOURCC('a','l','a','c'): {
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Found alac atom (%d)!\n", atom_len);
- if(atom_len > 8) {
- // copy all the atom (not only payload) for lavc alac decoder
- sh->codecdata_len = atom_len;
- sh->codecdata = malloc(sh->codecdata_len);
- memcpy(sh->codecdata, &trak->stdata[28], sh->codecdata_len);
- }
- } break;
- case MOV_FOURCC('d','a','m','r'):
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Found AMR audio atom %c%c%c%c (%d)!\n", trak->stdata[32+adjust],trak->stdata[33+adjust],trak->stdata[34+adjust],trak->stdata[35+adjust], atom_len);
- if (atom_len>14) {
- mp_msg(MSGT_DEMUX, MSGL_V, "mov: vendor: %c%c%c%c Version: %d\n",trak->stdata[36+adjust],trak->stdata[37+adjust],trak->stdata[38+adjust], trak->stdata[39+adjust],trak->stdata[40+adjust]);
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Modes set: %02x%02x\n",trak->stdata[41+adjust],trak->stdata[42+adjust]);
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Mode change period: %d Frames per sample: %d\n",trak->stdata[43+adjust],trak->stdata[44+adjust]);
- }
- break;
- default:
- mp_msg(MSGT_DEMUX, MSGL_V, "MOV: Found unknown audio atom %c%c%c%c (%d)!\n",
- trak->stdata[32+adjust],trak->stdata[33+adjust],trak->stdata[34+adjust],trak->stdata[35+adjust],
- atom_len);
- }
- }
- mp_msg(MSGT_DEMUX, MSGL_V, "Fourcc: %.4s\n",(char *)&trak->fourcc);
-#if 0
- { FILE* f=fopen("stdata.dat","wb");
- fwrite(trak->stdata,trak->stdata_len,1,f);
- fclose(f); }
- { FILE* f=fopen("tkdata.dat","wb");
- fwrite(trak->tkdata,trak->tkdata_len,1,f);
- fclose(f); }
-#endif
- // Emulate WAVEFORMATEX struct:
- sh->wf=calloc(1, sizeof(*sh->wf) + (is_vorbis ? sh->codecdata_len : 0));
- sh->wf->nChannels=sh->channels;
- sh->wf->wBitsPerSample=(trak->stdata[18]<<8)+trak->stdata[19];
- // sh->wf->nSamplesPerSec=trak->timescale;
- sh->wf->nSamplesPerSec=sh->samplerate;
- if(trak->stdata_len >= 44 && trak->stdata[9]>=1 && char2int(trak->stdata,28)>0){
- //Audio header: samp/pack=4096 bytes/pack=743 bytes/frame=1486 bytes/samp=2
- sh->wf->nAvgBytesPerSec=(sh->wf->nChannels*sh->wf->nSamplesPerSec*
- char2int(trak->stdata,32)+char2int(trak->stdata,28)/2)
- /char2int(trak->stdata,28);
- sh->wf->nBlockAlign=char2int(trak->stdata,36);
- } else {
- sh->wf->nAvgBytesPerSec=sh->wf->nChannels*sh->wf->wBitsPerSample*sh->wf->nSamplesPerSec/8;
- // workaround for ms11 ima4
- if (sh->format == 0x1100736d && trak->stdata_len >= 36)
- sh->wf->nBlockAlign=char2int(trak->stdata,36);
- }
-
- if(is_vorbis && sh->codecdata_len)
- {
- memcpy(sh->wf+1, sh->codecdata, sh->codecdata_len);
- sh->wf->cbSize = sh->codecdata_len;
- }
- // Selection:
-// if(demuxer->audio->id==-1 || demuxer->audio->id==priv->track_db){
-// // (auto)selected audio track:
-// demuxer->audio->id=priv->track_db;
-// demuxer->audio->sh=sh; sh->ds=demuxer->audio;
-// }
- return 1;
-}
-
-static int gen_sh_video(sh_video_t* sh, mov_track_t* trak, int timescale) {
- int depth, i, entry;
- int flag, start, count_flag, end, palette_count, gray;
- int hdr_ptr = 76; // the byte just after depth
- unsigned char *palette_map;
-
- sh->format=trak->fourcc;
-
- // crude video delay from editlist0 hack ::atm
- if(trak->editlist_size>=1) {
- if(trak->editlist[0].pos == -1) {
- sh->stream_delay = (float)trak->editlist[0].dur/(float)timescale;
- mp_msg(MSGT_DEMUX,MSGL_V,"MOV: Initial Video-Delay: %.3f sec\n", sh->stream_delay);
- }
- }
-
-
- if (trak->stdata_len < 78) {
- mp_msg(MSGT_DEMUXER, MSGL_WARN,
- "MOV: Invalid (%d bytes instead of >= 78) video trak desc\n",
- trak->stdata_len);
- return 0;
- }
-
- depth = trak->stdata[75] | (trak->stdata[74] << 8);
- if (trak->fourcc == mmioFOURCC('r', 'a', 'w', ' '))
- sh->format = IMGFMT_RGB | depth;
-
-// stdata[]:
-// 8 short version
-// 10 short revision
-// 12 int vendor_id
-// 16 int temporal_quality
-// 20 int spatial_quality
-// 24 short width
-// 26 short height
-// 28 int h_dpi
-// 32 int v_dpi
-// 36 int 0
-// 40 short frames_per_sample
-// 42 char[4] compressor_name
-// 74 short depth
-// 76 short color_table_id
-// additional atoms may follow,
-// eg esds atom from .MP4 files
-// 78 int atom size
-// 82 char[4] atom type
-// 86 ... atom data
-
- { ImageDescription* id=malloc(8+trak->stdata_len); // safe
- trak->desc=id;
- id->idSize=8+trak->stdata_len;
-// id->cType=bswap_32(trak->fourcc);
- id->cType=le2me_32(trak->fourcc);
- id->version=char2short(trak->stdata,8);
- id->revisio