2001-10-10 01:07:50 +00:00
// QuickTime MOV file parser by A'rpi
// based on TOOLS/movinfo.c by me & Al3x
// compressed header support from moov.c of the openquicktime lib.
2001-10-22 22:49:09 +00:00
// References: http://openquicktime.sf.net/, http://www.heroinewarrior.com/
2001-10-29 21:01:00 +00:00
// http://www.geocities.com/SiliconValley/Lakes/2160/fformats/files/mov.pdf
2001-08-12 01:58:05 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
2001-08-17 00:40:25 +00:00
# include "config.h"
# include "mp_msg.h"
2001-09-26 21:35:14 +00:00
# include "help_mp.h"
2001-08-12 01:58:05 +00:00
# include "stream.h"
# include "demuxer.h"
# include "stheader.h"
2001-10-22 22:49:09 +00:00
# include "bswap.h"
2002-01-24 05:20:19 +00:00
# include "qtpalette.h"
2001-10-10 01:07:50 +00:00
# ifdef HAVE_ZLIB
# include <zlib.h>
# endif
2001-11-09 17:00:12 +00:00
# include <fcntl.h>
2002-01-13 06:01:04 +00:00
# define BE_16(x) (be2me_16(*(unsigned short *)(x)))
# define BE_32(x) (be2me_32(*(unsigned int *)(x)))
2001-10-05 23:13:26 +00:00
typedef struct {
unsigned int pts ; // duration
unsigned int size ;
off_t pos ;
} mov_sample_t ;
typedef struct {
2001-10-29 22:40:25 +00:00
unsigned int sample ; // number of the first sample in the chunk
2001-10-07 00:22:43 +00:00
unsigned int size ; // number of samples in the chunk
int desc ; // for multiple codecs mode - not used
2001-10-05 23:13:26 +00:00
off_t pos ;
} mov_chunk_t ;
typedef struct {
unsigned int first ;
unsigned int spc ;
unsigned int sdid ;
} mov_chunkmap_t ;
2001-10-07 00:22:43 +00:00
typedef struct {
unsigned int num ;
unsigned int dur ;
} mov_durmap_t ;
2001-08-12 01:58:05 +00:00
typedef struct {
int id ;
int type ;
2002-01-05 19:29:52 +00:00
off_t pos ;
2001-10-06 00:58:23 +00:00
//
2001-08-12 01:58:05 +00:00
int timescale ;
2001-10-05 23:13:26 +00:00
unsigned int length ;
2001-10-07 00:22:43 +00:00
int samplesize ; // 0 = variable
int duration ; // 0 = variable
2001-08-12 01:58:05 +00:00
int width , height ; // for video
unsigned int fourcc ;
2001-10-07 00:22:43 +00:00
//
2001-10-06 00:58:23 +00:00
int tkdata_len ; // track data
unsigned char * tkdata ;
int stdata_len ; // stream data
unsigned char * stdata ;
2001-10-05 23:13:26 +00:00
int samples_size ;
mov_sample_t * samples ;
int chunks_size ;
mov_chunk_t * chunks ;
int chunkmap_size ;
mov_chunkmap_t * chunkmap ;
2001-10-07 00:22:43 +00:00
int durmap_size ;
mov_durmap_t * durmap ;
2001-10-29 21:55:07 +00:00
int keyframes_size ;
unsigned int * keyframes ;
2001-08-12 01:58:05 +00:00
} mov_track_t ;
2001-10-05 23:13:26 +00:00
void mov_build_index ( mov_track_t * trak ) {
int i , j , s ;
int last = trak - > chunks_size ;
2001-10-07 00:22:43 +00:00
unsigned int pts = 0 ;
2001-12-22 00:33:35 +00:00
#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 ;
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
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_HINT , " MOV track: %d chunks, %d samples \n " , trak - > chunks_size , trak - > samples_size ) ;
mp_msg ( MSGT_DEMUX , MSGL_HINT , " pts=%d scale=%d time=%5.3f \n " , trak - > length , trak - > timescale , ( float ) trak - > length / ( float ) trak - > timescale ) ;
2001-10-29 22:40:25 +00:00
2001-10-05 23:13:26 +00:00
// 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 ;
}
2001-10-07 00:22:43 +00:00
2001-12-22 00:33:35 +00:00
#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
2001-10-07 00:22:43 +00:00
// calc pts of chunks:
s = 0 ;
for ( j = 0 ; j < trak - > chunks_size ; j + + ) {
trak - > chunks [ j ] . sample = s ;
s + = trak - > chunks [ j ] . size ;
}
if ( ! trak - > samples_size ) {
// constant sampesize
if ( trak - > durmap_size = = 1 | | ( trak - > durmap_size = = 2 & & trak - > durmap [ 1 ] . num = = 1 ) ) {
2001-10-16 22:41:46 +00:00
trak - > duration = trak - > durmap [ 0 ] . dur ;
2001-10-26 14:04:17 +00:00
} else mp_msg ( MSGT_DEMUX , MSGL_ERR , " *** constant samplesize & variable duration not yet supported! *** \n Contact the author if you have such sample file! \n " ) ;
2001-10-07 00:22:43 +00:00
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 ;
}
}
2001-10-05 23:13:26 +00:00
// 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 ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_DBG3 , " Sample %5d: pts=%8d off=0x%08X size=%d \n " , s ,
2001-10-05 23:13:26 +00:00
trak - > samples [ s ] . pts ,
( int ) trak - > samples [ s ] . pos ,
trak - > samples [ s ] . size ) ;
pos + = trak - > samples [ s ] . size ;
+ + s ;
}
}
}
2001-08-12 01:58:05 +00:00
# define MOV_MAX_TRACKS 256
# define MOV_TRAK_UNKNOWN 0
# define MOV_TRAK_VIDEO 1
# define MOV_TRAK_AUDIO 2
2001-10-29 16:15:04 +00:00
# define MOV_TRAK_FLASH 3
2001-11-09 17:00:12 +00:00
# define MOV_TRAK_GENERIC 4
2001-11-22 15:43:24 +00:00
# define MOV_TRAK_CODE 5
2001-08-12 01:58:05 +00:00
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 ] ;
} mov_priv_t ;
2001-10-29 22:40:25 +00:00
# warning "FIXME - mov support is only working perfectly on Little Endian systems?!"
2001-11-22 15:43:24 +00:00
//#ifdef WORDS_BIGENDIAN
//#define MOV_FOURCC(a,b,c,d) ((d)|(c<<8)|(b<<16)|(a<<24))
//#else
2001-08-12 01:58:05 +00:00
# define MOV_FOURCC(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|(d))
2001-11-22 15:43:24 +00:00
//#endif
2001-08-12 01:58:05 +00:00
int mov_check_file ( demuxer_t * demuxer ) {
int flags = 0 ;
2001-11-13 21:11:10 +00:00
int no = 0 ;
2001-08-12 01:58:05 +00:00
mov_priv_t * priv = malloc ( sizeof ( mov_priv_t ) ) ;
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " Checking for MOV \n " ) ;
2001-08-12 01:58:05 +00:00
memset ( priv , 0 , sizeof ( mov_priv_t ) ) ;
demuxer - > priv = priv ;
while ( 1 ) {
2002-01-05 19:29:52 +00:00
int skipped = 8 ;
2001-08-12 01:58:05 +00:00
off_t len = stream_read_dword ( demuxer - > stream ) ;
unsigned int id = stream_read_dword ( demuxer - > stream ) ;
if ( stream_eof ( demuxer - > stream ) ) break ; // EOF
2002-01-05 19:29:52 +00:00
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 MPlayer compiled without LARGEFILE support! \n " ) ;
len = stream_read_dword ( demuxer - > stream ) ;
# else
len = stream_read_qword ( demuxer - > stream ) ;
# endif
skipped + = 8 ;
}
else if ( len < 8 ) break ; // invalid chunk
2001-08-12 01:58:05 +00:00
switch ( id ) {
case MOV_FOURCC ( ' m ' , ' o ' , ' o ' , ' v ' ) :
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: Movie header found! \n " ) ;
2001-08-12 01:58:05 +00:00
priv - > moov_start = stream_tell ( demuxer - > stream ) ;
2002-01-05 19:29:52 +00:00
priv - > moov_end = priv - > moov_start + len - skipped ;
2001-08-12 01:58:05 +00:00
flags | = 1 ;
break ;
case MOV_FOURCC ( ' m ' , ' d ' , ' a ' , ' t ' ) :
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: Movie DATA found! \n " ) ;
2001-08-12 01:58:05 +00:00
priv - > mdat_start = stream_tell ( demuxer - > stream ) ;
2002-01-05 19:29:52 +00:00
priv - > mdat_end = priv - > mdat_start + len - skipped ;
2001-08-12 01:58:05 +00:00
flags | = 2 ;
break ;
2001-10-23 16:21:24 +00:00
case MOV_FOURCC ( ' f ' , ' r ' , ' e ' , ' e ' ) :
2001-11-17 01:10:46 +00:00
case MOV_FOURCC ( ' s ' , ' k ' , ' i ' , ' p ' ) :
2001-10-29 22:40:25 +00:00
/* unused, if you edit a mov, you can use space provided by free atoms (redefining it) */
2001-10-23 16:21:24 +00:00
break ;
case MOV_FOURCC ( ' w ' , ' i ' , ' d ' , ' e ' ) :
2001-11-13 21:11:10 +00:00
break ;
2001-08-12 01:58:05 +00:00
default :
2001-11-13 21:11:10 +00:00
if ( no = = 0 ) return 0 ; // first chunk is bad!
2001-10-23 16:21:24 +00:00
id = bswap_32 ( id ) ;
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: unknown chunk: %.4s %d \n " , & id , ( int ) len ) ;
2001-08-12 01:58:05 +00:00
}
2002-01-05 19:29:52 +00:00
if ( ! stream_skip ( demuxer - > stream , len - skipped ) ) break ;
2001-11-13 21:11:10 +00:00
+ + no ;
2001-08-12 01:58:05 +00:00
}
2001-10-10 01:07:50 +00:00
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 " ) ;
2001-08-12 01:58:05 +00:00
return ( flags = = 3 ) ;
}
static void lschunks ( demuxer_t * demuxer , int level , off_t endpos , mov_track_t * trak ) {
mov_priv_t * priv = demuxer - > priv ;
while ( 1 ) {
off_t pos ;
off_t len ;
unsigned int id ;
//
pos = stream_tell ( demuxer - > stream ) ;
2001-10-10 01:07:50 +00:00
// printf("stream_tell==%d\n",pos);
2001-08-12 01:58:05 +00:00
if ( pos > = endpos ) return ; // END
len = stream_read_dword ( demuxer - > stream ) ;
2001-10-10 01:07:50 +00:00
// printf("len==%d\n",len);
2001-08-12 01:58:05 +00:00
if ( len < 8 ) return ; // error
len - = 8 ;
id = stream_read_dword ( demuxer - > stream ) ;
//
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " lschunks %.4s %d \n " , & id , ( int ) len ) ;
2001-08-12 01:58:05 +00:00
//
if ( trak ) {
switch ( id ) {
2001-11-22 15:43:24 +00:00
case MOV_FOURCC ( ' f ' , ' r ' , ' e ' , ' e ' ) :
2001-10-23 16:21:24 +00:00
case MOV_FOURCC ( ' u ' , ' d ' , ' t ' , ' a ' ) :
/* here not supported :p */
break ;
2001-08-12 01:58:05 +00:00
case MOV_FOURCC ( ' t ' , ' k ' , ' h ' , ' d ' ) : {
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sTrack header! \n " , level , " " ) ;
2001-10-06 00:58:23 +00:00
// read codec data
trak - > tkdata_len = len ;
trak - > tkdata = malloc ( trak - > tkdata_len ) ;
stream_read ( demuxer - > stream , trak - > tkdata , trak - > tkdata_len ) ;
2001-08-12 01:58:05 +00:00
break ;
}
case MOV_FOURCC ( ' m ' , ' d ' , ' h ' , ' d ' ) : {
2001-10-05 23:13:26 +00:00
unsigned int tmp ;
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sMedia header! \n " , level , " " ) ;
2001-10-05 23:13:26 +00:00
#if 0
tmp = stream_read_dword ( demuxer - > stream ) ;
printf ( " dword1: 0x%08X (%d) \n " , tmp , tmp ) ;
tmp = stream_read_dword ( demuxer - > stream ) ;
printf ( " dword2: 0x%08X (%d) \n " , tmp , tmp ) ;
tmp = stream_read_dword ( demuxer - > stream ) ;
printf ( " dword3: 0x%08X (%d) \n " , tmp , tmp ) ;
tmp = stream_read_dword ( demuxer - > stream ) ;
printf ( " dword4: 0x%08X (%d) \n " , tmp , tmp ) ;
tmp = stream_read_dword ( demuxer - > stream ) ;
printf ( " dword5: 0x%08X (%d) \n " , tmp , tmp ) ;
tmp = stream_read_dword ( demuxer - > stream ) ;
printf ( " dword6: 0x%08X (%d) \n " , tmp , tmp ) ;
# endif
stream_skip ( demuxer - > stream , 12 ) ;
2001-08-12 01:58:05 +00:00
// read timescale
2001-10-05 23:13:26 +00:00
trak - > timescale = stream_read_dword ( demuxer - > stream ) ;
// read length
trak - > length = stream_read_dword ( demuxer - > stream ) ;
2001-08-12 01:58:05 +00:00
break ;
}
case MOV_FOURCC ( ' v ' , ' m ' , ' h ' , ' d ' ) : {
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sVideo header! \n " , level , " " ) ;
2001-08-12 01:58:05 +00:00
trak - > type = MOV_TRAK_VIDEO ;
// read video data
break ;
}
case MOV_FOURCC ( ' s ' , ' m ' , ' h ' , ' d ' ) : {
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sSound header! \n " , level , " " ) ;
2001-08-12 01:58:05 +00:00
trak - > type = MOV_TRAK_AUDIO ;
// read audio data
break ;
}
2001-11-09 17:00:12 +00:00
case MOV_FOURCC ( ' g ' , ' m ' , ' h ' , ' d ' ) : {
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sGeneric header! \n " , level , " " ) ;
trak - > type = MOV_TRAK_GENERIC ;
break ;
}
2001-08-12 01:58:05 +00:00
case MOV_FOURCC ( ' s ' , ' t ' , ' s ' , ' d ' ) : {
int i = stream_read_dword ( demuxer - > stream ) ; // temp!
int count = stream_read_dword ( demuxer - > stream ) ;
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sDescription list! (cnt:%d) \n " , level , " " , count ) ;
2001-08-12 01:58:05 +00:00
for ( i = 0 ; i < count ; i + + ) {
off_t pos = stream_tell ( demuxer - > stream ) ;
off_t len = stream_read_dword ( demuxer - > stream ) ;
unsigned int fourcc = stream_read_dword_le ( demuxer - > stream ) ;
if ( len < 8 ) break ; // error
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*s desc #%d: %.4s " , level , " " , i , & fourcc ) ;
2001-08-12 01:58:05 +00:00
if ( ! i ) {
trak - > fourcc = fourcc ;
// read codec data
2001-10-06 00:58:23 +00:00
trak - > stdata_len = len - 8 ;
trak - > stdata = malloc ( trak - > stdata_len ) ;
stream_read ( demuxer - > stream , trak - > stdata , trak - > stdata_len ) ;
if ( trak - > type = = MOV_TRAK_VIDEO & & trak - > stdata_len > 43 ) {
mp_msg ( MSGT_DEMUX , MSGL_V , " '%.*s' " , trak - > stdata_len - 43 , trak - > stdata + 43 ) ;
2001-08-12 01:58:05 +00:00
}
}
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " \n " ) ;
2001-08-12 01:58:05 +00:00
if ( fourcc ! = trak - > fourcc & & i )
2001-09-26 21:35:14 +00:00
mp_msg ( MSGT_DEMUX , MSGL_WARN , MSGTR_MOVvariableFourCC ) ;
2001-08-12 01:58:05 +00:00
if ( ! stream_seek ( demuxer - > stream , pos + len ) ) break ;
}
break ;
}
2001-10-05 23:13:26 +00:00
case MOV_FOURCC ( ' s ' , ' t ' , ' t ' , ' s ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int len = stream_read_dword ( demuxer - > stream ) ;
int i ;
int x = 0 ;
unsigned int pts = 0 ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sSample duration table! (%d blocks) \n " , level , " " , len ) ;
2001-10-07 00:22:43 +00:00
trak - > durmap = malloc ( sizeof ( mov_durmap_t ) * len ) ;
memset ( trak - > durmap , 0 , sizeof ( mov_durmap_t ) * len ) ;
trak - > durmap_size = len ;
2001-10-05 23:13:26 +00:00
for ( i = 0 ; i < len ; i + + ) {
2001-10-07 00:22:43 +00:00
trak - > durmap [ i ] . num = stream_read_dword ( demuxer - > stream ) ;
trak - > durmap [ i ] . dur = stream_read_dword ( demuxer - > stream ) ;
pts + = trak - > durmap [ i ] . num * trak - > durmap [ i ] . dur ;
2001-10-22 22:49:09 +00:00
2001-11-09 17:00:12 +00:00
if ( i = = 0 & & trak - > type = = MOV_TRAK_VIDEO )
2001-10-22 22:49:09 +00:00
{
sh_video_t * sh = new_sh_video ( demuxer , priv - > track_db ) ;
if ( ! sh - > fps )
sh - > fps = trak - > timescale / trak - > durmap [ i ] . dur ;
/* initial fps */
}
2001-10-05 23:13:26 +00:00
}
2001-10-26 14:04:17 +00:00
if ( trak - > length ! = pts ) mp_msg ( MSGT_DEMUX , MSGL_WARN , " Warning! pts=%d length=%d \n " , pts , trak - > length ) ;
2001-10-05 23:13:26 +00:00
break ;
}
case MOV_FOURCC ( ' s ' , ' t ' , ' s ' , ' c ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int len = stream_read_dword ( demuxer - > stream ) ;
2001-10-29 16:56:36 +00:00
int ver = ( temp < < 24 ) ;
int flags = ( temp < < 16 ) | ( temp < < 8 ) | temp ;
2001-10-05 23:13:26 +00:00
int i ;
2001-10-29 16:56:36 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sSample->Chunk mapping table! (%d blocks) (ver:%d,flags:%ld) \n " ,
level , " " , len , ver , flags ) ;
2001-10-05 23:13:26 +00:00
// read data:
trak - > chunkmap_size = len ;
trak - > chunkmap = malloc ( sizeof ( mov_chunkmap_t ) * len ) ;
for ( i = 0 ; i < len ; i + + ) {
2001-10-06 01:23:39 +00:00
trak - > chunkmap [ i ] . first = stream_read_dword ( demuxer - > stream ) - 1 ;
2001-10-05 23:13:26 +00:00
trak - > chunkmap [ i ] . spc = stream_read_dword ( demuxer - > stream ) ;
trak - > chunkmap [ i ] . sdid = stream_read_dword ( demuxer - > stream ) ;
}
break ;
}
case MOV_FOURCC ( ' s ' , ' t ' , ' s ' , ' z ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int ss = stream_read_dword ( demuxer - > stream ) ;
2001-10-29 16:56:36 +00:00
int ver = ( temp < < 24 ) ;
int flags = ( temp < < 16 ) | ( temp < < 8 ) | temp ;
int entries = stream_read_dword ( demuxer - > stream ) ;
2001-10-29 22:40:25 +00:00
int i ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sSample size table! (entries=%d ss=%d) (ver:%d,flags:%ld) \n " ,
level , " " , entries , ss , ver , flags ) ;
2001-11-09 17:00:12 +00:00
trak - > samplesize = ss ;
if ( ! ss ) {
// variable samplesize
trak - > samples = realloc ( trak - > samples , sizeof ( mov_sample_t ) * entries ) ;
trak - > samples_size = entries ;
for ( i = 0 ; i < entries ; i + + )
2001-10-29 22:40:25 +00:00
trak - > samples [ i ] . size = stream_read_dword ( demuxer - > stream ) ;
2001-11-09 17:00:12 +00:00
}
2001-10-05 23:13:26 +00:00
break ;
}
case MOV_FOURCC ( ' s ' , ' t ' , ' c ' , ' o ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int len = stream_read_dword ( demuxer - > stream ) ;
int i ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sChunk offset table! (%d chunks) \n " , level , " " , len ) ;
// extend array if needed:
if ( len > trak - > chunks_size ) {
trak - > chunks = realloc ( trak - > chunks , sizeof ( mov_chunk_t ) * len ) ;
trak - > chunks_size = len ;
}
// read elements:
for ( i = 0 ; i < len ; i + + ) trak - > chunks [ i ] . pos = stream_read_dword ( demuxer - > stream ) ;
break ;
}
2001-12-22 00:33:35 +00:00
case MOV_FOURCC ( ' c ' , ' o ' , ' 6 ' , ' 4 ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int len = stream_read_dword ( demuxer - > stream ) ;
int i ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*s64bit chunk offset table! (%d chunks) \n " , level , " " , len ) ;
// extend array if needed:
if ( len > trak - > chunks_size ) {
trak - > chunks = realloc ( trak - > chunks , sizeof ( mov_chunk_t ) * len ) ;
trak - > chunks_size = len ;
}
// read elements:
for ( i = 0 ; i < len ; i + + )
{
2002-01-05 19:29:52 +00:00
# ifndef _LARGEFILE_SOURCE
if ( stream_read_dword ( demuxer - > stream ) ! = 0 )
2001-12-22 00:33:35 +00:00
mp_msg ( MSGT_DEMUX , MSGL_WARN , " Chunk %d has got 64bit address, but you've MPlayer compiled without LARGEFILE support! \n " , i ) ;
2002-01-05 19:29:52 +00:00
trak - > chunks [ i ] . pos = stream_read_dword ( demuxer - > stream ) ;
2001-12-22 00:33:35 +00:00
# else
2002-01-05 19:29:52 +00:00
trak - > chunks [ i ] . pos = stream_read_qword ( demuxer - > stream ) ;
2001-12-22 00:33:35 +00:00
# endif
}
break ;
}
2001-10-29 16:56:36 +00:00
case MOV_FOURCC ( ' s ' , ' t ' , ' s ' , ' s ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int entries = stream_read_dword ( demuxer - > stream ) ;
int ver = ( temp < < 24 ) ;
int flags = ( temp < < 16 ) | ( temp < < 8 ) | temp ;
int i ;
2001-10-29 21:01:00 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sSyncing samples (keyframes) table! (%d entries) (ver:%d,flags:%ld) \n " ,
2001-10-29 16:56:36 +00:00
level , " " , entries , ver , flags ) ;
2001-10-29 21:55:07 +00:00
trak - > keyframes_size = entries ;
trak - > keyframes = malloc ( sizeof ( unsigned int ) * entries ) ;
2001-10-29 22:40:25 +00:00
for ( i = 0 ; i < entries ; i + + )
trak - > keyframes [ i ] = stream_read_dword ( demuxer - > stream ) - 1 ;
2001-10-29 21:55:07 +00:00
// for (i=0;i<entries;i++) printf("%3d: %d\n",i,trak->keyframes[i]);
2001-10-29 16:56:36 +00:00
break ;
}
2001-08-12 01:58:05 +00:00
case MOV_FOURCC ( ' m ' , ' d ' , ' i ' , ' a ' ) : {
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sMedia stream! \n " , level , " " ) ;
2001-08-12 01:58:05 +00:00
lschunks ( demuxer , level + 1 , pos + len , trak ) ;
break ;
}
case MOV_FOURCC ( ' m ' , ' i ' , ' n ' , ' f ' ) : {
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sMedia info! \n " , level , " " ) ;
2001-08-12 01:58:05 +00:00
lschunks ( demuxer , level + 1 , pos + len , trak ) ;
break ;
}
case MOV_FOURCC ( ' s ' , ' t ' , ' b ' , ' l ' ) : {
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sSample info! \n " , level , " " ) ;
2001-08-12 01:58:05 +00:00
lschunks ( demuxer , level + 1 , pos + len , trak ) ;
break ;
}
2001-10-29 22:40:25 +00:00
case MOV_FOURCC ( ' e ' , ' d ' , ' t ' , ' s ' ) : {
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sEdit atom! \n " , level , " " ) ;
lschunks ( demuxer , level + 1 , pos + len , trak ) ;
break ;
}
case MOV_FOURCC ( ' e ' , ' l ' , ' s ' , ' t ' ) : {
int temp = stream_read_dword ( demuxer - > stream ) ;
int entries = stream_read_dword ( demuxer - > stream ) ;
int ver = ( temp < < 24 ) ;
int flags = ( temp < < 16 ) | ( temp < < 8 ) | temp ;
int i ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: %*sEdit list table (%d entries) (ver:%d,flags:%ld) \n " ,
level , " " , entries , ver , flags ) ;
#if 0
for ( i = 0 ; i < entries ; i + + )
{
printf ( " entry#%d: dur: %ld mtime: %ld mrate: %ld \n " ,
i , stream_read_dword ( demuxer - > stream ) ,
stream_read_dword ( demuxer - > stream ) ,
stream_read_dword ( demuxer - > stream ) ) ;
}
# endif
break ;
}
2001-11-09 17:00:12 +00:00
case MOV_FOURCC ( ' c ' , ' o ' , ' d ' , ' e ' ) :
{
2001-11-22 15:43:24 +00:00
# warning "Implement atom 'code' for FLASH support"
2001-11-09 17:00:12 +00:00
}
2001-10-29 16:15:04 +00:00
default :
id = bswap_32 ( id ) ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: unknown chunk: %.4s %d \n " , & id , ( int ) len ) ;
break ;
2001-08-12 01:58:05 +00:00
} //switch(id)
2001-10-29 16:15:04 +00:00
} else { /* not in track */
switch ( id ) {
case MOV_FOURCC ( ' t ' , ' r ' , ' a ' , ' k ' ) : {
2001-08-12 01:58:05 +00:00
// if(trak) printf("MOV: Warning! trak in trak?\n");
if ( priv - > track_db > = MOV_MAX_TRACKS ) {
2001-09-26 21:35:14 +00:00
mp_msg ( MSGT_DEMUX , MSGL_WARN , MSGTR_MOVtooManyTrk ) ;
2001-08-12 01:58:05 +00:00
return ;
}
trak = malloc ( sizeof ( mov_track_t ) ) ;
memset ( trak , 0 , sizeof ( mov_track_t ) ) ;
2001-08-17 00:40:25 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: Track #%d: \n " , priv - > track_db ) ;
2001-08-12 01:58:05 +00:00
trak - > id = priv - > track_db ;
2001-10-05 23:13:26 +00:00
priv - > tracks [ priv - > track_db ] = trak ;
2001-08-12 01:58:05 +00:00
lschunks ( demuxer , level + 1 , pos + len , trak ) ;
2001-10-05 23:13:26 +00:00
mov_build_index ( trak ) ;
switch ( trak - > type ) {
case MOV_TRAK_AUDIO : {
sh_audio_t * sh = new_sh_audio ( demuxer , priv - > track_db ) ;
sh - > format = trak - > fourcc ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Audio bits: %d chans: %d \n " , trak - > stdata [ 19 ] , trak - > stdata [ 17 ] ) ;
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Fourcc: %.4s \n " , & trak - > fourcc ) ;
2001-10-29 21:25:10 +00:00
#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
2001-10-06 00:58:23 +00:00
// Emulate WAVEFORMATEX struct:
sh - > wf = malloc ( sizeof ( WAVEFORMATEX ) ) ;
memset ( sh - > wf , 0 , sizeof ( WAVEFORMATEX ) ) ;
2001-10-29 21:25:10 +00:00
sh - > wf - > nChannels = ( trak - > stdata [ 16 ] < < 8 ) + trak - > stdata [ 17 ] ;
sh - > wf - > wBitsPerSample = ( trak - > stdata [ 18 ] < < 8 ) + trak - > stdata [ 19 ] ;
// sh->wf->nSamplesPerSec=trak->timescale;
sh - > wf - > nSamplesPerSec = ( trak - > stdata [ 24 ] < < 8 ) + trak - > stdata [ 25 ] ;
sh - > wf - > nAvgBytesPerSec = sh - > wf - > nChannels * sh - > wf - > wBitsPerSample * sh - > wf - > nSamplesPerSec / 8 ;
2001-10-06 00:58:23 +00:00
// 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 ;
}
2001-10-05 23:13:26 +00:00
break ;
}
case MOV_TRAK_VIDEO : {
2002-01-13 06:01:04 +00:00
int i , entry ;
int flag , start , count_flag , end , palette_count ;
int hdr_ptr = 43 + 33 ; // the byte just after depth
unsigned char * palette_map ;
2001-10-05 23:13:26 +00:00
sh_video_t * sh = new_sh_video ( demuxer , priv - > track_db ) ;
2001-12-22 00:33:35 +00:00
int depth = trak - > stdata [ 43 + 32 ] ; /* requested by Mike Melanson for Apple RLE decoder -- alex */
2001-10-05 23:13:26 +00:00
sh - > format = trak - > fourcc ;
2001-10-22 22:49:09 +00:00
if ( ! sh - > fps ) sh - > fps = trak - > timescale ;
2001-10-05 23:13:26 +00:00
sh - > frametime = 1.0f / sh - > fps ;
2001-10-06 00:58:23 +00:00
sh - > disp_w = trak - > tkdata [ 77 ] | ( trak - > tkdata [ 76 ] < < 8 ) ;
sh - > disp_h = trak - > tkdata [ 81 ] | ( trak - > tkdata [ 80 ] < < 8 ) ;
2002-01-13 06:01:04 +00:00
// palettized?
if ( ( depth = = 2 ) | | ( depth = = 4 ) | | ( depth = = 8 ) | |
( depth = = 34 ) | | ( depth = = 36 ) | | ( depth = = 40 ) )
palette_count = ( 1 < < ( depth & 0x0F ) ) ;
else
palette_count = 0 ;
2001-10-06 00:58:23 +00:00
// emulate BITMAPINFOHEADER:
2002-01-13 06:01:04 +00:00
if ( palette_count )
{
sh - > bih = malloc ( sizeof ( BITMAPINFOHEADER ) + palette_count * 4 ) ;
memset ( sh - > bih , 0 , sizeof ( BITMAPINFOHEADER ) + palette_count * 4 ) ;
sh - > bih - > biSize = 40 + palette_count * 4 ;
// fetch the relevant fields
flag = BE_16 ( & trak - > stdata [ hdr_ptr ] ) ;
hdr_ptr + = 2 ;
start = BE_32 ( & trak - > stdata [ hdr_ptr ] ) ;
hdr_ptr + = 4 ;
count_flag = BE_16 ( & trak - > stdata [ hdr_ptr ] ) ;
hdr_ptr + = 2 ;
end = BE_16 ( & trak - > stdata [ hdr_ptr ] ) ;
hdr_ptr + = 2 ;
palette_map = ( unsigned char * ) sh - > bih + 40 ;
2002-01-24 05:20:19 +00:00
// load default palette
2002-02-05 04:08:05 +00:00
if ( flag = = 0xFFFF )
2002-01-24 05:20:19 +00:00
{
if ( palette_count = = 4 )
memcpy ( palette_map , qt_default_palette_4 , 4 * 4 ) ;
else if ( palette_count = = 16 )
memcpy ( palette_map , qt_default_palette_16 , 16 * 4 ) ;
if ( palette_count = = 256 )
memcpy ( palette_map , qt_default_palette_256 , 256 * 4 ) ;
}
// load palette from file
else
2002-01-13 06:01:04 +00:00
{
2002-01-24 05:20:19 +00:00
for ( i = start ; i < = end ; i + + )
{
entry = BE_16 ( & trak - > stdata [ hdr_ptr ] ) ;
hdr_ptr + = 2 ;
// apparently, if count_flag is set, entry is same as i
if ( count_flag & 0x8000 )
entry = i ;
// only care about top 8 bits of 16-bit R, G, or B value
2002-01-27 02:48:39 +00:00
palette_map [ entry * 4 + 2 ] = trak - > stdata [ hdr_ptr + 0 ] ;
2002-01-24 05:20:19 +00:00
palette_map [ entry * 4 + 1 ] = trak - > stdata [ hdr_ptr + 2 ] ;
2002-01-27 02:48:39 +00:00
palette_map [ entry * 4 + 0 ] = trak - > stdata [ hdr_ptr + 4 ] ;
2002-01-24 05:20:19 +00:00
hdr_ptr + = 6 ;
}
2002-01-13 06:01:04 +00:00
}
}
else
{
sh - > bih = malloc ( sizeof ( BITMAPINFOHEADER ) ) ;
memset ( sh - > bih , 0 , sizeof ( BITMAPINFOHEADER ) ) ;
sh - > bih - > biSize = 40 ;
}
2001-10-06 00:58:23 +00:00
sh - > bih - > biWidth = sh - > disp_w ;
sh - > bih - > biHeight = sh - > disp_h ;
sh - > bih - > biPlanes = 0 ;
2001-12-22 00:33:35 +00:00
sh - > bih - > biBitCount = depth ;
2001-10-06 00:58:23 +00:00
sh - > bih - > biCompression = trak - > fourcc ;
sh - > bih - > biSizeImage = sh - > bih - > biWidth * sh - > bih - > biHeight ;
2001-12-22 00:33:35 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Image size: %d x %d (%dbits) \n " , sh - > disp_w , sh - > disp_h , sh - > bih - > biBitCount ) ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Fourcc: %.4s Codec: '%.*s' \n " , & trak - > fourcc , trak - > stdata_len - 43 , trak - > stdata + 43 ) ;
2001-10-07 00:22:43 +00:00
2001-10-06 00:58:23 +00:00
if ( demuxer - > video - > id = = - 1 | | demuxer - > video - > id = = priv - > track_db ) {
// (auto)selected video track:
demuxer - > video - > id = priv - > track_db ;
demuxer - > video - > sh = sh ; sh - > ds = demuxer - > video ;
}
2001-10-05 23:13:26 +00:00
break ;
}
2001-11-09 17:00:12 +00:00
case MOV_TRAK_GENERIC :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Generic track - not completly understood! (id: %d) \n " ,
trak - > id ) ;
2001-11-22 15:43:24 +00:00
# warning "Also this contains the FLASH data"
2001-11-09 17:00:12 +00:00
#if 0
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Extracting samples to files (possibly this is an flash anim) \n " ) ;
{
int pos = stream_tell ( demuxer - > stream ) ;
int i ;
int fd ;
char name [ 20 ] ;
for ( i = 0 ; i < trak - > samples_size ; i + + )
{
char buf [ trak - > samples [ i ] . size ] ;
stream_seek ( demuxer - > stream , trak - > samples [ i ] . pos ) ;
snprintf ( ( char * ) & name [ 0 ] , 20 , " samp%d " , i ) ;
fd = open ( ( char * ) & name [ 0 ] , O_CREAT | O_WRONLY ) ;
stream_read ( demuxer - > stream , & buf [ 0 ] , trak - > samples [ i ] . size ) ;
write ( fd , & buf [ 0 ] , trak - > samples [ i ] . size ) ;
close ( fd ) ;
}
for ( i = 0 ; i < trak - > chunks_size ; i + + )
{
char buf [ trak - > length ] ;
stream_seek ( demuxer - > stream , trak - > chunks [ i ] . pos ) ;
snprintf ( ( char * ) & name [ 0 ] , 20 , " chunk%d " , i ) ;
fd = open ( ( char * ) & name [ 0 ] , O_CREAT | O_WRONLY ) ;
stream_read ( demuxer - > stream , & buf [ 0 ] , trak - > length ) ;
write ( fd , & buf [ 0 ] , trak - > length ) ;
close ( fd ) ;
}
if ( trak - > samplesize > 0 )
{
char * buf ;
buf = malloc ( trak - > samplesize ) ;
stream_seek ( demuxer - > stream , trak - > chunks [ 0 ] . pos ) ;
snprintf ( ( char * ) & name [ 0 ] , 20 , " trak%d " , trak - > id ) ;
fd = open ( ( char * ) & name [ 0 ] , O_CREAT | O_WRONLY ) ;
stream_read ( demuxer - > stream , buf , trak - > samplesize ) ;
write ( fd , buf , trak - > samplesize ) ;
close ( fd ) ;
}
stream_seek ( demuxer - > stream , pos ) ;
}
# endif
break ;
2001-10-29 16:15:04 +00:00
default :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Unknown track type found (type: %d) \n " , trak - > type ) ;
break ;
2001-10-05 23:13:26 +00:00
}
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " -------------- \n " ) ;
2001-10-05 23:13:26 +00:00
priv - > track_db + + ;
2001-08-12 01:58:05 +00:00
trak = NULL ;
2001-10-29 16:15:04 +00:00
break ;
}
2001-10-10 01:07:50 +00:00
# ifndef HAVE_ZLIB
2001-10-29 16:15:04 +00:00
case MOV_FOURCC ( ' c ' , ' m ' , ' o ' , ' v ' ) : {
2001-09-26 21:35:14 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , MSGTR_MOVcomprhdr ) ;
2001-08-12 01:58:05 +00:00
return ;
}
2001-10-10 01:07:50 +00:00
# else
2001-10-29 16:15:04 +00:00
case MOV_FOURCC ( ' c ' , ' m ' , ' o ' , ' v ' ) : {
2001-10-10 01:07:50 +00:00
// mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_MOVcomprhdr);
lschunks ( demuxer , level + 1 , pos + len , NULL ) ;
2001-10-29 16:15:04 +00:00
break ;
}
case MOV_FOURCC ( ' d ' , ' c ' , ' o ' , ' m ' ) : {
2001-10-10 01:07:50 +00:00
// int temp=stream_read_dword(demuxer->stream);
2001-10-22 22:49:09 +00:00
unsigned int len = bswap_32 ( stream_read_dword ( demuxer - > stream ) ) ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Compressed header uses %.4s algo! \n " , & len ) ;
2001-10-29 16:15:04 +00:00
break ;
}
case MOV_FOURCC ( ' c ' , ' m ' , ' v ' , ' d ' ) : {
2001-10-10 01:07:50 +00:00
// int temp=stream_read_dword(demuxer->stream);
unsigned int moov_sz = stream_read_dword ( demuxer - > stream ) ;
unsigned int cmov_sz = len - 4 ;
unsigned char * cmov_buf = malloc ( cmov_sz ) ;
unsigned char * moov_buf = malloc ( moov_sz + 16 ) ;
int zret ;
z_stream zstrm ;
stream_t * backup ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Compressed header size: %d / %d \n " , cmov_sz , moov_sz ) ;
2001-10-10 01:07:50 +00:00
stream_read ( demuxer - > stream , cmov_buf , cmov_sz ) ;
zstrm . zalloc = ( alloc_func ) 0 ;
zstrm . zfree = ( free_func ) 0 ;
zstrm . opaque = ( voidpf ) 0 ;
zstrm . next_in = cmov_buf ;
zstrm . avail_in = cmov_sz ;
zstrm . next_out = moov_buf ;
zstrm . avail_out = moov_sz ;
zret = inflateInit ( & zstrm ) ;
if ( zret ! = Z_OK )
2001-10-26 14:04:17 +00:00
{ mp_msg ( MSGT_DEMUX , MSGL_ERR , " QT cmov: inflateInit err %d \n " , zret ) ;
2001-10-10 01:07:50 +00:00
return ;
}
zret = inflate ( & zstrm , Z_NO_FLUSH ) ;
if ( ( zret ! = Z_OK ) & & ( zret ! = Z_STREAM_END ) )
2001-10-26 14:04:17 +00:00
{ mp_msg ( MSGT_DEMUX , MSGL_ERR , " QT cmov inflate: ERR %d \n " , zret ) ;
2001-10-10 01:07:50 +00:00
return ;
}
#if 0
else {
FILE * DecOut ;
DecOut = fopen ( " Out.bin " , " w " ) ;
fwrite ( moov_buf , 1 , moov_sz , DecOut ) ;
fclose ( DecOut ) ;
}
# endif
2001-10-26 14:04:17 +00:00
if ( moov_sz ! = zstrm . total_out )
mp_msg ( MSGT_DEMUX , MSGL_WARN , " Warning! moov size differs cmov: %d zlib: %d \n " , moov_sz , zstrm . total_out ) ;
2001-10-10 01:07:50 +00:00
zret = inflateEnd ( & zstrm ) ;
backup = demuxer - > stream ;
demuxer - > stream = new_memory_stream ( moov_buf , moov_sz ) ;
stream_skip ( demuxer - > stream , 8 ) ;
lschunks ( demuxer , level + 1 , moov_sz , NULL ) ; // parse uncompr. 'moov'
//free_stream(demuxer->stream);
demuxer - > stream = backup ;
2001-10-26 14:04:17 +00:00
free ( cmov_buf ) ;
free ( moov_buf ) ;
2001-10-29 16:15:04 +00:00
break ;
2001-10-10 01:07:50 +00:00
}
# endif
2001-10-29 16:15:04 +00:00
case MOV_FOURCC ( ' u ' , ' d ' , ' t ' , ' a ' ) :
2001-10-23 16:21:24 +00:00
{
unsigned int udta_id ;
off_t udta_len ;
off_t udta_size = len ;
2001-08-12 01:58:05 +00:00
2001-10-23 16:21:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " mov: user data record found \n " ) ;
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Quicktime Clip Info: \n " ) ;
while ( ( len > 8 ) & & ( udta_size > 8 ) )
{
udta_len = stream_read_dword ( demuxer - > stream ) ;
udta_id = stream_read_dword ( demuxer - > stream ) ;
udta_size - = 8 ;
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " udta_id: %.4s (len: %d) \n " , & udta_id , udta_len ) ;
switch ( udta_id )
{
case MOV_FOURCC ( 0xa9 , ' c ' , ' p ' , ' y ' ) :
2001-10-29 21:01:00 +00:00
case MOV_FOURCC ( 0xa9 , ' d ' , ' a ' , ' y ' ) :
case MOV_FOURCC ( 0xa9 , ' d ' , ' i ' , ' r ' ) :
/* 0xa9,'e','d','1' - '9' : edit timestamps */
case MOV_FOURCC ( 0xa9 , ' f ' , ' m ' , ' t ' ) :
2001-10-23 16:21:24 +00:00
case MOV_FOURCC ( 0xa9 , ' i ' , ' n ' , ' f ' ) :
2001-10-29 21:01:00 +00:00
case MOV_FOURCC ( 0xa9 , ' p ' , ' r ' , ' d ' ) :
case MOV_FOURCC ( 0xa9 , ' p ' , ' r ' , ' f ' ) :
case MOV_FOURCC ( 0xa9 , ' r ' , ' e ' , ' q ' ) :
case MOV_FOURCC ( 0xa9 , ' s ' , ' r ' , ' c ' ) :
case MOV_FOURCC ( ' n ' , ' a ' , ' m ' , ' e ' ) :
2001-10-23 16:21:24 +00:00
case MOV_FOURCC ( 0xa9 , ' n ' , ' a ' , ' m ' ) :
case MOV_FOURCC ( 0xa9 , ' A ' , ' R ' , ' T ' ) :
case MOV_FOURCC ( 0xa9 , ' c ' , ' m ' , ' t ' ) :
2001-10-26 14:04:17 +00:00
case MOV_FOURCC ( 0xa9 , ' a ' , ' u ' , ' t ' ) :
case MOV_FOURCC ( 0xa9 , ' s ' , ' w ' , ' r ' ) :
2001-10-23 16:21:24 +00:00
{
off_t text_len = stream_read_word ( demuxer - > stream ) ;
char text [ text_len + 2 + 1 ] ;
stream_read ( demuxer - > stream , ( char * ) & text , text_len + 2 ) ;
text [ text_len + 2 ] = 0x0 ;
switch ( udta_id )
{
2001-10-26 14:04:17 +00:00
case MOV_FOURCC ( 0xa9 , ' a ' , ' u ' , ' t ' ) :
2001-11-22 15:43:24 +00:00
demux_info_add ( demuxer , " author " , & text [ 2 ] ) ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Author: %s \n " , & text [ 2 ] ) ;
break ;
2001-10-23 16:21:24 +00:00
case MOV_FOURCC ( 0xa9 , ' c ' , ' p ' , ' y ' ) :
2001-11-22 15:43:24 +00:00
demux_info_add ( demuxer , " copyright " , & text [ 2 ] ) ;
2001-10-23 16:21:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Copyright: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' i ' , ' n ' , ' f ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Info: %s \n " , & text [ 2 ] ) ;
break ;
2001-10-29 21:01:00 +00:00
case MOV_FOURCC ( ' n ' , ' a ' , ' m ' , ' e ' ) :
2001-10-23 16:21:24 +00:00
case MOV_FOURCC ( 0xa9 , ' n ' , ' a ' , ' m ' ) :
2001-11-22 15:43:24 +00:00
demux_info_add ( demuxer , " name " , & text [ 2 ] ) ;
2001-10-23 16:21:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Name: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' A ' , ' R ' , ' T ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Artist: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' d ' , ' i ' , ' r ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Director: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' c ' , ' m ' , ' t ' ) :
2001-11-22 15:43:24 +00:00
demux_info_add ( demuxer , " comments " , & text [ 2 ] ) ;
2001-10-23 16:21:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Comment: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' r ' , ' e ' , ' q ' ) :
2001-10-29 21:01:00 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Requirements: %s \n " , & text [ 2 ] ) ;
2001-10-23 16:21:24 +00:00
break ;
2001-10-26 14:04:17 +00:00
case MOV_FOURCC ( 0xa9 , ' s ' , ' w ' , ' r ' ) :
2001-11-22 15:43:24 +00:00
demux_info_add ( demuxer , " encoder " , & text [ 2 ] ) ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Software: %s \n " , & text [ 2 ] ) ;
break ;
2001-10-29 21:01:00 +00:00
case MOV_FOURCC ( 0xa9 , ' d ' , ' a ' , ' y ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Creation timestamp: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' f ' , ' m ' , ' t ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Format: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' p ' , ' r ' , ' d ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Producer: %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' p ' , ' r ' , ' f ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Performer(s): %s \n " , & text [ 2 ] ) ;
break ;
case MOV_FOURCC ( 0xa9 , ' s ' , ' r ' , ' c ' ) :
mp_msg ( MSGT_DEMUX , MSGL_INFO , " Source providers: %s \n " , & text [ 2 ] ) ;
break ;
2001-10-23 16:21:24 +00:00
}
udta_size - = 4 + text_len ;
break ;
}
2001-10-29 21:01:00 +00:00
/* some other shits: WLOC - window location,
LOOP - looping style ,
SelO - play only selected frames
AllF - play all frames
*/
case MOV_FOURCC ( ' W ' , ' L ' , ' O ' , ' C ' ) :
case MOV_FOURCC ( ' L ' , ' O ' , ' O ' , ' P ' ) :
case MOV_FOURCC ( ' S ' , ' e ' , ' l ' , ' O ' ) :
case MOV_FOURCC ( ' A ' , ' l ' , ' l ' , ' F ' ) :
2001-10-23 16:21:24 +00:00
default :
{
char dump [ udta_len - 4 ] ;
stream_read ( demuxer - > stream , ( char * ) & dump , udta_len - 4 - 4 ) ;
udta_size - = udta_len ;
}
}
}
2001-10-29 16:15:04 +00:00
break ;
2001-10-23 16:21:24 +00:00
} /* eof udta */
2001-10-29 16:15:04 +00:00
default :
id = bswap_32 ( id ) ;
mp_msg ( MSGT_DEMUX , MSGL_V , " MOV: unknown chunk: %.4s %d \n " , & id , ( int ) len ) ;
} /* endof switch */
} /* endof else */
2001-10-23 16:21:24 +00:00
2001-08-12 01:58:05 +00:00
pos + = len + 8 ;
if ( pos > = endpos ) break ;
if ( ! stream_seek ( demuxer - > stream , pos ) ) break ;
}
}
int mov_read_header ( demuxer_t * demuxer ) {
mov_priv_t * priv = demuxer - > priv ;
2001-10-26 14:04:17 +00:00
mp_msg ( MSGT_DEMUX , MSGL_DBG3 , " mov_read_header! \n " ) ;
2001-08-12 01:58:05 +00:00
// Parse header:
2001-10-05 23:13:26 +00:00
stream_reset ( demuxer - > stream ) ;
2001-08-12 01:58:05 +00:00
if ( ! stream_seek ( demuxer - > stream , priv - > moov_start ) ) return 0 ; // ???
lschunks ( demuxer , 0 , priv - > moov_end , NULL ) ;
return 1 ;
}
2001-10-06 00:58:23 +00:00
// return value:
// 0 = EOF or no stream found
// 1 = successfully read a packet
int demux_mov_fill_buffer ( demuxer_t * demuxer , demux_stream_t * ds ) {
mov_priv_t * priv = demuxer - > priv ;
mov_track_t * trak = NULL ;
float pts ;
if ( ds - > id < 0 | | ds - > id > = priv - > track_db ) return 0 ;
trak = priv - > tracks [ ds - > id ] ;
2001-10-07 00:22:43 +00:00
if ( trak - > samplesize ) {
// read chunk:
2001-10-23 13:55:49 +00:00
int x ;
2001-10-07 00:22:43 +00:00
if ( trak - > pos > = trak - > chunks_size ) return 0 ; // EOF
stream_seek ( demuxer - > stream , trak - > chunks [ trak - > pos ] . pos ) ;
pts = ( float ) ( trak - > chunks [ trak - > pos ] . sample * trak - > duration ) / ( float ) trak - > timescale ;
2001-11-22 15:43:24 +00:00
if ( trak - > samplesize ! = 1 )
{
mp_msg ( MSGT_DEMUX , MSGL_WARN , " WARNING! Samplesize(%d) != 1 \n " ,
trak - > samplesize ) ;
x = trak - > chunks [ trak - > pos ] . size * trak - > samplesize ;
}
else
x = trak - > chunks [ trak - > pos ] . size ;
2001-12-22 00:33:35 +00:00
// printf("X = %d\n", x);
2001-10-29 21:25:10 +00:00
if ( trak - > stdata_len > = 36 ) {
// extended stsd header - works for CBR MP3:
x / = ( trak - > stdata [ 30 ] < < 8 ) + trak - > stdata [ 31 ] ; // samples/packet
// x*=(trak->stdata[34]<<8)+trak->stdata[35]; // bytes/packet
x * = ( trak - > stdata [ 38 ] < < 8 ) + trak - > stdata [ 39 ] ; // bytes/frame
} else {
// works for ima4: -- we should find this info in mov headers!
2001-10-29 22:41:54 +00:00
if ( ds - > ss_div ! = 1 | | ds - > ss_mul ! = 1 ) {
x / = ds - > ss_div ; x * = ds - > ss_mul ; // compression ratio fix ! HACK !
} else {
x * = ( trak - > stdata [ 18 ] < < 8 ) + trak - > stdata [ 19 ] ; x / = 8 ; // bits/sample
}
2001-10-29 21:25:10 +00:00
}
2001-10-23 13:55:49 +00:00
ds_read_packet ( ds , demuxer - > stream , x , pts , trak - > chunks [ trak - > pos ] . pos , 0 ) ;
2001-10-26 14:04:17 +00:00
if ( ds = = demuxer - > audio ) mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " sample %d bytes pts %5.3f \n " , trak - > chunks [ trak - > pos ] . size * trak - > samplesize , pts ) ;
2001-10-07 00:22:43 +00:00
} else {
2001-10-06 00:58:23 +00:00
// read sample:
if ( trak - > pos > = trak - > samples_size ) return 0 ; // EOF
stream_seek ( demuxer - > stream , trak - > samples [ trak - > pos ] . pos ) ;
pts = ( float ) trak - > samples [ trak - > pos ] . pts / ( float ) trak - > timescale ;
ds_read_packet ( ds , demuxer - > stream , trak - > samples [ trak - > pos ] . size , pts , trak - > samples [ trak - > pos ] . pos , 0 ) ;
2001-10-07 00:22:43 +00:00
}
2001-10-06 00:58:23 +00:00
+ + trak - > pos ;
2001-10-07 00:22:43 +00:00
2001-10-06 00:58:23 +00:00
return 1 ;
}
2001-10-16 22:41:46 +00:00
static float mov_seek_track ( mov_track_t * trak , float pts , int flags ) {
// printf("MOV track seek called %5.3f \n",pts);
if ( flags & 2 ) pts * = trak - > length ; else pts * = ( float ) trak - > timescale ;
if ( trak - > samplesize ) {
int sample = pts / trak - > duration ;
// printf("MOV track seek - chunk: %d (pts: %5.3f dur=%d) \n",sample,pts,trak->duration);
if ( ! ( flags & 1 ) ) sample + = trak - > chunks [ trak - > pos ] . sample ; // relative
trak - > pos = 0 ;
while ( trak - > pos < trak - > chunks_size & & trak - > chunks [ trak - > pos ] . sample < sample ) + + trak - > pos ;
pts = ( float ) ( trak - > chunks [ trak - > pos ] . sample * trak - > duration ) / ( float ) trak - > timescale ;
} else {
2001-10-29 22:11:40 +00:00
unsigned int ipts ;
if ( ! ( flags & 1 ) ) pts + = trak - > samples [ trak - > pos ] . pts ;
if ( pts < 0 ) pts = 0 ;
ipts = pts ;
//printf("MOV track seek - sample: %d \n",ipts);
2001-10-29 21:55:07 +00:00
for ( trak - > pos = 0 ; trak - > pos < trak - > samples_size ; + + trak - > pos ) {
if ( trak - > samples [ trak - > pos ] . pts > = ipts ) break ; // found it!
}
if ( trak - > keyframes_size ) {
// find nearest keyframe
int i ;
for ( i = 0 ; i < trak - > keyframes_size ; i + + ) {
if ( trak - > keyframes [ i ] > = trak - > pos ) break ;
}
2001-10-29 22:40:25 +00:00
if ( i > 0 & & ( trak - > keyframes [ i ] - trak - > pos ) > ( trak - > pos - trak - > keyframes [ i - 1 ] ) )
- - i ;
2001-10-29 21:55:07 +00:00
trak - > pos = trak - > keyframes [ i ] ;
// printf("nearest keyframe: %d \n",trak->pos);
}
2001-10-16 22:41:46 +00:00
pts = ( float ) trak - > samples [ trak - > pos ] . pts / ( float ) trak - > timescale ;
}
// printf("MOV track seek done: %5.3f \n",pts);
return pts ;
}
void demux_seek_mov ( demuxer_t * demuxer , float pts , int flags ) {
mov_priv_t * priv = demuxer - > priv ;
demux_stream_t * ds ;
// printf("MOV seek called %5.3f flag=%d \n",pts,flags);
ds = demuxer - > video ;
if ( ds & & ds - > id > = 0 & & ds - > id < priv - > track_db ) {
mov_track_t * trak = priv - > tracks [ ds - > id ] ;
//if(flags&2) pts*=(float)trak->length/(float)trak->timescale;
//if(!(flags&1)) pts+=ds->pts;
pts = ds - > pts = mov_seek_track ( trak , pts , flags ) ;
flags = 1 ; // absolute seconds
}
ds = demuxer - > audio ;
if ( ds & & ds - > id > = 0 & & ds - > id < priv - > track_db ) {
mov_track_t * trak = priv - > tracks [ ds - > id ] ;
//if(flags&2) pts*=(float)trak->length/(float)trak->timescale;
//if(!(flags&1)) pts+=ds->pts;
ds - > pts = mov_seek_track ( trak , pts , flags ) ;
}
}