diff options
Diffstat (limited to 'core/OgmMux.c')
-rw-r--r-- | core/OgmMux.c | 531 |
1 files changed, 228 insertions, 303 deletions
diff --git a/core/OgmMux.c b/core/OgmMux.c index fef1ae01b..e99a494f5 100644 --- a/core/OgmMux.c +++ b/core/OgmMux.c @@ -1,4 +1,4 @@ -/* $Id: OgmMux.c,v 1.7 2004/03/08 11:32:48 titer Exp $ +/* $Id: OgmMux.c,v 1.13 2004/05/13 21:10:56 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -8,209 +8,26 @@ #include <ogg/ogg.h> -static void OgmMuxThread( void * ); -static int OgmStart( HBOgmMux * ); -static int OgmFlush( HBOgmMux *, int ); -static int OgmEnd( HBOgmMux * ); +static int OgmStart( HBMux * ); +static int OgmMux( HBMux *, void *, HBBuffer * ); +static int OgmEnd( HBMux * ); -struct HBOgmMux +struct HBMux { - HBHandle *handle; - HBTitle *title; + HB_MUX_COMMON_MEMBERS - volatile int die; - HBThread *thread; - - FILE *file; - - int i_tk; - struct - { - HBFifo *fifo; - - int codec; - - ogg_stream_state os; - int i_packet_no; - - } tk[100]; /* The first who set more than 100 stream !! */ + HBHandle * handle; + HBTitle * title; + FILE * file; }; -HBOgmMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ) -{ - HBOgmMux *ogm = malloc( sizeof( HBOgmMux ) ); - - ogm->handle = handle; - ogm->title = title; - - ogm->file = NULL; - ogm->i_tk = 0; - - ogm->die = 0; - ogm->thread = HBThreadInit( "ogm muxer", OgmMuxThread, ogm, HB_NORMAL_PRIORITY ); - return ogm; -} - -void HBOgmMuxClose( HBOgmMux ** _ogm ) -{ - HBOgmMux *ogm = *_ogm; - - ogm->die = 1; - HBThreadClose( &ogm->thread ); - - free( ogm ); - - *_ogm = NULL; -} - -static int OgmDataWait( HBOgmMux *ogm ) -{ - int i; - - for( i = 0; i < ogm->i_tk; i++ ) - { - while( !ogm->die && HBFifoSize( ogm->tk[i].fifo ) <= 0 ) - { - HBSnooze( 10000 ); - } - } - return ogm->die ? -1 : 0; -} - -static void OgmMuxThread( void * _this ) +typedef struct { - HBOgmMux *ogm = _this; - - HBTitle *title = ogm->title; - - int i; - - /* Open output file */ - if( ( ogm->file = fopen( title->file, "w" ) ) == NULL ) - { - HBLog( "HBOgmMux: failed to open `%s'", title->file ); - /* FIXME */ - HBErrorOccured( ogm->handle, HB_ERROR_AVI_WRITE ); - return; - } - HBLog( "HBOgmMux: `%s' opened", title->file ); - - - /* Wait for data in each fifo */ - HBLog( "HBOgmMux: waiting video/audio data" ); - if( OgmDataWait( ogm ) < 0 ) - { - HBLog( "HBOgmMux: exiting" ); - fclose( ogm->file ); - unlink( title->file ); - return; - } - - if( OgmStart( ogm ) < 0 ) - { - HBLog( "HBOgmMux: failed to write headers" ); - fclose( ogm->file ); - unlink( title->file ); - return; - } + int codec; + ogg_stream_state os; + int i_packet_no; - HBLog( "HBOgmMux: headers written" ); - - for( ;; ) - { - HBBuffer *buffer; - ogg_packet op; - int i_tk; - - /* Wait data */ - if( OgmDataWait( ogm ) < 0 ) - { - break; - } - - /* Choose the right track to write (interleaved data) */ - for( i = 0, i_tk = -1; i < ogm->i_tk; i++ ) - { - if( i_tk < 0 || - HBFifoPosition( ogm->tk[i].fifo ) < HBFifoPosition( ogm->tk[i_tk].fifo ) ) - { - i_tk = i; - } - } - - buffer = HBFifoPop( ogm->tk[i_tk].fifo ); - - switch( ( ogm->tk[i_tk].codec ) ) - { - case HB_CODEC_FFMPEG: - case HB_CODEC_XVID: - case HB_CODEC_X264: - op.bytes = buffer->size + 1; - op.packet = malloc( op.bytes ); - op.packet[0] = buffer->keyFrame ? 0x08 : 0x00; - memcpy( &op.packet[1], buffer->data, buffer->size ); - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = ogm->tk[i_tk].i_packet_no; - op.packetno = ogm->tk[i_tk].i_packet_no++; - break; - case HB_CODEC_MP3: - op.bytes = buffer->size + 1; - op.packet = malloc( op.bytes ); - op.packet[0] = 0x08; - memcpy( &op.packet[1], buffer->data, buffer->size ); - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = ogm->tk[i_tk].i_packet_no * 1152; - op.packetno = ogm->tk[i_tk].i_packet_no++; - break; - case HB_CODEC_VORBIS: - memcpy( &op, buffer->data, sizeof( ogg_packet ) ); - - op.packet = malloc( op.bytes ); - memcpy( op.packet, buffer->data + sizeof( ogg_packet ), op.bytes ); - break; - - default: - HBLog( "HBOgmMux: unhandled codec" ); - op.bytes = 0; - op.packet = NULL; - break; - } - - if( op.packet ) - { - ogg_stream_packetin( &ogm->tk[i_tk].os, &op ); - - for( ;; ) - { - ogg_page og; - if( ogg_stream_pageout( &ogm->tk[i_tk].os, &og ) == 0 ) - { - break; - } - - if( fwrite( og.header, og.header_len, 1, ogm->file ) <= 0 || - fwrite( og.body, og.body_len, 1, ogm->file ) <= 0 ) - { - HBLog( "HBOgmMux: write failed" ); - break; - } - } - free( op.packet ); - } - - HBBufferClose( &buffer ); - } - - if( OgmEnd( ogm ) < 0 ) - { - HBLog( "HBOgmMux: flush failed" ); - } - - fclose( ogm->file ); - HBLog( "HBOgmMux: `%s' closed", title->file ); -} +} OgmMuxData; typedef struct __attribute__((__packed__)) { @@ -268,17 +85,66 @@ static void _SetQWLE( uint8_t *p, uint64_t i_qw ) SetDWLE( p+4, ( i_qw >> 32)&0xffffffff ); } -static int OgmFlush( HBOgmMux *ogm, int i_tk ) +HBMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ) +{ + HBMux * m; + HBAudio * audio; + int i; + + if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) + { + HBLog( "HBOgmMux: malloc failed, gonna crash" ); + return NULL; + } + m->start = OgmStart; + m->muxVideo = OgmMux; + m->muxAudio = OgmMux; + m->end = OgmEnd; + + m->handle = handle; + m->title = title; + + /* Alloc muxer data */ + title->muxData = calloc( sizeof( OgmMuxData ), 1 ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + audio->muxData = calloc( sizeof( OgmMuxData ), 1 ); + } + + return m; +} + +void HBOgmMuxClose( HBMux ** _m ) +{ + HBMux * m = *_m; + HBTitle * title = m->title; + HBAudio * audio; + int i; + + /* Free muxer data */ + free( title->muxData ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + free( audio->muxData ); + } + + free( m ); + *_m = NULL; +} + +static int OgmFlush( HBMux * m, OgmMuxData * muxData ) { for( ;; ) { ogg_page og; - if( ogg_stream_flush( &ogm->tk[i_tk].os, &og ) == 0 ) + if( ogg_stream_flush( &muxData->os, &og ) == 0 ) { break; } - if( fwrite( og.header, og.header_len, 1, ogm->file ) <= 0 || - fwrite( og.body, og.body_len, 1, ogm->file ) <= 0 ) + if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || + fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) { return -1; } @@ -286,92 +152,87 @@ static int OgmFlush( HBOgmMux *ogm, int i_tk ) return 0; } -static int OgmStart( HBOgmMux *ogm ) +static int OgmStart( HBMux * m ) { - HBTitle *title = ogm->title; - int i; + HBTitle * title = m->title; + HBAudio * audio; + OgmMuxData * muxData; + ogg_packet op; + ogg_stream_header_t h; + int i; - ogg_packet op; + /* Open output file */ + if( ( m->file = fopen( title->file, "wb" ) ) == NULL ) + { + HBLog( "HBOgmMux: failed to open `%s'", title->file ); + /* FIXME */ + HBErrorOccured( m->handle, HB_ERROR_AVI_WRITE ); + return -1; + } + HBLog( "HBOgmMux: `%s' opened", title->file ); - /* Init track */ - ogm->tk[0].codec = title->codec; - ogm->tk[0].fifo = title->outFifo; - ogm->tk[0].i_packet_no = 0; - ogg_stream_init (&ogm->tk[0].os, 0 ); + /* Init tracks */ - for( i = 1; i < HBListCount( title->ripAudioList ) + 1; i++ ) + /* Video */ + muxData = (OgmMuxData *) title->muxData; + muxData->codec = title->codec; + muxData->i_packet_no = 0; + ogg_stream_init( &muxData->os, 0 ); + + /* Audio */ + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - HBAudio *audio = HBListItemAt( title->ripAudioList, i - 1 ); + HBAudio * audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + muxData = (OgmMuxData *) audio->muxData; - ogm->tk[i].codec = audio->outCodec; - ogm->tk[i].fifo = audio->outFifo; - ogm->tk[i].i_packet_no = 0; - ogg_stream_init (&ogm->tk[i].os, i ); + muxData->codec = audio->outCodec; + muxData->i_packet_no = 0; + ogg_stream_init( &muxData->os, i + 1 ); } - ogm->i_tk = 1 + HBListCount( title->ripAudioList ); - /* Wait data for each track */ - for( i = 0; i < ogm->i_tk; i++ ) + /* First pass: all b_o_s packets */ + + /* Video */ + muxData = (OgmMuxData *) title->muxData; + memset( &h, 0, sizeof( ogg_stream_header_t ) ); + h.i_packet_type = 0x01; + memcpy( h.stream_type, "video ", 8 ); + if( muxData->codec == HB_CODEC_X264 ) { - while( !ogm->die && - ( ( ogm->tk[i].codec == HB_CODEC_VORBIS && HBFifoSize( ogm->tk[i].fifo ) <= 3 ) || - HBFifoSize( ogm->tk[i].fifo ) <= 0 ) ) - { - HBSnooze( 10000 ); - } + memcpy( h.sub_type, "H264", 4 ); } - - if( ogm->die ) + else { - return -1; + memcpy( h.sub_type, "XVID", 4 ); } - - /* First pass: all b_o_s packets */ - for( i = 0; i < ogm->i_tk; i++ ) + SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); + SetQWLE( &h.i_time_unit, (int64_t)10*1000*1000*(int64_t)title->rateBase/(int64_t)title->rate ); + SetQWLE( &h.i_samples_per_unit, 1 ); + SetDWLE( &h.i_default_len, 0 ); + SetDWLE( &h.i_buffer_size, 1024*1024 ); + SetWLE ( &h.i_bits_per_sample, 0 ); + SetDWLE( &h.header.video.i_width, title->outWidth ); + SetDWLE( &h.header.video.i_height, title->outHeight ); + op.packet = (char*)&h; + op.bytes = sizeof( ogg_stream_header_t ); + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = muxData->i_packet_no++; + ogg_stream_packetin( &muxData->os, &op ); + OgmFlush( m, muxData ); + + /* Audio */ + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - ogg_stream_header_t h; - + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + muxData = (OgmMuxData *) audio->muxData; memset( &h, 0, sizeof( ogg_stream_header_t ) ); - - switch( ogm->tk[i].codec ) + switch( muxData->codec ) { - case HB_CODEC_FFMPEG: - case HB_CODEC_XVID: - case HB_CODEC_X264: - h.i_packet_type = 0x01; - memcpy( h.stream_type, "video ", 8 ); - if( ogm->tk[i].codec == HB_CODEC_X264 ) - { - memcpy( h.sub_type, "H264", 4 ); - } - else - { - memcpy( h.sub_type, "XVID", 4 ); - } - - SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); - SetQWLE( &h.i_time_unit, (int64_t)10*1000*1000*(int64_t)title->rateBase/(int64_t)title->rate ); - SetQWLE( &h.i_samples_per_unit, 1 ); - SetDWLE( &h.i_default_len, 0 ); - SetDWLE( &h.i_buffer_size, 1024*1024 ); - SetWLE ( &h.i_bits_per_sample, 0 ); - SetDWLE( &h.header.video.i_width, title->outWidth ); - SetDWLE( &h.header.video.i_height, title->outHeight ); - - op.packet = (char*)&h; - op.bytes = sizeof( ogg_stream_header_t ); - op.b_o_s = 1; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = ogm->tk[i].i_packet_no++; - ogg_stream_packetin( &ogm->tk[i].os, &op ); - break; - case HB_CODEC_MP3: { - HBAudio *audio = HBListItemAt( title->ripAudioList, i - 1 ); - h.i_packet_type = 0x01; memcpy( h.stream_type, "audio ", 8 ); memcpy( h.sub_type, "55 ", 4 ); @@ -385,87 +246,151 @@ static int OgmStart( HBOgmMux *ogm ) SetDWLE( &h.header.audio.i_channels, 2 ); SetDWLE( &h.header.audio.i_block_align, 0 ); - SetDWLE( &h.header.audio.i_avgbytespersec, audio->outBitrate / 8 ); - + SetDWLE( &h.header.audio.i_avgbytespersec, + audio->outBitrate / 8 ); op.packet = (char*)&h; op.bytes = sizeof( ogg_stream_header_t ); op.b_o_s = 1; op.e_o_s = 0; op.granulepos = 0; - op.packetno = ogm->tk[i].i_packet_no++; - ogg_stream_packetin( &ogm->tk[i].os, &op ); + op.packetno = muxData->i_packet_no++; + ogg_stream_packetin( &muxData->os, &op ); break; } case HB_CODEC_VORBIS: { - HBBuffer *h = HBFifoPop( ogm->tk[i].fifo ); + HBBuffer *h = HBFifoPop( audio->outFifo ); memcpy( &op, h->data, sizeof( ogg_packet ) ); op.packet = h->data + sizeof( ogg_packet ); - ogg_stream_packetin( &ogm->tk[i].os, &op ); + ogg_stream_packetin( &muxData->os, &op ); break; } - case HB_CODEC_AAC: - break; default: - HBLog( "unhandled codec" ); + HBLog( "HBOgmMux: unhandled codec" ); break; } - OgmFlush( ogm, i ); + OgmFlush( m, muxData ); } /* second pass: all non b_o_s packets */ - for( i = 0; i < ogm->i_tk; i++ ) + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - if( ogm->tk[i].codec == HB_CODEC_VORBIS ) + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + if( audio->outCodec == HB_CODEC_VORBIS ) { HBBuffer *h; int j; + muxData = (OgmMuxData *) audio->muxData; for( j = 0; j < 2; j++ ) { - HBFifoWait( ogm->tk[i].fifo ); - h = HBFifoPop( ogm->tk[i].fifo ); + h = HBFifoPop( audio->outFifo ); memcpy( &op, h->data, sizeof( ogg_packet ) ); op.packet = h->data + sizeof( ogg_packet ); - ogg_stream_packetin( &ogm->tk[i].os, &op ); + ogg_stream_packetin( &muxData->os, &op ); - OgmFlush( ogm, i ); + OgmFlush( m, muxData ); } } -#if 0 - else + } + + HBLog( "HBOgmMux: headers written" ); + return 0; +} + +static int OgmMux( HBMux * m, void * _muxData, HBBuffer * buffer ) +{ + OgmMuxData * muxData = (OgmMuxData *) _muxData; + ogg_packet op; + + switch( muxData->codec ) + { + case HB_CODEC_FFMPEG: + case HB_CODEC_XVID: + case HB_CODEC_X264: + op.bytes = buffer->size + 1; + op.packet = malloc( op.bytes ); + op.packet[0] = buffer->keyFrame ? 0x08 : 0x00; + memcpy( &op.packet[1], buffer->data, buffer->size ); + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = muxData->i_packet_no; + op.packetno = muxData->i_packet_no++; + break; + case HB_CODEC_MP3: + op.bytes = buffer->size + 1; + op.packet = malloc( op.bytes ); + op.packet[0] = 0x08; + memcpy( &op.packet[1], buffer->data, buffer->size ); + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = muxData->i_packet_no * 1152; + op.packetno = muxData->i_packet_no++; + break; + case HB_CODEC_VORBIS: + memcpy( &op, buffer->data, sizeof( ogg_packet ) ); + op.packet = malloc( op.bytes ); + memcpy( op.packet, buffer->data + sizeof( ogg_packet ), op.bytes ); + break; + + default: + HBLog( "HBOgmMux: unhandled codec" ); + op.bytes = 0; + op.packet = NULL; + break; + } + + if( op.packet ) + { + ogg_stream_packetin( &muxData->os, &op ); + + for( ;; ) { - /* Home made commentary */ - op.packet = "\003Handbrake"; - op.bytes = strlen( "\003Handbrake" );; - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = ogm->tk[i].i_packet_no++; - - ogg_stream_packetin( &ogm->tk[i].os, &op ); - OgmFlush( ogm, i ); + ogg_page og; + if( ogg_stream_pageout( &muxData->os, &og ) == 0 ) + { + break; + } + + if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || + fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) + { + HBLog( "HBOgmMux: write failed" ); + break; + } } -#endif + free( op.packet ); } - return 0; } -static int OgmEnd( HBOgmMux *ogm ) +static int OgmEnd( HBMux * m ) { - int i; + HBTitle * title = m->title; + HBAudio * audio; + OgmMuxData * muxData; + int i; - for( i = 0; i < ogm->i_tk; i++ ) + muxData = (OgmMuxData *) title->muxData; + if( OgmFlush( m, muxData ) < 0 ) { - if( OgmFlush( ogm, i ) < 0 ) + return -1; + } + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + muxData = (OgmMuxData *) audio->muxData; + if( OgmFlush( m, muxData ) < 0 ) { return -1; } } + + fclose( m->file ); + HBLog( "HBOgmMux: `%s' closed", title->file ); return 0; } |