2001-04-23 05:42:17 +02:00
# include <stdio.h>
# include <stdlib.h>
2001-10-29 01:55:15 +01:00
# include <string.h>
2002-12-27 23:43:20 +01:00
# include <inttypes.h>
2002-12-28 01:48:07 +01:00
# include <unistd.h>
2004-03-17 15:50:37 +01:00
# include <limits.h>
2001-10-29 01:55:15 +01:00
2001-10-30 18:03:11 +01:00
# include "config.h"
2005-11-18 15:39:25 +01:00
# include "version.h"
2001-10-30 18:03:11 +01:00
2007-03-15 19:36:36 +01:00
# include "stream/stream.h"
2004-03-17 15:50:37 +01:00
# include "demuxer.h"
# include "stheader.h"
2001-04-23 05:42:17 +02:00
2002-12-27 23:43:20 +01:00
# include "muxer.h"
2002-08-05 13:26:26 +02:00
# include "aviheader.h"
2004-04-28 12:18:33 +02:00
# include "ms_hdr.h"
2004-03-17 15:50:37 +01:00
# include "mp_msg.h"
2005-11-29 23:04:57 +01:00
# include "help_mp.h"
2001-04-23 05:42:17 +02:00
2002-08-29 22:50:49 +02:00
extern char * info_name ;
extern char * info_artist ;
extern char * info_genre ;
extern char * info_subject ;
extern char * info_copyright ;
extern char * info_sourceform ;
extern char * info_comment ;
2004-03-17 15:50:37 +01:00
/* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
# define ODML_CHUNKLEN 0x40000000
# define ODML_NOTKEYFRAME 0x80000000U
# define MOVIALIGN 0x00001000
2004-03-24 16:16:36 +01:00
float avi_aspect_override = - 1.0 ;
2004-04-30 23:33:53 +02:00
int write_odml = 1 ;
2004-03-21 22:32:54 +01:00
2004-03-17 15:50:37 +01:00
struct avi_odmlidx_entry {
uint64_t ofs ;
uint32_t len ;
uint32_t flags ;
} ;
struct avi_odmlsuperidx_entry {
uint64_t ofs ;
uint32_t len ;
uint32_t duration ;
} ;
struct avi_stream_info {
int idxsize ;
int idxpos ;
int superidxpos ;
int superidxsize ;
2004-04-19 04:14:09 +02:00
int riffofspos ;
int riffofssize ;
off_t * riffofs ;
2004-03-17 15:50:37 +01:00
struct avi_odmlidx_entry * idx ;
struct avi_odmlsuperidx_entry * superidx ;
} ;
2004-03-24 16:16:36 +01:00
static unsigned int avi_aspect ( muxer_stream_t * vstream )
{
int x , y ;
float aspect = vstream - > aspect ;
if ( avi_aspect_override > 0.0 ) {
aspect = avi_aspect_override ;
}
if ( aspect < = 0.0 ) return 0 ;
if ( aspect > 15.99 / 9.0 & & aspect < 16.01 / 9.0 ) {
return MAKE_AVI_ASPECT ( 16 , 9 ) ;
}
if ( aspect > 3.99 / 3.0 & & aspect < 4.01 / 3.0 ) {
return MAKE_AVI_ASPECT ( 4 , 3 ) ;
}
if ( aspect > = 1.0 ) {
x = 16384 ;
y = ( float ) x / aspect ;
} else {
y = 16384 ;
x = ( float ) y * aspect ;
}
return MAKE_AVI_ASPECT ( x , y ) ;
}
2002-12-27 23:43:20 +01:00
static muxer_stream_t * avifile_new_stream ( muxer_t * muxer , int type ) {
2004-03-17 15:50:37 +01:00
struct avi_stream_info * si ;
2002-12-27 23:43:20 +01:00
muxer_stream_t * s ;
2003-01-19 01:33:11 +01:00
if ( ! muxer ) return NULL ;
2002-12-27 23:43:20 +01:00
if ( muxer - > avih . dwStreams > = MUXER_MAX_STREAMS ) {
2004-03-17 15:50:37 +01:00
mp_msg ( MSGT_MUXER , MSGL_ERR , " Too many streams! increase MUXER_MAX_STREAMS ! \n " ) ;
2001-10-29 01:55:15 +01:00
return NULL ;
}
2002-12-27 23:43:20 +01:00
s = malloc ( sizeof ( muxer_stream_t ) ) ;
memset ( s , 0 , sizeof ( muxer_stream_t ) ) ;
2001-10-29 01:55:15 +01:00
if ( ! s ) return NULL ; // no mem!?
muxer - > streams [ muxer - > avih . dwStreams ] = s ;
s - > type = type ;
s - > id = muxer - > avih . dwStreams ;
s - > timer = 0.0 ;
2001-11-03 21:57:13 +01:00
s - > size = 0 ;
2003-01-19 01:33:11 +01:00
s - > muxer = muxer ;
2004-03-17 15:50:37 +01:00
s - > priv = si = malloc ( sizeof ( struct avi_stream_info ) ) ;
memset ( si , 0 , sizeof ( struct avi_stream_info ) ) ;
si - > idxsize = 256 ;
2006-06-05 00:41:27 +02:00
si - > idx = calloc ( si - > idxsize , sizeof ( struct avi_odmlidx_entry ) ) ;
2004-04-19 04:14:09 +02:00
si - > riffofssize = 16 ;
2006-06-05 00:41:27 +02:00
si - > riffofs = calloc ( ( si - > riffofssize + 1 ) , sizeof ( off_t ) ) ;
2004-04-19 04:14:09 +02:00
memset ( si - > riffofs , 0 , sizeof ( off_t ) * si - > riffofssize ) ;
2004-03-17 15:50:37 +01:00
2001-10-29 01:55:15 +01:00
switch ( type ) {
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_VIDEO :
2001-10-29 01:55:15 +01:00
s - > ckid = mmioFOURCC ( ( ' 0 ' + s - > id / 10 ) , ( ' 0 ' + ( s - > id % 10 ) ) , ' d ' , ' c ' ) ;
s - > h . fccType = streamtypeVIDEO ;
if ( ! muxer - > def_v ) muxer - > def_v = s ;
break ;
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_AUDIO :
2001-10-29 01:55:15 +01:00
s - > ckid = mmioFOURCC ( ( ' 0 ' + s - > id / 10 ) , ( ' 0 ' + ( s - > id % 10 ) ) , ' w ' , ' b ' ) ;
s - > h . fccType = streamtypeAUDIO ;
break ;
default :
2004-03-17 15:50:37 +01:00
mp_msg ( MSGT_MUXER , MSGL_WARN , " Warning! unknown stream type: %d \n " , type ) ;
2001-10-29 01:55:15 +01:00
return NULL ;
}
muxer - > avih . dwStreams + + ;
return s ;
}
2001-02-24 21:28:24 +01:00
2006-12-18 22:03:59 +01:00
static void write_avi_chunk ( stream_t * stream , unsigned int id , int len , void * data ) {
2002-08-05 13:26:26 +02:00
int le_len = le2me_32 ( len ) ;
int le_id = le2me_32 ( id ) ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( stream , & le_id , 4 ) ;
stream_write_buffer ( stream , & le_len , 4 ) ;
2002-08-05 13:26:26 +02:00
2001-02-24 21:28:24 +01:00
if ( len > 0 ) {
if ( data ) {
// DATA
2006-12-18 22:03:59 +01:00
stream_write_buffer ( stream , data , len ) ;
2001-02-24 21:28:24 +01:00
if ( len & 1 ) { // padding
unsigned char zerobyte = 0 ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( stream , & zerobyte , 1 ) ;
2001-02-24 21:28:24 +01:00
}
} else {
// JUNK
char * avi_junk_data = " [= MPlayer junk data! =] " ;
if ( len & 1 ) + + len ; // padding
while ( len > 0 ) {
int l = strlen ( avi_junk_data ) ;
if ( l > len ) l = len ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( stream , avi_junk_data , l ) ;
2001-02-24 21:28:24 +01:00
len - = l ;
}
}
}
}
2006-12-18 22:03:59 +01:00
static void write_avi_list ( stream_t * s , unsigned int id , int len ) ;
2004-04-30 23:33:53 +02:00
static void avifile_write_standard_index ( muxer_t * muxer ) ;
2004-03-17 15:50:37 +01:00
static void avifile_odml_new_riff ( muxer_t * muxer )
{
2004-04-19 04:14:09 +02:00
struct avi_stream_info * vsi = muxer - > def_v - > priv ;
2004-03-17 15:50:37 +01:00
uint32_t riff [ 3 ] ;
2004-05-23 09:34:32 +02:00
mp_msg ( MSGT_MUXER , MSGL_INFO , " ODML: Starting new RIFF chunk at %dMB. \n " , ( int ) ( muxer - > file_end / 1024 / 1024 ) ) ;
2004-04-19 04:14:09 +02:00
vsi - > riffofspos + + ;
if ( vsi - > riffofspos > = vsi - > riffofssize ) {
vsi - > riffofssize + = 16 ;
2006-06-05 00:41:27 +02:00
vsi - > riffofs = realloc_struct ( vsi - > riffofs , ( vsi - > riffofssize + 1 ) , sizeof ( off_t ) ) ;
2004-04-19 04:14:09 +02:00
}
2006-12-18 22:03:59 +01:00
vsi - > riffofs [ vsi - > riffofspos ] = stream_tell ( muxer - > stream ) ;
2004-03-17 15:50:37 +01:00
/* RIFF/AVIX chunk */
riff [ 0 ] = le2me_32 ( mmioFOURCC ( ' R ' , ' I ' , ' F ' , ' F ' ) ) ;
riff [ 1 ] = 0 ;
riff [ 2 ] = le2me_32 ( mmioFOURCC ( ' A ' , ' V ' , ' I ' , ' X ' ) ) ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( muxer - > stream , riff , 12 ) ;
2004-03-17 15:50:37 +01:00
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , listtypeAVIMOVIE , 0 ) ;
2004-04-19 04:14:09 +02:00
2006-12-18 22:03:59 +01:00
muxer - > file_end = stream_tell ( muxer - > stream ) ;
2004-03-17 15:50:37 +01:00
}
2004-09-05 18:55:06 +02:00
static void avifile_write_header ( muxer_t * muxer ) ;
2006-01-26 20:32:07 +01:00
static void avifile_write_chunk ( muxer_stream_t * s , size_t len , unsigned int flags , double dts , double pts ) {
2004-04-19 04:14:09 +02:00
off_t rifflen ;
2003-01-19 01:33:11 +01:00
muxer_t * muxer = s - > muxer ;
2004-04-19 04:14:09 +02:00
struct avi_stream_info * si = s - > priv ;
struct avi_stream_info * vsi = muxer - > def_v - > priv ;
int paddedlen = len + ( len & 1 ) ;
2004-03-17 15:50:37 +01:00
2004-09-05 18:51:15 +02:00
if ( s - > type = = MUXER_TYPE_VIDEO & & ! s - > h . dwSuggestedBufferSize ) {
2006-12-18 22:03:59 +01:00
off_t pos = stream_tell ( muxer - > stream ) ;
stream_seek ( muxer - > stream , 0 ) ;
2004-09-05 18:51:15 +02:00
avifile_write_header ( muxer ) ;
2006-12-18 22:03:59 +01:00
stream_seek ( muxer - > stream , pos ) ;
2004-09-05 18:51:15 +02:00
}
2007-01-08 17:23:31 +01:00
if ( index_mode ) {
2004-04-19 04:14:09 +02:00
rifflen = muxer - > file_end - vsi - > riffofs [ vsi - > riffofspos ] - 8 ;
if ( vsi - > riffofspos = = 0 ) {
rifflen + = 8 + muxer - > idx_pos * sizeof ( AVIINDEXENTRY ) ;
}
2004-04-30 23:33:53 +02:00
if ( rifflen + paddedlen > ODML_CHUNKLEN & & write_odml = = 1 ) {
2004-04-19 04:14:09 +02:00
if ( vsi - > riffofspos = = 0 ) {
2004-04-30 23:33:53 +02:00
avifile_write_standard_index ( muxer ) ;
2004-04-19 04:14:09 +02:00
}
avifile_odml_new_riff ( muxer ) ;
}
if ( vsi - > riffofspos = = 0 ) {
2004-03-17 15:50:37 +01:00
// add to the traditional index:
if ( muxer - > idx_pos > = muxer - > idx_size ) {
muxer - > idx_size + = 256 ; // 4kB
2006-06-05 00:41:27 +02:00
muxer - > idx = realloc_struct ( muxer - > idx , muxer - > idx_size , 16 ) ;
2004-03-17 15:50:37 +01:00
}
muxer - > idx [ muxer - > idx_pos ] . ckid = s - > ckid ;
muxer - > idx [ muxer - > idx_pos ] . dwFlags = flags ; // keyframe?
2004-04-19 04:14:09 +02:00
muxer - > idx [ muxer - > idx_pos ] . dwChunkOffset = muxer - > file_end - ( muxer - > movi_start - 4 ) ;
2004-03-17 15:50:37 +01:00
muxer - > idx [ muxer - > idx_pos ] . dwChunkLength = len ;
+ + muxer - > idx_pos ;
}
// add to odml index
if ( si - > idxpos > = si - > idxsize ) {
si - > idxsize + = 256 ;
2006-06-05 00:41:27 +02:00
si - > idx = realloc_struct ( si - > idx , si - > idxsize , sizeof ( * si - > idx ) ) ;
2004-03-17 15:50:37 +01:00
}
si - > idx [ si - > idxpos ] . flags = ( flags & AVIIF_KEYFRAME ) ? 0 : ODML_NOTKEYFRAME ;
2004-04-19 04:14:09 +02:00
si - > idx [ si - > idxpos ] . ofs = muxer - > file_end ;
2004-03-17 15:50:37 +01:00
si - > idx [ si - > idxpos ] . len = len ;
+ + si - > idxpos ;
2007-01-08 17:23:31 +01:00
}
2001-10-29 01:55:15 +01:00
// write out the chunk:
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , s - > ckid , len , s - > buffer ) ; /* unsigned char */
2002-08-05 13:26:26 +02:00
2004-03-17 15:50:37 +01:00
if ( len > s - > h . dwSuggestedBufferSize ) {
s - > h . dwSuggestedBufferSize = len ;
}
2002-12-27 23:43:20 +01:00
if ( ( unsigned int ) len > s - > h . dwSuggestedBufferSize ) s - > h . dwSuggestedBufferSize = len ;
2001-10-29 01:55:15 +01:00
2004-04-19 04:14:09 +02:00
muxer - > file_end + = 8 + paddedlen ;
2001-10-29 01:55:15 +01:00
}
2006-12-18 22:03:59 +01:00
static void write_avi_list ( stream_t * stream , unsigned int id , int len ) {
2001-02-24 21:28:24 +01:00
unsigned int list_id = FOURCC_LIST ;
2002-08-05 13:26:26 +02:00
int le_len ;
int le_id ;
2001-02-24 21:28:24 +01:00
len + = 4 ; // list fix
2002-08-05 13:26:26 +02:00
list_id = le2me_32 ( list_id ) ;
le_len = le2me_32 ( len ) ;
le_id = le2me_32 ( id ) ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( stream , & list_id , 4 ) ;
stream_write_buffer ( stream , & le_len , 4 ) ;
stream_write_buffer ( stream , & le_id , 4 ) ;
2001-02-24 21:28:24 +01:00
}
2003-11-03 17:25:31 +01:00
# define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
2001-11-02 18:43:05 +01:00
2003-01-19 01:33:11 +01:00
static void avifile_write_header ( muxer_t * muxer ) {
2002-12-27 23:43:20 +01:00
uint32_t riff [ 3 ] ;
2004-03-17 15:50:37 +01:00
unsigned int dmlh [ 1 ] ;
2002-12-27 23:43:20 +01:00
unsigned int i ;
2001-10-29 01:55:15 +01:00
unsigned int hdrsize ;
2002-12-27 23:43:20 +01:00
muxer_info_t info [ 16 ] ;
2004-03-17 15:50:37 +01:00
VideoPropHeader vprp ;
2004-03-24 16:16:36 +01:00
uint32_t aspect = avi_aspect ( muxer - > def_v ) ;
2004-04-19 04:14:09 +02:00
struct avi_stream_info * vsi = muxer - > def_v - > priv ;
int isodml = vsi - > riffofspos > 0 ;
2004-03-17 15:50:37 +01:00
2005-11-29 23:04:57 +01:00
mp_msg ( MSGT_MUXER , MSGL_INFO , MSGTR_WritingHeader ) ;
2004-03-24 16:16:36 +01:00
if ( aspect = = 0 ) {
mp_msg ( MSGT_MUXER , MSGL_INFO , " ODML: Aspect information not (yet?) available or unspecified, not writing vprp header. \n " ) ;
} else {
mp_msg ( MSGT_MUXER , MSGL_INFO , " ODML: vprp aspect is %d:%d. \n " , aspect > > 16 , aspect & 0xffff ) ;
}
2006-02-19 10:34:37 +01:00
/* deal with stream delays */
for ( i = 0 ; muxer - > streams [ i ] & & i < MUXER_MAX_STREAMS ; + + i ) {
muxer_stream_t * s = muxer - > streams [ i ] ;
if ( s - > type = = MUXER_TYPE_AUDIO & & muxer - > audio_delay_fix > 0.0 ) {
2006-09-22 12:27:17 +02:00
s - > h . dwStart = muxer - > audio_delay_fix * s - > h . dwRate / s - > h . dwScale + 0.5 ;
2006-02-19 10:34:37 +01:00
mp_msg ( MSGT_MUXER , MSGL_INFO , MSGTR_SettingAudioDelay , ( float ) s - > h . dwStart * s - > h . dwScale / s - > h . dwRate ) ;
}
if ( s - > type = = MUXER_TYPE_VIDEO & & muxer - > audio_delay_fix < 0.0 ) {
2006-09-22 12:27:17 +02:00
s - > h . dwStart = - muxer - > audio_delay_fix * s - > h . dwRate / s - > h . dwScale + 0.5 ;
2006-02-19 10:34:37 +01:00
mp_msg ( MSGT_MUXER , MSGL_INFO , MSGTR_SettingVideoDelay , ( float ) s - > h . dwStart * s - > h . dwScale / s - > h . dwRate ) ;
}
}
2004-03-17 15:50:37 +01:00
if ( isodml ) {
unsigned int rifflen , movilen ;
2004-04-19 04:14:09 +02:00
int i ;
2004-03-17 15:50:37 +01:00
2004-04-19 04:14:09 +02:00
vsi - > riffofs [ vsi - > riffofspos + 1 ] = muxer - > file_end ;
/* fixup RIFF lengths */
for ( i = 0 ; i < = vsi - > riffofspos ; i + + ) {
rifflen = vsi - > riffofs [ i + 1 ] - vsi - > riffofs [ i ] - 8 ;
movilen = le2me_32 ( rifflen - 12 ) ;
rifflen = le2me_32 ( rifflen ) ;
2006-12-18 22:03:59 +01:00
stream_seek ( muxer - > stream , vsi - > riffofs [ i ] + 4 ) ;
stream_write_buffer ( muxer - > stream , & rifflen , 4 ) ;
2004-04-19 04:14:09 +02:00
/* fixup movi length */
if ( i > 0 ) {
2006-12-18 22:03:59 +01:00
stream_seek ( muxer - > stream , vsi - > riffofs [ i ] + 16 ) ;
stream_write_buffer ( muxer - > stream , & movilen , 4 ) ;
2004-04-19 04:14:09 +02:00
}
2004-03-17 15:50:37 +01:00
}
2006-12-18 22:03:59 +01:00
stream_seek ( muxer - > stream , 12 ) ;
2004-03-17 15:50:37 +01:00
} else {
// RIFF header:
riff [ 0 ] = mmioFOURCC ( ' R ' , ' I ' , ' F ' , ' F ' ) ;
riff [ 1 ] = muxer - > file_end - 2 * sizeof ( unsigned int ) ; // filesize
riff [ 2 ] = formtypeAVI ; // 'AVI '
riff [ 0 ] = le2me_32 ( riff [ 0 ] ) ;
riff [ 1 ] = le2me_32 ( riff [ 1 ] ) ;
riff [ 2 ] = le2me_32 ( riff [ 2 ] ) ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( muxer - > stream , & riff , 12 ) ;
2004-03-17 15:50:37 +01:00
}
2001-10-29 01:55:15 +01:00
// update AVI header:
if ( muxer - > def_v ) {
2004-03-17 15:50:37 +01:00
int i ;
2001-10-29 01:55:15 +01:00
muxer - > avih . dwMicroSecPerFrame = 1000000.0 * muxer - > def_v - > h . dwScale / muxer - > def_v - > h . dwRate ;
2001-11-02 18:43:05 +01:00
// muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
// muxer->avih.dwPaddingGranularity=2; // ???
2001-10-29 01:55:15 +01:00
muxer - > avih . dwFlags | = AVIF_ISINTERLEAVED | AVIF_TRUSTCKTYPE ;
2004-03-17 15:50:37 +01:00
muxer - > avih . dwTotalFrames = 0 ;
for ( i = 0 ; i < muxer - > idx_pos ; i + + ) {
if ( muxer - > idx [ i ] . ckid = = muxer - > def_v - > ckid )
muxer - > avih . dwTotalFrames + + ;
}
2001-11-02 18:43:05 +01:00
// muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
2001-10-29 01:55:15 +01:00
muxer - > avih . dwWidth = muxer - > def_v - > bih - > biWidth ;
muxer - > avih . dwHeight = muxer - > def_v - > bih - > biHeight ;
}
2001-02-24 21:28:24 +01:00
// AVI header:
2001-10-29 01:55:15 +01:00
hdrsize = sizeof ( muxer - > avih ) + 8 ;
2004-03-17 15:50:37 +01:00
if ( isodml ) hdrsize + = sizeof ( dmlh ) + 20 ; // dmlh
2001-10-29 01:55:15 +01:00
// calc total header size:
for ( i = 0 ; i < muxer - > avih . dwStreams ; i + + ) {
2004-03-17 15:50:37 +01:00
muxer_stream_t * s = muxer - > streams [ i ] ;
struct avi_stream_info * si = s - > priv ;
2001-10-29 01:55:15 +01:00
hdrsize + = 12 ; // LIST
hdrsize + = sizeof ( muxer - > streams [ i ] - > h ) + 8 ; // strh
switch ( muxer - > streams [ i ] - > type ) {
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_VIDEO :
2001-10-29 01:55:15 +01:00
hdrsize + = muxer - > streams [ i ] - > bih - > biSize + 8 ; // strf
2004-03-24 16:16:36 +01:00
if ( aspect ! = 0 ) {
2004-03-21 22:32:54 +01:00
hdrsize + = 8 + 4 * ( 9 + 8 * 1 ) ; // vprp
}
2001-10-29 01:55:15 +01:00
break ;
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_AUDIO :
2001-11-02 18:43:05 +01:00
hdrsize + = WFSIZE ( muxer - > streams [ i ] - > wf ) + 8 ; // strf
2001-10-29 01:55:15 +01:00
break ;
}
2004-03-17 15:50:37 +01:00
if ( isodml & & si & & si - > superidx & & si - > superidxsize ) {
hdrsize + = 32 + 16 * si - > superidxsize ; //indx
}
2001-10-29 01:55:15 +01:00
}
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , listtypeAVIHEADER , hdrsize ) ;
2002-08-05 13:26:26 +02:00
le2me_MainAVIHeader ( & muxer - > avih ) ;
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , ckidAVIMAINHDR , sizeof ( muxer - > avih ) , & muxer - > avih ) ; /* MainAVIHeader */
2002-08-05 13:26:26 +02:00
le2me_MainAVIHeader ( & muxer - > avih ) ;
2001-10-29 01:55:15 +01:00
// stream headers:
for ( i = 0 ; i < muxer - > avih . dwStreams ; i + + ) {
2004-03-17 15:50:37 +01:00
muxer_stream_t * s = muxer - > streams [ i ] ;
struct avi_stream_info * si = s - > priv ;
unsigned int idxhdr [ 8 ] ;
int j , n ;
hdrsize = sizeof ( s - > h ) + 8 ; // strh
if ( si & & si - > superidx & & si - > superidxsize ) {
hdrsize + = 32 + 16 * si - > superidxsize ; //indx
}
switch ( s - > type ) {
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_VIDEO :
2004-03-17 15:50:37 +01:00
hdrsize + = s - > bih - > biSize + 8 ; // strf
s - > h . fccHandler = s - > bih - > biCompression ;
s - > h . rcFrame . right = s - > bih - > biWidth ;
s - > h . rcFrame . bottom = s - > bih - > biHeight ;
2004-03-24 16:16:36 +01:00
if ( aspect ! = 0 ) {
2004-03-21 22:32:54 +01:00
// fill out vprp info
memset ( & vprp , 0 , sizeof ( vprp ) ) ;
vprp . dwVerticalRefreshRate = ( s - > h . dwRate + s - > h . dwScale - 1 ) / s - > h . dwScale ;
vprp . dwHTotalInT = muxer - > avih . dwWidth ;
vprp . dwVTotalInLines = muxer - > avih . dwHeight ;
2004-03-24 16:16:36 +01:00
vprp . dwFrameAspectRatio = aspect ;
2004-03-21 22:32:54 +01:00
vprp . dwFrameWidthInPixels = muxer - > avih . dwWidth ;
vprp . dwFrameHeightInLines = muxer - > avih . dwHeight ;
vprp . nbFieldPerFrame = 1 ;
vprp . FieldInfo [ 0 ] . CompressedBMHeight = muxer - > avih . dwHeight ;
vprp . FieldInfo [ 0 ] . CompressedBMWidth = muxer - > avih . dwWidth ;
vprp . FieldInfo [ 0 ] . ValidBMHeight = muxer - > avih . dwHeight ;
vprp . FieldInfo [ 0 ] . ValidBMWidth = muxer - > avih . dwWidth ;
hdrsize + = 8 + 4 * ( 9 + 8 * 1 ) ; // vprp
}
2001-10-29 01:55:15 +01:00
break ;
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_AUDIO :
2004-03-17 15:50:37 +01:00
hdrsize + = WFSIZE ( s - > wf ) + 8 ; // strf
s - > h . fccHandler = s - > wf - > wFormatTag ;
2001-10-29 01:55:15 +01:00
break ;
}
2004-03-17 15:50:37 +01:00
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , listtypeSTREAMHEADER , hdrsize ) ;
2004-03-17 15:50:37 +01:00
le2me_AVIStreamHeader ( & s - > h ) ;
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , ckidSTREAMHEADER , sizeof ( s - > h ) , & s - > h ) ; /* AVISTreamHeader */ // strh
2004-03-17 15:50:37 +01:00
le2me_AVIStreamHeader ( & s - > h ) ;
2002-08-05 13:26:26 +02:00
2004-03-17 15:50:37 +01:00
switch ( s - > type ) {
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_VIDEO :
2002-08-05 13:26:26 +02:00
{
2004-03-17 15:50:37 +01:00
int biSize = s - > bih - > biSize ;
le2me_BITMAPINFOHEADER ( s - > bih ) ;
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , ckidSTREAMFORMAT , biSize , s - > bih ) ; /* BITMAPINFOHEADER */
2004-03-22 02:42:43 +01:00
le2me_BITMAPINFOHEADER ( s - > bih ) ;
2004-03-24 16:16:36 +01:00
if ( aspect ! = 0 ) {
2004-03-22 02:42:43 +01:00
int fields = vprp . nbFieldPerFrame ;
2004-03-21 22:32:54 +01:00
le2me_VideoPropHeader ( & vprp ) ;
le2me_VIDEO_FIELD_DESC ( & vprp . FieldInfo [ 0 ] ) ;
le2me_VIDEO_FIELD_DESC ( & vprp . FieldInfo [ 1 ] ) ;
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , mmioFOURCC ( ' v ' , ' p ' , ' r ' , ' p ' ) ,
2004-03-22 02:42:43 +01:00
sizeof ( VideoPropHeader ) -
sizeof ( VIDEO_FIELD_DESC ) * ( 2 - fields ) ,
& vprp ) ; /* Video Properties Header */
2004-03-21 22:32:54 +01:00
}
2002-08-05 13:26:26 +02:00
}
2001-10-29 01:55:15 +01:00
break ;
2002-12-27 23:43:20 +01:00
case MUXER_TYPE_AUDIO :
2002-08-05 13:26:26 +02:00
{
2004-03-17 15:50:37 +01:00
int wfsize = WFSIZE ( s - > wf ) ;
le2me_WAVEFORMATEX ( s - > wf ) ;
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , ckidSTREAMFORMAT , wfsize , s - > wf ) ; /* WAVEFORMATEX */
2004-03-17 15:50:37 +01:00
le2me_WAVEFORMATEX ( s - > wf ) ;
2002-08-05 13:26:26 +02:00
}
2001-10-29 01:55:15 +01:00
break ;
}
2004-03-17 15:50:37 +01:00
if ( isodml & & si & & si - > superidx & & si - > superidxsize ) {
n = si - > superidxsize ;
idxhdr [ 0 ] = le2me_32 ( mmioFOURCC ( ' i ' , ' n ' , ' d ' , ' x ' ) ) ;
idxhdr [ 1 ] = le2me_32 ( 24 + 16 * n ) ;
idxhdr [ 2 ] = le2me_32 ( 0x00000004 ) ;
idxhdr [ 3 ] = le2me_32 ( si - > superidxpos ) ;
idxhdr [ 4 ] = le2me_32 ( s - > ckid ) ;
idxhdr [ 5 ] = 0 ;
idxhdr [ 6 ] = 0 ;
idxhdr [ 7 ] = 0 ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( muxer - > stream , idxhdr , sizeof ( idxhdr ) ) ;
2004-03-17 15:50:37 +01:00
for ( j = 0 ; j < n ; j + + ) {
struct avi_odmlsuperidx_entry * entry = & si - > superidx [ j ] ;
unsigned int data [ 4 ] ;
data [ 0 ] = le2me_32 ( entry - > ofs ) ;
data [ 1 ] = le2me_32 ( entry - > ofs > > 32 ) ;
data [ 2 ] = le2me_32 ( entry - > len ) ;
data [ 3 ] = le2me_32 ( entry - > duration ) ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( muxer - > stream , data , sizeof ( data ) ) ;
2004-03-17 15:50:37 +01:00
}
}
}
// ODML
if ( isodml ) {
memset ( dmlh , 0 , sizeof ( dmlh ) ) ;
dmlh [ 0 ] = le2me_32 ( muxer - > avih . dwTotalFrames ) ;
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , mmioFOURCC ( ' o ' , ' d ' , ' m ' , ' l ' ) , sizeof ( dmlh ) + 8 ) ;
write_avi_chunk ( muxer - > stream , mmioFOURCC ( ' d ' , ' m ' , ' l ' , ' h ' ) , sizeof ( dmlh ) , dmlh ) ;
2001-10-29 01:55:15 +01:00
}
2002-08-29 22:50:49 +02:00
// ============= INFO ===============
// always include software info
info [ 0 ] . id = mmioFOURCC ( ' I ' , ' S ' , ' F ' , ' T ' ) ; // Software:
info [ 0 ] . text = " MEncoder " VERSION ;
// include any optional strings
i = 1 ;
if ( info_name ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' N ' , ' A ' , ' M ' ) ; // Name:
info [ i + + ] . text = info_name ;
}
if ( info_artist ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' A ' , ' R ' , ' T ' ) ; // Artist:
info [ i + + ] . text = info_artist ;
}
if ( info_genre ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' G ' , ' N ' , ' R ' ) ; // Genre:
info [ i + + ] . text = info_genre ;
}
if ( info_subject ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' S ' , ' B ' , ' J ' ) ; // Subject:
info [ i + + ] . text = info_subject ;
}
if ( info_copyright ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' C ' , ' O ' , ' P ' ) ; // Copyright:
info [ i + + ] . text = info_copyright ;
}
if ( info_sourceform ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' S ' , ' R ' , ' F ' ) ; // Source Form:
info [ i + + ] . text = info_sourceform ;
}
if ( info_comment ! = NULL ) {
info [ i ] . id = mmioFOURCC ( ' I ' , ' C ' , ' M ' , ' T ' ) ; // Comment:
info [ i + + ] . text = info_comment ;
}
info [ i ] . id = 0 ;
hdrsize = 0 ;
// calc info size:
for ( i = 0 ; info [ i ] . id ! = 0 ; i + + ) if ( info [ i ] . text ) {
size_t sz = strlen ( info [ i ] . text ) + 1 ;
hdrsize + = sz + 8 + sz % 2 ;
}
// write infos:
if ( hdrsize ! = 0 ) {
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , mmioFOURCC ( ' I ' , ' N ' , ' F ' , ' O ' ) , hdrsize ) ;
2002-08-29 22:50:49 +02:00
for ( i = 0 ; info [ i ] . id ! = 0 ; i + + ) if ( info [ i ] . text ) {
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , info [ i ] . id , strlen ( info [ i ] . text ) + 1 , info [ i ] . text ) ;
2002-08-29 22:50:49 +02:00
}
}
2001-10-29 01:55:15 +01:00
// JUNK:
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , ckidAVIPADDING , MOVIALIGN - ( stream_tell ( muxer - > stream ) % MOVIALIGN ) - 8 , NULL ) ; /* junk */
2004-03-17 15:50:37 +01:00
if ( ! isodml ) {
// 'movi' header:
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , listtypeAVIMOVIE , muxer - > movi_end - stream_tell ( muxer - > stream ) - 12 ) ;
2004-03-17 15:50:37 +01:00
} else {
2006-12-18 22:03:59 +01:00
if ( stream_tell ( muxer - > stream ) ! = MOVIALIGN ) {
2004-03-17 15:50:37 +01:00
mp_msg ( MSGT_MUXER , MSGL_ERR , " Opendml superindex is too big for reserved space! \n " ) ;
2006-12-18 22:03:59 +01:00
mp_msg ( MSGT_MUXER , MSGL_ERR , " Expected filepos %d, real filepos %ld, missing space %ld \n " , MOVIALIGN , stream_tell ( muxer - > stream ) , stream_tell ( muxer - > stream ) - MOVIALIGN ) ;
2004-03-17 16:36:33 +01:00
mp_msg ( MSGT_MUXER , MSGL_ERR , " Try increasing MOVIALIGN in libmpdemux/muxer_avi.c \n " ) ;
2004-03-17 15:50:37 +01:00
}
2006-12-18 22:03:59 +01:00
write_avi_list ( muxer - > stream , listtypeAVIMOVIE , muxer - > movi_end - stream_tell ( muxer - > stream ) - 12 ) ;
2004-03-17 15:50:37 +01:00
}
2006-12-18 22:03:59 +01:00
muxer - > movi_start = stream_tell ( muxer - > stream ) ;
if ( muxer - > file_end = = 0 ) muxer - > file_end = stream_tell ( muxer - > stream ) ;
2004-03-17 15:50:37 +01:00
}
static void avifile_odml_write_index ( muxer_t * muxer ) {
muxer_stream_t * s ;
struct avi_stream_info * si ;
int i ;
for ( i = 0 ; i < muxer - > avih . dwStreams ; i + + ) {
int j , k , n , idxpos , len , last , entries_per_subidx ;
unsigned int idxhdr [ 8 ] ;
s = muxer - > streams [ i ] ;
si = s - > priv ;
/*
* According to Avery Lee MSMP wants the subidx chunks to have the same size .
*
* So this code figures out how many entries we can put into
* an ix ? ? chunk , so that each ix ? ? chunk has the same size and the offsets
* don ' t overflow ( Using ODML_CHUNKLEN for that is a bit more restrictive
* than it has to be though ) .
*/
len = 0 ;
n = 0 ;
entries_per_subidx = INT_MAX ;
do {
off_t start = si - > idx [ 0 ] . ofs ;
last = entries_per_subidx ;
for ( j = 0 ; j < si - > idxpos ; j + + ) {
len = si - > idx [ j ] . ofs - start ;
if ( len > = ODML_CHUNKLEN | | n > = entries_per_subidx ) {
if ( entries_per_subidx > n ) {
entries_per_subidx = n ;
}
start = si - > idx [ j ] . ofs ;
len = 0 ;
n = 0 ;
}
n + + ;
}
} while ( last ! = entries_per_subidx ) ;
si - > superidxpos = ( si - > idxpos + entries_per_subidx - 1 ) / entries_per_subidx ;
mp_msg ( MSGT_MUXER , MSGL_V , " ODML: Stream %d: Using %d entries per subidx, %d entries in superidx \n " ,
i , entries_per_subidx , si - > superidxpos ) ;
si - > superidxsize = si - > superidxpos ;
2006-06-05 00:41:27 +02:00
si - > superidx = calloc ( si - > superidxsize , sizeof ( * si - > superidx ) ) ;
2004-03-17 15:50:37 +01:00
memset ( si - > superidx , 0 , sizeof ( * si - > superidx ) * si - > superidxsize ) ;
idxpos = 0 ;
for ( j = 0 ; j < si - > superidxpos ; j + + ) {
off_t start = si - > idx [ idxpos ] . ofs ;
int duration ;
duration = 0 ;
for ( k = 0 ; k < entries_per_subidx & & idxpos + k < si - > idxpos ; k + + ) {
duration + = s - > h . dwSampleSize ? si - > idx [ idxpos + k ] . len / s - > h . dwSampleSize : 1 ;
}
idxhdr [ 0 ] = le2me_32 ( ( s - > ckid < < 16 ) | mmioFOURCC ( ' i ' , ' x ' , 0 , 0 ) ) ;
idxhdr [ 1 ] = le2me_32 ( 24 + 8 * k ) ;
idxhdr [ 2 ] = le2me_32 ( 0x01000002 ) ;
idxhdr [ 3 ] = le2me_32 ( k ) ;
idxhdr [ 4 ] = le2me_32 ( s - > ckid ) ;
idxhdr [ 5 ] = le2me_32 ( start + 8 ) ;
idxhdr [ 6 ] = le2me_32 ( ( start + 8 ) > > 32 ) ;
idxhdr [ 7 ] = 0 ; /* unused */
si - > superidx [ j ] . len = 32 + 8 * k ;
2006-12-18 22:03:59 +01:00
si - > superidx [ j ] . ofs = stream_tell ( muxer - > stream ) ;
2004-03-17 15:50:37 +01:00
si - > superidx [ j ] . duration = duration ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( muxer - > stream , idxhdr , sizeof ( idxhdr ) ) ;
2004-03-17 15:50:37 +01:00
for ( k = 0 ; k < entries_per_subidx & & idxpos < si - > idxpos ; k + + ) {
unsigned int entry [ 2 ] ;
entry [ 0 ] = le2me_32 ( si - > idx [ idxpos ] . ofs - start ) ;
entry [ 1 ] = le2me_32 ( si - > idx [ idxpos ] . len | si - > idx [ idxpos ] . flags ) ;
idxpos + + ;
2006-12-18 22:03:59 +01:00
stream_write_buffer ( muxer - > stream , entry , sizeof ( entry ) ) ;
2004-03-17 15:50:37 +01:00
}
}
}
2006-12-18 22:03:59 +01:00
muxer - > file_end = stream_tell ( muxer - > stream ) ;
2001-02-24 21:28:24 +01:00
}
2004-04-30 23:33:53 +02:00
static void avifile_write_standard_index ( muxer_t * muxer ) {
2004-03-17 15:50:37 +01:00
2006-12-18 22:03:59 +01:00
muxer - > movi_end = stream_tell ( muxer - > stream ) ;
2001-10-29 01:55:15 +01:00
if ( muxer - > idx & & muxer - > idx_pos > 0 ) {
2002-08-05 13:26:26 +02:00
int i ;
2001-10-29 01:55:15 +01:00
// fixup index entries:
// for(i=0;i<muxer->idx_pos;i++) muxer->idx[i].dwChunkOffset-=muxer->movi_start-4;
// write index chunk:
2002-08-05 13:26:26 +02:00
for ( i = 0 ; i < muxer - > idx_pos ; i + + ) le2me_AVIINDEXENTRY ( ( & muxer - > idx [ i ] ) ) ;
2006-12-18 22:03:59 +01:00
write_avi_chunk ( muxer - > stream , ckidAVINEWINDEX , 16 * muxer - > idx_pos , muxer - > idx ) ; /* AVIINDEXENTRY */
2002-08-05 13:26:26 +02:00
for ( i = 0 ; i < muxer - > idx_pos ; i + + ) le2me_AVIINDEXENTRY ( ( & muxer - > idx [ i ] ) ) ;
2001-10-29 01:55:15 +01:00
muxer - > avih . dwFlags | = AVIF_HASINDEX ;
2001-02-24 21:28:24 +01:00
}
2006-12-18 22:03:59 +01:00
muxer - > file_end = stream_tell ( muxer - > stream ) ;
2001-02-24 21:28:24 +01:00
}
2004-04-30 23:33:53 +02:00
static void avifile_write_index ( muxer_t * muxer ) {
struct avi_stream_info * vsi = muxer - > def_v - > priv ;
2005-11-29 23:04:57 +01:00
mp_msg ( MSGT_MUXER , MSGL_INFO , MSGTR_WritingTrailer ) ;
2004-04-30 23:33:53 +02:00
if ( vsi - > riffofspos > 0 ) {
avifile_odml_write_index ( muxer ) ;
} else {
avifile_write_standard_index ( muxer ) ;
}
}
2006-02-21 10:39:22 +01:00
static void avifile_fix_parameters ( muxer_stream_t * s ) {
/* adjust audio_delay_fix according to individual stream delay */
if ( s - > type = = MUXER_TYPE_AUDIO )
s - > muxer - > audio_delay_fix - = ( float ) s - > decoder_delay * s - > h . dwScale / s - > h . dwRate ;
if ( s - > type = = MUXER_TYPE_VIDEO )
s - > muxer - > audio_delay_fix + = ( float ) s - > decoder_delay * s - > h . dwScale / s - > h . dwRate ;
}
2005-02-21 22:45:49 +01:00
int muxer_init_muxer_avi ( muxer_t * muxer ) {
2002-12-27 23:43:20 +01:00
muxer - > cont_new_stream = & avifile_new_stream ;
muxer - > cont_write_chunk = & avifile_write_chunk ;
muxer - > cont_write_header = & avifile_write_header ;
muxer - > cont_write_index = & avifile_write_index ;
2006-02-21 10:39:22 +01:00
muxer - > fix_stream_parameters = & avifile_fix_parameters ;
2005-02-21 22:45:49 +01:00
return 1 ;
2002-12-27 23:43:20 +01:00
}