diff options
Diffstat (limited to 'core')
40 files changed, 3145 insertions, 3532 deletions
diff --git a/core/Ac3Dec.c b/core/Ac3Dec.c index d5430d49e..e1b027887 100644 --- a/core/Ac3Dec.c +++ b/core/Ac3Dec.c @@ -1,23 +1,18 @@ -/* $Id: Ac3Dec.c,v 1.4 2003/11/04 20:16:44 titer Exp $ +/* $Id: Ac3Dec.c,v 1.12 2004/01/16 19:04:03 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Ac3Dec.h" -#include "Fifo.h" -#include "Work.h" +#include "HBInternal.h" -#include <a52dec/a52.h> +/* liba52 */ +#include "a52dec/a52.h" -/* Local prototypes */ -static int Ac3DecWork( HBWork * ); -static int GetBytes( HBAc3Dec *, int ); - -struct HBAc3Dec +typedef struct HBAc3Dec { HB_WORK_COMMON_MEMBERS - + HBHandle * handle; HBAudio * audio; @@ -35,9 +30,13 @@ struct HBAc3Dec int nextFrameSize; /* In bytes */ float position; HBBuffer * rawBuffer; -}; +} HBAc3Dec; + +/* Local prototypes */ +static int Ac3DecWork( HBWork * ); +static int GetBytes( HBAc3Dec *, int ); -HBAc3Dec * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) +HBWork * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) { HBAc3Dec * a; if( !( a = malloc( sizeof( HBAc3Dec ) ) ) ) @@ -59,8 +58,15 @@ HBAc3Dec * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) /* Let it do the downmixing */ a->outFlags = A52_STEREO; - /* Lame wants samples from -32768 to 32768 */ - a->sampleLevel = 32768.0; + if( audio->codec == HB_CODEC_MP3 ) + /* Lame wants 16 bits samples */ + a->sampleLevel = 32768.0; + else if( audio->codec == HB_CODEC_AAC ) + /* Faac wants 24 bits samples */ + a->sampleLevel = 8388608.0; + else if( audio->codec == HB_CODEC_VORBIS ) + /* Vorbis wants FIXME bits samples */ + a->sampleLevel = 32768.0; a->ac3FrameSize = 0; a->ac3Buffer = NULL; @@ -69,13 +75,13 @@ HBAc3Dec * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) a->position = 0.0; a->rawBuffer = NULL; - return a; + return (HBWork*) a; } -void HBAc3DecClose( HBAc3Dec ** _a ) +void HBAc3DecClose( HBWork ** _a ) { - HBAc3Dec * a = *_a; - + HBAc3Dec * a = (HBAc3Dec*) *_a; + if( a->ac3Buffer ) HBBufferClose( &a->ac3Buffer ); if( a->rawBuffer ) HBBufferClose( &a->rawBuffer ); a52_free( a->state ); @@ -89,7 +95,7 @@ static int Ac3DecWork( HBWork * w ) { HBAc3Dec * a = (HBAc3Dec*) w; HBAudio * audio = a->audio; - + int didSomething = 0; /* Push decoded buffer */ @@ -135,7 +141,7 @@ static int Ac3DecWork( HBWork * w ) sample_t * samples; HBBuffer * rawBuffer; int i; - + if( GetBytes( a, a->nextFrameSize ) ) { didSomething = 1; @@ -153,6 +159,9 @@ static int Ac3DecWork( HBWork * w ) /* 6 blocks per frame, 256 samples per block, 2 channels */ rawBuffer = HBBufferInit( 12 * 256 * sizeof( float ) ); rawBuffer->position = a->position; + rawBuffer->samples = 6 * 256; + rawBuffer->left = (float*) rawBuffer->data; + rawBuffer->right = rawBuffer->left + 6 * 256; for( i = 0; i < 6; i++ ) { @@ -163,41 +172,34 @@ static int Ac3DecWork( HBWork * w ) samples = a52_samples( a->state ); /* Copy left channel data */ - memcpy( rawBuffer->data + i * 256 * sizeof( float ), - samples, + memcpy( rawBuffer->left + i * 256, samples, 256 * sizeof( float ) ); /* Copy right channel data */ - memcpy( rawBuffer->data + ( 6 + i ) * 256 * sizeof( float ), - samples + 256, + memcpy( rawBuffer->right + i * 256, samples + 256, 256 * sizeof( float ) ); } a->rawBuffer = rawBuffer; } - + return didSomething; } static int GetBytes( HBAc3Dec * a, int size ) { int i; - + while( a->ac3FrameSize < size ) { if( !a->ac3Buffer ) { - if( !( a->ac3Buffer = HBFifoPop( a->audio->ac3Fifo ) ) ) + if( !( a->ac3Buffer = HBFifoPop( a->audio->inFifo ) ) ) { return 0; } a->ac3BufferPos = 0; a->position = a->ac3Buffer->position; - - if( a->ac3Buffer->last ) - { - HBDone( a->handle ); - } } i = MIN( size - a->ac3FrameSize, diff --git a/core/Ac3Dec.h b/core/Ac3Dec.h deleted file mode 100644 index a1ecaff66..000000000 --- a/core/Ac3Dec.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: Ac3Dec.h,v 1.1 2003/11/03 12:08:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_AC3_DEC_H -#define HB_AC3_DEC_H - -#include "HandBrakeInternal.h" - -HBAc3Dec * HBAc3DecInit( HBHandle *, HBAudio * ); -void HBAc3DecClose( HBAc3Dec ** ); - -#endif diff --git a/core/AviMux.c b/core/AviMux.c index ca34d3cab..71238425e 100644 --- a/core/AviMux.c +++ b/core/AviMux.c @@ -1,42 +1,38 @@ -/* $Id: AviMux.c,v 1.6 2003/11/13 01:18:52 titer Exp $ +/* $Id: AviMux.c,v 1.15 2004/02/18 17:07:20 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "AviMux.h" -#include "Fifo.h" -#include "Thread.h" +#include "HBInternal.h" -/* Local structures */ -typedef struct AviMainHeader AviMainHeader; -typedef struct AviStreamHeader AviStreamHeader; -typedef struct BitmapInfo BitmapInfo; -typedef struct WaveFormatEx WaveFormatEx; +int64_t videoFrames; +int64_t videoBytes; +int64_t audioFrames; +int64_t audioBytes; /* Local prototypes */ static void AviMuxThread( void * ); static void InitAviHeaders( HBAviMux * ); -static void AddChunk( HBAviMux *, HBBuffer **, uint32_t, - AviStreamHeader * ); +static void AddChunk( HBAviMux *, HBBuffer *, uint32_t, + HBAviStreamHeader * ); static void AddIndex( HBAviMux * ); static void WriteInt8( FILE *, uint8_t ); static void WriteInt16( FILE *, uint16_t ); static void WriteInt32( FILE *, uint32_t ); static void WriteBuffer( FILE *, HBBuffer * ); -static void WriteMainHeader( FILE *, AviMainHeader * ); -static void WriteStreamHeader( FILE *, AviStreamHeader * ); -static void WriteBitmapInfo( FILE *, BitmapInfo * ); -static void WriteWaveFormatEx( FILE *, WaveFormatEx * ); +static void WriteMainHeader( FILE *, HBAviMainHeader * ); +static void WriteStreamHeader( FILE *, HBAviStreamHeader * ); +static void WriteHBBitmapInfo( FILE *, HBBitmapInfo * ); +static void WriteHBWaveFormatEx( FILE *, HBWaveFormatEx * ); static void IndexAddInt32( HBBuffer * buffer, uint32_t ); -static HBBuffer * Pop( HBAviMux *, HBFifo * ); #define AVIF_HASINDEX 0x10 #define AVIIF_KEYFRAME 0x10 #define FOURCC(a) ((a[3]<<24)|(a[2]<<16)|(a[1]<<8)|a[0]) /* Structures definitions */ -struct __attribute__((__packed__)) AviMainHeader +struct __attribute__((__packed__)) HBAviMainHeader { uint32_t FourCC; uint32_t BytesCount; @@ -53,7 +49,7 @@ struct __attribute__((__packed__)) AviMainHeader uint32_t Reserved[4]; }; -struct __attribute__((__packed__)) AviStreamHeader +struct __attribute__((__packed__)) HBAviStreamHeader { uint32_t FourCC; uint32_t BytesCount; @@ -76,7 +72,7 @@ struct __attribute__((__packed__)) AviStreamHeader int16_t Bottom; }; -struct __attribute__((__packed__)) BitmapInfo +struct __attribute__((__packed__)) HBBitmapInfo { uint32_t FourCC; uint32_t BytesCount; @@ -91,13 +87,9 @@ struct __attribute__((__packed__)) BitmapInfo uint32_t YPelsPerMeter; uint32_t ClrUsed; uint32_t ClrImportant; - uint8_t Blue; - uint8_t Green; - uint8_t Red; - uint8_t Reserved; }; -struct __attribute__((__packed__)) WaveFormatEx +struct __attribute__((__packed__)) HBWaveFormatEx { uint32_t FourCC; uint32_t BytesCount; @@ -121,28 +113,18 @@ struct HBAviMux { HBHandle * handle; HBTitle * title; - HBAudio * audio; - HBAudio * optAudio; - - AviMainHeader mainHeader; - AviStreamHeader videoHeader; - BitmapInfo videoFormat; - AviStreamHeader audioHeader; - WaveFormatEx audioFormat; - AviStreamHeader optAudioHeader; - WaveFormatEx optAudioFormat; /* Data size in bytes, not including headers */ unsigned size; + FILE * file; HBBuffer * index; - int die; + volatile int die; HBThread * thread; }; -HBAviMux * HBAviMuxInit( HBHandle * handle, HBTitle * title, - HBAudio * audio, HBAudio * optAudio ) +HBAviMux * HBAviMuxInit( HBHandle * handle, HBTitle * title ) { HBAviMux * a; if( !( a = malloc( sizeof( HBAviMux ) ) ) ) @@ -153,8 +135,11 @@ HBAviMux * HBAviMuxInit( HBHandle * handle, HBTitle * title, a->handle = handle; a->title = title; - a->audio = audio; - a->optAudio = optAudio; + + videoFrames = 0; + videoBytes = 0; + audioFrames = 0; + audioBytes = 0; a->size = 0; a->file = NULL; @@ -170,9 +155,23 @@ HBAviMux * HBAviMuxInit( HBHandle * handle, HBTitle * title, void HBAviMuxClose( HBAviMux ** _a ) { HBAviMux * a = *_a; + FILE * file; + long size; a->die = 1; HBThreadClose( &a->thread ); + + file = fopen( a->title->file, "r" ); + fseek( file, 0, SEEK_END ); + size = ftell( file ); + fclose( file ); + + HBLog( "HBAviMux: videoFrames=%lld, %lld bytes", videoFrames, videoBytes ); + HBLog( "HBAviMux: audioFrames=%lld, %lld bytes", audioFrames, audioBytes ); + HBLog( "HBAviMux: overhead=%.2f bytes / frame", + ( (float) size - videoBytes - audioBytes ) / + ( videoFrames + audioFrames ) ); + free( a ); *_a = NULL; @@ -180,14 +179,13 @@ void HBAviMuxClose( HBAviMux ** _a ) static void AviMuxThread( void * _a ) { - HBAviMux * a = (HBAviMux*) _a; - HBTitle * title = a->title; - HBAudio * audio = a->audio; - HBAudio * optAudio = a->optAudio; + HBAviMux * a = (HBAviMux*) _a; + HBTitle * title = a->title; + int audioCount = HBListCount( title->ripAudioList ); - HBBuffer * videoBuffer = NULL; - HBBuffer * audioBuffer = NULL; - HBBuffer * optAudioBuffer = NULL; + HBAudio * audio; + HBBuffer * buffer; + int i; /* Open destination file */ HBLog( "HBAviMux: opening %s", title->file ); @@ -198,21 +196,25 @@ static void AviMuxThread( void * _a ) return; } - /* Get a buffer for each track */ - videoBuffer = Pop( a, title->mpeg4Fifo ); - audioBuffer = Pop( a, audio->mp3Fifo ); - if( optAudio ) + /* Wait until we have one encoded frame for each track */ + while( !a->die && !HBFifoSize( title->outFifo ) ) { - optAudioBuffer = Pop( a, optAudio->mp3Fifo ); + HBSnooze( 10000 ); + } + for( i = 0; i < audioCount; i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + while( !a->die && !HBFifoSize( audio->outFifo ) ) + { + HBSnooze( 10000 ); + } } - /* Failed ? Then forget it */ - if( !videoBuffer || !audioBuffer || - ( optAudio && !optAudioBuffer ) ) + if( a->die ) { fclose( a->file ); a->file = NULL; - + HBLog( "HBAviMux: deleting %s", title->file ); unlink( title->file ); return; @@ -222,48 +224,56 @@ static void AviMuxThread( void * _a ) for( ;; ) { - /* Get a buffer for each track */ - if( !videoBuffer ) - { - videoBuffer = Pop( a, title->mpeg4Fifo ); - } - if( !audioBuffer ) + /* Wait until we have one encoded frame for each track */ + if( !HBFifoWait( title->outFifo ) ) { - audioBuffer = Pop( a, audio->mp3Fifo ); + a->die = 1; } - if( optAudio && !optAudioBuffer ) + for( i = 0; i < audioCount; i++ ) { - optAudioBuffer = Pop( a, optAudio->mp3Fifo ); + audio = HBListItemAt( title->ripAudioList, i ); + if( !HBFifoWait( audio->outFifo ) ) + { + a->die = 1; + break; + } } - if( !videoBuffer && !audioBuffer && !optAudioBuffer ) + if( a->die ) { - /* Couldn't get anything -> must exit NOW */ break; } /* Interleave frames in the same order than they were in the original MPEG stream */ - if( videoBuffer && - ( !audioBuffer || - videoBuffer->position < audioBuffer->position ) && - ( !optAudioBuffer || - videoBuffer->position < optAudioBuffer->position ) ) + audio = NULL; + for( i = 0; i < audioCount; i++ ) { - AddChunk( a, &videoBuffer, FOURCC( "00dc" ), - &a->videoHeader ); + HBAudio * otherAudio; + otherAudio = HBListItemAt( title->ripAudioList, i ); + if( !audio || HBFifoPosition( otherAudio->outFifo ) < + HBFifoPosition( audio->outFifo ) ) + { + audio = otherAudio; + } } - else if( audioBuffer && - ( !optAudioBuffer || - audioBuffer->position < optAudioBuffer->position ) ) + + if( audio == NULL || + HBFifoPosition( title->outFifo ) < HBFifoPosition( audio->outFifo ) ) { - AddChunk( a, &audioBuffer, FOURCC( "01wb" ), - &a->audioHeader ); + buffer = HBFifoPop( title->outFifo ); + AddChunk( a, buffer, FOURCC( "00dc" ), title->aviVideoHeader ); + videoFrames++; + videoBytes += buffer->size; + HBBufferClose( &buffer ); } else { - AddChunk( a, &optAudioBuffer, FOURCC( "02wb" ), - &a->optAudioHeader ); + buffer = HBFifoPop( audio->outFifo ); + AddChunk( a, buffer, audio->aviFourCC, audio->aviAudioHeader ); + audioFrames++; + audioBytes += buffer->size; + HBBufferClose( &buffer ); } } @@ -275,49 +285,57 @@ static void AviMuxThread( void * _a ) static void InitAviHeaders( HBAviMux * a ) { - HBTitle * title = a->title; - HBAudio * audio = a->audio; - HBAudio * optAudio = a->optAudio; - AviMainHeader * mainHeader = &a->mainHeader; - AviStreamHeader * videoHeader = &a->videoHeader; - BitmapInfo * videoFormat = &a->videoFormat; - AviStreamHeader * audioHeader = &a->audioHeader; - WaveFormatEx * audioFormat = &a->audioFormat; - AviStreamHeader * optAudioHeader = &a->optAudioHeader; - WaveFormatEx * optAudioFormat = &a->optAudioFormat; - FILE * file = a->file; - int hdrlBytes; - int i; + HBTitle * title = a->title; + FILE * file = a->file; + int audioCount = HBListCount( title->ripAudioList ); + + HBAudio * audio; + HBAviMainHeader * mainHeader; + HBAviStreamHeader * videoHeader; + HBBitmapInfo * videoFormat; + HBAviStreamHeader * audioHeader; + HBWaveFormatEx * audioFormat; + int hdrlBytes; + int i; /* AVI main header */ - memset( mainHeader, 0, sizeof( AviMainHeader ) ); + mainHeader = calloc( sizeof( HBAviMainHeader ), 1 ); + mainHeader->FourCC = FOURCC( "avih" ); - mainHeader->BytesCount = sizeof( AviMainHeader ) - 8; + mainHeader->BytesCount = sizeof( HBAviMainHeader ) - 8; mainHeader->MicroSecPerFrame = (uint64_t) 1000000 * title->rateBase / title->rate; - mainHeader->Streams = optAudio ? 3 : 2; + mainHeader->Streams = 1 + audioCount; mainHeader->Width = title->outWidth; mainHeader->Height = title->outHeight; + title->aviMainHeader = mainHeader; + /* Video stream header */ - memset( videoHeader, 0, sizeof( AviStreamHeader ) ); + videoHeader = calloc( sizeof( HBAviStreamHeader ), 1 ); + videoHeader->FourCC = FOURCC( "strh" ); - videoHeader->BytesCount = sizeof( AviStreamHeader ) - 8; + videoHeader->BytesCount = sizeof( HBAviStreamHeader ) - 8; videoHeader->Type = FOURCC( "vids" ); - + if( title->codec == HB_CODEC_FFMPEG ) videoHeader->Handler = FOURCC( "divx" ); else if( title->codec == HB_CODEC_XVID ) videoHeader->Handler = FOURCC( "xvid" ); - + else if( title->codec == HB_CODEC_X264 ) + videoHeader->Handler = FOURCC( "H264" ); + videoHeader->Scale = title->rateBase; videoHeader->Rate = title->rate; + title->aviVideoHeader = videoHeader; + /* Video stream format */ - memset( videoFormat, 0, sizeof( BitmapInfo ) ); + videoFormat = calloc( sizeof( HBBitmapInfo ), 1 ); + videoFormat->FourCC = FOURCC( "strf" ); - videoFormat->BytesCount = sizeof( BitmapInfo ) - 8; - videoFormat->Size = sizeof( BitmapInfo ) - 8; + videoFormat->BytesCount = sizeof( HBBitmapInfo ) - 8; + videoFormat->Size = sizeof( HBBitmapInfo ) - 8; videoFormat->Width = title->outWidth; videoFormat->Height = title->outHeight; videoFormat->Planes = 1; @@ -326,66 +344,51 @@ static void InitAviHeaders( HBAviMux * a ) videoFormat->Compression = FOURCC( "DX50" ); else if( title->codec == HB_CODEC_XVID ) videoFormat->Compression = FOURCC( "XVID" ); + else if( title->codec == HB_CODEC_X264 ) + videoFormat->Compression = FOURCC( "H264" ); - /* Audio stream header */ - memset( audioHeader, 0, sizeof( AviStreamHeader ) ); - audioHeader->FourCC = FOURCC( "strh" ); - audioHeader->BytesCount = sizeof( AviStreamHeader ) - 8; - audioHeader->Type = FOURCC( "auds" ); - audioHeader->InitialFrames = 1; - audioHeader->Scale = 1152; - audioHeader->Rate = audio->outSampleRate; - audioHeader->Quality = 0xFFFFFFFF; - - /* Audio stream format */ - memset( audioFormat, 0, sizeof( WaveFormatEx ) ); - audioFormat->FourCC = FOURCC( "strf" ); - audioFormat->BytesCount = sizeof( WaveFormatEx ) - 8; - audioFormat->FormatTag = 0x55; - audioFormat->Channels = 2; - audioFormat->SamplesPerSec = audio->outSampleRate; - audioFormat->AvgBytesPerSec = audio->outBitrate * 1024 / 8; - audioFormat->BlockAlign = 1152; - audioFormat->Size = 12; - audioFormat->Id = 1; - audioFormat->Flags = 2; - audioFormat->BlockSize = 1152; - audioFormat->FramesPerBlock = 1; - audioFormat->CodecDelay = 1393; - - if( optAudio ) + title->aviVideoFormat = videoFormat; + + for( i = 0; i < audioCount; i++ ) { - /* optAudio stream header */ - memset( optAudioHeader, 0, sizeof( AviStreamHeader ) ); - optAudioHeader->FourCC = FOURCC( "strh" ); - optAudioHeader->BytesCount = sizeof( AviStreamHeader ) - 8; - optAudioHeader->Type = FOURCC( "auds" ); - optAudioHeader->InitialFrames = 1; - optAudioHeader->Scale = 1152; - optAudioHeader->Rate = optAudio->outSampleRate; - optAudioHeader->Quality = 0xFFFFFFFF; - - /* optAudio stream format */ - memset( optAudioFormat, 0, sizeof( WaveFormatEx ) ); - optAudioFormat->FourCC = FOURCC( "strf" ); - optAudioFormat->BytesCount = sizeof( WaveFormatEx ) - 8; - optAudioFormat->FormatTag = 0x55; - optAudioFormat->Channels = 2; - optAudioFormat->SamplesPerSec = optAudio->outSampleRate; - optAudioFormat->AvgBytesPerSec = optAudio->outBitrate * 1024 / 8; - optAudioFormat->BlockAlign = 1152; - optAudioFormat->Size = 12; - optAudioFormat->Id = 1; - optAudioFormat->Flags = 2; - optAudioFormat->BlockSize = 1152; - optAudioFormat->FramesPerBlock = 1; - optAudioFormat->CodecDelay = 1393; + audio = HBListItemAt( title->ripAudioList, i ); + + /* Audio stream header */ + audioHeader = calloc( sizeof( HBAviStreamHeader ), 1 ); + + audioHeader->FourCC = FOURCC( "strh" ); + audioHeader->BytesCount = sizeof( HBAviStreamHeader ) - 8; + audioHeader->Type = FOURCC( "auds" ); + audioHeader->InitialFrames = 1; + audioHeader->Scale = 1152; + audioHeader->Rate = audio->outSampleRate; + audioHeader->Quality = 0xFFFFFFFF; + + audio->aviAudioHeader = audioHeader; + + /* Audio stream format */ + audioFormat = calloc( sizeof( HBWaveFormatEx ), 1 ); + + audioFormat->FourCC = FOURCC( "strf" ); + audioFormat->BytesCount = sizeof( HBWaveFormatEx ) - 8; + audioFormat->FormatTag = 0x55; + audioFormat->Channels = 2; + audioFormat->SamplesPerSec = audio->outSampleRate; + audioFormat->AvgBytesPerSec = audio->outBitrate * 1024 / 8; + audioFormat->BlockAlign = 1152; + audioFormat->Size = 12; + audioFormat->Id = 1; + audioFormat->Flags = 2; + audioFormat->BlockSize = 1152; + audioFormat->FramesPerBlock = 1; + audioFormat->CodecDelay = 1393; + + audio->aviAudioFormat = audioFormat; } - hdrlBytes = 4 + sizeof( AviMainHeader ) + - ( optAudio ? 3 : 2 ) * ( 12 + sizeof( AviStreamHeader ) ) + - sizeof( BitmapInfo ) + - ( optAudio ? 2 : 1 ) * sizeof( WaveFormatEx ); + hdrlBytes = 4 + sizeof( HBAviMainHeader ) + ( 1 + audioCount ) * + ( 12 + sizeof( HBAviStreamHeader ) ) + sizeof( HBBitmapInfo ) + + audioCount * sizeof( HBWaveFormatEx ); /* Here we really start to write into the file */ @@ -395,28 +398,31 @@ static void InitAviHeaders( HBAviMux * a ) WriteInt32( file, FOURCC( "LIST" ) ); WriteInt32( file, hdrlBytes ); WriteInt32( file, FOURCC( "hdrl" ) ); - WriteMainHeader( file, mainHeader ); + WriteMainHeader( file, title->aviMainHeader ); WriteInt32( file, FOURCC( "LIST" ) ); - WriteInt32( file, 4 + sizeof( AviStreamHeader ) + - sizeof( BitmapInfo ) ); + WriteInt32( file, 4 + sizeof( HBAviStreamHeader ) + + sizeof( HBBitmapInfo ) ); WriteInt32( file, FOURCC( "strl" ) ); - WriteStreamHeader( file, videoHeader ); - WriteBitmapInfo( file, videoFormat ); - WriteInt32( file, FOURCC( "LIST" ) ); - WriteInt32( file, 4 + sizeof( AviStreamHeader ) + - sizeof( WaveFormatEx ) ); - WriteInt32( file, FOURCC( "strl" ) ); - WriteStreamHeader( file, audioHeader ); - WriteWaveFormatEx( file, audioFormat ); - if( optAudio ) + WriteStreamHeader( file, title->aviVideoHeader ); + WriteHBBitmapInfo( file, title->aviVideoFormat ); + + for( i = 0; i < audioCount; i++ ) { + char fourCC[5]; + + audio = HBListItemAt( title->ripAudioList, i ); + + snprintf( fourCC, 5, "%02dwb", i + 1 ); + audio->aviFourCC = FOURCC( fourCC ); + WriteInt32( file, FOURCC( "LIST" ) ); - WriteInt32( file, 4 + sizeof( AviStreamHeader ) + - sizeof( WaveFormatEx ) ); + WriteInt32( file, 4 + sizeof( HBAviStreamHeader ) + + sizeof( HBWaveFormatEx ) ); WriteInt32( file, FOURCC( "strl" ) ); - WriteStreamHeader( file, optAudioHeader ); - WriteWaveFormatEx( file, optAudioFormat ); + WriteStreamHeader( file, audio->aviAudioHeader ); + WriteHBWaveFormatEx( file, audio->aviAudioFormat ); } + WriteInt32( file, FOURCC( "JUNK" ) ); WriteInt32( file, 2008 - hdrlBytes ); for( i = 0; i < 2008 - hdrlBytes; i++ ) @@ -428,11 +434,14 @@ static void InitAviHeaders( HBAviMux * a ) WriteInt32( file, FOURCC( "movi" ) ); } -static void AddChunk( HBAviMux * a, HBBuffer ** _buffer, - uint32_t fourCC, AviStreamHeader * header ) +static void AddChunk( HBAviMux * a, HBBuffer * buffer, + uint32_t fourCC, HBAviStreamHeader * header ) { - HBBuffer * buffer = *_buffer; - + HBTitle * title = a->title; + + HBAudio * audio; + int i; + /* Update index */ IndexAddInt32( a->index, fourCC ); IndexAddInt32( a->index, buffer->keyFrame ? AVIIF_KEYFRAME : 0 ); @@ -459,28 +468,28 @@ static void AddChunk( HBAviMux * a, HBBuffer ** _buffer, fseek( a->file, 4, SEEK_SET ); WriteInt32( a->file, 2040 + a->size ); - /* AviStreamHeader's length */ + /* HBAviStreamHeader's lengths */ fseek( a->file, 140, SEEK_SET ); - WriteInt32( a->file, a->videoHeader.Length ); - fseek( a->file, 268, SEEK_SET ); - WriteInt32( a->file, a->audioHeader.Length ); - if( a->optAudio ) + WriteInt32( a->file, title->aviVideoHeader->Length ); + + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - fseek( a->file, 382, SEEK_SET ); - WriteInt32( a->file, a->optAudioHeader.Length ); + audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); + fseek( a->file, 268 + i * 114, SEEK_SET ); + WriteInt32( a->file, audio->aviAudioHeader->Length ); } /* movi size */ fseek( a->file, 2040, SEEK_SET ); WriteInt32( a->file, 4 + a->size ); - - HBBufferClose( _buffer ); } static void AddIndex( HBAviMux * a ) { + HBTitle * title = a->title; + fseek( a->file, 0, SEEK_END ); - + WriteInt32( a->file, FOURCC( "idx1" ) ); WriteInt32( a->file, a->index->size ); WriteBuffer( a->file, a->index ); @@ -488,9 +497,9 @@ static void AddIndex( HBAviMux * a ) a->size += 8 + a->index->size; fseek( a->file, 4, SEEK_SET ); WriteInt32( a->file, 2040 + a->size ); - a->mainHeader.Flags |= AVIF_HASINDEX; + title->aviMainHeader->Flags |= AVIF_HASINDEX; fseek( a->file, 24, SEEK_SET ); - WriteMainHeader( a->file, &a->mainHeader ); + WriteMainHeader( a->file, title->aviMainHeader ); } static void WriteInt8( FILE * file, uint8_t val ) @@ -517,7 +526,7 @@ static void WriteBuffer( FILE * file, HBBuffer * buffer ) fwrite( buffer->data, buffer->size, 1, file ); } -static void WriteBitmapInfo( FILE * file, BitmapInfo * bitmapInfo ) +static void WriteHBBitmapInfo( FILE * file, HBBitmapInfo * bitmapInfo ) { WriteInt32( file, bitmapInfo->FourCC ); WriteInt32( file, bitmapInfo->BytesCount ); @@ -532,13 +541,15 @@ static void WriteBitmapInfo( FILE * file, BitmapInfo * bitmapInfo ) WriteInt32( file, bitmapInfo->YPelsPerMeter ); WriteInt32( file, bitmapInfo->ClrUsed ); WriteInt32( file, bitmapInfo->ClrImportant ); +#if 0 WriteInt8( file, bitmapInfo->Blue ); WriteInt8( file, bitmapInfo->Green ); WriteInt8( file, bitmapInfo->Red ); WriteInt8( file, bitmapInfo->Reserved ); +#endif } -static void WriteWaveFormatEx( FILE * file, WaveFormatEx * waveFormatEx ) +static void WriteHBWaveFormatEx( FILE * file, HBWaveFormatEx * waveFormatEx ) { WriteInt32( file, waveFormatEx->FourCC ); WriteInt32( file, waveFormatEx->BytesCount ); @@ -556,7 +567,7 @@ static void WriteWaveFormatEx( FILE * file, WaveFormatEx * waveFormatEx ) WriteInt16( file, waveFormatEx->CodecDelay ); } -static void WriteMainHeader( FILE * file, AviMainHeader * mainHeader ) +static void WriteMainHeader( FILE * file, HBAviMainHeader * mainHeader ) { WriteInt32( file, mainHeader->FourCC ); WriteInt32( file, mainHeader->BytesCount ); @@ -576,7 +587,7 @@ static void WriteMainHeader( FILE * file, AviMainHeader * mainHeader ) WriteInt32( file, mainHeader->Reserved[3] ); } -static void WriteStreamHeader( FILE * file, AviStreamHeader * streamHeader ) +static void WriteStreamHeader( FILE * file, HBAviStreamHeader * streamHeader ) { WriteInt32( file, streamHeader->FourCC ); WriteInt32( file, streamHeader->BytesCount ); @@ -614,27 +625,3 @@ static void IndexAddInt32( HBBuffer * b, uint32_t val ) b->data[b->size++] = val >> 24; } -static HBBuffer * Pop( HBAviMux * a, HBFifo * fifo ) -{ - HBBuffer * buffer; - - for( ;; ) - { - HBCheckPaused( a->handle ); - - if( ( buffer = HBFifoPop( fifo ) ) ) - { - return buffer; - } - - if( a->die ) - { - break; - } - - HBSnooze( 10000 ); - } - - return NULL; -} - diff --git a/core/AviMux.h b/core/AviMux.h deleted file mode 100644 index 1fccbe971..000000000 --- a/core/AviMux.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: AviMux.h,v 1.1 2003/11/03 12:08:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_AVI_MUX_H -#define HB_AVI_MUX_H - -#include "HandBrakeInternal.h" - -HBAviMux * HBAviMuxInit( HBHandle *, HBTitle *, HBAudio *, HBAudio * ); -void HBAviMuxClose( HBAviMux ** ); - -#endif diff --git a/core/DVDRead.c b/core/DVDRead.c index 58e8f1031..f90660948 100644 --- a/core/DVDRead.c +++ b/core/DVDRead.c @@ -1,18 +1,17 @@ -/* $Id: DVDRead.c,v 1.4 2003/11/06 13:03:19 titer Exp $ +/* $Id: DVDRead.c,v 1.9 2004/01/16 19:04:03 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "DVDRead.h" -#include "Fifo.h" -#include "Thread.h" +#include "HBInternal.h" -#include <dvdread/ifo_types.h> -#include <dvdplay/dvdplay.h> -#include <dvdplay/info.h> -#include <dvdplay/state.h> -#include <dvdplay/nav.h> +/* libdvdplay */ +#include "dvdread/ifo_types.h" +#include "dvdplay/dvdplay.h" +#include "dvdplay/info.h" +#include "dvdplay/state.h" +#include "dvdplay/nav.h" /* Local prototypes */ static void DVDReadThread( void * ); @@ -22,30 +21,21 @@ static int Push( HBDVDRead *, HBFifo * fifo, HBBuffer ** buffer ); struct HBDVDRead { - HBHandle * handle; - - dvdplay_ptr vmg; - HBTitle * title; - HBAudio * audio; - HBAudio * optAudio; - int beginPosition; - int endPosition; - int pass; - HBBuffer * psBuffer; - HBList * esBufferList; - HBBuffer * videoBuf; - HBBuffer * audioBuf; - HBBuffer * optAudioBuf; - int videoStart; - int audioStart; - int optAudioStart; - - int die; - HBThread * thread; + HBHandle * handle; + + dvdplay_ptr vmg; + HBTitle * title; + int beginPosition; + int endPosition; + int pass; + HBBuffer * psBuffer; + HBList * esBufferList; + + volatile int die; + HBThread * thread; }; -HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * t, - HBAudio * a1, HBAudio * a2 ) +HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * title ) { HBDVDRead * d; if( !( d = malloc( sizeof( HBDVDRead ) ) ) ) @@ -57,20 +47,12 @@ HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * t, /* Initializations */ d->handle = handle; d->vmg = NULL; - d->title = t; - d->audio = a1; - d->optAudio = a2; + d->title = title; d->beginPosition = 0; d->endPosition = 0; d->pass = 0; d->psBuffer = NULL; d->esBufferList = HBListInit(); - d->videoBuf = NULL; - d->audioBuf = NULL; - d->optAudioBuf = NULL; - d->videoStart = -1; - d->audioStart = -1; - d->optAudioStart = -1; /* Launch the thread */ d->die = 0; @@ -83,13 +65,13 @@ HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * t, void HBDVDReadClose( HBDVDRead ** _d ) { HBBuffer * buffer; - + HBDVDRead * d = *_d; - + /* Stop the thread */ d->die = 1; HBThreadClose( &d->thread ); - + /* Clean up */ while( ( buffer = (HBBuffer*) HBListItemAt( d->esBufferList, 0 ) ) ) { @@ -98,72 +80,58 @@ void HBDVDReadClose( HBDVDRead ** _d ) } HBListClose( &d->esBufferList ) ; free( d ); - + (*_d) = NULL; } static void DVDReadThread( void * _d ) { - HBDVDRead * d = (HBDVDRead*) _d; + HBDVDRead * d = (HBDVDRead*) _d; + HBTitle * title = d->title; + uint8_t dummy[DVD_VIDEO_LB_LEN]; int i; /* Open the device */ - d->vmg = dvdplay_open( d->title->device, NULL, NULL ); + d->vmg = dvdplay_open( title->device, NULL, NULL ); if( !d->vmg ) { HBLog( "HBDVDRead: dvdplay_open() failed" ); HBErrorOccured( d->handle, HB_ERROR_DVD_OPEN ); return; - } - + } + /* Open the title */ - dvdplay_start( d->vmg, d->title->index ); + dvdplay_start( d->vmg, title->index ); d->beginPosition = dvdplay_title_first( d->vmg ); d->endPosition = dvdplay_title_end( d->vmg ); - + HBLog( "HBDVDRead: starting, blocks: %d to %d", d->beginPosition, d->endPosition ); - + /* Lalala */ dvdplay_read( d->vmg, dummy, 1 ); - + /* Do the job */ - for( i = 0; i < ( d->title->twoPass ? 2 : 1 ); i++ ) + for( i = 0; i < ( title->twoPass ? 2 : 1 ); i++ ) { dvdplay_seek( d->vmg, 0 ); - + HBLog( "HBDVDRead: starting pass %d of %d", i + 1, - d->title->twoPass ? 2 : 1 ); - - d->pass = d->title->twoPass ? ( i + 1 ) : 0; + title->twoPass ? 2 : 1 ); + + d->pass = title->twoPass ? ( i + 1 ) : 0; if( !DoPass( d ) ) { break; - } - } + } + } - /* Flag the latest buffers so we know when we're done */ if( !d->die ) { HBLog( "HBDVDRead: done" ); - - if( d->videoBuf ) - { - d->videoBuf->last = 1; - Push( d, d->title->mpeg2Fifo, &d->videoBuf ); - } - if( d->audioBuf ) - { - d->audioBuf->last = 1; - Push( d, d->audio->ac3Fifo, &d->audioBuf ); - } - if( d->optAudioBuf ) - { - d->optAudioBuf->last = 1; - Push( d, d->optAudio->ac3Fifo, &d->optAudioBuf ); - } + HBDone( d->handle ); } /* Clean up */ @@ -180,20 +148,20 @@ static int DoPass( HBDVDRead * d ) d->psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); d->psBuffer->position = (float) i / ( d->endPosition - d->beginPosition ); - + if( d->pass ) { d->psBuffer->position /= 2; - + if( d->pass == 2 ) { d->psBuffer->position += 0.5; } } d->psBuffer->pass = d->pass; - + if( dvdplay_read( d->vmg, d->psBuffer->data, 1 ) < 0 ) - { + { HBLog( "HBDVDRead: dvdplay_read() failed" ); HBErrorOccured( d->handle, HB_ERROR_DVD_READ ); HBBufferClose( &d->psBuffer ); @@ -211,7 +179,11 @@ static int DoPass( HBDVDRead * d ) static int Demux( HBDVDRead * d ) { + HBTitle * title = d->title; + + HBAudio * audio; HBBuffer * esBuffer; + int i; /* Demux */ HBPStoES( &d->psBuffer, d->esBufferList ); @@ -229,72 +201,48 @@ static int Demux( HBDVDRead * d ) if( esBuffer->streamId == 0xE0 ) { - if( d->videoStart < 0 ) + if( title->start < 0 ) { - d->videoStart = esBuffer->pts / 90; + title->start = esBuffer->pts / 90; HBLog( "HBDVDRead: got first 0xE0 packet (%d)", - d->videoStart ); + title->start ); } - if( d->videoBuf ) + HBListRemove( d->esBufferList, esBuffer ); + if( !Push( d, title->inFifo, &esBuffer ) ) { - d->videoBuf->last = 0; - if( !Push( d, d->title->mpeg2Fifo, &d->videoBuf ) ) - { - return 0; - } + return 0; } - - HBListRemove( d->esBufferList, esBuffer ); - d->videoBuf = esBuffer; + continue; } - else if( esBuffer->streamId == d->audio->id ) - { - if( d->audioStart < 0 ) - { - d->audioStart = esBuffer->pts / 90; - HBLog( "HBDVDRead: got first 0x%x packet (%d)", - d->audio->id, d->audioStart ); - d->audio->delay = d->audioStart - d->videoStart; - } + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); - if( d->audioBuf ) + if( esBuffer->streamId != audio->id ) { - d->audioBuf->last = 0; - if( !Push( d, d->audio->ac3Fifo, &d->audioBuf ) ) - { - return 0; - } + continue; } - HBListRemove( d->esBufferList, esBuffer ); - d->audioBuf = esBuffer; - } - else if( d->optAudio && esBuffer->streamId == d->optAudio->id ) - { - if( d->optAudioStart < 0 ) + if( audio->start < 0 ) { - d->optAudioStart = esBuffer->pts / 90; + audio->start = esBuffer->pts / 90; HBLog( "HBDVDRead: got first 0x%x packet (%d)", - d->optAudio->id, d->optAudioStart ); + audio->id, audio->start ); - d->optAudio->delay = d->optAudioStart - d->videoStart; + audio->delay = audio->start - title->start; } - if( d->optAudioBuf ) + HBListRemove( d->esBufferList, esBuffer ); + if( !Push( d, audio->inFifo, &esBuffer ) ) { - d->optAudioBuf->last = 0; - if( !Push( d, d->optAudio->ac3Fifo, &d->optAudioBuf ) ) - { - return 0; - } + return 0; } - - HBListRemove( d->esBufferList, esBuffer ); - d->optAudioBuf = esBuffer; + break; } - else + + if( esBuffer ) { HBListRemove( d->esBufferList, esBuffer ); HBBufferClose( &esBuffer ); @@ -303,24 +251,16 @@ static int Demux( HBDVDRead * d ) return 1; } - + static int Push( HBDVDRead * d, HBFifo * fifo, HBBuffer ** buffer ) { - for( ;; ) + while( !d->die ) { - HBCheckPaused( d->handle ); - if( HBFifoPush( fifo, buffer ) ) { return 1; } - - if( d->die ) - { - break; - } - - HBSnooze( 10000 ); + HBSnooze( 5000 ); } return 0; diff --git a/core/DVDRead.h b/core/DVDRead.h deleted file mode 100644 index 7a9aa7e21..000000000 --- a/core/DVDRead.h +++ /dev/null @@ -1,16 +0,0 @@ -/* $Id: DVDRead.h,v 1.1 2003/11/03 12:08:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_DVD_READ_H -#define HB_DVD_READ_H - -#include "HandBrakeInternal.h" - -HBDVDRead * HBDVDReadInit( HBHandle *, HBTitle *, - HBAudio *, HBAudio * ); -void HBDVDReadClose( HBDVDRead ** ); - -#endif diff --git a/core/FaacEnc.c b/core/FaacEnc.c new file mode 100644 index 000000000..b55a9deb6 --- /dev/null +++ b/core/FaacEnc.c @@ -0,0 +1,214 @@ +/* $Id: FaacEnc.c,v 1.15 2004/02/18 17:07:20 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "HBInternal.h" + +/* libfaac */ +#include "faac.h" + +typedef struct HBFaacEnc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBAudio * audio; + + faacEncHandle * faac; + unsigned long inputSamples; + unsigned long maxOutputBytes; + int32_t * inputBuffer; + unsigned long samplesGot; + HBBuffer * rawBuffer; + int rawBufferPos; /* in bytes */ + float position; + HBBuffer * aacBuffer; + + /* Stats */ + int64_t samples; + int64_t bytes; +} HBFaacEnc; + +/* Local prototypes */ +static int FaacEncWork( HBWork * ); +static int GetSamples( HBFaacEnc * ); + +HBWork * HBFaacEncInit( HBHandle * handle, HBAudio * audio ) +{ + HBFaacEnc * f; + if( !( f = calloc( sizeof( HBFaacEnc ), 1 ) ) ) + { + HBLog( "HBFaacEncInit: malloc() failed, gonna crash" ); + return NULL; + } + + f->name = strdup( "FaacEnc" ); + f->work = FaacEncWork; + + f->handle = handle; + f->audio = audio; + + return (HBWork*) f; +} + +void HBFaacEncClose( HBWork ** _f ) +{ + HBFaacEnc * f = (HBFaacEnc*) *_f; + + if( f->faac ) + { + faacEncClose( f->faac ); + free( f->inputBuffer ); + } + + if( f->samples ) + { + int64_t bytes = 128 * f->audio->outBitrate * f->samples / + f->audio->outSampleRate; + float bitrate = (float) f->bytes * f->audio->inSampleRate / + f->samples / 128; + + HBLog( "HBFaacEnc: %lld samples encoded (%lld bytes), %.2f kbps", + f->samples, f->bytes, bitrate ); + HBLog( "HBFaacEnc: error is %lld bytes", f->bytes - bytes ); + } + + free( f->name ); + free( f ); + + *_f = NULL; +} + +static int FaacEncWork( HBWork * w ) +{ + HBFaacEnc * f = (HBFaacEnc*) w; + HBAudio * audio = f->audio; + + int didSomething = 0; + + if( !f->faac ) + { + faacEncConfigurationPtr config; + + /* Get a first buffer so we know that audio->inSampleRate is + correct */ + if( ( f->rawBuffer = HBFifoPop( audio->rawFifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + f->rawBufferPos = 0; + f->position = f->rawBuffer->position; + + HBLog( "HBFaacEnc: opening libfaac (%x)", audio->id ); + + /* No resampling */ + audio->outSampleRate = audio->inSampleRate; + + f->faac = faacEncOpen( audio->outSampleRate, 2, + &f->inputSamples, &f->maxOutputBytes ); + f->inputBuffer = malloc( f->inputSamples * sizeof( int32_t ) ); + config = faacEncGetCurrentConfiguration( f->faac ); + config->mpegVersion = MPEG4; + config->aacObjectType = LOW; + config->allowMidside = 1; + config->useLfe = 0; + config->useTns = 0; + config->bitRate = audio->outBitrate * 512; + config->bandWidth = 0; + config->outputFormat = 0; + faacEncSetConfiguration( f->faac, config ); + faacEncGetDecoderSpecificInfo( f->faac, &audio->esConfig, + &audio->esConfigLength ); + } + + /* Push encoded buffer */ + if( f->aacBuffer ) + { + if( HBFifoPush( audio->outFifo, &f->aacBuffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + if( GetSamples( f ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + f->samplesGot = 0; + + f->aacBuffer = HBBufferInit( f->maxOutputBytes ); + f->aacBuffer->position = f->position; + f->aacBuffer->size = faacEncEncode( f->faac, f->inputBuffer, + f->inputSamples, f->aacBuffer->data, f->maxOutputBytes ); + + f->samples += f->inputSamples / 2; + + if( !f->aacBuffer->size ) + { + HBBufferClose( &f->aacBuffer ); + } + else if( f->aacBuffer->size < 0 ) + { + HBLog( "HBFaacEnc: faacEncEncode() failed" ); + } + else + { + f->bytes += f->aacBuffer->size; + } + + return didSomething; +} + +static int GetSamples( HBFaacEnc * f ) +{ + while( f->samplesGot < f->inputSamples ) + { + int i, copy; + + if( !f->rawBuffer ) + { + if( !( f->rawBuffer = HBFifoPop( f->audio->rawFifo ) ) ) + { + return 0; + } + + f->rawBufferPos = 0; + f->position = f->rawBuffer->position; + } + + copy = MIN( f->inputSamples - f->samplesGot, + ( f->rawBuffer->samples - f->rawBufferPos ) * 2 ); + + for( i = 0; i < copy; i += 2 ) + { + f->inputBuffer[f->samplesGot++] = + f->rawBuffer->left[f->rawBufferPos]; + f->inputBuffer[f->samplesGot++] = + f->rawBuffer->right[f->rawBufferPos]; + f->rawBufferPos++; + } + + if( f->rawBufferPos == f->rawBuffer->samples ) + { + HBBufferClose( &f->rawBuffer ); + } + } + + return 1; +} + diff --git a/core/FfmpegEnc.c b/core/FfmpegEnc.c index 2118c29d6..4028dc5fb 100644 --- a/core/FfmpegEnc.c +++ b/core/FfmpegEnc.c @@ -1,38 +1,40 @@ -/* $Id: FfmpegEnc.c,v 1.5 2003/11/06 13:03:19 titer Exp $ +/* $Id: FfmpegEnc.c,v 1.18 2004/01/21 17:59:33 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "FfmpegEnc.h" -#include "Fifo.h" -#include "Work.h" +#include "HBInternal.h" -#include <ffmpeg/avcodec.h> +/* libavcodec */ +#include "ffmpeg/avcodec.h" -/* Extern functions */ -void HBSetPosition( HBHandle *, float ); - -/* Local prototypes */ -static int FfmpegEncWork( HBWork * ); - -struct HBFfmpegEnc +typedef struct HBFfmpegEnc { HB_WORK_COMMON_MEMBERS - HBHandle * handle; - HBTitle * title; + HBHandle * handle; + HBTitle * title; - HBBuffer * mpeg4Buffer; - int pass; + HBBuffer * mpeg4Buffer; + int pass; AVCodecContext * context; - FILE * file; -}; + FILE * file; + + /* Stats */ + int frames; + int64_t bytes; +} HBFfmpegEnc; -HBFfmpegEnc * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) +/* Local prototypes */ +static int FfmpegEncWork( HBWork * ); +static int InitAvcodec( HBFfmpegEnc * ); +static void CloseAvcodec( HBFfmpegEnc * ); + +HBWork * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) { HBFfmpegEnc * f; - if( !( f = malloc( sizeof( HBFfmpegEnc ) ) ) ) + if( !( f = calloc( sizeof( HBFfmpegEnc ), 1 ) ) ) { HBLog( "HBFfmpegEncInit: malloc() failed, gonna crash" ); return NULL; @@ -42,31 +44,32 @@ HBFfmpegEnc * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) f->work = FfmpegEncWork; f->handle = handle; - f->title = title; - - f->mpeg4Buffer = NULL; - f->pass = 42; - f->context = NULL; - f->file = NULL; + f->title = title; + f->pass = 42; - return f; + return (HBWork*) f; } -void HBFfmpegEncClose( HBFfmpegEnc ** _f ) +void HBFfmpegEncClose( HBWork ** _f ) { - HBFfmpegEnc * f = *_f; + HBFfmpegEnc * f = (HBFfmpegEnc*) *_f; if( f->context ) { - HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", - f->pass ); + CloseAvcodec( f ); + } - avcodec_close( f->context ); - if( f->file ) - { - fclose( f->file ); - f->file = NULL; - } + /* Stats */ + if( f->frames ) + { + float bitrate = (float) f->bytes * f->title->rate / + f->frames / f->title->rateBase / 128; + int64_t bytes = (int64_t) f->frames * f->title->bitrate * 128 * + f->title->rateBase / f->title->rate; + + HBLog( "HBFfmpegEnc: %d frames encoded (%lld bytes), %.2f kbps", + f->frames, f->bytes, bitrate ); + HBLog( "HBFfmpegEnc: error is %lld bytes", f->bytes - bytes ); } free( f->name ); free( f ); @@ -87,7 +90,7 @@ static int FfmpegEncWork( HBWork * w ) if( f->mpeg4Buffer ) { - if( HBFifoPush( title->mpeg4Fifo, &f->mpeg4Buffer ) ) + if( HBFifoPush( title->outFifo, &f->mpeg4Buffer ) ) { didSomething = 1; } @@ -109,94 +112,26 @@ static int FfmpegEncWork( HBWork * w ) /* Init or re-init if needed */ if( scaledBuffer->pass != f->pass ) { - AVCodec * codec; - AVCodecContext * context; - if( f->context ) { - HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", - f->pass ); - - avcodec_close( f->context ); - if( f->file ) - { - fclose( f->file ); - f->file = NULL; - } + CloseAvcodec( f ); } - + f->pass = scaledBuffer->pass; - - HBLog( "HBFfmpegEnc: opening libavcodec (pass %d)", f->pass ); - codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); - if( !codec ) + + if( !InitAvcodec( f ) ) { - HBLog( "HBFfmpegEnc: avcodec_find_encoder() failed" ); HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); return didSomething; } - - context = avcodec_alloc_context(); - context->bit_rate = 1024 * title->bitrate; - context->bit_rate_tolerance = 10240 * title->bitrate; - context->width = title->outWidth; - context->height = title->outHeight; - context->frame_rate = title->rate; - context->frame_rate_base = title->rateBase; - context->gop_size = 10 * title->rate / - title->rateBase; - - if( f->pass ) - { - char fileName[1024]; memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", - HBGetPid( f->handle ) ); - - if( f->pass == 1 ) - { - f->file = fopen( fileName, "w" ); - - context->flags |= CODEC_FLAG_PASS1; - } - else - { - FILE * file; - int size; - char * log; - - file = fopen( fileName, "r" ); - fseek( file, 0, SEEK_END ); - size = ftell( file ); - fseek( file, 0, SEEK_SET ); - if( !( log = malloc( size + 1 ) ) ) - { - HBLog( "HBFfmpegEnc: malloc() failed, gonna crash" ); - } - log[size] = '\0'; - fread( log, size, 1, file ); - fclose( file ); - - context->flags |= CODEC_FLAG_PASS2; - context->stats_in = log; - } - } - - if( avcodec_open( context, codec ) < 0 ) - { - HBLog( "HBFfmpegEnc: avcodec_open() failed" ); - HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); - return didSomething; - } - - f->context = context; } - frame = avcodec_alloc_frame(); - frame->data[0] = scaledBuffer->data; - frame->data[1] = frame->data[0] + title->outWidth * - title->outHeight; - frame->data[2] = frame->data[1] + title->outWidth * - title->outHeight / 4; + frame = avcodec_alloc_frame(); + frame->data[0] = scaledBuffer->data; + frame->data[1] = frame->data[0] + title->outWidth * + title->outHeight; + frame->data[2] = frame->data[1] + title->outWidth * + title->outHeight / 4; frame->linesize[0] = title->outWidth; frame->linesize[1] = title->outWidth / 2; frame->linesize[2] = title->outWidth / 2; @@ -204,9 +139,8 @@ static int FfmpegEncWork( HBWork * w ) mpeg4Buffer = HBBufferInit( 3 * title->outWidth * title->outHeight / 2 ); mpeg4Buffer->position = scaledBuffer->position; - mpeg4Buffer->size = - avcodec_encode_video( f->context, mpeg4Buffer->data, - mpeg4Buffer->alloc, frame ); + mpeg4Buffer->size = avcodec_encode_video( f->context, + mpeg4Buffer->data, mpeg4Buffer->alloc, frame ); mpeg4Buffer->keyFrame = f->context->coded_frame->key_frame; /* Inform the GUI about the current position */ @@ -220,11 +154,128 @@ static int FfmpegEncWork( HBWork * w ) } HBBufferClose( &mpeg4Buffer ); } + else + { + f->mpeg4Buffer = mpeg4Buffer; + + /* Stats */ + f->frames++; + f->bytes += mpeg4Buffer->size; + } HBBufferClose( &scaledBuffer ); free( frame ); - f->mpeg4Buffer = mpeg4Buffer; - return didSomething; } + +static int InitAvcodec( HBFfmpegEnc * f ) +{ + AVCodec * codec; + AVCodecContext * context; + HBTitle * title = f->title; + + HBLog( "HBFfmpegEnc: opening libavcodec (pass %d)", f->pass ); + + codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); + if( !codec ) + { + HBLog( "HBFfmpegEnc: avcodec_find_encoder() failed" ); + HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); + return 0; + } + + context = avcodec_alloc_context(); + context->bit_rate = 1024 * title->bitrate; + context->bit_rate_tolerance = 10 * context->bit_rate; + context->width = title->outWidth; + context->height = title->outHeight; + context->frame_rate = title->rate; + context->frame_rate_base = title->rateBase; + context->gop_size = 10 * title->rate / title->rateBase; + + if( title->mux == HB_MUX_MP4 && f->pass != 1 ) + { + context->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + + if( f->pass ) + { + char fileName[1024]; memset( fileName, 0, 1024 ); + sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", + HBGetPid( f->handle ) ); + + if( f->pass == 1 ) + { + f->file = fopen( fileName, "w" ); + context->flags |= CODEC_FLAG_PASS1; + } + else + { + FILE * file; + int size; + char * log; + + file = fopen( fileName, "r" ); + fseek( file, 0, SEEK_END ); + size = ftell( file ); + fseek( file, 0, SEEK_SET ); + if( !( log = malloc( size + 1 ) ) ) + { + HBLog( "HBFfmpegEnc: malloc() failed, gonna crash" ); + } + log[size] = '\0'; + fread( log, size, 1, file ); + fclose( file ); + + context->flags |= CODEC_FLAG_PASS2; + context->stats_in = log; + } + } + +#ifdef HB_NOMMX + context->dct_algo = FF_DCT_INT; + context->idct_algo = FF_IDCT_INT; + context->dsp_mask = 0x1F; +#endif + + if( avcodec_open( context, codec ) < 0 ) + { + HBLog( "HBFfmpegEnc: avcodec_open() failed" ); + return 0; + } + + if( title->mux == HB_MUX_MP4 && f->pass != 1 ) + { + /* UGLY */ + title->esConfig = malloc( 15 ); + title->esConfigLength = 15; + memcpy( title->esConfig, context->extradata + 15, 15 ); + } + + f->context = context; + return 1; +} + +static void CloseAvcodec( HBFfmpegEnc * f ) +{ + HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", + f->pass ); + + if( f->context->stats_in ) + { + free( f->context->stats_in ); + } + avcodec_close( f->context ); + if( f->file ) + { + fclose( f->file ); + f->file = NULL; + } + if( f->title->esConfig ) + { + free( f->title->esConfig ); + f->title->esConfigLength = 0; + } +} + diff --git a/core/FfmpegEnc.h b/core/FfmpegEnc.h deleted file mode 100644 index 8ab622011..000000000 --- a/core/FfmpegEnc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: FfmpegEnc.h,v 1.1 2003/11/03 12:08:01 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_FFMPEG_ENC_H -#define HB_FFMPEG_ENC_H - -#include "HandBrakeInternal.h" - -HBFfmpegEnc * HBFfmpegEncInit( HBHandle *, HBTitle * ); -void HBFfmpegEncClose( HBFfmpegEnc ** ); - -#endif diff --git a/core/Fifo.c b/core/Fifo.c index 74658d5d8..af6d90cfe 100644 --- a/core/Fifo.c +++ b/core/Fifo.c @@ -1,4 +1,4 @@ -/* $Id: Fifo.c,v 1.3 2003/11/09 14:27:56 titer Exp $ +/* $Id: Fifo.c,v 1.8 2004/01/16 19:04:03 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,7 +9,7 @@ HBBuffer * HBBufferInit( int size ) { HBBuffer * b; - if( !( b = malloc( sizeof( HBBuffer ) ) ) ) + if( !( b = calloc( sizeof( HBBuffer ), 1 ) ) ) { HBLog( "HBBufferInit: malloc() failed, gonna crash" ); return NULL; @@ -26,11 +26,6 @@ HBBuffer * HBBufferInit( int size ) } b->position = 0.0; - b->streamId = 0; - b->keyFrame = 0; - b->pts = 0; - b->pass = 0; - b->last = 0; return b; } @@ -49,7 +44,7 @@ void HBBufferReAlloc( HBBuffer * b, int size ) void HBBufferClose( HBBuffer ** _b ) { HBBuffer * b = *_b; - + free( b->data ); free( b ); @@ -65,6 +60,7 @@ HBFifo * HBFifoInit( int capacity ) return NULL; } + f->die = 0; f->capacity = capacity; f->whereToPush = 0; f->whereToPop = 0; @@ -75,22 +71,23 @@ HBFifo * HBFifoInit( int capacity ) free( f ); return NULL; } - + f->lock = HBLockInit(); + f->cond = HBCondInit(); return f; } -int HBFifoSize( HBFifo * f ) +void HBFifoDie( HBFifo * f ) { - return ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % - ( f->capacity + 1 ); + f->die = 1; + HBCondSignal( f->cond ); } void HBFifoClose( HBFifo ** _f ) { HBFifo * f = (*_f); - + HBLog( "HBFifoClose: trashing %d buffer%s", HBFifoSize( f ), ( HBFifoSize( f ) > 1 ) ? "s" : "" ); @@ -102,6 +99,7 @@ void HBFifoClose( HBFifo ** _f ) } HBLockClose( &f->lock ); + HBCondClose( &f->cond ); free( f->buffers ); free( f ); diff --git a/core/Fifo.h b/core/Fifo.h index 758125ebd..d9240fb25 100644 --- a/core/Fifo.h +++ b/core/Fifo.h @@ -1,4 +1,4 @@ -/* $Id: Fifo.h,v 1.3 2003/11/06 13:07:52 titer Exp $ +/* $Id: Fifo.h,v 1.10 2004/01/16 19:04:04 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -12,16 +12,27 @@ struct HBBuffer { + /* Members used everywhere */ int alloc; int size; uint8_t * data; - float position; + int pass; + + /* Only used for PStoES */ int streamId; - int keyFrame; uint64_t pts; - int pass; - int last; + + /* NTSC suxx */ + int repeat; + + /* Only used for raw audio buffers */ + int samples; /* Number of samples for each track */ + float * left; + float * right; + + /* Only used for MPEG-4, MP3 and AAC buffers */ + int keyFrame; }; HBBuffer * HBBufferInit( int size ); @@ -30,24 +41,40 @@ void HBBufferClose( HBBuffer ** ); struct HBFifo { + int die; int capacity; int whereToPush; int whereToPop; HBBuffer ** buffers; HBLock * lock; + HBCond * cond; }; HBFifo * HBFifoInit( int capacity ); -int HBFifoSize( HBFifo * ); +static inline int HBFifoSize( HBFifo * ); static inline int HBFifoPush( HBFifo *, HBBuffer ** ); static inline HBBuffer * HBFifoPop( HBFifo * ); +static inline int HBFifoWait( HBFifo * ); +static inline float HBFifoPosition( HBFifo * ); +void HBFifoDie( HBFifo * ); void HBFifoClose( HBFifo ** ); -static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) +static inline int HBFifoSize( HBFifo * f ) { + int size; HBLockLock( f->lock ); + size = ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % + ( f->capacity + 1 ); + HBLockUnlock( f->lock ); + return size; +} - if( HBFifoSize( f ) < f->capacity ) +static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) +{ + HBLockLock( f->lock ); + HBCondSignal( f->cond ); + if( ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % + ( f->capacity + 1 ) != f->capacity ) { f->buffers[f->whereToPush] = *b; f->whereToPush++; @@ -56,7 +83,6 @@ static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) *b = NULL; return 1; } - HBLockUnlock( f->lock ); return 0; } @@ -64,7 +90,6 @@ static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) static inline HBBuffer * HBFifoPop( HBFifo * f ) { HBLockLock( f->lock ); - if( f->whereToPush != f->whereToPop ) { HBBuffer * b = f->buffers[f->whereToPop]; @@ -73,9 +98,47 @@ static inline HBBuffer * HBFifoPop( HBFifo * f ) HBLockUnlock( f->lock ); return b; } - HBLockUnlock( f->lock ); return NULL; } +static inline int HBFifoWait( HBFifo * f ) +{ + HBLockLock( f->lock ); + if( f->whereToPush != f->whereToPop ) + { + HBLockUnlock( f->lock ); + return 1; + } + if( f->die ) + { + HBLockUnlock( f->lock ); + return 0; + } + HBCondWait( f->cond, f->lock ); + if( f->whereToPush != f->whereToPop ) + { + HBLockUnlock( f->lock ); + return 1; + } + HBLockUnlock( f->lock ); + return 0; +} + +static inline float HBFifoPosition( HBFifo * f ) +{ + float pos; + HBLockLock( f->lock ); + if( f->whereToPush != f->whereToPop ) + { + pos = f->buffers[f->whereToPop]->position; + } + else + { + pos = 0.0; + } + HBLockUnlock( f->lock ); + return pos; +} + #endif diff --git a/core/HBInternal.h b/core/HBInternal.h new file mode 100644 index 000000000..169451980 --- /dev/null +++ b/core/HBInternal.h @@ -0,0 +1,81 @@ +/* $Id: HBInternal.h,v 1.4 2004/01/16 20:55:21 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#ifndef HB_INTERNAL_H +#define HB_INTERNAL_H + +#include "HandBrake.h" +#include "Fifo.h" +#include "Thread.h" +#include "Work.h" + +/* Demuxer */ +HBDVDRead * HBDVDReadInit( HBHandle *, HBTitle * ); +void HBDVDReadClose( HBDVDRead ** ); + +/* Decoders */ +HBWork * HBMpeg2DecInit( HBHandle *, HBTitle * ); +void HBMpeg2DecClose( HBWork ** ); +HBWork * HBAc3DecInit( HBHandle *, HBAudio * ); +void HBAc3DecClose( HBWork ** ); +HBWork * HBMadDecInit( HBHandle *, HBAudio * ); +void HBMadDecClose( HBWork ** ); + +/* Scaler */ +HBWork * HBScaleInit( HBHandle *, HBTitle * ); +void HBScaleClose( HBWork ** ); + +/* Encoders */ +HBWork * HBFfmpegEncInit( HBHandle *, HBTitle * ); +void HBFfmpegEncClose( HBWork ** ); +HBWork * HBXvidEncInit( HBHandle *, HBTitle * ); +void HBXvidEncClose( HBWork ** ); +HBWork * HBX264EncInit( HBHandle *, HBTitle * ); +void HBX264EncClose( HBWork ** ); +HBWork * HBMp3EncInit( HBHandle *, HBAudio * ); +void HBMp3EncClose( HBWork ** ); +HBWork * HBFaacEncInit( HBHandle *, HBAudio * ); +void HBFaacEncClose( HBWork ** ); +HBWork * HBVorbisEncInit ( HBHandle *, HBAudio * ); +void HBVorbisEncClose( HBWork ** ); + +/* Muxers */ +HBAviMux * HBAviMuxInit( HBHandle *, HBTitle * ); +void HBAviMuxClose( HBAviMux ** ); +HBMp4Mux * HBMp4MuxInit( HBHandle *, HBTitle * ); +void HBMp4MuxClose( HBMp4Mux ** ); +HBOgmMux * HBOgmMuxInit( HBHandle *, HBTitle * ); +void HBOgmMuxClose( HBOgmMux ** ); + +/* Scanner */ +HBScan * HBScanInit( HBHandle *, const char * device, int title ); +void HBScanClose( HBScan ** ); + +/* Called by HBScan to tell the GUI how far we've been */ +void HBScanning( HBHandle *, int title, int titleCount ); + +/* Called by HBScan. titleList is a list of all valid titles which + should be shown on the interface */ +void HBScanDone( HBHandle *, HBList * titleList ); + +/* Used to create temporary files (/tmp/HB.pid.whatever) */ +int HBGetPid( HBHandle * ); + +/* Called by every thread involved in the rip process. Returns + immediately is rip isn't paused, blocks until the rip is resumed + otherwise */ +void HBCheckPaused( HBHandle * ); + +/* Called by the decoders when the last packet is being proceeded */ +void HBDone( HBHandle * ); + +/* Called by the video encoder to update the GUI progress */ +void HBPosition( HBHandle *, float ); + +/* Called by any thread which couldn't continue and asks to stop */ +void HBErrorOccured( HBHandle *, int error ); + +#endif diff --git a/core/HandBrake.c b/core/HandBrake.c index c76a27b3c..010f1a3cf 100644 --- a/core/HandBrake.c +++ b/core/HandBrake.c @@ -1,25 +1,13 @@ -/* $Id: HandBrake.c,v 1.18 2003/11/13 01:17:33 titer Exp $ +/* $Id: HandBrake.c,v 1.42 2004/02/18 17:07:20 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "HandBrakeInternal.h" +#include "HBInternal.h" -#include <ffmpeg/avcodec.h> - -#include "Ac3Dec.h" -#include "AviMux.h" -#include "DVDRead.h" -#include "FfmpegEnc.h" -#include "Fifo.h" -#include "Mp3Enc.h" -#include "Mpeg2Dec.h" -#include "Scale.h" -#include "Scan.h" -#include "Thread.h" -#include "Work.h" -#include "XvidEnc.h" +/* libavcodec */ +#include "ffmpeg/avcodec.h" /* Local prototypes */ static void HandBrakeThread( void * ); @@ -29,39 +17,37 @@ static int GetCPUCount(); struct HBHandle { - HBThread * thread; - int die; - int pid; - - int cpuCount; - - int stopScan; - int stopRip; - int ripDone; - int error; - - HBScan * scan; - - HBLock * lock; - HBStatus status; - int modeChanged; - HBTitle * curTitle; - HBAudio * curAudio; - HBAudio * curOptAudio; - - int frames; - uint64_t beginDate; - int framesSinceFpsUpdate; - uint64_t lastFpsUpdate; - uint64_t pauseDate; - - HBLock * pauseLock; + int cpuCount; + HBCallbacks cb; + + int stopScan; + int stopRip; + int ripDone; + int error; + + HBScan * scan; + HBList * titleList; + HBTitle * curTitle; + uint64_t beginDate; + uint64_t pauseDate; + uint64_t lastPosUpdate; + uint64_t lastFpsUpdate; + int framesSinceBegin; + int framesSinceFps; + float curFrameRate; + float avgFrameRate; + int remainingTime; + + HBLock * pauseLock; + volatile int die; + HBThread * thread; + int pid; }; HBHandle * HBInit( int debug, int cpuCount ) { HBHandle * h; - if( !( h = malloc( sizeof( HBHandle ) ) ) ) + if( !( h = calloc( sizeof( HBHandle ), 1 ) ) ) { HBLog( "HBInit: malloc() failed, gonna crash" ); return NULL; @@ -105,190 +91,105 @@ HBHandle * HBInit( int debug, int cpuCount ) h->cpuCount = cpuCount; } } - - /* Initializations */ - h->stopScan = 0; - h->stopRip = 0; - h->ripDone = 0; - h->error = 0; - - h->scan = NULL; - - h->lock = HBLockInit(); - h->modeChanged = 1; - h->status.mode = HB_MODE_NEED_DEVICE; - h->status.titleList = NULL; - h->curTitle = NULL; - h->curAudio = NULL; - h->curOptAudio = NULL; h->pauseLock = HBLockInit(); - - h->die = 0; - h->thread = HBThreadInit( "libhb", HandBrakeThread, h, - HB_NORMAL_PRIORITY ); - + h->thread = HBThreadInit( "libhb", HandBrakeThread, h, + HB_NORMAL_PRIORITY ); return h; } -int HBGetStatus( HBHandle * h, HBStatus * status ) +void HBSetCallbacks( HBHandle * h, HBCallbacks callbacks ) { - HBLockLock( h->lock ); - memcpy( status, &h->status, sizeof( HBStatus ) ); - - if( !h->modeChanged ) - { - HBLockUnlock( h->lock ); - return 0; - } - - h->modeChanged = 0; - HBLockUnlock( h->lock ); - return 1; + h->cb = callbacks; } -void HBScanDevice( HBHandle * h, char * device, int title ) +void HBScanDVD( HBHandle * h, const char * dvd, int title ) { - if( !( h->status.mode & ( HB_MODE_NEED_DEVICE | - HB_MODE_INVALID_DEVICE ) ) ) - { - HBLog( "HBScanDevice: current mode is %d, aborting", - h->status.mode ); - return; - } - - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_SCANNING; - h->status.scannedTitle = 0; - HBLockUnlock( h->lock ); - - h->scan = HBScanInit( h, device, title ); + h->scan = HBScanInit( h, dvd, title ); } -void HBStartRip( HBHandle * h, HBTitle * t, - HBAudio * a1, HBAudio * a2 ) +void HBStartRip( HBHandle * h, HBTitle * title ) { int i; - - if( !( h->status.mode & ( HB_MODE_READY_TO_RIP | HB_MODE_DONE | - HB_MODE_CANCELED | HB_MODE_ERROR ) ) ) - { - HBLog( "HBStartRip: current mode is %d, aborting", - h->status.mode ); - return; + HBAudio * audio; + + h->beginDate = HBGetDate(); + h->lastPosUpdate = 0; + h->lastFpsUpdate = 0; + h->framesSinceBegin = 0; + h->framesSinceFps = 0; + + FixPictureSettings( title ); + + /* Video fifos */ + title->inFifo = HBFifoInit( 1024 ); + title->rawFifo = HBFifoInit( 1 ); + title->scaledFifo = HBFifoInit( 1 ); + title->outFifo = HBFifoInit( 1 ); + + /* Video work objects */ + title->decoder = HBMpeg2DecInit( h, title ); + title->scale = HBScaleInit( h, title ); + if( title->codec == HB_CODEC_FFMPEG ) + title->encoder = HBFfmpegEncInit( h, title ); + else if( title->codec == HB_CODEC_XVID ) + title->encoder = HBXvidEncInit( h, title ); + else if( title->codec == HB_CODEC_X264 ) + title->encoder = HBX264EncInit( h, title ); + + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + + /* Audio fifos */ + audio->inFifo = HBFifoInit( 1024 ); + audio->rawFifo = HBFifoInit( 1 ); + audio->outFifo = HBFifoInit( 4 ); /* At least 4 for Vorbis */ + + /* Audio work objects */ + audio->decoder = HBAc3DecInit( h, audio ); + if( audio->codec == HB_CODEC_MP3 ) + audio->encoder = HBMp3EncInit( h, audio ); + else if( audio->codec == HB_CODEC_AAC ) + audio->encoder = HBFaacEncInit( h, audio ); + else if( audio->codec == HB_CODEC_VORBIS ) + audio->encoder = HBVorbisEncInit( h, audio ); } - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_ENCODING; - h->status.position = 0.0; - h->status.pass = 1; - h->status.passCount = t->twoPass ? 2 : 1; - h->frames = 0; - h->framesSinceFpsUpdate = 0; - HBLockUnlock( h->lock ); - - FixPictureSettings( t ); + /* Create threads */ + title->dvdRead = HBDVDReadInit( h, title ); - /* Create fifos */ - t->mpeg2Fifo = HBFifoInit( 1024 ); - t->rawFifo = HBFifoInit( 1 ); - t->scaledFifo = HBFifoInit( 1 ); - t->mpeg4Fifo = HBFifoInit( 1 ); - a1->ac3Fifo = HBFifoInit( 1024 ); - a1->rawFifo = HBFifoInit( 1 ); - a1->mp3Fifo = HBFifoInit( 1 ); - if( a2 ) - { - a2->ac3Fifo = HBFifoInit( 1024 ); - a2->rawFifo = HBFifoInit( 1 ); - a2->mp3Fifo = HBFifoInit( 1 ); - } + if( title->mux == HB_MUX_AVI ) + title->aviMux = HBAviMuxInit( h, title ); + else if( title->mux == HB_MUX_MP4 ) + title->mp4Mux = HBMp4MuxInit( h, title ); + else if( title->mux == HB_MUX_OGM ) + title->ogmMux = HBOgmMuxInit( h, title ); - /* Create work objects */ - t->mpeg2Dec = HBMpeg2DecInit( h, t ); - t->scale = HBScaleInit( h, t ); - - if( t->codec == HB_CODEC_FFMPEG ) - t->ffmpegEnc = HBFfmpegEncInit( h, t ); - else if( t->codec == HB_CODEC_XVID ) - t->xvidEnc = HBXvidEncInit( h, t ); - - a1->ac3Dec = HBAc3DecInit( h, a1 ); - a1->mp3Enc = HBMp3EncInit( h, a1 ); - if( a2 ) - { - a2->ac3Dec = HBAc3DecInit( h, a2 ); - a2->mp3Enc = HBMp3EncInit( h, a2 ); - } - - /* Create threads */ - t->dvdRead = HBDVDReadInit( h, t, a1, a2 ); - t->aviMux = HBAviMuxInit( h, t, a1, a2 ); for( i = 0; i < h->cpuCount; i++ ) { - t->workThreads[i] = HBWorkThreadInit( h, t, a1, a2, i ? 0 : 1 ); + title->workThreads[i] = HBWorkThreadInit( h, title, i ? 0 : 1 ); } - h->curTitle = t; - h->curAudio = a1; - h->curOptAudio = a2; + h->curTitle = title; } void HBPauseRip( HBHandle * h ) { - if( h->status.mode != HB_MODE_ENCODING ) - { - HBLog( "HBPauseRip: current mode is %d, aborting", - h->status.mode ); - return; - } - h->pauseDate = HBGetDate(); HBLockLock( h->pauseLock ); - HBLockLock( h->lock ); - h->status.mode = HB_MODE_PAUSED; - h->modeChanged = 1; - HBLockUnlock( h->lock ); } void HBResumeRip( HBHandle * h ) { - if( h->status.mode != HB_MODE_PAUSED ) - { - HBLog( "HBResumeRip: current mode is %d, aborting", - h->status.mode ); - return; - } - h->beginDate += HBGetDate() - h->pauseDate; + h->lastPosUpdate += HBGetDate() - h->pauseDate; h->lastFpsUpdate += HBGetDate() - h->pauseDate; HBLockUnlock( h->pauseLock ); - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_ENCODING; - HBLockUnlock( h->lock ); } void HBStopRip( HBHandle * h ) { - if( !( h->status.mode & ( HB_MODE_ENCODING | HB_MODE_PAUSED ) ) ) - { - HBLog( "HBStopRip: current mode is %d, aborting", - h->status.mode ); - return; - } - - if( h->status.mode & HB_MODE_PAUSED ) - { - HBLockUnlock( h->pauseLock ); - } - - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_STOPPING; - HBLockUnlock( h->lock ); h->stopRip = 1; } @@ -314,7 +215,7 @@ uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) HBLog( "HBGetPreview: malloc() failed, gonna crash" ); return NULL; } - + /* Original YUV picture */ avpicture_fill( &pic1, buf1, PIX_FMT_YUV420P, t->inWidth, t->inHeight ); @@ -393,7 +294,7 @@ uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) for( i = 0; i < t->outHeight; i++ ) { uint8_t * nextLine = pen + 4 * ( t->outWidthMax + 2 ); - + memset( pen, 0xFF, 4 ); pen += 4; memcpy( pen, buf4 + 4 * t->outWidth * i, 4 * t->outWidth ); @@ -415,48 +316,90 @@ uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) return NULL; } +int HBGetBitrateForSize( HBTitle * title, int size, int muxer, + int audioCount, int audioBitrate ) +{ + int64_t available; + int overheadPerFrame; + int sampleRate; + int samplesPerFrame; + + switch( muxer ) + { + case HB_MUX_MP4: + overheadPerFrame = 5; /* hopefully */ + sampleRate = 48000; /* No resampling */ + samplesPerFrame = 1024; /* AAC */ + break; + case HB_MUX_AVI: + overheadPerFrame = 24; + sampleRate = 44100; /* Resampling */ + samplesPerFrame = 1152; /* MP3 */ + break; + case HB_MUX_OGM: + overheadPerFrame = 0; /* XXX */ + sampleRate = 48000; /* No resampling */ + samplesPerFrame = 1024; /* Vorbis */ + break; + default: + return 0; + } + + /* Actually target 1 MB less */ + available = (int64_t) ( size - 1 ) * 1024 * 1024; + + /* Audio data */ + available -= audioCount * title->length * audioBitrate * 128; + + /* Video headers */ + available -= (int64_t) title->length * title->rate * + overheadPerFrame / title->rateBase; + + /* Audio headers */ + available -= (int64_t) audioCount * title->length * sampleRate * + overheadPerFrame / samplesPerFrame; + + if( available < 0 ) + { + return 0; + } + return( available / ( 128 * title->length ) ); +} + void HBClose( HBHandle ** _h ) { char command[1024]; - + HBHandle * h = *_h; - + h->die = 1; HBThreadClose( &h->thread ); - if( h->status.mode == HB_MODE_SCANNING ) + if( h->scan ) { HBScanClose( &h->scan ); } - else if( h->status.mode == HB_MODE_PAUSED ) + if( h->curTitle ) { - HBLockUnlock( h->pauseLock ); _StopRip( h ); } - else if( h->status.mode == HB_MODE_ENCODING ) + if( h->titleList ) { - _StopRip( h ); + HBTitle * title; + while( ( title = (HBTitle*) HBListItemAt( h->titleList, 0 ) ) ) + { + HBListRemove( h->titleList, title ); + HBTitleClose( &title ); + } } memset( command, 0, 1024 ); sprintf( command, "rm -f /tmp/HB.%d.*", h->pid ); system( command ); - if( h->status.titleList ) - { - HBTitle * title; - while( ( title = HBListItemAt( h->status.titleList, 0 ) ) ) - { - HBListRemove( h->status.titleList, title ); - HBTitleClose( &title ); - } - HBListClose( &h->status.titleList ); - } - - HBLockClose( &h->lock ); HBLockClose( &h->pauseLock ); free( h ); - + *_h = NULL; } @@ -467,17 +410,16 @@ void HBCheckPaused( HBHandle * h ) HBLockUnlock( h->pauseLock ); } -void HBScanning( HBHandle * h, int title ) +void HBScanning( HBHandle * h, int title, int titleCount ) { - HBLockLock( h->lock ); - h->status.scannedTitle = title; - HBLockUnlock( h->lock ); + h->cb.scanning( h->cb.data, title, titleCount ); } void HBScanDone( HBHandle * h, HBList * titleList ) { - h->status.titleList = titleList; - h->stopScan = 1; + h->stopScan = 1; + h->titleList = titleList; + h->cb.scanDone( h->cb.data, titleList ); } int HBGetPid( HBHandle * h ) @@ -492,59 +434,47 @@ void HBDone( HBHandle * h ) void HBPosition( HBHandle * h, float position ) { - if( !h->frames ) - { - h->beginDate = HBGetDate(); - h->lastFpsUpdate = h->beginDate; - } - - h->frames++; - h->framesSinceFpsUpdate++; - - HBLockLock( h->lock ); - h->status.position = position; + int pass, passCount; + + h->framesSinceBegin++; + h->framesSinceFps++; + if( h->curTitle->twoPass ) { - h->status.pass = ( position < 0.5 ) ? 1 : 2; + pass = ( position < 0.5 ) ? 1 : 2; + passCount = 2; } else { - h->status.pass = 1; + passCount = pass = 1; } + if( HBGetDate() - h->lastPosUpdate < 200000 ) + return; + + h->lastPosUpdate = HBGetDate(); + if( HBGetDate() - h->lastFpsUpdate > 1000000 ) { - h->status.frameRate = 1000000.0 * h->framesSinceFpsUpdate / - ( HBGetDate() - h->lastFpsUpdate ); - h->status.avFrameRate = 1000000.0 * h->frames / - ( HBGetDate() - h->beginDate ); - h->status.remainingTime = ( 1.0 - h->status.position ) * - ( HBGetDate() - h->beginDate ) / - h->status.position / 1000000; - - HBLog( "Progress: %.2f %%", position * 100 ); - HBLog( "Speed: %.2f fps (average: %.2f fps, " - "remaining: %02d:%02d:%02d)", - h->status.frameRate, h->status.avFrameRate, - h->status.remainingTime / 3600, - ( h->status.remainingTime / 60 ) % 60, - h->status.remainingTime % 60 ); - - h->lastFpsUpdate = HBGetDate(); - h->framesSinceFpsUpdate = 0; + h->curFrameRate = 1000000.0 * h->framesSinceFps / + ( HBGetDate() - h->lastFpsUpdate ); + h->avgFrameRate = 1000000.0 * h->framesSinceBegin / + ( HBGetDate() - h->beginDate ); + h->remainingTime = ( 1.0 - position ) * + ( HBGetDate() - h->beginDate ) / position / 1000000; + + h->lastFpsUpdate = HBGetDate(); + h->framesSinceFps = 0; } - HBLockUnlock( h->lock ); + + h->cb.encoding( h->cb.data, position, pass, passCount, + h->curFrameRate, h->avgFrameRate, + h->remainingTime ); } -void HBErrorOccured( HBHandle * h, HBError error ) +void HBErrorOccured( HBHandle * h, int error ) { - if( !( h->status.mode & ( HB_MODE_ENCODING | HB_MODE_PAUSED ) ) ) - { - return; - } - - h->status.error = error; - h->error = 1; + h->error = error; } /* Local functions */ @@ -559,49 +489,55 @@ static void HandBrakeThread( void * _h ) if( h->stopScan ) { HBScanClose( &h->scan ); - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HBListCountItems( h->status.titleList ) ? - HB_MODE_READY_TO_RIP : HB_MODE_INVALID_DEVICE; - HBLockUnlock( h->lock ); h->stopScan = 0; } if( h->stopRip ) { _StopRip( h ); - - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_CANCELED; - HBLockUnlock( h->lock ); - + h->cb.ripDone( h->cb.data, HB_CANCELED ); h->stopRip = 0; } if( h->ripDone ) { - /* Wait a bit */ - HBSnooze( 500000 ); + HBTitle * title = h->curTitle; + HBAudio * audio; + int i, ok = 0; + + /* Wait until we're done with the decoding of one track */ + for( ;; ) + { + if( !HBFifoSize( title->inFifo ) && + !HBFifoSize( title->rawFifo ) && + !HBFifoSize( title->scaledFifo ) ) + { + break; + } + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); + if( !HBFifoSize( title->inFifo ) && + !HBFifoSize( title->rawFifo ) ) + { + ok = 1; + break; + } + } + HBSnooze( 5000 ); + } + HBSnooze( 500000 ); _StopRip( h ); - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_DONE; - HBLockUnlock( h->lock ); - + h->cb.ripDone( h->cb.data, HB_SUCCESS ); + h->ripDone = 0; } if( h->error ) { _StopRip( h ); - - HBLockLock( h->lock ); - h->modeChanged = 1; - h->status.mode = HB_MODE_ERROR; - HBLockUnlock( h->lock ); - + h->cb.ripDone( h->cb.data, h->error ); h->error = 0; } @@ -611,52 +547,77 @@ static void HandBrakeThread( void * _h ) static void _StopRip( HBHandle * h ) { + HBTitle * title = h->curTitle; + HBAudio * audio; int i; + /* Invalidate fifos */ + HBFifoDie( title->outFifo ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + HBFifoDie( audio->outFifo ); + } + /* Stop threads */ - HBDVDReadClose( &h->curTitle->dvdRead ); - HBAviMuxClose( &h->curTitle->aviMux ); + HBDVDReadClose( &title->dvdRead ); + + if( title->mux == HB_MUX_AVI ) + HBAviMuxClose( &title->aviMux ); + else if( title->mux == HB_MUX_MP4 ) + HBMp4MuxClose( &title->mp4Mux ); + else if( title->mux == HB_MUX_OGM ) + HBOgmMuxClose( &title->ogmMux ); + for( i = 0; i < h->cpuCount; i++ ) { - HBWorkThreadClose( &h->curTitle->workThreads[h->cpuCount-i-1] ); + HBWorkThreadClose( &title->workThreads[h->cpuCount-i-1] ); } /* Clean up */ - HBMpeg2DecClose( &h->curTitle->mpeg2Dec ); - HBScaleClose( &h->curTitle->scale ); - - if( h->curTitle->codec == HB_CODEC_FFMPEG ) - HBFfmpegEncClose( &h->curTitle->ffmpegEnc ); - else if( h->curTitle->codec == HB_CODEC_XVID ) - HBXvidEncClose( &h->curTitle->xvidEnc ); - - HBAc3DecClose( &h->curAudio->ac3Dec ); - HBMp3EncClose( &h->curAudio->mp3Enc ); - if( h->curOptAudio ) - { - HBAc3DecClose( &h->curOptAudio->ac3Dec ); - HBMp3EncClose( &h->curOptAudio->mp3Enc ); - } + HBMpeg2DecClose( &title->decoder ); + HBScaleClose( &title->scale ); - /* Destroy fifos */ - HBFifoClose( &h->curTitle->mpeg2Fifo ); - HBFifoClose( &h->curTitle->rawFifo ); - HBFifoClose( &h->curTitle->scaledFifo ); - HBFifoClose( &h->curTitle->mpeg4Fifo ); - HBFifoClose( &h->curAudio->ac3Fifo ); - HBFifoClose( &h->curAudio->rawFifo ); - HBFifoClose( &h->curAudio->mp3Fifo ); - if( h->curOptAudio ) + if( title->codec == HB_CODEC_FFMPEG ) + HBFfmpegEncClose( &title->encoder ); + else if( title->codec == HB_CODEC_XVID ) + HBXvidEncClose( &title->encoder ); + else if( title->codec == HB_CODEC_X264 ) + HBX264EncClose( &title->encoder ); + + HBFifoClose( &title->inFifo ); + HBFifoClose( &title->rawFifo ); + HBFifoClose( &title->scaledFifo ); + HBFifoClose( &title->outFifo ); + + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - HBFifoClose( &h->curOptAudio->ac3Fifo ); - HBFifoClose( &h->curOptAudio->rawFifo ); - HBFifoClose( &h->curOptAudio->mp3Fifo ); + audio = HBListItemAt( title->ripAudioList, i ); + + /* Audio work objects */ + HBAc3DecClose( &audio->decoder ); + if( audio->codec == HB_CODEC_MP3 ) + HBMp3EncClose( &audio->encoder ); + else if( audio->codec == HB_CODEC_AAC ) + HBFaacEncClose( &audio->encoder ); + else if( audio->codec == HB_CODEC_VORBIS ) + HBVorbisEncClose( &audio->encoder ); + + /* Audio fifos */ + HBFifoClose( &audio->inFifo ); + HBFifoClose( &audio->rawFifo ); + HBFifoClose( &audio->outFifo ); + + HBListRemove( title->ripAudioList, audio ); } + + h->curTitle = NULL; } static void FixPictureSettings( HBTitle * t ) { /* Sanity checks */ + t->outWidth = MULTIPLE_16( t->outWidth ); t->topCrop = EVEN( t->topCrop ); t->bottomCrop = EVEN( t->bottomCrop ); t->leftCrop = EVEN( t->leftCrop ); @@ -693,12 +654,12 @@ static int GetCPUCount() { int CPUCount = 1; -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) system_info info; get_system_info( &info ); CPUCount = info.cpu_count; -#elif defined( SYS_MACOSX ) +#elif defined( HB_MACOSX ) FILE * info; char buffer[256]; @@ -726,8 +687,8 @@ static int GetCPUCount() { HBLog( "GetCPUCount: popen() failed" ); } - -#elif defined( SYS_LINUX ) + +#elif defined( HB_LINUX ) FILE * info; char buffer[256]; @@ -755,11 +716,11 @@ static int GetCPUCount() { HBLog( "GetCPUCount: fopen() failed" ); } - -#elif defined( SYS_CYGWIN ) + +#elif defined( HB_CYGWIN ) /* TODO */ CPUCount = 1; - + #endif CPUCount = MAX( 1, CPUCount ); CPUCount = MIN( CPUCount, 8 ); diff --git a/core/HandBrake.h b/core/HandBrake.h index 35ec0fc0a..9d84d39dc 100644 --- a/core/HandBrake.h +++ b/core/HandBrake.h @@ -1,4 +1,4 @@ -/* $Id: HandBrake.h,v 1.3 2003/11/06 13:03:19 titer Exp $ +/* $Id: HandBrake.h,v 1.10 2004/01/21 18:40:36 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -13,36 +13,56 @@ extern "C" { #include "Utils.h" +/* Interface callbacks */ +typedef struct HBCallbacks +{ + void * data; + + void (*scanning) ( void * data, int title, int titleCount ); + void (*scanDone) ( void * data, HBList * titleList ); + void (*encoding) ( void * data, float position, int pass, + int passCount, float curFrameRate, + float avgFrameRate, int remainingTime ); + void (*ripDone) ( void * data, int result ); + +} HBCallbacks; + /* Init libhb. Set debug to 0 to see no output, 1 to see all libhb logs. Set cpuCount to 0 if you want libhb to autodetect */ HBHandle * HBInit( int debug, int cpuCount ); -/* Fills the HBStatus * argument with infos about the current status. - Returns 1 if mode has changed, 0 otherwise */ -int HBGetStatus( HBHandle *, HBStatus * ); +/* Tell libhb what functions should be called when a GUI should be + updated. */ +void HBSetCallbacks( HBHandle *, HBCallbacks callbacks ); -/* Launch a thread which scans the specified device and title. Use +/* Launch a thread which scans the specified DVD and title. Use title = 0 to scan all titles. Returns immediately */ -void HBScanDevice( HBHandle *, char * device, int title ); +void HBScanDVD( HBHandle *, const char * dvd, int title ); + +/* Calculate bitrate so the output file fits in X MB */ +int HBGetBitrateForSize( HBTitle * title, int size, int muxer, + int audioCount, int audioBitrate ); -/* Start ripping the specified title with specified audio tracks. - Returns immediatly */ -void HBStartRip( HBHandle *, HBTitle *, HBAudio *, HBAudio * ); +/* Start ripping the specified title. Returns immediatly */ +void HBStartRip( HBHandle *, HBTitle * ); -/* Suspend rip. Returns immediatly */ +/* Suspend rip */ void HBPauseRip( HBHandle * ); -/* Resume rip. Returns immediatly */ +/* Resume rip */ void HBResumeRip( HBHandle * ); -/* Cancel rip. Returns immediatly */ +/* Cancel rip. Returns immediatly - you'll be noticed by the ripDone + callback when it's really stopped. + If the rip was paused, you _must_ call HBResumeRip() first. */ void HBStopRip( HBHandle * ); /* Calculate preview for the specified picture of the specified title, taking care of the current cropping & scaling settings. Returns a - pointer to raw RGBA data. It includes the white border around the - picture, so the size of the picture is ( maxWidth + 2 ) x - ( maxHeight + 2 ) */ + pointer to raw RGBA data that _has_ to be freed by the calling + function. The picture includes the white border around the picture, + so its size is ( maxWidth + 2 ) x ( maxHeight + 2 ). + The data belongs to the caller, who must free it. */ uint8_t * HBGetPreview( HBHandle *, HBTitle *, int picture ); /* Clean up things */ diff --git a/core/HandBrakeInternal.h b/core/HandBrakeInternal.h deleted file mode 100644 index 7c10512c9..000000000 --- a/core/HandBrakeInternal.h +++ /dev/null @@ -1,35 +0,0 @@ -/* $Id: HandBrakeInternal.h,v 1.2 2003/11/04 15:44:24 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_HANDBRAKE_INTERNAL_H -#define HB_HANDBRAKE_INTERNAL_H - -#include "HandBrake.h" - -/* Called by HBScan to tell the GUI how far we are */ -void HBScanning( HBHandle *, int title ); - -/* Called by HBScan. titleList is a list of all valid titles which - should be shown on the interface */ -void HBScanDone( HBHandle *, HBList * titleList ); - -/* Used to create temporary files (/tmp/HB.pid.whatever) */ -int HBGetPid( HBHandle * ); - -/* Called by every thread involved in the rip process. Returns - immediately is rip isn't paused, blocks if it is */ -void HBCheckPaused( HBHandle * ); - -/* Called by the decoders when the last packet is being proceeded */ -void HBDone( HBHandle * ); - -/* Called by the video encoder to update the GUI progress */ -void HBPosition( HBHandle *, float ); - -/* Called by any thread which couldn't continue and ask to stop */ -void HBErrorOccured( HBHandle *, HBError ); - -#endif diff --git a/core/Jamfile b/core/Jamfile new file mode 100644 index 000000000..d33688722 --- /dev/null +++ b/core/Jamfile @@ -0,0 +1,47 @@ +# $Id: Jamfile,v 1.5 2004/01/16 19:04:04 titer Exp $ +# +# This file is part of the HandBrake source code. +# Homepage: <http://handbrake.m0k.org/>. +# It may be used under the terms of the GNU General Public License. + +SubDir TOP core ; + +SOURCES_HBCORE = +Ac3Dec.c +AviMux.c +DVDRead.c +FaacEnc.c +FfmpegEnc.c +Fifo.c +HandBrake.c +MadDec.c +Mp3Enc.c +Mp4Mux.c +Mpeg2Dec.c +OgmMux.c +Scale.c +Scan.c +Thread.c +Utils.c +VorbisEnc.c +Work.c +X264Enc.c +XvidEnc.c ; + +ObjectCcFlags $(SOURCES_HBCORE) : + -I$(TOP)/contrib/liba52 + -I$(TOP)/contrib/libavcodec + -I$(TOP)/contrib/libdvdplay + -I$(TOP)/contrib/libdvdread + -I$(TOP)/contrib/libfaac + -I$(TOP)/contrib/libmp3lame + -I$(TOP)/contrib/libmp4v2 + -I$(TOP)/contrib/libmpeg2 + -I$(TOP)/contrib/libogg + -I$(TOP)/contrib/libvorbis + -I$(TOP)/contrib/libx264 + -I$(TOP)/contrib/libxvidcore + -g -Wall ; + +Library libhb.a : $(SOURCES_HBCORE) ; + diff --git a/core/MadDec.c b/core/MadDec.c index deecfeebd..da79ad886 100644 --- a/core/MadDec.c +++ b/core/MadDec.c @@ -1,9 +1,8 @@ -/* $Id: MadDec.c,v 1.1 2003/11/03 12:08:01 titer Exp $ +/* $Id: MadDec.c,v 1.2 2003/12/26 20:03:27 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "MadDec.h" -#include "Fifo.h" +#include "HBInternal.h" diff --git a/core/MadDec.h b/core/MadDec.h deleted file mode 100644 index b1624338f..000000000 --- a/core/MadDec.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: MadDec.h,v 1.1 2003/11/03 12:08:01 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MAD_DEC_H -#define HB_MAD_DEC_H - -#include "HandBrakeInternal.h" - -HBMadDec * HBMadDecInit( HBHandle *, HBAudio * ); -void HBMadDecClose( HBMadDec * ); - -#endif diff --git a/core/Mp3Enc.c b/core/Mp3Enc.c index 70693467f..bd62df4ae 100644 --- a/core/Mp3Enc.c +++ b/core/Mp3Enc.c @@ -1,20 +1,15 @@ -/* $Id: Mp3Enc.c,v 1.5 2003/11/07 21:52:57 titer Exp $ +/* $Id: Mp3Enc.c,v 1.13 2004/01/21 17:59:33 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Fifo.h" -#include "Mp3Enc.h" -#include "Work.h" +#include "HBInternal.h" -#include <lame/lame.h> +/* libmp3lame */ +#include "lame/lame.h" -/* Local prototypes */ -static int Mp3EncWork( HBWork * ); -static int GetBytes( HBMp3Enc * ); - -struct HBMp3Enc +typedef struct HBMp3Enc { HB_WORK_COMMON_MEMBERS @@ -24,17 +19,25 @@ struct HBMp3Enc HBBuffer * rawBuffer; int rawBufferPos; float position; - int samplesNeeded; + int inputSamples; int samplesGot; float * left; float * right; HBBuffer * mp3Buffer; -}; -HBMp3Enc * HBMp3EncInit( HBHandle * handle, HBAudio * audio ) + /* Stats */ + int64_t samples; + int64_t bytes; +} HBMp3Enc; + +/* Local prototypes */ +static int Mp3EncWork( HBWork * ); +static int GetSamples( HBMp3Enc * ); + +HBWork * HBMp3EncInit( HBHandle * handle, HBAudio * audio ) { HBMp3Enc * m; - if( !( m = malloc( sizeof( HBMp3Enc ) ) ) ) + if( !( m = calloc( sizeof( HBMp3Enc ), 1 ) ) ) { HBLog( "HBMp3EncInit: malloc() failed, gonna crash" ); return NULL; @@ -42,31 +45,35 @@ HBMp3Enc * HBMp3EncInit( HBHandle * handle, HBAudio * audio ) m->name = strdup( "Mp3Enc" ); m->work = Mp3EncWork; - + m->handle = handle; m->audio = audio; - m->globalFlags = NULL; - m->rawBuffer = NULL; - m->rawBufferPos = 0; - m->position = 0.0; - m->samplesNeeded = 0; - m->samplesGot = 0; - m->left = NULL; - m->right = NULL; - m->mp3Buffer = NULL; - - return m; + + return (HBWork*) m; } -void HBMp3EncClose( HBMp3Enc ** _m ) +void HBMp3EncClose( HBWork ** _m ) { - HBMp3Enc * m = *_m; - + HBMp3Enc * m = (HBMp3Enc*) *_m; + if( m->globalFlags ) lame_close( m->globalFlags ); if( m->rawBuffer ) HBBufferClose( &m->rawBuffer ); if( m->left ) free( m->left ); if( m->right ) free( m->right ); if( m->mp3Buffer ) HBBufferClose( &m->mp3Buffer ); + + if( m->samples ) + { + int64_t bytes = 128 * m->audio->outBitrate * m->samples / + m->audio->inSampleRate; + float bitrate = (float) m->bytes * m->audio->inSampleRate / + m->samples / 128; + + HBLog( "HBMp3Enc: %lld samples encoded (%lld bytes), %.2f kbps", + m->samples, m->bytes, bitrate ); + HBLog( "HBFaacEnc: error is %lld bytes", m->bytes - bytes ); + } + free( m->name ); free( m ); @@ -86,7 +93,7 @@ static int Mp3EncWork( HBWork * w ) if( !m->globalFlags ) { int i; - + /* Get a first buffer so we know that audio->inSampleRate is correct */ if( ( m->rawBuffer = HBFifoPop( audio->rawFifo ) ) ) @@ -105,7 +112,8 @@ static int Mp3EncWork( HBWork * w ) outSampleRate, we will give ( 1152 * inSampleRate ) / ( 2 * outSampleRate ) samples to libmp3lame so we are sure we will never get more than 1 frame at a time */ - m->samplesNeeded = 1152 * audio->inSampleRate / + audio->outSampleRate = 44100; + m->inputSamples = 1152 * audio->inSampleRate / audio->outSampleRate / 2; HBLog( "HBMp3Enc: opening lame (%d->%d Hz, %d kbps)", @@ -123,15 +131,15 @@ static int Mp3EncWork( HBWork * w ) return didSomething; } - m->left = malloc( m->samplesNeeded * sizeof( float ) ); - m->right = malloc( m->samplesNeeded * sizeof( float ) ); + m->left = malloc( m->inputSamples * sizeof( float ) ); + m->right = malloc( m->inputSamples * sizeof( float ) ); if( !m->left || !m->right ) { HBLog( "HBMp3Enc: malloc() failed, gonna crash" ); } - for( i = 0; i < m->samplesNeeded; i++ ) + for( i = 0; i < m->inputSamples; i++ ) { m->left[i] = 0.0; m->right[i] = 0.0; @@ -141,7 +149,7 @@ static int Mp3EncWork( HBWork * w ) /* Push encoded buffer */ if( m->mp3Buffer ) { - if( HBFifoPush( audio->mp3Fifo, &m->mp3Buffer ) ) + if( HBFifoPush( audio->outFifo, &m->mp3Buffer ) ) { didSomething = 1; } @@ -156,12 +164,12 @@ static int Mp3EncWork( HBWork * w ) if( audio->delay > 0 ) { /* Audio starts later - insert some silence */ - int length = m->samplesNeeded * 1000 / audio->inSampleRate; - + int length = m->inputSamples * 1000 / audio->inSampleRate; + if( audio->delay > length ) { HBLog( "HBMp3Enc: adding %d ms of silence", length ); - m->samplesGot = m->samplesNeeded; + m->samplesGot = m->inputSamples; audio->delay -= length; } else @@ -172,11 +180,11 @@ static int Mp3EncWork( HBWork * w ) else if( audio->delay < 0 ) { /* Audio starts sooner - trash some */ - int length = m->samplesNeeded * 1000 / audio->inSampleRate; + int length = m->inputSamples * 1000 / audio->inSampleRate; if( - audio->delay > length ) { - if( GetBytes( m ) ) + if( GetSamples( m ) ) { didSomething = 1; HBLog( "HBMp3Enc: trashing %d ms", length ); @@ -196,7 +204,7 @@ static int Mp3EncWork( HBWork * w ) } /* Get new samples */ - if( GetBytes( m ) ) + if( GetSamples( m ) ) { didSomething = 1; } @@ -209,9 +217,11 @@ static int Mp3EncWork( HBWork * w ) mp3Buffer = HBBufferInit( LAME_MAXMP3BUFFER ); ret = lame_encode_buffer_float( m->globalFlags, m->left, - m->right, m->samplesNeeded, + m->right, m->inputSamples, mp3Buffer->data, mp3Buffer->size ); + /* Stats */ + m->samples += m->inputSamples; if( ret < 0 ) { @@ -232,19 +242,21 @@ static int Mp3EncWork( HBWork * w ) mp3Buffer->size = ret; mp3Buffer->keyFrame = 1; mp3Buffer->position = m->position; - m->mp3Buffer = mp3Buffer; + + /* Stats */ + m->bytes += ret; } return didSomething; } -static int GetBytes( HBMp3Enc * m ) +static int GetSamples( HBMp3Enc * m ) { - while( m->samplesGot < m->samplesNeeded ) + while( m->samplesGot < m->inputSamples ) { int i; - + if( !m->rawBuffer ) { if( !( m->rawBuffer = HBFifoPop( m->audio->rawFifo ) ) ) @@ -256,22 +268,20 @@ static int GetBytes( HBMp3Enc * m ) m->position = m->rawBuffer->position; } - i = MIN( m->samplesNeeded - m->samplesGot, - ( m->rawBuffer->size / 2 - - m->rawBufferPos ) / sizeof( float ) ); + i = MIN( m->inputSamples - m->samplesGot, + m->rawBuffer->samples - m->rawBufferPos ); memcpy( m->left + m->samplesGot, - m->rawBuffer->data + m->rawBufferPos, + m->rawBuffer->left + m->rawBufferPos, i * sizeof( float ) ); memcpy( m->right + m->samplesGot, - m->rawBuffer->data + m->rawBuffer->size / 2 + - m->rawBufferPos, + m->rawBuffer->right + m->rawBufferPos, i * sizeof( float ) ); m->samplesGot += i; - m->rawBufferPos += i * sizeof( float ); + m->rawBufferPos += i; - if( m->rawBufferPos == m->rawBuffer->size / 2 ) + if( m->rawBufferPos == m->rawBuffer->samples ) { HBBufferClose( &m->rawBuffer ); } diff --git a/core/Mp3Enc.h b/core/Mp3Enc.h deleted file mode 100644 index db02f4f44..000000000 --- a/core/Mp3Enc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: Mp3Enc.h,v 1.1 2003/11/03 12:08:01 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MP3_ENCODER_H -#define HB_MP3_ENCODER_H - -#include "HandBrakeInternal.h" - -HBMp3Enc * HBMp3EncInit( HBHandle *, HBAudio * ); -void HBMp3EncClose( HBMp3Enc ** ); - -#endif diff --git a/core/Mp4Mux.c b/core/Mp4Mux.c new file mode 100644 index 000000000..f780cab01 --- /dev/null +++ b/core/Mp4Mux.c @@ -0,0 +1,210 @@ +/* $Id: Mp4Mux.c,v 1.22 2004/02/18 17:07:20 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "HBInternal.h" + +/* libmp4v2 */ +#include "mp4.h" + +int64_t videoFrames; +int64_t videoBytes; +int64_t audioFrames; +int64_t audioBytes; + +/* Local prototypes */ +static void Mp4MuxThread( void * ); + +struct HBMp4Mux +{ + HBHandle * handle; + HBTitle * title; + + volatile int die; + HBThread * thread; +}; + +HBMp4Mux * HBMp4MuxInit( HBHandle * handle, HBTitle * title ) +{ + HBMp4Mux * m; + if( !( m = malloc( sizeof( HBMp4Mux ) ) ) ) + { + HBLog( "HBMp4MuxInit: malloc() failed, gonna crash" ); + return NULL; + } + + videoFrames = 0; + videoBytes = 0; + audioFrames = 0; + audioBytes = 0; + + m->handle = handle; + m->title = title; + + m->die = 0; + m->thread = HBThreadInit( "mp4 muxer", Mp4MuxThread, m, + HB_NORMAL_PRIORITY ); + return m; +} + +void HBMp4MuxClose( HBMp4Mux ** _m ) +{ + HBMp4Mux * m = *_m; + FILE * file; + long size; + + m->die = 1; + HBThreadClose( &m->thread ); + + file = fopen( m->title->file, "r" ); + fseek( file, 0, SEEK_END ); + size = ftell( file ); + fclose( file ); + + HBLog( "HBMp4Mux: videoFrames=%lld, %lld bytes", videoFrames, videoBytes ); + HBLog( "HBMp4Mux: audioFrames=%lld, %lld bytes", audioFrames, audioBytes ); + HBLog( "HBMp4Mux: overhead=%.2f bytes / frame", + ( (float) size - videoBytes - audioBytes ) / + ( videoFrames + audioFrames ) ); + + free( m ); + + *_m = NULL; +} + +static void Mp4MuxThread( void * _m ) +{ + HBMp4Mux * m = (HBMp4Mux*) _m; + HBTitle * title = m->title; + HBAudio * audio; + HBBuffer * buffer; + char tmpFile[1024]; + + int audioCount = HBListCount( m->title->ripAudioList ); + int i; + + MP4FileHandle file; + + /* Wait until we have one encoded frame for each track */ + while( !m->die && !HBFifoSize( title->outFifo ) ) + { + HBSnooze( 10000 ); + } + for( i = 0; i < audioCount; i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + while( !m->die && !HBFifoSize( audio->outFifo ) ) + { + HBSnooze( 10000 ); + } + } + + if( m->die ) + { + return; + } + + /* Write file headers */ + file = MP4Create( title->file, 0, 0 ); + MP4SetTimeScale( file, 90000 ); + title->track = MP4AddVideoTrack( file, 90000, + MP4_INVALID_DURATION, + title->outWidth, title->outHeight, + MP4_MPEG4_VIDEO_TYPE ); + MP4SetVideoProfileLevel( file, 0x03 ); + MP4SetTrackESConfiguration( file, title->track, title->esConfig, + title->esConfigLength ); + + for( i = 0; i < audioCount; i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + audio->track = MP4AddAudioTrack( file, audio->outSampleRate, + 1024, MP4_MPEG4_AUDIO_TYPE ); + MP4SetAudioProfileLevel( file, 0x0F ); + MP4SetTrackESConfiguration( file, audio->track, audio->esConfig, + audio->esConfigLength ); + } + + for( ;; ) + { + /* Wait until we have one encoded frame for each track */ + if( !HBFifoWait( title->outFifo ) ) + { + m->die = 1; + break; + } + for( i = 0; i < audioCount; i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + if( !HBFifoWait( audio->outFifo ) ) + { + m->die = 1; + break; + } + } + + if( m->die ) + { + break; + } + + /* Interleave frames in the same order than they were in the + original MPEG stream */ + audio = NULL; + for( i = 0; i < audioCount; i++ ) + { + HBAudio * otherAudio; + otherAudio = HBListItemAt( title->ripAudioList, i ); + if( !audio || HBFifoPosition( otherAudio->outFifo ) < + HBFifoPosition( audio->outFifo ) ) + { + audio = otherAudio; + } + } + + if( !audio || HBFifoPosition( title->outFifo ) < + HBFifoPosition( audio->outFifo ) ) + { + buffer = HBFifoPop( title->outFifo ); + MP4WriteSample( file, title->track, buffer->data, + buffer->size, + (uint64_t) 90000 * title->rateBase / title->rate, + 0, buffer->keyFrame ); + videoFrames++; + videoBytes += buffer->size; + HBBufferClose( &buffer ); + } + else + { + buffer = HBFifoPop( audio->outFifo ); + MP4WriteSample( file, audio->track, buffer->data, + buffer->size, MP4_INVALID_DURATION, + 0, buffer->keyFrame ); + audioFrames++; + audioBytes += buffer->size; + HBBufferClose( &buffer ); + } + } + + MP4Close( file ); + + if( !MP4MakeIsmaCompliant( title->file, 0 /*MP4_DETAILS_ALL*/, 1 ) ) + { + HBLog( "HBMp4Mux: MP4MakeIsmaCompliant() failed" ); + } + + sprintf( tmpFile, "%s.tmp", title->file ); + tmpFile[strlen( title->file ) + 4] = '\0'; + if( !MP4Optimize( title->file, tmpFile, 0 /*MP4_DETAILS_ALL*/ ) ) + { + HBLog( "HBMp4Mux: MP4Optimize() failed" ); + unlink( tmpFile ); + } + else + { + rename( tmpFile, title->file ); + } +} + diff --git a/core/Mpeg2Dec.c b/core/Mpeg2Dec.c index fb81f8080..ea3ffa2e4 100644 --- a/core/Mpeg2Dec.c +++ b/core/Mpeg2Dec.c @@ -1,19 +1,14 @@ -/* $Id: Mpeg2Dec.c,v 1.4 2003/11/12 21:46:59 titer Exp $ +/* $Id: Mpeg2Dec.c,v 1.12 2004/01/16 19:04:04 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Fifo.h" -#include "Mpeg2Dec.h" -#include "Work.h" +#include "HBInternal.h" -#include <mpeg2dec/mpeg2.h> +#include "mpeg2dec/mpeg2.h" -/* Local prototypes */ -static int Mpeg2DecWork( HBWork * ); - -struct HBMpeg2Dec +typedef struct HBMpeg2Dec { HB_WORK_COMMON_MEMBERS @@ -24,9 +19,12 @@ struct HBMpeg2Dec mpeg2dec_t * libmpeg2; const mpeg2_info_t * info; int lateField; -}; +} HBMpeg2Dec; + +/* Local prototypes */ +static int Mpeg2DecWork( HBWork * ); -HBMpeg2Dec * HBMpeg2DecInit( HBHandle * handle, HBTitle * title ) +HBWork * HBMpeg2DecInit( HBHandle * handle, HBTitle * title ) { HBMpeg2Dec * m ; if( !( m = malloc( sizeof( HBMpeg2Dec ) ) ) ) @@ -47,15 +45,15 @@ HBMpeg2Dec * HBMpeg2DecInit( HBHandle * handle, HBTitle * title ) m->info = NULL; m->lateField = 0; - return m; + return (HBWork*) m; } -void HBMpeg2DecClose( HBMpeg2Dec ** _m ) +void HBMpeg2DecClose( HBWork ** _m ) { HBBuffer * buffer; - - HBMpeg2Dec * m = *_m; - + + HBMpeg2Dec * m = (HBMpeg2Dec*) *_m; + if( m->libmpeg2 ) { HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", m->pass ); @@ -69,7 +67,7 @@ void HBMpeg2DecClose( HBMpeg2Dec ** _m ) HBListClose( &m->rawBufferList ); free( m->name ); free( m ); - + *_m = NULL; } @@ -81,7 +79,7 @@ static int Mpeg2DecWork( HBWork * w ) HBBuffer * rawBuffer; HBBuffer * tmpBuffer; mpeg2_state_t state; - + int didSomething = 0; /* Push decoded buffers */ @@ -101,7 +99,7 @@ static int Mpeg2DecWork( HBWork * w ) } /* Get a new buffer to decode */ - if( ( mpeg2Buffer = HBFifoPop( title->mpeg2Fifo ) ) ) + if( ( mpeg2Buffer = HBFifoPop( title->inFifo ) ) ) { didSomething = 1; } @@ -122,6 +120,9 @@ static int Mpeg2DecWork( HBWork * w ) m->pass = mpeg2Buffer->pass; HBLog( "HBMpeg2Dec: opening libmpeg2 (pass %d)", m->pass ); +#ifdef HB_NOMMX + mpeg2_accel( 0 ); +#endif m->libmpeg2 = mpeg2_init(); m->info = mpeg2_info( m->libmpeg2 ); m->lateField = 0; @@ -143,7 +144,7 @@ static int Mpeg2DecWork( HBWork * w ) m->info->display_fbuf ) { rawBuffer = HBBufferInit( 3 * title->inWidth * - title->outWidth ); + title->inHeight ); /* TODO: make libmpeg2 write directly in our buffer */ memcpy( rawBuffer->data, m->info->display_fbuf->buf[0], @@ -164,16 +165,12 @@ static int Mpeg2DecWork( HBWork * w ) /* NTSC pulldown kludge */ if( m->info->display_picture->nb_fields == 3 ) { - if( m->lateField ) - { - tmpBuffer = HBBufferInit( rawBuffer->size ); - tmpBuffer->position = rawBuffer->position; - tmpBuffer->pass = rawBuffer->pass; - memcpy( tmpBuffer->data, rawBuffer->data, - tmpBuffer->size ); - HBListAdd( m->rawBufferList, tmpBuffer ); - } - m->lateField = !m->lateField; + rawBuffer->repeat = m->lateField; + m->lateField = !m->lateField; + } + else + { + rawBuffer->repeat = 0; } } else if( state == STATE_INVALID ) @@ -183,11 +180,6 @@ static int Mpeg2DecWork( HBWork * w ) } } - if( mpeg2Buffer->last ) - { - HBDone( m->handle ); - } - HBBufferClose( &mpeg2Buffer ); return didSomething; diff --git a/core/Mpeg2Dec.h b/core/Mpeg2Dec.h deleted file mode 100644 index af7f18c44..000000000 --- a/core/Mpeg2Dec.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: Mpeg2Dec.h,v 1.1 2003/11/03 12:08:01 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MPEG2_DEC_H -#define HB_MPEG2_DEC_H - -#include "HandBrakeInternal.h" - -HBMpeg2Dec * HBMpeg2DecInit( HBHandle *, HBTitle * ); -void HBMpeg2DecClose( HBMpeg2Dec ** ); - -#endif diff --git a/core/OgmMux.c b/core/OgmMux.c new file mode 100644 index 000000000..d4712594b --- /dev/null +++ b/core/OgmMux.c @@ -0,0 +1,471 @@ +/* $Id: OgmMux.c,v 1.6 2004/02/13 15:12:09 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "HBInternal.h" + +#include <ogg/ogg.h> + +static void OgmMuxThread( void * ); +static int OgmStart( HBOgmMux * ); +static int OgmFlush( HBOgmMux *, int ); +static int OgmEnd( HBOgmMux * ); + +struct HBOgmMux +{ + HBHandle *handle; + HBTitle *title; + + 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 !! */ +}; + +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 ) +{ + 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; + } + + 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 ); +} + +typedef struct __attribute__((__packed__)) +{ + uint8_t i_packet_type; + + char stream_type[8]; + char sub_type[4]; + + int32_t i_size; + + int64_t i_time_unit; + int64_t i_samples_per_unit; + int32_t i_default_len; + + int32_t i_buffer_size; + int16_t i_bits_per_sample; + int16_t i_padding_0; // hum hum + union + { + struct + { + int32_t i_width; + int32_t i_height; + + } video; + struct + { + int16_t i_channels; + int16_t i_block_align; + int32_t i_avgbytespersec; + } audio; + } header; + +} ogg_stream_header_t; + +#define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v) +static void _SetWLE( uint8_t *p, uint16_t i_dw ) +{ + p[1] = ( i_dw >> 8 )&0xff; + p[0] = ( i_dw )&0xff; +} + +#define SetDWLE( p, v ) _SetDWLE( (uint8_t*)p, v) +static void _SetDWLE( uint8_t *p, uint32_t i_dw ) +{ + p[3] = ( i_dw >> 24 )&0xff; + p[2] = ( i_dw >> 16 )&0xff; + p[1] = ( i_dw >> 8 )&0xff; + p[0] = ( i_dw )&0xff; +} +#define SetQWLE( p, v ) _SetQWLE( (uint8_t*)p, v) +static void _SetQWLE( uint8_t *p, uint64_t i_qw ) +{ + SetDWLE( p, i_qw&0xffffffff ); + SetDWLE( p+4, ( i_qw >> 32)&0xffffffff ); +} + +static int OgmFlush( HBOgmMux *ogm, int i_tk ) +{ + for( ;; ) + { + ogg_page og; + if( ogg_stream_flush( &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 ) + { + return -1; + } + } + return 0; +} + +static int OgmStart( HBOgmMux *ogm ) +{ + HBTitle *title = ogm->title; + int i; + + ogg_packet op; + + /* 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 ); + + for( i = 1; i < HBListCount( title->ripAudioList ) + 1; i++ ) + { + HBAudio *audio = HBListItemAt( title->ripAudioList, i - 1 ); + + ogm->tk[i].codec = audio->codec; + ogm->tk[i].fifo = audio->outFifo; + ogm->tk[i].i_packet_no = 0; + ogg_stream_init (&ogm->tk[i].os, i ); + + } + ogm->i_tk = 1 + HBListCount( title->ripAudioList ); + + /* Wait data for each track */ + for( i = 0; i < ogm->i_tk; i++ ) + { + while( !ogm->die && + ( ( ogm->tk[i].codec == HB_CODEC_VORBIS && HBFifoSize( ogm->tk[i].fifo ) <= 3 ) || + HBFifoSize( ogm->tk[i].fifo ) <= 0 ) ) + { + HBSnooze( 10000 ); + } + } + + if( ogm->die ) + { + return -1; + } + + /* First pass: all b_o_s packets */ + for( i = 0; i < ogm->i_tk; i++ ) + { + ogg_stream_header_t h; + + memset( &h, 0, sizeof( ogg_stream_header_t ) ); + + switch( ogm->tk[i].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 ); + + SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); + SetQWLE( &h.i_time_unit, 0 ); + SetQWLE( &h.i_samples_per_unit, audio->outSampleRate ); + SetDWLE( &h.i_default_len, 1 ); + SetDWLE( &h.i_buffer_size, 30*1024 ); + SetWLE ( &h.i_bits_per_sample, 0 ); + + SetDWLE( &h.header.audio.i_channels, 2 ); + SetDWLE( &h.header.audio.i_block_align, 0 ); + 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 ); + break; + } + case HB_CODEC_VORBIS: + { + HBBuffer *h = HBFifoPop( ogm->tk[i].fifo ); + + memcpy( &op, h->data, sizeof( ogg_packet ) ); + op.packet = h->data + sizeof( ogg_packet ); + ogg_stream_packetin( &ogm->tk[i].os, &op ); + break; + } + case HB_CODEC_AAC: + break; + default: + HBLog( "unhandled codec" ); + break; + } + OgmFlush( ogm, i ); + } + + /* second pass: all non b_o_s packets */ + for( i = 0; i < ogm->i_tk; i++ ) + { + if( ogm->tk[i].codec == HB_CODEC_VORBIS ) + { + HBBuffer *h; + int j; + + for( j = 0; j < 2; j++ ) + { + HBFifoWait( ogm->tk[i].fifo ); + h = HBFifoPop( ogm->tk[i].fifo ); + + memcpy( &op, h->data, sizeof( ogg_packet ) ); + op.packet = h->data + sizeof( ogg_packet ); + ogg_stream_packetin( &ogm->tk[i].os, &op ); + + OgmFlush( ogm, i ); + } + } +#if 0 + else + { + /* 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 ); + } +#endif + } + + return 0; +} + +static int OgmEnd( HBOgmMux *ogm ) +{ + int i; + + for( i = 0; i < ogm->i_tk; i++ ) + { + if( OgmFlush( ogm, i ) < 0 ) + { + return -1; + } + } + return 0; +} + diff --git a/core/Scale.c b/core/Scale.c index 7e9295962..464623c1e 100644 --- a/core/Scale.c +++ b/core/Scale.c @@ -1,19 +1,14 @@ -/* $Id: Scale.c,v 1.4 2003/11/06 13:03:19 titer Exp $ +/* $Id: Scale.c,v 1.9 2004/01/16 19:39:23 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Fifo.h" -#include "Scale.h" -#include "Work.h" +#include "HBInternal.h" -#include <ffmpeg/avcodec.h> +#include "ffmpeg/avcodec.h" -/* Local prototypes */ -static int ScaleWork( HBWork * ); - -struct HBScale +typedef struct HBScale { HB_WORK_COMMON_MEMBERS @@ -24,11 +19,14 @@ struct HBScale AVPicture rawPicture; HBBuffer * deintBuffer; AVPicture deintPicture; - HBBuffer * scaledBuffer; + HBList * scaledBufferList; AVPicture scaledPicture; -}; +} HBScale; -HBScale * HBScaleInit( HBHandle * handle, HBTitle * title ) +/* Local prototypes */ +static int ScaleWork( HBWork * ); + +HBWork * HBScaleInit( HBHandle * handle, HBTitle * title ) { HBScale * s; if( !( s = malloc( sizeof( HBScale ) ) ) ) @@ -51,25 +49,26 @@ HBScale * HBScaleInit( HBHandle * handle, HBTitle * title ) title->leftCrop, title->rightCrop ); /* Allocate a constant buffer used for deinterlacing */ - s->deintBuffer = HBBufferInit( 3 * title->inWidth * + s->deintBuffer = HBBufferInit( 3 * title->inWidth * title->inHeight / 2 ); avpicture_fill( &s->deintPicture, s->deintBuffer->data, PIX_FMT_YUV420P, title->inWidth, title->inHeight ); - s->scaledBuffer = NULL; + s->scaledBufferList = HBListInit(); - return s; + return (HBWork*) s; } -void HBScaleClose( HBScale ** _s ) +void HBScaleClose( HBWork ** _s ) { - HBScale * s = *_s; - + HBScale * s = (HBScale*) *_s; + img_resample_close( s->context ); + HBListClose( &s->scaledBufferList ); HBBufferClose( &s->deintBuffer ); free( s->name ); free( s ); - + *_s = NULL; } @@ -78,15 +77,20 @@ static int ScaleWork( HBWork * w ) HBScale * s = (HBScale*) w; HBTitle * title = s->title; HBBuffer * rawBuffer; + HBBuffer * scaledBuffer; + HBBuffer * tmpBuffer; int didSomething = 0; - /* Push scaled buffer */ - if( s->scaledBuffer ) + /* Push scaled buffer(s) */ + while( ( scaledBuffer = (HBBuffer*) + HBListItemAt( s->scaledBufferList, 0 ) ) ) { - if( HBFifoPush( title->scaledFifo, &s->scaledBuffer ) ) + tmpBuffer = scaledBuffer; + if( HBFifoPush( title->scaledFifo, &scaledBuffer ) ) { didSomething = 1; + HBListRemove( s->scaledBufferList, tmpBuffer ); } else { @@ -105,15 +109,15 @@ static int ScaleWork( HBWork * w ) } /* Allocate new buffer for the scaled picture */ - s->scaledBuffer = HBBufferInit( 3 * title->outWidth * - title->outHeight / 2 ); - s->scaledBuffer->position = rawBuffer->position; - s->scaledBuffer->pass = rawBuffer->pass; + scaledBuffer = HBBufferInit( 3 * title->outWidth * + title->outHeight / 2 ); + scaledBuffer->position = rawBuffer->position; + scaledBuffer->pass = rawBuffer->pass; /* libavcodec stuff */ avpicture_fill( &s->rawPicture, rawBuffer->data, PIX_FMT_YUV420P, title->inWidth, title->inHeight ); - avpicture_fill( &s->scaledPicture, s->scaledBuffer->data, + avpicture_fill( &s->scaledPicture, scaledBuffer->data, PIX_FMT_YUV420P, title->outWidth, title->outHeight ); @@ -131,9 +135,22 @@ static int ScaleWork( HBWork * w ) img_resample( s->context, &s->scaledPicture, &s->rawPicture ); } + HBListAdd( s->scaledBufferList, scaledBuffer ); + + if( rawBuffer->repeat ) + { + tmpBuffer = HBBufferInit( scaledBuffer->size ); + tmpBuffer->position = scaledBuffer->position; + tmpBuffer->pass = scaledBuffer->pass; + memcpy( tmpBuffer->data, scaledBuffer->data, + scaledBuffer->size ); + + HBListAdd( s->scaledBufferList, tmpBuffer ); + } + /* Free memory */ HBBufferClose( &rawBuffer ); - + return didSomething; } diff --git a/core/Scale.h b/core/Scale.h deleted file mode 100644 index cf06ad661..000000000 --- a/core/Scale.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: Scale.h,v 1.1 2003/11/03 12:08:01 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_SCALE_H -#define HB_SCALE_H - -#include "HandBrakeInternal.h" - -HBScale * HBScaleInit( HBHandle *, HBTitle * ); -void HBScaleClose( HBScale ** ); - -#endif diff --git a/core/Scan.c b/core/Scan.c index 7a62a97e0..f2afd5e6c 100644 --- a/core/Scan.c +++ b/core/Scan.c @@ -1,21 +1,19 @@ -/* $Id: Scan.c,v 1.5 2003/11/09 21:28:22 titer Exp $ +/* $Id: Scan.c,v 1.14 2004/01/18 13:21:12 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Fifo.h" +#include "HBInternal.h" #include "Languages.h" -#include "Scan.h" -#include "Thread.h" -#include <dvdread/ifo_types.h> -#include <dvdplay/dvdplay.h> -#include <dvdplay/info.h> -#include <dvdplay/state.h> -#include <dvdplay/nav.h> +#include "dvdread/ifo_types.h" +#include "dvdplay/dvdplay.h" +#include "dvdplay/info.h" +#include "dvdplay/state.h" +#include "dvdplay/nav.h" -#include <mpeg2dec/mpeg2.h> +#include "mpeg2dec/mpeg2.h" /* Local prototypes */ static void ScanThread( void * ); @@ -26,14 +24,14 @@ static char * LanguageForCode( int code ); struct HBScan { - HBHandle * handle; - char * device; - int title; - int die; - HBThread * thread; + HBHandle * handle; + char * device; + int title; + volatile int die; + HBThread * thread; }; -HBScan * HBScanInit( HBHandle * handle, char * device, int title ) +HBScan * HBScanInit( HBHandle * handle, const char * device, int title ) { HBScan * s; if( !( s = malloc( sizeof( HBScan ) ) ) ) @@ -55,7 +53,7 @@ HBScan * HBScanInit( HBHandle * handle, char * device, int title ) void HBScanClose( HBScan ** _s ) { HBScan * s = *_s; - + s->die = 1; HBThreadClose( &s->thread ); @@ -66,65 +64,77 @@ void HBScanClose( HBScan ** _s ) static void ScanThread( void * _s ) { - HBScan * s = (HBScan*) _s; - dvdplay_ptr vmg; - HBList * titleList = HBListInit(); - HBTitle * title; - int i; + HBScan * s = (HBScan*) _s; + dvdplay_ptr vmg; + HBList * titleList = HBListInit(); + HBTitle * title; + int i; HBLog( "HBScan: opening device %s", s->device ); - HBScanning( s->handle, 0 ); vmg = dvdplay_open( s->device, NULL, NULL ); if( !vmg ) { HBLog( "HBScan: dvdplay_open() failed (%s)", s->device ); - HBScanDone( s->handle, titleList ); + HBListClose( &titleList ); + HBScanDone( s->handle, NULL ); return; } /* Detect titles */ - for( i = ( s->title ? s->title - 1 : 0 ); - i < ( s->title ? s->title : dvdplay_title_nr( vmg ) ); - i++ ) + i = s->title ? ( s->title - 1 ) : 0; + while( !s->die ) { - if( s->die ) + if( ( title = ScanTitle( s, vmg, i + 1 ) ) ) { - break; + HBListAdd( titleList, title ); } - - if( !( title = ScanTitle( s, vmg, i + 1 ) ) ) + if( s->title || i == dvdplay_title_nr( vmg ) - 1 ) { - continue; + break; } - - HBListAdd( titleList, title ); + i++; } HBLog( "HBScan: closing device %s", s->device ); dvdplay_close( vmg ); + if( s->die ) + { + while( ( title = HBListItemAt( titleList, 0 ) ) ) + { + HBListRemove( titleList, title ); + HBTitleClose( &title ); + } + HBListClose( &titleList ); + return; + } + + if( !HBListCount( titleList ) ) + { + HBListClose( &titleList ); + } HBScanDone( s->handle, titleList ); } static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) { - HBTitle * title; - int audio_nr, foo; + HBTitle * title; + int audio_nr, foo; audio_attr_t * attr; - HBAudio * audio; - int i; - uint8_t dummy[DVD_VIDEO_LB_LEN]; - - HBLog( "HBScan: scanning title %d", index ); - HBScanning( s->handle, index ); + HBAudio * audio; + int i; + uint8_t dummy[DVD_VIDEO_LB_LEN]; + + HBScanning( s->handle, index, dvdplay_title_nr( vmg ) ); title = HBTitleInit( s->device, index ); dvdplay_start( vmg, index ); /* Length */ title->length = dvdplay_title_time( vmg ); - HBLog( "HBScan: title length is %d seconds", title->length ); + HBLog( "HBScan: title %d: length is %d seconds", index, + title->length ); /* Discard titles under 10 seconds */ if( title->length < 10 ) @@ -139,9 +149,8 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) for( i = 0; i < audio_nr; i++ ) { - int id; - int j; - + int id, j; + if( s->die ) { break; @@ -156,13 +165,14 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) if( ( id & 0xF0FF ) != 0x80BD ) { - HBLog( "HBScan: non-AC3 audio track detected, ignoring" ); + HBLog( "HBScan: title %d: non-AC3 audio track detected, " + "ignoring", index ); continue; } /* Check if we don't already found an track with the same id */ audio = NULL; - for( j = 0; j < HBListCountItems( title->audioList ); j++ ) + for( j = 0; j < HBListCount( title->audioList ); j++ ) { audio = (HBAudio*) HBListItemAt( title->audioList, j ); if( id == audio->id ) @@ -177,28 +187,29 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) if( audio ) { - HBLog( "HBScan: discarding duplicate track %x", id ); + HBLog( "HBScan: title %d: discarding duplicate track %x", + index, id ); continue; } - attr = dvdplay_audio_attr( vmg, j ); + attr = dvdplay_audio_attr( vmg, j ); audio = HBAudioInit( id, LanguageForCode( attr->lang_code ) ); - HBLog( "HBScan: new language (%x, %s)", id, audio->language ); + HBLog( "HBScan: title %d: new language (%x, %s)", index, id, + audio->language ); HBListAdd( title->audioList, audio ); } /* Discard titles with no audio tracks */ - if( !HBListCountItems( title->audioList ) ) + if( !HBListCount( title->audioList ) ) { HBLog( "HBScan: ignoring title %d (no audio track)", index ); HBTitleClose( &title ); return NULL; } - /* Kludge : libdvdplay wants we to read a first block before seeking */ + /* Kludge : libdvdplay wants us to read a first block before seeking */ dvdplay_read( vmg, dummy, 1 ); - for( i = 0; i < 10; i++ ) { if( s->die ) @@ -215,6 +226,7 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) } } + /* Handle ratio */ if( title->inHeight * title->aspect > title->inWidth * VOUT_ASPECT_FACTOR ) { @@ -248,8 +260,9 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, mpeg2dec_t * handle; const mpeg2_info_t * info; mpeg2_state_t state; - char fileName[1024]; - FILE * file; + char fileName[1024]; + FILE * file; + int ret = 1; HBList * esBufferList = HBListInit(); HBBuffer * psBuffer = NULL; @@ -259,43 +272,34 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, dvdplay_seek( vmg, pictureStart ); /* Init libmpeg2 */ +#ifdef HB_NOMMX + mpeg2_accel( 0 ); +#endif handle = mpeg2_init(); info = mpeg2_info( handle ); - + /* Init the destination file */ memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.%d.%d", HBGetPid( s->handle ), + sprintf( fileName, "/tmp/HB.%d.%d.%d", HBGetPid( s->handle ), title->index, which ); file = fopen( fileName, "w" ); -#define CLEANUP \ - while( ( esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ) ) ) \ - { \ - HBListRemove( esBufferList, esBuffer ); \ - HBBufferClose( &esBuffer ); \ - } \ - HBListClose( &esBufferList ); \ - if( psBuffer ) HBBufferClose( &psBuffer ); \ - if( esBuffer ) HBBufferClose( &esBuffer ); \ - mpeg2_close( handle ); \ - fclose( file ) - for( ;; ) - { + { state = mpeg2_parse( handle ); if( state == STATE_BUFFER ) - { + { /* Free the previous buffer */ if( esBuffer ) - { + { HBBufferClose( &esBuffer ); } - + /* Get a new one */ while( !esBuffer ) { - while( !HBListCountItems( esBufferList ) ) + while( !HBListCount( esBufferList ) ) { psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); if( dvdplay_read( vmg, psBuffer->data, 1 ) != 1 || @@ -303,18 +307,21 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, { HBLog( "HBScan: failed to get a valid PS " "packet" ); - CLEANUP; - return 0; + break; } if( dvdplay_position( vmg ) >= pictureEnd ) { HBLog( "HBScan: gone too far, aborting" ); - CLEANUP; - return 0; + break; } } + if( !HBListCount( esBufferList ) ) + { + break; + } + esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ); HBListRemove( esBufferList, esBuffer ); @@ -324,27 +331,80 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, } } + if( !esBuffer ) + { + ret = 0; + break; + } + /* Feed libmpeg2 */ mpeg2_buffer( handle, esBuffer->data, esBuffer->data + esBuffer->size ); } else if( state == STATE_SEQUENCE ) { - /* Get size & framerate info */ - title->inWidth = info->sequence->width; - title->inHeight = info->sequence->height; - title->aspect = (uint64_t)info->sequence->display_width * - info->sequence->pixel_width * VOUT_ASPECT_FACTOR / - ( info->sequence->display_height * - info->sequence->pixel_height ); - title->rate = 27000000; - title->rateBase = info->sequence->frame_period; + if( !which ) + { + /* Get size & framerate info */ + title->inWidth = info->sequence->width; + title->inHeight = info->sequence->height; + title->aspect = (uint64_t)info->sequence->display_width * + info->sequence->pixel_width * VOUT_ASPECT_FACTOR / + ( info->sequence->display_height * + info->sequence->pixel_height ); + title->rate = 27000000; + title->rateBase = info->sequence->frame_period; + + title->autoTopCrop = title->inHeight / 2; + title->autoBottomCrop = title->inHeight / 2; + title->autoLeftCrop = title->inWidth / 2; + title->autoRightCrop = title->inWidth / 2; + } } else if( ( state == STATE_SLICE || state == STATE_END ) && ( info->display_fbuf ) && ( info->display_picture->flags & PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I ) { +#define Y info->display_fbuf->buf[0] +#define DARK 64 + /* Detect black borders */ + int i, j; + for( i = 0; i < title->inWidth; i++ ) + { + for( j = 0; j < title->autoTopCrop; j++ ) + if( Y[ j * title->inWidth + i ] > DARK ) + { + title->autoTopCrop = j; + break; + } + for( j = 0; j < title->autoBottomCrop; j++ ) + if( Y[ ( title->inHeight - j - 1 ) * + title->inWidth + i ] > DARK ) + { + title->autoBottomCrop = j; + break; + } + } + for( i = 0; i < title->inHeight; i++ ) + { + for( j = 0; j < title->autoLeftCrop; j++ ) + if( Y[ i * title->inWidth + j ] > DARK ) + { + title->autoLeftCrop = j; + break; + } + for( j = 0; j < title->autoRightCrop; j++ ) + if( Y[ i * title->inWidth + + title->inWidth - j - 1 ] > DARK ) + { + title->autoRightCrop = j; + break; + } + } +#undef Y +#undef DARK + /* Write the raw picture to a file */ fwrite( info->display_fbuf->buf[0], title->inWidth * title->inHeight, 1, file ); @@ -358,15 +418,25 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, { /* Reset libmpeg2 */ mpeg2_close( handle ); +#ifdef HB_NOMMX + mpeg2_accel( 0 ); +#endif handle = mpeg2_init(); } } - CLEANUP; - - return 1; + while( ( esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ) ) ) + { + HBListRemove( esBufferList, esBuffer ); + HBBufferClose( &esBuffer ); + } + HBListClose( &esBufferList ); + if( psBuffer ) HBBufferClose( &psBuffer ); + if( esBuffer ) HBBufferClose( &esBuffer ); + mpeg2_close( handle ); + fclose( file ); -#undef CLEANUP + return ret; } static char * LanguageForCode( int code ) diff --git a/core/Scan.h b/core/Scan.h deleted file mode 100644 index 5cc8542e7..000000000 --- a/core/Scan.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: Scan.h,v 1.2 2003/11/06 13:03:19 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_SCAN_H -#define HB_SCAN_H - -#include "HandBrakeInternal.h" - -HBScan * HBScanInit( HBHandle *, char * device, int title ); -void HBScanClose( HBScan ** ); - -#endif diff --git a/core/Thread.c b/core/Thread.c index f0d8e628b..01af1b0b6 100644 --- a/core/Thread.c +++ b/core/Thread.c @@ -1,13 +1,10 @@ -/* $Id: Thread.c,v 1.5 2003/11/12 16:09:34 titer Exp $ +/* $Id: Thread.c,v 1.10 2004/01/14 21:37:25 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ #include "Thread.h" -#ifdef SYS_CYGWIN -# include <windows.h> -#endif struct HBThread { @@ -15,12 +12,12 @@ struct HBThread int priority; void (*function) ( void * ); void * arg; - -#if defined( SYS_BEOS ) + +#if defined( HB_BEOS ) int thread; -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_t thread; -#elif defined( SYS_CYGWIN ) +#elif defined( HB_CYGWIN ) HANDLE thread; #endif }; @@ -42,14 +39,14 @@ HBThread * HBThreadInit( char * name, void (* function)(void *), t->function = function; t->arg = arg; -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) t->thread = spawn_thread( (int32 (*)( void * )) ThreadFunc, name, priority, t ); resume_thread( t->thread ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_create( &t->thread, NULL, (void * (*)( void * )) ThreadFunc, t ); -#elif defined( SYS_CYGWIN ) +#elif defined( HB_CYGWIN ) t->thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc, t, 0, NULL ); #endif @@ -64,7 +61,7 @@ static void ThreadFunc( void * _t ) { HBThread * t = (HBThread*) _t; -#if defined( SYS_MACOSX ) +#if defined( HB_MACOSX ) struct sched_param param; memset( ¶m, 0, sizeof( struct sched_param ) ); param.sched_priority = t->priority; @@ -80,13 +77,13 @@ static void ThreadFunc( void * _t ) void HBThreadClose( HBThread ** _t ) { HBThread * t = *_t; - -#if defined( SYS_BEOS ) + +#if defined( HB_BEOS ) long exitValue; wait_for_thread( t->thread, &exitValue ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_join( t->thread, NULL ); -#elif defined( SYS_CYGWIN ) +#elif defined( HB_CYGWIN ) WaitForSingleObject( t->thread, INFINITE ); #endif @@ -107,12 +104,12 @@ HBLock * HBLockInit() return NULL; } -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) l->sem = create_sem( 1, "sem" ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_mutex_init( &l->mutex, NULL ); -#elif defined( SYS_CYGWIN ) - /* TODO */ +#elif defined( HB_CYGWIN ) + l->mutex = CreateMutex( 0, FALSE, 0 ); #endif return l; @@ -121,16 +118,46 @@ HBLock * HBLockInit() void HBLockClose( HBLock ** _l ) { HBLock * l = *_l; - -#if defined( SYS_BEOS ) + +#if defined( HB_BEOS ) delete_sem( l->sem ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_mutex_destroy( &l->mutex ); -#elif defined( SYS_CYGWIN ) - /* TODO */ +#elif defined( HB_CYGWIN ) + CloseHandle( l->mutex ); #endif free( l ); *_l = NULL; } +HBCond * HBCondInit() +{ + HBCond * c = malloc( sizeof( HBCond ) ); + +#if defined( HB_BEOS ) + c->thread = -1; +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) + pthread_cond_init( &c->cond, NULL ); +#elif defined( HB_CYGWIN ) + /* TODO */ +#endif + + return c; +} + +void HBCondClose( HBCond ** _c ) +{ + HBCond * c = *_c; + +#if defined( HB_BEOS ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) + pthread_cond_destroy( &c->cond ); +#elif defined( HB_CYGWIN ) + /* TODO */ +#endif + free( c ); + + *_c = NULL; +} + diff --git a/core/Thread.h b/core/Thread.h index 58700aae1..4d6288e5b 100644 --- a/core/Thread.h +++ b/core/Thread.h @@ -1,4 +1,4 @@ -/* $Id: Thread.h,v 1.3 2003/11/06 15:51:36 titer Exp $ +/* $Id: Thread.h,v 1.8 2004/01/14 21:37:25 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -7,64 +7,125 @@ #ifndef HB_THREAD_H #define HB_THREAD_H -#if defined( SYS_BEOS ) +/* System headers */ +#if defined( HB_BEOS ) # include <OS.h> -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) # include <pthread.h> +#elif defined( HB_CYGWIN ) +# include <windows.h> #endif #include "Utils.h" -#if defined( SYS_BEOS ) +/* Thread priorities */ +#if defined( HB_BEOS ) # define HB_LOW_PRIORITY 5 # define HB_NORMAL_PRIORITY 10 -#elif defined( SYS_MACOSX ) +#elif defined( HB_MACOSX ) # define HB_LOW_PRIORITY 0 # define HB_NORMAL_PRIORITY 31 -#elif defined( SYS_LINUX ) || defined( SYS_CYGWIN ) +#elif defined( HB_LINUX ) || defined( HB_CYGWIN ) /* Actually unused */ # define HB_LOW_PRIORITY 0 # define HB_NORMAL_PRIORITY 0 #endif +/* Functions declarations */ HBThread * HBThreadInit( char * name, void (* function)(void *), void * arg, int priority ); void HBThreadClose( HBThread ** ); +HBLock * HBLockInit(); +static inline void HBLockLock( HBLock * ); +static inline void HBLockUnlock( HBLock * ); +void HBLockClose( HBLock ** ); + +HBCond * HBCondInit(); +static inline void HBCondWait( HBCond *, HBLock * ); +static inline void HBCondSignal( HBCond * ); +void HBCondClose( HBCond ** ); + +/* Inlined stuff */ struct HBLock { -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) sem_id sem; -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_mutex_t mutex; -#elif defined( SYS_CYGWIN ) - /* TODO */ +#elif defined( HB_CYGWIN ) + HANDLE mutex; #endif }; -HBLock * HBLockInit(); -static inline void HBLockLock( HBLock * ); -static inline void HBLockUnlock( HBLock * ); -void HBLockClose( HBLock ** ); - static inline void HBLockLock( HBLock * l ) { -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) acquire_sem( l->sem ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_mutex_lock( &l->mutex ); -#elif defined( SYS_CYGWIN ) - /* TODO */ +#elif defined( HB_CYGWIN ) + WaitForSingleObject( l->mutex, INFINITE ); #endif } static inline void HBLockUnlock( HBLock * l ) { -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) release_sem( l->sem ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) pthread_mutex_unlock( &l->mutex ); -#elif defined( SYS_CYGWIN ) +#elif defined( HB_CYGWIN ) + ReleaseMutex( l->mutex ); +#endif +} + +struct HBCond +{ +#if defined( HB_BEOS ) + int thread; +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) + pthread_cond_t cond; +#elif defined( HB_CYGWIN ) + /* TODO */ +#endif + +}; + +static inline void HBCondWait( HBCond * c, HBLock * lock ) +{ +#if defined( HB_BEOS ) + c->thread = find_thread( NULL ); + release_sem( lock->sem ); + suspend_thread( c->thread ); + acquire_sem( lock->sem ); + c->thread = -1; +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) + pthread_cond_wait( &c->cond, &lock->mutex ); +#elif defined( HB_CYGWIN ) + /* TODO */ +#endif +} + +static inline void HBCondSignal( HBCond * c ) +{ +#if defined( HB_BEOS ) + while( c->thread != -1 ) + { + thread_info info; + get_thread_info( c->thread, &info ); + if( info.state == B_THREAD_SUSPENDED ) + { + resume_thread( c->thread ); + break; + } + /* In case HBCondSignal is called between HBCondWait's + release_sem() and suspend_thread() lines, wait a bit */ + snooze( 5000 ); + } +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) + pthread_cond_signal( &c->cond ); +#elif defined( HB_CYGWIN ) /* TODO */ #endif } diff --git a/core/Utils.c b/core/Utils.c index 566979901..f9451bb9a 100644 --- a/core/Utils.c +++ b/core/Utils.c @@ -1,4 +1,4 @@ -/* $Id: Utils.c,v 1.8 2003/11/12 16:09:34 titer Exp $ +/* $Id: Utils.c,v 1.14 2004/01/16 19:04:04 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -7,7 +7,7 @@ #include <stdarg.h> #include <time.h> #include <sys/time.h> -#ifdef SYS_CYGWIN +#ifdef HB_CYGWIN # include <windows.h> #endif @@ -23,22 +23,22 @@ struct HBList void HBSnooze( int time ) { -#if defined( SYS_BEOS ) +#if defined( HB_BEOS ) snooze( time ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +#elif defined( HB_MACOSX ) || defined( HB_LINUX ) usleep( time ); -#elif defined( SYS_CYGWIN ) +#elif defined( HB_CYGWIN ) Sleep( time / 1000 ); #endif } void HBLog( char * log, ... ) { - char string[81]; - time_t _now; + char string[80]; + time_t _now; struct tm * now; - va_list args; - int ret; + va_list args; + int ret; if( !getenv( "HB_DEBUG" ) ) { @@ -47,13 +47,13 @@ void HBLog( char * log, ... ) /* Show the time */ _now = time( NULL ); - now = localtime( &_now ); + now = localtime( &_now ); sprintf( string, "[%02d:%02d:%02d] ", now->tm_hour, now->tm_min, now->tm_sec ); /* Convert the message to a string */ va_start( args, log ); - ret = vsnprintf( string + 11, 68, log, args ); + ret = vsnprintf( string + 11, 67, log, args ); va_end( args ); /* Add the end of line */ @@ -66,7 +66,7 @@ void HBLog( char * log, ... ) uint64_t HBGetDate() { -#ifndef SYS_CYGWIN +#ifndef HB_CYGWIN struct timeval tv; gettimeofday( &tv, NULL ); return( (uint64_t) tv.tv_sec * 1000000 + (uint64_t) tv.tv_usec ); @@ -112,11 +112,11 @@ int HBPStoES( HBBuffer ** _psBuffer, HBList * esBufferList ) while( pos + 6 < psBuffer->size && d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 ) { - uint32_t streamId; - uint32_t PES_packet_length; - uint32_t PES_packet_end; - uint32_t PES_header_d_length; - uint32_t PES_header_end; + int streamId; + int PES_packet_length; + int PES_packet_end; + int PES_header_d_length; + int PES_header_end; int hasPTS; uint64_t PTS = 0; @@ -163,11 +163,10 @@ int HBPStoES( HBBuffer ** _psBuffer, HBList * esBufferList ) /* Sanity check */ if( pos >= PES_packet_end ) { - HBLog( "HBPStoES: pos >= PES_packet_end" ); pos = PES_packet_end; continue; } - + /* Here we hit we ES payload */ esBuffer = HBBufferInit( PES_packet_end - pos ); @@ -183,6 +182,8 @@ int HBPStoES( HBBuffer ** _psBuffer, HBList * esBufferList ) pos = PES_packet_end; } +#undef d + HBBufferClose( _psBuffer ); return 1; @@ -204,14 +205,14 @@ HBList * HBListInit() free( l ); return NULL; } - + l->allocItems = HBLIST_DEFAULT_SIZE; l->nbItems = 0; - + return l; } -int HBListCountItems( HBList * l ) +int HBListCount( HBList * l ) { return l->nbItems; } @@ -278,7 +279,7 @@ void * HBListItemAt( HBList * l, int index ) void HBListClose( HBList ** _l ) { HBList * l = *_l; - + free( l->items ); free( l ); @@ -287,23 +288,32 @@ void HBListClose( HBList ** _l ) HBTitle * HBTitleInit( char * device, int index ) { - HBTitle * t = calloc( sizeof( HBTitle ), 1 ); + HBTitle * t; + + if( !( t = calloc( sizeof( HBTitle ), 1 ) ) ) + { + HBLog( "HBTitleInit: calloc() failed, gonna crash" ); + return NULL; + } + + t->device = strdup( device ); + t->index = index; + + t->codec = HB_CODEC_FFMPEG; + t->mux = HB_MUX_MP4; + + t->audioList = HBListInit(); + t->ripAudioList = HBListInit(); - t->device = strdup( device ); - t->index = index; + t->start = -1; - t->codec = HB_CODEC_FFMPEG; - t->bitrate = 1024; - - t->audioList = HBListInit(); - return t; } void HBTitleClose( HBTitle ** _t ) { HBTitle * t = *_t; - + HBAudio * audio; while( ( audio = HBListItemAt( t->audioList, 0 ) ) ) { @@ -311,7 +321,8 @@ void HBTitleClose( HBTitle ** _t ) HBAudioClose( &audio ); } HBListClose( &t->audioList ); - + HBListClose( &t->ripAudioList ); + if( t->file ) free( t->file ); free( t->device ); free( t ); @@ -322,30 +333,23 @@ void HBTitleClose( HBTitle ** _t ) HBAudio * HBAudioInit( int id, char * language ) { HBAudio * a; - if( !( a = malloc( sizeof( HBAudio ) ) ) ) + if( !( a = calloc( sizeof( HBAudio ), 1 ) ) ) { - HBLog( "HBAudioInit: malloc() failed, gonna crash" ); + HBLog( "HBAudioInit: calloc() failed, gonna crash" ); return NULL; } a->id = id; a->language = strdup( language ); - a->inSampleRate = 0; - a->outSampleRate = 44100; - a->delay = 0; - a->ac3Fifo = NULL; - a->rawFifo = NULL; - a->mp3Fifo = NULL; - a->ac3Dec = NULL; - a->mp3Enc = NULL; - + a->start = -1; + return a; } void HBAudioClose( HBAudio ** _a ) { HBAudio * a = *_a; - + free( a->language ); free( a ); diff --git a/core/Utils.h b/core/Utils.h index ba1a9101e..a83c36c65 100644 --- a/core/Utils.h +++ b/core/Utils.h @@ -1,4 +1,4 @@ -/* $Id: Utils.h,v 1.6 2003/11/07 21:22:17 titer Exp $ +/* $Id: Utils.h,v 1.22 2004/01/21 18:40:36 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -14,7 +14,7 @@ #include <unistd.h> #include <inttypes.h> typedef uint8_t byte_t; -#ifdef SYS_BEOS +#ifdef HB_BEOS # include <OS.h> #endif @@ -35,27 +35,33 @@ typedef uint8_t byte_t; #define VOUT_ASPECT_FACTOR 432000 #endif -typedef struct HBAc3Dec HBAc3Dec; +typedef struct HBHandle HBHandle; + +/* Utils */ typedef struct HBAudio HBAudio; -typedef struct HBAviMux HBAviMux; typedef struct HBBuffer HBBuffer; -typedef struct HBDVDRead HBDVDRead; +typedef struct HBCond HBCond; typedef struct HBFifo HBFifo; typedef struct HBList HBList; typedef struct HBLock HBLock; -typedef struct HBHandle HBHandle; -typedef struct HBMp3Enc HBMp3Enc; -typedef struct HBMpeg2Dec HBMpeg2Dec; -typedef struct HBFfmpegEnc HBFfmpegEnc; -typedef struct HBMadDec HBMadDec; -typedef struct HBScale HBScale; -typedef struct HBScan HBScan; -typedef struct HBStatus HBStatus; -typedef struct HBThread HBThread; typedef struct HBTitle HBTitle; +typedef struct HBThread HBThread; + +/* (De)Muxers */ +typedef struct HBAviMux HBAviMux; +typedef struct HBOgmMux HBOgmMux; +typedef struct HBDVDRead HBDVDRead; +typedef struct HBMp4Mux HBMp4Mux; +typedef struct HBScan HBScan; + typedef struct HBWork HBWork; typedef struct HBWorkThread HBWorkThread; -typedef struct HBXvidEnc HBXvidEnc; + +/* AVI stuff */ +typedef struct HBAviMainHeader HBAviMainHeader; +typedef struct HBAviStreamHeader HBAviStreamHeader; +typedef struct HBBitmapInfo HBBitmapInfo; +typedef struct HBWaveFormatEx HBWaveFormatEx; /* Misc functions which may be used from anywhere */ void HBSnooze( int time ); @@ -65,7 +71,7 @@ int HBPStoES( HBBuffer ** psBuffer, HBList * esBufferList ); /* HBList functions */ HBList * HBListInit(); -int HBListCountItems( HBList * ); +int HBListCount( HBList * ); void HBListAdd( HBList *, void * item ); void HBListRemove( HBList *, void * item ); void * HBListItemAt( HBList *, int index ); @@ -79,135 +85,143 @@ void HBTitleClose( HBTitle ** ); HBAudio * HBAudioInit( int id, char * language ); void HBAudioClose( HBAudio ** ); -/* Possible states */ -typedef enum -{ - HB_MODE_UNDEF = 00000, - HB_MODE_NEED_DEVICE = 00001, - HB_MODE_SCANNING = 00002, - HB_MODE_INVALID_DEVICE = 00004, - HB_MODE_READY_TO_RIP = 00010, - HB_MODE_ENCODING = 00020, - HB_MODE_PAUSED = 00040, - HB_MODE_STOPPING = 00100, - HB_MODE_DONE = 00200, - HB_MODE_CANCELED = 00400, - HB_MODE_ERROR = 01000, - HB_MODE_EXITING = 02000 -} HBMode; - -/* Possible errors */ -typedef enum -{ - HB_ERROR_A52_SYNC = 0, - HB_ERROR_AVI_WRITE, - HB_ERROR_DVD_OPEN, - HB_ERROR_DVD_READ, - HB_ERROR_MP3_INIT, - HB_ERROR_MP3_ENCODE, - HB_ERROR_MPEG4_INIT -} HBError; +#define HB_SUCCESS 0x00 +#define HB_CANCELED 0x01 +#define HB_ERROR_A52_SYNC 0x02 +#define HB_ERROR_AVI_WRITE 0x04 +#define HB_ERROR_DVD_OPEN 0x08 +#define HB_ERROR_DVD_READ 0x10 +#define HB_ERROR_MP3_INIT 0x20 +#define HB_ERROR_MP3_ENCODE 0x40 +#define HB_ERROR_MPEG4_INIT 0x80 /* Possible codecs */ -typedef enum -{ - HB_CODEC_FFMPEG = 0, - HB_CODEC_XVID -} HBCodec; +#define HB_CODEC_MPEG2 0x00 +#define HB_CODEC_FFMPEG 0x01 +#define HB_CODEC_XVID 0x02 +#define HB_CODEC_AC3 0x04 +#define HB_CODEC_MP3 0x08 +#define HB_CODEC_AAC 0x10 +#define HB_CODEC_X264 0x20 +#define HB_CODEC_VORBIS 0x40 + +/* Possible muxers */ +#define HB_MUX_AVI 0x00 +#define HB_MUX_MP4 0x01 +#define HB_MUX_OGM 0x02 -struct HBStatus +struct HBTitle { - HBMode mode; - - /* HB_MODE_SCANNING */ - int scannedTitle; + /* DVD info */ + char * device; + int index; + int length; - /* HB_MODE_SCANDONE */ - HBList * titleList; - - /* HB_MODE_ENCODING || HB_MODE_PAUSED */ - float position; - int pass; - int passCount; - float frameRate; - float avFrameRate; - uint32_t remainingTime; /* in seconds */ + /* Audio infos */ + HBList * audioList; + HBList * ripAudioList; - /* HB_MODE_ERROR */ - HBError error; -}; - -struct HBTitle -{ - char * device; - int index; - int length; - char * file; + /* See DVDRead.c */ + int64_t start; /* Video input */ - int inWidth; - int inHeight; - int aspect; - int rate; - int rateBase; + int inWidth; + int inHeight; + int aspect; + int rate; + int rateBase; /* Video output */ - int outWidth; - int outHeight; - int outWidthMax; - int outHeightMax; - int topCrop; - int bottomCrop; - int leftCrop; - int rightCrop; - int deinterlace; - HBCodec codec; - int bitrate; - int twoPass; - - /* Audio infos */ - HBList * audioList; + int outWidth; + int outHeight; + int outWidthMax; + int outHeightMax; + int topCrop; + int bottomCrop; + int leftCrop; + int rightCrop; + int deinterlace; + int autoTopCrop; + int autoBottomCrop; + int autoLeftCrop; + int autoRightCrop; + + /* Encoder settings */ + int codec; + int bitrate; + int twoPass; + + /* Muxer settings */ + char * file; + int mux; + + /* MP4 muxer specific */ + int track; + uint8_t * esConfig; + int esConfigLength; + + /* AVI muxer specific */ + HBAviMainHeader * aviMainHeader; + HBAviStreamHeader * aviVideoHeader; + HBBitmapInfo * aviVideoFormat; /* Fifos */ - HBFifo * mpeg2Fifo; - HBFifo * rawFifo; - HBFifo * scaledFifo; - HBFifo * mpeg4Fifo; + HBFifo * inFifo; + HBFifo * rawFifo; + HBFifo * scaledFifo; + HBFifo * outFifo; /* Threads */ HBDVDRead * dvdRead; - HBMpeg2Dec * mpeg2Dec; - HBScale * scale; - HBFfmpegEnc * ffmpegEnc; - HBXvidEnc * xvidEnc; HBAviMux * aviMux; + HBMp4Mux * mp4Mux; + HBOgmMux * ogmMux; HBWorkThread * workThreads[8]; + + /* Work objects */ + HBWork * decoder; + HBWork * scale; + HBWork * encoder; }; struct HBAudio { - /* Ident */ - uint32_t id; - char * language; - - /* Settings */ - int inSampleRate; - int outSampleRate; - int inBitrate; - int outBitrate; - - int delay; /* in ms */ - - /* Fifos */ - HBFifo * ac3Fifo; - HBFifo * rawFifo; - HBFifo * mp3Fifo; - - /* Threads */ - HBAc3Dec * ac3Dec; - HBMp3Enc * mp3Enc; -}; + /* Ident */ + uint32_t id; + char * language; + + /* Settings */ + int codec; + int inSampleRate; + int outSampleRate; + int inBitrate; + int outBitrate; + + int delay; /* in ms */ + + /* See DVDRead.c */ + int64_t start; + + /* MPEG-4 config, used in the MP4 muxer */ + uint8_t * esConfig; + unsigned long esConfigLength; + /* MP4 track id */ + int track; + /* AVI stuff */ + uint32_t aviFourCC; + HBAviStreamHeader * aviAudioHeader; + HBWaveFormatEx * aviAudioFormat; + + /* Fifos */ + HBFifo * inFifo; + HBFifo * rawFifo; + HBFifo * outFifo; + + /* Work objects */ + HBWork * decoder; + HBWork * encoder;; +}; #endif diff --git a/core/VorbisEnc.c b/core/VorbisEnc.c new file mode 100644 index 000000000..a4f305720 --- /dev/null +++ b/core/VorbisEnc.c @@ -0,0 +1,257 @@ +/* $Id: VorbisEnc.c,v 1.4 2003/12/26 20:03:27 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "HBInternal.h" + +/* libvorbis */ +#include <vorbis/vorbisenc.h> + +#define OGGVORBIS_FRAME_SIZE 1024 + +typedef struct HBVorbisEnc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBAudio * audio; + + int inited; + vorbis_info vi; + vorbis_comment vc; + vorbis_dsp_state vd; + vorbis_block vb; + + HBBuffer *rawBuffer; + int rawBufferPos; /* in bytes */ + float position; + int32_t * inputBuffer; + unsigned long samplesGot; + unsigned long inputSamples; + + HBBuffer *vorbisBuffer; + + HBBuffer *header[3]; +} HBVorbisEnc; + +/* Local prototypes */ +static int VorbisEncWork( HBWork * ); +static int GetSamples( HBVorbisEnc * ); + +HBWork *HBVorbisEncInit ( HBHandle *handle, HBAudio *audio ) +{ + HBVorbisEnc *enc = malloc( sizeof( HBVorbisEnc ) ); + + enc->name = strdup( "VorbisEnc" ); + enc->work = VorbisEncWork; + + enc->handle = handle; + enc->audio = audio; + + enc->inited = 0; + enc->rawBuffer = NULL; + enc->inputSamples = 2 * OGGVORBIS_FRAME_SIZE; + enc->inputBuffer = malloc( 2 * OGGVORBIS_FRAME_SIZE * sizeof( int32_t ) ); + enc->samplesGot = 0; + + enc->vorbisBuffer = NULL; + + return (HBWork*) enc; +} + +void HBVorbisEncClose( HBWork **_enc ) +{ + HBVorbisEnc *enc = (HBVorbisEnc*) *_enc; + + if( enc->inited ) + { + vorbis_block_clear( &enc->vb ); + vorbis_dsp_clear( &enc->vd ); + vorbis_comment_clear( &enc->vc ); + vorbis_info_clear( &enc->vi ); + } + + free( enc->name ); + free( enc ); + + *_enc = NULL; +} + +static HBBuffer *PacketToBuffer( ogg_packet *op ) +{ + HBBuffer *buf = HBBufferInit( sizeof( ogg_packet ) + op->bytes ); + + memcpy( buf->data, op, sizeof( ogg_packet ) ); + memcpy( buf->data + sizeof( ogg_packet ), op->packet, op->bytes ); + + return buf; +} + +static int VorbisEncWork( HBWork *w ) +{ + HBVorbisEnc *enc = (HBVorbisEnc*)w; + HBAudio *audio = enc->audio; + int didSomething = 0; + + float **buffer; + int i; + + + if( !enc->inited ) + { + ogg_packet header[3]; + + /* Get a first buffer so we know that audio->inSampleRate is correct */ + if( ( enc->rawBuffer = HBFifoPop( audio->rawFifo ) ) == NULL ) + { + return 0; + } + enc->inited = 1; + + didSomething = 1; + enc->rawBufferPos = 0; + enc->position = enc->rawBuffer->position; + + /* No resampling */ + audio->outSampleRate = audio->inSampleRate; + + /* init */ + vorbis_info_init( &enc->vi ); + if( vorbis_encode_setup_vbr( &enc->vi, 2 /* channel */, audio->inSampleRate, 1.0/* quality 0.0 -> 1.0*/ ) ) + { + HBLog( "VorbisEnc: vorbis_encode_setup_vbr failed" ); + return 0; + } + vorbis_encode_setup_init( &enc->vi ); + + /* add a comment */ + vorbis_comment_init( &enc->vc ); + vorbis_comment_add_tag( &enc->vc, "ENCODER", "Handbrake"); + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init( &enc->vd, &enc->vi); + vorbis_block_init( &enc->vd, &enc->vb); + + + /* get the 3 headers */ + vorbis_analysis_headerout( &enc->vd, &enc->vc, + &header[0], &header[1], &header[2] ); + + enc->header[0] = PacketToBuffer( &header[0] ); + enc->header[1] = PacketToBuffer( &header[1] ); + enc->header[2] = PacketToBuffer( &header[2] ); + } + + if( enc->header[0] ) + { + HBLog( "VorbisEncWork: sending header 1" ); + if( !HBFifoPush( audio->outFifo, &enc->header[0] ) ) + { + return didSomething; + } + didSomething = 1; + } + if( enc->header[1] ) + { + HBLog( "VorbisEncWork: sending header 2" ); + if( !HBFifoPush( audio->outFifo, &enc->header[1] ) ) + { + return didSomething; + } + didSomething = 1; + } + if( enc->header[2] ) + { + HBLog( "VorbisEncWork: sending header 3" ); + if( !HBFifoPush( audio->outFifo, &enc->header[2] ) ) + { + return didSomething; + } + didSomething = 1; + } + + /* Push already encoded data */ + if( enc->vorbisBuffer ) + { + if( !HBFifoPush( audio->outFifo, &enc->vorbisBuffer ) ) + { + return didSomething; + } + } + + /* Try to extract more data */ + if( vorbis_analysis_blockout( &enc->vd, &enc->vb ) == 1 ) + { + ogg_packet op; + + vorbis_analysis( &enc->vb, NULL ); + vorbis_bitrate_addblock( &enc->vb ); + + if( vorbis_bitrate_flushpacket( &enc->vd, &op ) ) + { + enc->vorbisBuffer = PacketToBuffer( &op ); + enc->vorbisBuffer->position = enc->position; + return 1; + } + } + + didSomething = 1; + + /* FUCK -Werror ! */ + if( !GetSamples( enc ) ) + { + return didSomething; + } + + buffer = vorbis_analysis_buffer( &enc->vd, OGGVORBIS_FRAME_SIZE ); + for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ ) + { + buffer[0][i] = (float)enc->inputBuffer[2 * i + 0]/32768.f; + buffer[1][i] = (float)enc->inputBuffer[2 * i + 1]/32768.f; + } + vorbis_analysis_wrote( &enc->vd, OGGVORBIS_FRAME_SIZE ); + + enc->samplesGot = 0; + + return 1; +} + +static int GetSamples( HBVorbisEnc * f ) +{ + while( f->samplesGot < f->inputSamples ) + { + int i, copy; + + if( !f->rawBuffer ) + { + if( !( f->rawBuffer = HBFifoPop( f->audio->rawFifo ) ) ) + { + return 0; + } + + f->rawBufferPos = 0; + f->position = f->rawBuffer->position; + } + + copy = MIN( f->inputSamples - f->samplesGot, + ( f->rawBuffer->samples - f->rawBufferPos ) * 2 ); + + for( i = 0; i < copy; i += 2 ) + { + f->inputBuffer[f->samplesGot++] = + f->rawBuffer->left[f->rawBufferPos]; + f->inputBuffer[f->samplesGot++] = + f->rawBuffer->right[f->rawBufferPos]; + f->rawBufferPos++; + } + + if( f->rawBufferPos == f->rawBuffer->samples ) + { + HBBufferClose( &f->rawBuffer ); + } + } + + return 1; +} diff --git a/core/Work.c b/core/Work.c index b15e50839..f2f05030a 100644 --- a/core/Work.c +++ b/core/Work.c @@ -1,11 +1,10 @@ -/* $Id: Work.c,v 1.4 2003/11/06 12:33:11 titer Exp $ +/* $Id: Work.c,v 1.12 2004/01/05 16:50:25 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Thread.h" -#include "Work.h" +#include "HBInternal.h" /* Local prototypes */ static void WorkThread( void * t ); @@ -17,22 +16,22 @@ struct HBWork struct HBWorkThread { - HBHandle * handle; + HBHandle * handle; - HBList * workList; - int firstThread; + HBList * workList; + int firstThread; - int die; - HBThread * thread; + volatile int die; + HBThread * thread; }; HBWorkThread * HBWorkThreadInit( HBHandle * handle, HBTitle * title, - HBAudio * audio, HBAudio * optAudio, int firstThread ) { int i; - HBWork * w; - + HBWork * w; + HBAudio * audio; + HBWorkThread * t; if( !( t = malloc( sizeof( HBWorkThread ) ) ) ) { @@ -44,22 +43,17 @@ HBWorkThread * HBWorkThreadInit( HBHandle * handle, HBTitle * title, /* Build a list of work objects. They all include HB_WORK_COMMON_MEMBERS, so we'll be able to do the job without - knowing what each one actually do */ + knowing what each one actually does */ t->workList = HBListInit(); - HBListAdd( t->workList, title->mpeg2Dec ); + HBListAdd( t->workList, title->decoder ); HBListAdd( t->workList, title->scale ); + HBListAdd( t->workList, title->encoder ); - if( title->codec == HB_CODEC_FFMPEG ) - HBListAdd( t->workList, title->ffmpegEnc ); - else if( title->codec == HB_CODEC_XVID ) - HBListAdd( t->workList, title->xvidEnc ); - - HBListAdd( t->workList, audio->ac3Dec ); - HBListAdd( t->workList, audio->mp3Enc ); - if( optAudio ) + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - HBListAdd( t->workList, optAudio->ac3Dec ); - HBListAdd( t->workList, optAudio->mp3Enc ); + audio = HBListItemAt( title->ripAudioList, i ); + HBListAdd( t->workList, audio->decoder ); + HBListAdd( t->workList, audio->encoder ); } t->firstThread = firstThread; @@ -69,7 +63,7 @@ HBWorkThread * HBWorkThreadInit( HBHandle * handle, HBTitle * title, is done by the first worker thread (see HBStartRip) */ if( t->firstThread ) { - for( i = 0; i < HBListCountItems( t->workList ); i++ ) + for( i = 0; i < HBListCount( t->workList ); i++ ) { w = (HBWork*) HBListItemAt( t->workList, i ); w->lock = HBLockInit(); @@ -100,15 +94,15 @@ void HBWorkThreadClose( HBWorkThread ** _t ) { int i; uint64_t total = 0; - - for( i = 0; i < HBListCountItems( t->workList ); i++ ) + + for( i = 0; i < HBListCount( t->workList ); i++ ) { w = (HBWork*) HBListItemAt( t->workList, i ); HBLockClose( &w->lock ); total += w->time; } - for( i = 0; i < HBListCountItems( t->workList ); i++ ) + for( i = 0; i < HBListCount( t->workList ); i++ ) { w = (HBWork*) HBListItemAt( t->workList, i ); HBLog( "HBWorkThreadClose: %- 9s = %05.2f %%", w->name, @@ -116,12 +110,12 @@ void HBWorkThreadClose( HBWorkThread ** _t ) } } - + /* Free memory */ HBListClose( &t->workList ); free( t ); - (*_t) = NULL; + *_t = NULL; } static void WorkThread( void * _t ) @@ -131,57 +125,51 @@ static void WorkThread( void * _t ) int didSomething, i; uint64_t date; - for( ;; ) + didSomething = 0; + + for( i = 0; !t->die; i++ ) { HBCheckPaused( t->handle ); - - didSomething = 0; - for( i = 0; i < HBListCountItems( t->workList ); i++ ) + if( i == HBListCount( t->workList ) ) { - if( t->die ) + /* If nothing could be done, wait a bit to prevent a useless + CPU-consuming loop */ + if( !didSomething ) { - break; + HBSnooze( 5000 ); } - - w = (HBWork*) HBListItemAt( t->workList, i ); + didSomething = 0; + i = 0; + } - /* Check if another thread isn't using this work object. - If not, lock it */ - HBLockLock( w->lock ); - if( w->used ) - { - HBLockUnlock( w->lock ); - continue; - } - w->used = 1; - HBLockUnlock( w->lock ); - - /* Actually do the job */ - date = HBGetDate(); - if( w->work( w ) ) - { - w->time += HBGetDate() - date; - didSomething = 1; - } + w = (HBWork*) HBListItemAt( t->workList, i ); - /* Unlock */ - HBLockLock( w->lock ); - w->used = 0; + /* Check if another thread isn't using this work object */ + HBLockLock( w->lock ); + if( w->used ) + { + /* It's in use. Forget about this one and try the next + one */ HBLockUnlock( w->lock ); + continue; } + /* It's unused, lock it */ + w->used = 1; + HBLockUnlock( w->lock ); - if( t->die ) + /* Do the job */ + date = HBGetDate(); + if( w->work( w ) ) { - break; + w->time += HBGetDate() - date; + didSomething = 1; } - /* If nothing could be done, wait a bit to prevent a useless - CPU-consuming loop */ - if( !didSomething ) - { - HBSnooze( 10000 ); - } + /* Unlock it */ + HBLockLock( w->lock ); + w->used = 0; + HBLockUnlock( w->lock ); } } diff --git a/core/Work.h b/core/Work.h index 8d3cfba15..b764e1160 100644 --- a/core/Work.h +++ b/core/Work.h @@ -1,4 +1,4 @@ -/* $Id: Work.h,v 1.1 2003/11/03 12:08:01 titer Exp $ +/* $Id: Work.h,v 1.4 2003/12/26 20:03:27 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -7,8 +7,6 @@ #ifndef HB_WORK_H #define HB_WORK_H -#include "HandBrakeInternal.h" - #define HB_WORK_COMMON_MEMBERS \ char * name; \ HBLock * lock; \ @@ -16,12 +14,8 @@ uint64_t time; \ int (*work) ( HBWork * ); -void HBWorkLock( HBWork * ); -void HBWorkWork( HBWork * ); -void HBWorkUnlock( HBWork * ); - -HBWorkThread * HBWorkThreadInit( HBHandle *, HBTitle *, HBAudio *, - HBAudio *, int firstThread ); +HBWorkThread * HBWorkThreadInit( HBHandle *, HBTitle *, + int firstThread ); void HBWorkThreadClose( HBWorkThread ** ); #endif diff --git a/core/X264Enc.c b/core/X264Enc.c new file mode 100644 index 000000000..50b9ab8bf --- /dev/null +++ b/core/X264Enc.c @@ -0,0 +1,167 @@ +/* $Id: X264Enc.c,v 1.3 2003/12/26 20:03:27 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "HBInternal.h" + +/* x264 */ +#include "x264.h" + +typedef struct HBX264Enc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle *handle; + HBTitle *title; + + HBBuffer *buffer; + + x264_t *h; + x264_picture_t picture; +} HBX264Enc; + +/* Local prototypes */ +static int HBX264EncWork( HBWork * ); + +HBWork *HBX264EncInit( HBHandle * handle, HBTitle * title ) +{ + HBX264Enc *f = malloc( sizeof( HBX264Enc ) ); + + if( f ) + { + x264_param_t param; + + f->name = strdup( "X264Enc" ); + f->work = HBX264EncWork; + + f->handle = handle; + f->title = title; + + f->buffer = NULL; + + x264_param_default( ¶m ); + + param.i_width = title->outWidth; + param.i_height= title->outHeight; + param.i_iframe = 5 * title->rate / title->rateBase; + /* FIXME */ + param.b_deblocking_filter = 0; + param.i_me = 1; + + if( ( f->h = x264_encoder_open( ¶m ) ) == NULL ) + { + HBLog( "x264: x264_encoder_new failed" ); + return NULL; + } + memset( &f->picture, 0, sizeof( x264_picture_t ) ); + f->picture.i_width = param.i_width; + f->picture.i_height = param.i_height; + f->picture.i_plane = 3; + + HBLog( "x264: opening with %dx%d iframes=%d", param.i_width, param.i_height, param.i_iframe ); + } + + return (HBWork*) f; +} + +void HBX264EncClose( HBWork **_f ) +{ + HBX264Enc *f = (HBX264Enc*) *_f; + + x264_encoder_close( f->h ); + + if( f->buffer ) + { + HBBufferClose( &f->buffer ); + } + + free( f->name ); + + free( f ); + + *_f = NULL; +} + +/* TODO trash buffer->pass == 1 + * return 0 ->rien fait + * 1 -> sinon + */ +static int HBX264EncWork( HBWork * w ) +{ + HBX264Enc * f = (HBX264Enc*) w; + HBTitle * title = f->title; + + HBBuffer * frame; + int didSomething = 0; + + x264_nal_t *nal; + int i_nal; + int i; + + if( f->buffer ) + { + if( !HBFifoPush( title->outFifo, &f->buffer ) ) + { + /* nothing done */ + return 0; + } + didSomething = 1; + } + + if( ( frame = HBFifoPop( title->scaledFifo ) ) == NULL ) + { + return didSomething; + } + + if( frame->pass == 1 ) + { + /* Trash all first pass buffer */ + HBBufferClose( &frame ); + return 1; + } + + f->picture.i_stride[0] = title->outWidth; + f->picture.i_stride[1] = title->outWidth/2; + f->picture.i_stride[2] = title->outWidth/2; + + f->picture.plane[0] = frame->data; + f->picture.plane[1] = &f->picture.plane[0][title->outWidth*title->outHeight]; + f->picture.plane[2] = &f->picture.plane[1][title->outWidth*title->outHeight/4]; + + x264_encoder_encode( f->h, &nal, &i_nal, &f->picture ); + + f->buffer = HBBufferInit( 3 * title->outWidth * title->outHeight / 2 ); /* FIXME */ + f->buffer->keyFrame = 0; + f->buffer->position = frame->position; + f->buffer->size = 0; + + for( i = 0; i < i_nal; i++ ) + { + int i_data = f->buffer->alloc - f->buffer->size; + int i_size; + + i_size = x264_nal_encode( &f->buffer->data[f->buffer->size], + &i_data, 1, &nal[i] ); + if( i_size <= 0 ) + { + fprintf( stderr, "#################### error" ); + } + + f->buffer->size += i_size; + + if( nal[i].i_ref_idc == NAL_PRIORITY_HIGH || + nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) + { + f->buffer->keyFrame = 1; + } + } + + /* Inform the GUI about the current position */ + HBPosition( f->handle, frame->position ); + + HBBufferClose( &frame ); + + return 1; +} diff --git a/core/XvidEnc.c b/core/XvidEnc.c index 2ca6bca6f..fe9e8ddbc 100644 --- a/core/XvidEnc.c +++ b/core/XvidEnc.c @@ -1,34 +1,33 @@ -/* $Id: XvidEnc.c,v 1.7 2003/11/09 21:26:52 titer Exp $ +/* $Id: XvidEnc.c,v 1.18 2004/01/08 22:02:29 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include "Fifo.h" -#include "Work.h" -#include "XvidEnc.h" -#include "XvidVbr.h" +#include "HBInternal.h" -#include <xvid.h> +#include "xvid.h" -/* Local prototypes */ -static int XvidEncWork( HBWork * ); - -struct HBXvidEnc +typedef struct HBXvidEnc { HB_WORK_COMMON_MEMBERS HBHandle * handle; HBTitle * title; + char file[1024]; void * xvid; - vbr_control_t xvidVbr; - XVID_ENC_FRAME frame; + xvid_enc_frame_t frame; HBBuffer * mpeg4Buffer; int pass; -}; + int frames; + int64_t bytes; +} HBXvidEnc; + +/* Local prototypes */ +static int XvidEncWork( HBWork * ); -HBXvidEnc * HBXvidEncInit( HBHandle * handle, HBTitle * title ) +HBWork * HBXvidEncInit( HBHandle * handle, HBTitle * title ) { HBXvidEnc * x; if( !( x = malloc( sizeof( HBXvidEnc ) ) ) ) @@ -43,38 +42,53 @@ HBXvidEnc * HBXvidEncInit( HBHandle * handle, HBTitle * title ) x->handle = handle; x->title = title; - x->xvid = NULL; - - x->frame.general = XVID_H263QUANT | XVID_HALFPEL | XVID_INTER4V; - x->frame.motion = PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | - PMV_EXTSEARCH16 | PMV_EARLYSTOP8 | - PMV_HALFPELREFINE8 | PMV_HALFPELDIAMOND8 | - PMV_USESQUARES16; - - x->frame.colorspace = XVID_CSP_I420; - - x->frame.quant_intra_matrix = NULL; - x->frame.quant_inter_matrix = NULL; + memset( x->file, 0, 1024 ); + snprintf( x->file, 1023, "/tmp/HB.%d.xvid.log", + HBGetPid( x->handle ) ); + x->xvid = NULL; x->mpeg4Buffer = NULL; x->pass = 42; + x->frames = 0; + x->bytes = 0; - return x; + return (HBWork*) x; } -void HBXvidEncClose( HBXvidEnc ** _x ) +void HBXvidEncClose( HBWork ** _x ) { - HBXvidEnc * x = *_x; + HBXvidEnc * x = (HBXvidEnc*) *_x; if( x->xvid ) { HBLog( "HBXvidEnc: closing libxvidcore (pass %d)", x->pass ); - xvid_encore( x->xvid, XVID_ENC_DESTROY, NULL, NULL); - vbrFinish( &x->xvidVbr ); } - + if( x->frames ) + { + float bitrate = (float) x->bytes * x->title->rate / x->frames / + x->title->rateBase / 128; + int64_t bytes = (int64_t) x->frames * x->title->bitrate * 128 * + x->title->rateBase / x->title->rate; + + HBLog( "HBXvidEnc: %d frames encoded (%lld bytes), %.2f kbps", + x->frames, x->bytes, bitrate ); + + if( x->bytes > bytes ) + { + HBLog( "HBXvidEnc: %lld more bytes than expected " + "(error=%.2f %%)", x->bytes - bytes, + 100.0 * ( x->bytes - bytes ) / bytes ); + } + else if( x->bytes < bytes ) + { + HBLog( "HBXvidEnc: %lld less bytes than expected " + "(error=%.2f %%)", bytes - x->bytes, + 100.0 * ( bytes - x->bytes ) / bytes ); + } + } + free( x->name ); free( x ); *_x = NULL; @@ -86,13 +100,12 @@ static int XvidEncWork( HBWork * w ) HBTitle * title = x->title; HBBuffer * scaledBuffer; HBBuffer * mpeg4Buffer; - XVID_ENC_STATS stats; int didSomething = 0; if( x->mpeg4Buffer ) { - if( HBFifoPush( title->mpeg4Fifo, &x->mpeg4Buffer ) ) + if( HBFifoPush( title->outFifo, &x->mpeg4Buffer ) ) { didSomething = 1; } @@ -114,8 +127,12 @@ static int XvidEncWork( HBWork * w ) /* Init or re-init if needed */ if( scaledBuffer->pass != x->pass ) { - XVID_INIT_PARAM xinit; - XVID_ENC_PARAM xparam; + xvid_gbl_init_t xvid_gbl_init; + xvid_enc_create_t xvid_enc_create; + xvid_plugin_single_t single; + xvid_plugin_2pass1_t rc2pass1; + xvid_plugin_2pass2_t rc2pass2; + xvid_enc_plugin_t plugins[7]; if( x->xvid ) { @@ -123,89 +140,93 @@ static int XvidEncWork( HBWork * w ) x->pass ); xvid_encore( x->xvid, XVID_ENC_DESTROY, NULL, NULL); - vbrFinish( &x->xvidVbr ); } x->pass = scaledBuffer->pass;; - HBLog( "HBXvidEnc: opening libxvidcore (pass %d)", x->pass ); - xinit.cpu_flags = 0; - xvid_init( NULL, 0, &xinit, NULL ); + memset( &xvid_gbl_init, 0, sizeof( xvid_gbl_init ) ); + xvid_gbl_init.version = XVID_VERSION; + xvid_global( NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL ); - xparam.width = title->outWidth; - xparam.height = title->outHeight; + memset(&xvid_enc_create, 0, sizeof(xvid_enc_create)); + xvid_enc_create.version = XVID_VERSION; + xvid_enc_create.width = title->outWidth; + xvid_enc_create.height = title->outHeight; + xvid_enc_create.zones = NULL; + xvid_enc_create.num_zones = 0; + xvid_enc_create.plugins = plugins; + xvid_enc_create.num_plugins = 0; - xparam.fincr = title->rateBase; - xparam.fbase = title->rate; - - xparam.rc_bitrate = title->bitrate * 1024; - - /* Default values should be ok */ - xparam.rc_reaction_delay_factor = -1; - xparam.rc_averaging_period = -1; - xparam.rc_buffer = -1; - xparam.max_quantizer = -1; - xparam.min_quantizer = -1; - xparam.max_key_interval = -1; - - if( xvid_encore( NULL, XVID_ENC_CREATE, &xparam, NULL ) ) - { - HBLog( "HBXvidEnc: xvid_encore() failed" ); - } - - x->xvid = xparam.handle; - - /* Init VBR engine */ - vbrSetDefaults( &x->xvidVbr ); if( !x->pass ) { - x->xvidVbr.mode = VBR_MODE_1PASS; + memset( &single, 0, sizeof( single ) ); + single.version = XVID_VERSION; + single.bitrate = 1024 * title->bitrate; + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single; + plugins[xvid_enc_create.num_plugins].param = &single; + xvid_enc_create.num_plugins++; } else if( x->pass == 1 ) { - x->xvidVbr.mode = VBR_MODE_2PASS_1; + memset( &rc2pass1, 0, sizeof( rc2pass1 ) ); + rc2pass1.version = XVID_VERSION; + rc2pass1.filename = x->file; + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass1; + plugins[xvid_enc_create.num_plugins].param = &rc2pass1; + xvid_enc_create.num_plugins++; } - else + else if( x->pass == 2 ) { - x->xvidVbr.mode = VBR_MODE_2PASS_2; + memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t)); + rc2pass2.version = XVID_VERSION; + rc2pass2.filename = x->file; + rc2pass2.bitrate = 1024 * title->bitrate; + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; + plugins[xvid_enc_create.num_plugins].param = &rc2pass2; + xvid_enc_create.num_plugins++; } - x->xvidVbr.fps = (double) title->rate / title->rateBase; - x->xvidVbr.debug = 0; - x->xvidVbr.filename = malloc( 1024 ); - memset( x->xvidVbr.filename, 0, 1024 ); - snprintf( x->xvidVbr.filename, 1023, "/tmp/HB.%d.xvid.log", - HBGetPid( x->handle ) ); - x->xvidVbr.desired_bitrate = title->bitrate * 1024; - x->xvidVbr.max_key_interval = 10 * title->rate / title->rateBase; - - vbrInit( &x->xvidVbr ); + + xvid_enc_create.num_threads = 0; + xvid_enc_create.fincr = title->rateBase; + xvid_enc_create.fbase = title->rate; + xvid_enc_create.max_key_interval = 10 * title->rate / title->rateBase; + xvid_enc_create.max_bframes = 0; + xvid_enc_create.bquant_ratio = 150; + xvid_enc_create.bquant_offset = 100; + xvid_enc_create.frame_drop_ratio = 0; + xvid_enc_create.global = 0; + + xvid_encore( NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL ); + x->xvid = xvid_enc_create.handle; } mpeg4Buffer = HBBufferInit( title->outWidth * title->outHeight * 3 / 2 ); mpeg4Buffer->position = scaledBuffer->position; + memset( &x->frame, 0, sizeof( x->frame ) ); + x->frame.version = XVID_VERSION; x->frame.bitstream = mpeg4Buffer->data; - x->frame.length = -1; - - x->frame.image = scaledBuffer->data; - - x->frame.quant = vbrGetQuant( &x->xvidVbr ); - x->frame.intra = vbrGetIntra( &x->xvidVbr ); - - x->frame.hint.hintstream = NULL; - - if( xvid_encore( x->xvid, XVID_ENC_ENCODE, &x->frame, &stats ) ) - { - HBLog( "HBXvidEnc: xvid_encore() failed" ); - } - - vbrUpdate( &x->xvidVbr, stats.quant, x->frame.intra, stats.hlength, - x->frame.length, stats.kblks, stats.mblks, stats.ublks ); + x->frame.length = -1; + x->frame.input.plane[0] = scaledBuffer->data; + x->frame.input.csp = XVID_CSP_I420; + x->frame.input.stride[0] = title->outWidth; + x->frame.vol_flags = 0; + x->frame.vop_flags = XVID_VOP_HALFPEL | XVID_VOP_INTER4V | + XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED; + x->frame.type = XVID_TYPE_AUTO; + x->frame.quant = 0; + x->frame.motion = XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | + XVID_ME_EXTSEARCH16 | XVID_ME_ADVANCEDDIAMOND8 | + XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 | + XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP; + x->frame.quant_intra_matrix = NULL; + x->frame.quant_inter_matrix = NULL; - mpeg4Buffer->size = x->frame.length; - mpeg4Buffer->keyFrame = x->frame.intra; + mpeg4Buffer->size = xvid_encore( x->xvid, XVID_ENC_ENCODE, + &x->frame, NULL ); + mpeg4Buffer->keyFrame = ( x->frame.out_flags & XVID_KEYFRAME ); /* Inform the GUI about the current position */ HBPosition( x->handle, scaledBuffer->position ); @@ -217,8 +238,20 @@ static int XvidEncWork( HBWork * w ) HBBufferClose( &mpeg4Buffer ); return didSomething; } + else + { + if( !title->esConfig ) + { + /* KLUDGE */ + title->esConfig = malloc( 15 ); + title->esConfigLength = 15; + memcpy( title->esConfig, mpeg4Buffer->data + 4, 15 ); + } + x->frames++; + x->bytes += mpeg4Buffer->size; + x->mpeg4Buffer = mpeg4Buffer; + } - x->mpeg4Buffer = mpeg4Buffer; return didSomething; } diff --git a/core/XvidEnc.h b/core/XvidEnc.h deleted file mode 100644 index 01cb6f4d4..000000000 --- a/core/XvidEnc.h +++ /dev/null @@ -1,15 +0,0 @@ -/* $Id: XvidEnc.h,v 1.1 2003/11/03 12:08:01 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_XVID_ENC_H -#define HB_XVID_ENC_H - -#include "HandBrakeInternal.h" - -HBXvidEnc * HBXvidEncInit( HBHandle *, HBTitle * ); -void HBXvidEncClose( HBXvidEnc ** ); - -#endif diff --git a/core/XvidVbr.c b/core/XvidVbr.c deleted file mode 100644 index ce66c3769..000000000 --- a/core/XvidVbr.c +++ /dev/null @@ -1,1648 +0,0 @@ -/****************************************************************************** - * - * XviD VBR Library - * - * Copyright (C) 2002 Edouard Gomez <[email protected]> - * - * The curve treatment algorithm is based on work done by Foxer <email?> and - * Dirk Knop <[email protected]> for the XviD vfw dynamic library. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - *****************************************************************************/ - -/* Standard Headers */ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <math.h> - -/* Local headers */ -#include "XvidVbr.h" - -/****************************************************************************** - * Build time constants - *****************************************************************************/ - -/* - * Portability note - * Perhaps the msvc headers define Pi with another constant name - */ -#define DEG2RAD (M_PI / 180.0) - -/* Defaults settings will be computed with the help of these constants */ -#define DEFAULT_DESIRED_SIZE 700 -#define DEFAULT_AUDIO_BITRATE 128 -#define DEFAULT_MOVIE_LENGTH 2 -#define DEFAULT_TWOPASS_BOOST 1000 -#define DEFAULT_FPS 25.0f -#define DEFAULT_CREDITS_SIZE 0 - -#define DEFAULT_XVID_DBG_FILE "xvid.dbg" -#define DEFAULT_XVID_STATS_FILE "xvid.stats" - - -/****************************************************************************** - * Local prototypes - *****************************************************************************/ - -/* Sub vbrInit cases functions */ -static vbr_init_function vbr_init_dummy; -static vbr_init_function vbr_init_2pass1; -static vbr_init_function vbr_init_2pass2; -static vbr_init_function vbr_init_fixedquant; - -/* Sub vbrGetQuant cases functions */ -static vbr_get_quant_function vbr_getquant_1pass; -static vbr_get_quant_function vbr_getquant_2pass1; -static vbr_get_quant_function vbr_getquant_2pass2; -static vbr_get_quant_function vbr_getquant_fixedquant; - -/* Sub vbrGetIntra cases functions */ -static vbr_get_intra_function vbr_getintra_1pass; -static vbr_get_intra_function vbr_getintra_2pass1; -static vbr_get_intra_function vbr_getintra_2pass2; -static vbr_get_intra_function vbr_getintra_fixedquant; - -/* Sub vbrUpdate prototypes */ -static vbr_update_function vbr_update_dummy; -static vbr_update_function vbr_update_2pass1; -static vbr_update_function vbr_update_2pass2; - -/* Sub vbrFinish cases functions */ -static vbr_finish_function vbr_finish_dummy; -static vbr_finish_function vbr_finish_2pass1; -static vbr_finish_function vbr_finish_2pass2; - -/* Is the encoder in the credits */ -#define FRAME_TYPE_NORMAL_MOVIE 0x00 -#define FRAME_TYPE_STARTING_CREDITS 0x01 -#define FRAME_TYPE_ENDING_CREDITS 0x02 - -/****************************************************************************** - * Inline utility functions - *****************************************************************************/ - -static __inline int util_frametype(vbr_control_t *state) -{ - - if(state->credits_start) { - - if(state->cur_frame >= state->credits_start_begin && - state->cur_frame < state->credits_start_end) - return(FRAME_TYPE_STARTING_CREDITS); - - } - - if(state->credits_end) { - - if(state->cur_frame >= state->credits_end_begin && - state->cur_frame < state->credits_end_end) - return(FRAME_TYPE_ENDING_CREDITS); - - } - - return(FRAME_TYPE_NORMAL_MOVIE); - - -} - -static __inline int util_creditsframes(vbr_control_t *state) -{ - - int frames = 0; - - if(state->credits_start) - frames += state->credits_start_end - state->credits_start_begin; - if(state->credits_end) - frames += state->credits_end_end - state->credits_end_begin; - - return(frames); - -} - -/****************************************************************************** - * Functions - *****************************************************************************/ - -/***************************************************************************** - * Function description : - * - * This function initialiazes the vbr_control_t with safe defaults for all - * modes. - * - * Return Values : - * = 0 - ****************************************************************************/ - -int vbrSetDefaults(vbr_control_t *state) -{ - - /* Set all the structure to zero */ - memset(state, 0, sizeof(state)); - - /* Default mode is CBR */ - state->mode = VBR_MODE_1PASS; - - /* Default statistic filename */ - state->filename = DEFAULT_XVID_STATS_FILE; - - /* - * Default is a 2hour movie on 700Mo CD-ROM + 128kbit sound track - * This represents a target bitrate of 687kbit/s - */ - state->desired_size = DEFAULT_DESIRED_SIZE*1024*1024 - - DEFAULT_MOVIE_LENGTH*3600*DEFAULT_AUDIO_BITRATE*1000/8; - state->desired_bitrate = state->desired_size*8/(DEFAULT_MOVIE_LENGTH*3600); - - /* Credits */ - state->credits_mode = VBR_CREDITS_MODE_RATE; - state->credits_start = 0; - state->credits_start_begin = 0; - state->credits_start_end = 0; - state->credits_end = 0; - state->credits_end_begin = 0; - state->credits_end_end = 0; - state->credits_quant_ratio = 20; - state->credits_fixed_quant = 20; - state->credits_quant_i = 20; - state->credits_quant_p = 20; - state->credits_start_size = DEFAULT_CREDITS_SIZE*1024*1024; - state->credits_end_size = DEFAULT_CREDITS_SIZE*1024*1024; - - /* Keyframe boost */ - state->keyframe_boost = 0; - state->kftreshold = 10; - state->kfreduction = 30; - state->min_key_interval = 1; - state->max_key_interval = (int)DEFAULT_FPS*10; - - /* Normal curve treatment */ - state->curve_compression_high = 25; - state->curve_compression_low = 10; - - /* Alt curve */ - state->use_alt_curve = 1; - state->alt_curve_type = VBR_ALT_CURVE_LINEAR; - state->alt_curve_low_dist = 90; - state->alt_curve_high_dist = 500; - state->alt_curve_min_rel_qual = 50; - state->alt_curve_use_auto = 1; - state->alt_curve_auto_str = 30; - state->alt_curve_use_auto_bonus_bias = 1; - state->alt_curve_bonus_bias = 50; - state->bitrate_payback_method = VBR_PAYBACK_BIAS; - state->bitrate_payback_delay = 250; - state->twopass_max_bitrate = DEFAULT_TWOPASS_BOOST*state->desired_bitrate; - state->twopass_max_overflow_improvement = 60; - state->twopass_max_overflow_degradation = 60; - state->max_iquant = 31; - state->min_iquant = 2; - state->max_pquant = 31; - state->min_pquant = 2; - state->fixed_quant = 3; - - state->max_framesize = (1.0/(float)DEFAULT_FPS) * state->twopass_max_bitrate / 8; - - state->fps = (float)DEFAULT_FPS; - - return(0); - -} - -/***************************************************************************** - * Function description : - * - * This function initialiaze the vbr_control_t state passed in parameter. - * - * The initialization depends on state->mode, there are 4 modes allowed. - * Each mode description is done in the README file shipped with the lib. - * - * Return values : - * - * = 0 on success - * = -1 on error - *****************************************************************************/ - -int vbrInit(vbr_control_t *state) -{ - - if(state == NULL) return(-1); - - /* Function pointers safe initialization */ - state->init = NULL; - state->getquant = NULL; - state->getintra = NULL; - state->update = NULL; - state->finish = NULL; - - if(state->debug) { - - state->debug_file = fopen(DEFAULT_XVID_DBG_FILE, "w+"); - - if(state->debug_file == NULL) - return(-1); - - fprintf(state->debug_file, "# XviD Debug output\n"); - fprintf(state->debug_file, "# quant | intra | header bytes" - "| total bytes | kblocks | mblocks | ublocks" - "| vbr overflow | vbr kf overflow" - "| vbr kf partial overflow\n\n"); - } - - /* Function pointers sub case initialization */ - switch(state->mode) { - case VBR_MODE_1PASS: - state->init = vbr_init_dummy; - state->getquant = vbr_getquant_1pass; - state->getintra = vbr_getintra_1pass; - state->update = vbr_update_dummy; - state->finish = vbr_finish_dummy; - break; - case VBR_MODE_2PASS_1: - state->init = vbr_init_2pass1; - state->getquant = vbr_getquant_2pass1; - state->getintra = vbr_getintra_2pass1; - state->update = vbr_update_2pass1; - state->finish = vbr_finish_2pass1; - break; - case VBR_MODE_FIXED_QUANT: - state->init = vbr_init_fixedquant; - state->getquant = vbr_getquant_fixedquant; - state->getintra = vbr_getintra_fixedquant; - state->update = vbr_update_dummy; - state->finish = vbr_finish_dummy; - break; - case VBR_MODE_2PASS_2: - state->init = vbr_init_2pass2; - state->getintra = vbr_getintra_2pass2; - state->getquant = vbr_getquant_2pass2; - state->update = vbr_update_2pass2; - state->finish = vbr_finish_2pass2; - break; - default: - return(-1); - } - - return(state->init(state)); - -} - -/****************************************************************************** - * Function description : - * - * This function returns an adapted quantizer according to the current vbr - * controler state - * - * Return values : - * the quantizer value (0 <= value <= 31) - * (0 is a special case, means : let XviD decide) - * - *****************************************************************************/ - -int vbrGetQuant(vbr_control_t *state) -{ - - /* Returns Zero, so XviD decides alone */ - if(state == NULL || state->getquant == NULL) return(0); - - return(state->getquant(state)); - -} - -/****************************************************************************** - * Function description : - * - * This function returns the type of the frame to be encoded next (I or P/B) - * - * Return values : - * = -1 let the XviD encoder decide wether or not the next frame is I - * = 0 no I frame - * = 1 force keyframe - * - *****************************************************************************/ - -int vbrGetIntra(vbr_control_t *state) -{ - - /* Returns -1, means let XviD decide */ - if(state == NULL || state->getintra == NULL) return(-1); - - return(state->getintra(state)); - -} - -/****************************************************************************** - * Function description : - * - * This function updates the vbr control state according to collected statistics - * from XviD core - * - * Return values : - * - * = 0 on success - * = -1 on error - *****************************************************************************/ - -int vbrUpdate(vbr_control_t *state, - int quant, - int intra, - int header_bytes, - int total_bytes, - int kblocks, - int mblocks, - int ublocks) -{ - - if(state == NULL || state->update == NULL) return(-1); - - if(state->debug && state->debug_file != NULL) { - int idx; - - fprintf(state->debug_file, "%d %d %d %d %d %d %d %d %d %d\n", - quant, intra, header_bytes, total_bytes, kblocks, - mblocks, ublocks, state->overflow, state->KFoverflow, - state->KFoverflow_partial); - - idx = quant; - - if(quant < 1) - idx = 1; - if(quant > 31) - idx = 31; - - idx--; - - state->debug_quant_count[idx]++; - - } - - return(state->update(state, quant, intra, header_bytes, total_bytes, - kblocks, mblocks, ublocks)); - -} - -/****************************************************************************** - * Function description : - * - * This function stops the vbr controller - * - * Return values : - * - * = 0 on success - * = -1 on error - *****************************************************************************/ - -int vbrFinish(vbr_control_t *state) -{ - - if(state == NULL || state->finish == NULL) return(-1); - - if(state->debug && state->debug_file != NULL) { - - int i; - - fprintf(state->debug_file, "\n\n"); - - for(i=0; i<79; i++) - fprintf(state->debug_file, "#"); - - fprintf(state->debug_file, "\n# Quantizer distribution :\n\n"); - - for(i=0;i<32; i++) { - - fprintf(state->debug_file, "# quant %d : %d\n", - i+1, - state->debug_quant_count[i]); - - } - - fclose(state->debug_file); - - } - - return(state->finish(state)); - -} - -/****************************************************************************** - * Dummy functions - Used when a mode does not need such a function - *****************************************************************************/ - -static int vbr_init_dummy(void *sstate) -{ - - vbr_control_t *state = sstate; - - state->cur_frame = 0; - - return(0); - -} - -static int vbr_update_dummy(void *state, - int quant, - int intra, - int header_bytes, - int total_bytes, - int kblocks, - int mblocks, - int ublocks) -{ - - ((vbr_control_t*)state)->cur_frame++; - - return(0); - -} - -static int vbr_finish_dummy(void *state) -{ - - return(0); - -} - -/****************************************************************************** - * 1 pass mode - XviD will do its job alone. - *****************************************************************************/ - -static int vbr_getquant_1pass(void *state) -{ - - return(0); - -} - -static int vbr_getintra_1pass(void *state) -{ - - return(-1); - -} - -/****************************************************************************** - * 2 pass mode - first pass functions - *****************************************************************************/ - -static int vbr_init_2pass1(void *sstate) -{ - - FILE *f; - vbr_control_t *state = sstate; - - /* Check the filename */ - if(state->filename == NULL || state->filename[0] == '\0') - return(-1); - - /* Initialize safe defaults for 2pass 1 */ - state->pass1_file = NULL; - state->nb_frames = 0; - state->nb_keyframes = 0; - state->cur_frame = 0; - - /* Open the 1st pass file */ - if((f = fopen(state->filename, "w+")) == NULL) - return(-1); - - /* - * The File Header - * - * The extra white spaces will be used during the vbrFinish to write - * the resulting number of frames and keyframes (10 spaces == maximum - * string length of an int on 32bit machines, i don't think anyone is - * encoding more than 4 billion frames :-) - */ - fprintf(f, "# ASCII XviD vbr stat file version %d\n#\n", VBR_VERSION); - fprintf(f, "# frames : \n"); - fprintf(f, "# keyframes : \n"); - fprintf(f, "#\n# quant | intra | header bytes | total bytes | kblocks |" - " mblocks | ublocks\n\n"); - - /* Save file pointer */ - state->pass1_file = f; - - return(0); - -} - -static int vbr_getquant_2pass1(void *state) -{ - - return(2); - -} - -static int vbr_getintra_2pass1(void *state) -{ - - return(-1); - -} - -static int vbr_update_2pass1(void *sstate, - int quant, - int intra, - int header_bytes, - int total_bytes, - int kblocks, - int mblocks, - int ublocks) - - -{ - - vbr_control_t *state = sstate; - - if(state->pass1_file == NULL) - return(-1); - - /* Writes the resulting statistics */ - fprintf(state->pass1_file, "%d %d %d %d %d %d %d\n", - quant, - intra, - header_bytes, - total_bytes, - kblocks, - mblocks, - ublocks); - - /* Update vbr control state */ - if(intra) state->nb_keyframes++; - state->nb_frames++; - state->cur_frame++; - - return(0); - -} - -static int vbr_finish_2pass1(void *sstate) -{ - - int c, i; - vbr_control_t *state = sstate; - - if(state->pass1_file == NULL) - return(-1); - - /* Goto to the file beginning */ - fseek(state->pass1_file, 0, SEEK_SET); - - /* Skip the version line and the empty line */ - c = i = 0; - do { - c = fgetc(state->pass1_file); - - if(c == EOF) return(-1); - if(c == '\n') i++; - - }while(i < 2); - - /* Prepare to write to the stream */ - fseek( state->pass1_file, 0L, SEEK_CUR ); - - /* Overwrite the frame field - safe as we have written extra spaces */ - fprintf(state->pass1_file, "# frames : %.10d\n", state->nb_frames); - - /* Overwrite the keyframe field */ - fprintf(state->pass1_file, "# keyframes : %.10d\n", - state->nb_keyframes); - - /* Close the file */ - if(fclose(state->pass1_file) != 0) - return(-1); - - return(0); - -} - -/****************************************************************************** - * 2 pass mode - 2nd pass functions (Need to be finished) - *****************************************************************************/ - -static int vbr_init_2pass2(void *sstate) -{ - - FILE *f; - int c, n, pos_firstframe, credits_frames; - long long credits1_bytes; - long long credits2_bytes; - long long desired; - long long total_bytes; - long long itotal_bytes; - long long start_curved; - long long end_curved; - double total1; - double total2; - - vbr_control_t *state = sstate; - - /* Check the filename */ - if(state->filename == NULL || state->filename[0] == '\0') - return(-1); - - /* Initialize safe defaults for 2pass 2 */ - state->pass1_file = NULL; - state->nb_frames = 0; - state->nb_keyframes = 0; - - /* Open the 1st pass file */ - if((f = fopen(state->filename, "r")) == NULL) - return(-1); - - state->pass1_file = f; - - /* Get the file version and check against current version */ - fscanf(state->pass1_file, "# ASCII XviD vbr stat file version %d\n", &n); - - if(n != VBR_VERSION) { - fclose(state->pass1_file); - state->pass1_file = NULL; - return(-1); - } - - /* Skip the blank commented line */ - c = n = 0; - do { - - c = fgetc(state->pass1_file); - - if(c == EOF) { - fclose(state->pass1_file); - state->pass1_file = NULL; - return(-1); - } - - if(c == '\n') n++; - - }while(n < 1); - - - /* Get the number of frames */ - fscanf(state->pass1_file, "# frames : %d\n", &state->nb_frames); - - /* Compute the desired size */ - state->desired_size = (long long) - (((long long)state->nb_frames * (long long)state->desired_bitrate) / - (state->fps * 8.0)); - - /* Get the number of keyframes */ - fscanf(state->pass1_file, "# keyframes : %d\n", &state->nb_keyframes); - - /* Allocate memory space for the keyframe_location array */ - if((state->keyframe_locations - = (int*)malloc((state->nb_keyframes+1)*sizeof(int))) == NULL) { - fclose(state->pass1_file); - state->pass1_file = NULL; - return(-1); - } - - /* Skip the blank commented line and the colum description */ - c = n = 0; - do { - - c = fgetc(state->pass1_file); - - if(c == EOF) { - fclose(state->pass1_file); - state->pass1_file = NULL; - return(-1); - } - - if(c == '\n') n++; - - }while(n < 2); - - /* Save position for future use */ - pos_firstframe = ftell(state->pass1_file); - - /* Read and initialize some variables */ - credits1_bytes = credits2_bytes = 0; - total_bytes = itotal_bytes = 0; - start_curved = end_curved = 0; - credits_frames = 0; - - for(state->cur_frame = c = 0; state->cur_frame<state->nb_frames; state->cur_frame++) { - - int quant, keyframe, frame_hbytes, frame_bytes; - int kblocks, mblocks, ublocks; - - fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n", - &quant, &keyframe, &frame_hbytes, &frame_bytes, - &kblocks, &mblocks, &ublocks); - - /* Is the frame in the beginning credits */ - if(util_frametype(state) == FRAME_TYPE_STARTING_CREDITS) { - credits1_bytes += frame_bytes; - credits_frames++; - continue; - } - - /* Is the frame in the eding credits */ - if(util_frametype(state) == FRAME_TYPE_ENDING_CREDITS) { - credits2_bytes += frame_bytes; - credits_frames++; - continue; - } - - /* We only care about Keyframes when not in credits */ - if(keyframe) { - itotal_bytes += frame_bytes + frame_bytes * - state->keyframe_boost / 100; - total_bytes += frame_bytes * - state->keyframe_boost / 100; - state->keyframe_locations[c++] = state->cur_frame; - } - - total_bytes += frame_bytes; - - } - - /* - * Last frame is treated like an I Frame so we can dispatch overflow - * all other the last film segment - */ - state->keyframe_locations[c] = state->cur_frame; - - desired = state->desired_size; - - switch(state->credits_mode) { - case VBR_CREDITS_MODE_QUANT : - - state->movie_curve = (double) - (total_bytes - credits1_bytes - credits2_bytes) / - (desired - credits1_bytes - credits2_bytes); - - start_curved = credits1_bytes; - end_curved = credits2_bytes; - - break; - case VBR_CREDITS_MODE_SIZE: - - /* start curve = (start / start desired size) */ - state->credits_start_curve = (double) - (credits1_bytes / state->credits_start_size); - - /* end curve = (end / end desired size) */ - state->credits_end_curve = (double) - (credits2_bytes / state->credits_end_size); - - start_curved = (long long) - (credits1_bytes / state->credits_start_curve); - - end_curved = (long long) - (credits2_bytes / state->credits_end_curve); - - /* movie curve=(total-credits)/(desired_size-curved credits) */ - state->movie_curve = (double) - (total_bytes - credits1_bytes - credits2_bytes) / - (desired - start_curved - end_curved); - - break; - case VBR_CREDITS_MODE_RATE: - default: - - /* credits curve = (total/desired_size)*(100/credits_rate) */ - state->credits_start_curve = state->credits_end_curve = - ((double)total_bytes / desired) * - ((double)100 / state->credits_quant_ratio); - - start_curved = - (long long)(credits1_bytes/state->credits_start_curve); - - end_curved = - (long long)(credits2_bytes/state->credits_end_curve); - - state->movie_curve = (double) - (total_bytes - credits1_bytes - credits2_bytes) / - (desired - start_curved - end_curved); - - break; - } - - /* - * average frame size = (desired - curved credits - curved keyframes) / - * (frames - credits frames - keyframes) - */ - state->average_frame = (double) - (desired - start_curved - end_curved - - (itotal_bytes / state->movie_curve)) / - (state->nb_frames - util_creditsframes(state) - - state->nb_keyframes); - - /* Initialize alt curve parameters */ - if (state->use_alt_curve) { - - state->alt_curve_low = - state->average_frame - state->average_frame * - (double)(state->alt_curve_low_dist / 100.0); - - state->alt_curve_low_diff = - state->average_frame - state->alt_curve_low; - - state->alt_curve_high = - state->average_frame + state->average_frame * - (double)(state->alt_curve_high_dist / 100.0); - - state->alt_curve_high_diff = - state->alt_curve_high - state->average_frame; - - if (state->alt_curve_use_auto) { - - if (state->movie_curve > 1.0) { - - state->alt_curve_min_rel_qual = - (int)(100.0 - (100.0 - 100.0 / state->movie_curve) * - (double)state->alt_curve_auto_str / 100.0); - - if (state->alt_curve_min_rel_qual < 20) - state->alt_curve_min_rel_qual = 20; - } - else { - state->alt_curve_min_rel_qual = 100; - } - - } - - state->alt_curve_mid_qual = - (1.0 + (double)state->alt_curve_min_rel_qual / 100.0) / 2.0; - - state->alt_curve_qual_dev = 1.0 - state->alt_curve_mid_qual; - - if (state->alt_curve_low_dist > 100) { - - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - /* Sine Curve (high aggressiveness) */ - state->alt_curve_qual_dev *= - 2.0 / - (1.0 + sin(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff))); - - state->alt_curve_mid_qual = - 1.0 - state->alt_curve_qual_dev * - sin(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff)); - break; - - default: - case VBR_ALT_CURVE_LINEAR: - /* Linear (medium aggressiveness) */ - state->alt_curve_qual_dev *= - 2.0 / - (1.0 + state->average_frame / state->alt_curve_low_diff); - - state->alt_curve_mid_qual = - 1.0 - state->alt_curve_qual_dev * - state->average_frame / state->alt_curve_low_diff; - - break; - - case VBR_ALT_CURVE_SOFT: - /* Cosine Curve (low aggressiveness) */ - state->alt_curve_qual_dev *= - 2.0 / - (1.0 + (1.0 - cos(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff)))); - - state->alt_curve_mid_qual = - 1.0 - state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * (state->average_frame * 90.0 / state->alt_curve_low_diff))); - - break; - } - } - } - - /* Go to the first non credits frame stats line into file */ - fseek(state->pass1_file, pos_firstframe, SEEK_SET); - - /* Perform prepass to compensate for over/undersizing */ - total1 = total2 = 0.0; - for(state->cur_frame=0; state->cur_frame<state->nb_frames; state->cur_frame++) { - - int quant, keyframe, frame_hbytes, frame_bytes; - int kblocks, mblocks, ublocks; - - fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n", - &quant, &keyframe, &frame_hbytes, &frame_bytes, - &kblocks, &mblocks, &ublocks); - - if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) - continue; - - if(!keyframe) { - - double dbytes = frame_bytes / state->movie_curve; - total1 += dbytes; - - if (state->use_alt_curve) { - - if (dbytes > state->average_frame) { - - if (dbytes >= state->alt_curve_high) { - total2 += dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev); - } - else { - - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - - total2 += - dbytes * - (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff))); - break; - default: - case VBR_ALT_CURVE_LINEAR: - - total2 += - dbytes * - (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (dbytes - state->average_frame) / state->alt_curve_high_diff); - break; - case VBR_ALT_CURVE_SOFT: - total2 += - dbytes * - (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff)))); - } - } - } - else { - - if (dbytes <= state->alt_curve_low) { - total2 += dbytes; - } - else { - - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - total2 += - dbytes * - (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff))); - break; - default: - case VBR_ALT_CURVE_LINEAR: - total2 += - dbytes * - (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (dbytes - state->average_frame) / state->alt_curve_low_diff); - break; - case VBR_ALT_CURVE_SOFT: - total2 += - dbytes * - (state->alt_curve_mid_qual + state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff)))); - } - } - } - } - else { - if (dbytes > state->average_frame) { - total2 += - ((double)dbytes + - (state->average_frame - dbytes) * - state->curve_compression_high / 100.0); - } - else { - total2 += - ((double)dbytes + - (state->average_frame - dbytes) * - state->curve_compression_low / 100.0); - } - } - } - } - - state->curve_comp_scale = total1 / total2; - - if (state->use_alt_curve) { - - double curve_temp, dbytes; - int newquant, percent; - int oldquant = 1; - - if (state->alt_curve_use_auto_bonus_bias) - state->alt_curve_bonus_bias = state->alt_curve_min_rel_qual; - - state->curve_bias_bonus = - (total1 - total2) * (double)state->alt_curve_bonus_bias / - (100.0 * (double)(state->nb_frames - util_creditsframes(state) - state->nb_keyframes)); - state->curve_comp_scale = - ((total1 - total2) * (1.0 - (double)state->alt_curve_bonus_bias / 100.0) + total2) / - total2; - - - for (n=1; n <= (int)(state->alt_curve_high*2) + 1; n++) { - dbytes = n; - if (dbytes > state->average_frame) - { - if (dbytes >= state->alt_curve_high) { - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev); - } - else { - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff))); - break; - default: - case VBR_ALT_CURVE_LINEAR: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (dbytes - state->average_frame) / state->alt_curve_high_diff); - break; - case VBR_ALT_CURVE_SOFT: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff)))); - } - } - } - else { - if (dbytes <= state->alt_curve_low) { - curve_temp = dbytes; - } - else { - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff))); - break; - default: - case VBR_ALT_CURVE_LINEAR: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (dbytes - state->average_frame) / state->alt_curve_low_diff); - break; - case VBR_ALT_CURVE_SOFT: - curve_temp = dbytes * (state->alt_curve_mid_qual + state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff)))); - } - } - } - - if (state->movie_curve > 1.0) - dbytes *= state->movie_curve; - - newquant = (int)(dbytes * 2.0 / (curve_temp * state->curve_comp_scale + state->curve_bias_bonus)); - if (newquant > 1) - { - if (newquant != oldquant) - { - oldquant = newquant; - percent = (int)((n - state->average_frame) * 100.0 / state->average_frame); - } - - } - - } - - } - - state->overflow = 0; - state->KFoverflow = 0; - state->KFoverflow_partial = 0; - state->KF_idx = 1; - - for (n=0 ; n < 32 ; n++) { - state->quant_error[n] = 0.0; - state->quant_count[n] = 0; - } - - state->curve_comp_error = 0.0; - state->last_quant = 0; - - /* - * Above this frame size limit, normal vbr rules will not apply - * This means : - * 1 - Quant can de/increase more than -/+2 between 2 frames - * 2 - Leads to artifacts because of 1 - */ - state->max_framesize = state->twopass_max_bitrate/state->fps; - - /* Get back to the beginning of frame statistics */ - fseek(state->pass1_file, pos_firstframe, SEEK_SET); - - /* - * Small hack : We have to get next frame stats before the - * getintra/quant calls - * User clients update the data when they call vbrUpdate - * we are just bypassing this because we don't have to update - * the overflow and so on... - */ - { - - /* Fake vars */ - int next_hbytes, next_kblocks, next_mblocks, next_ublocks; - - fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n", - &state->pass1_quant, &state->pass1_intra, &next_hbytes, - &state->pass1_bytes, &next_kblocks, &next_mblocks, - &next_ublocks); - - } - - /* Initialize the frame counter */ - state->cur_frame = 0; - state->last_keyframe = 0; - - return(0); - -} - -static int vbr_getquant_2pass2(void *sstate) -{ - - int quant; - int intra; - int bytes1, bytes2; - int overflow; - int capped_to_max_framesize = 0; - int KFdistance, KF_min_size; - vbr_control_t *state = sstate; - - bytes1 = state->pass1_bytes; - overflow = state->overflow / 8; - /* To shut up gcc warning */ - bytes2 = bytes1; - - - if (state->pass1_intra) - { - overflow = 0; - } - - if (util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) { - - - switch (state->credits_mode) { - case VBR_CREDITS_MODE_QUANT : - if (state->credits_quant_i != state->credits_quant_p) { - quant = state->pass1_intra ? - state->credits_quant_i: - state->credits_quant_p; - } - else { - quant = state->credits_quant_p; - } - - state->bytes1 = bytes1; - state->bytes2 = bytes1; - state->desired_bytes2 = bytes1; - return(quant); - default: - case VBR_CREDITS_MODE_RATE : - case VBR_CREDITS_MODE_SIZE : - if(util_frametype(state) == FRAME_TYPE_STARTING_CREDITS) - bytes2 = (int)(bytes1 / state->credits_start_curve); - else - bytes2 = (int)(bytes1 / state->credits_end_curve); - break; - } - } - else { - /* Foxer: apply curve compression outside credits */ - double dbytes, curve_temp; - - bytes2 = bytes1; - - if (state->pass1_intra) - dbytes = ((int)(bytes2 + bytes2 * state->keyframe_boost / 100)) / - state->movie_curve; - else - dbytes = bytes2 / state->movie_curve; - - /* spread the compression error accross payback_delay frames */ - if (state->bitrate_payback_method == VBR_PAYBACK_BIAS) { - bytes2 = (int)(state->curve_comp_error / state->bitrate_payback_delay); - } - else { - bytes2 = (int)(state->curve_comp_error * dbytes / - state->average_frame / state->bitrate_payback_delay); - - if (labs(bytes2) > fabs(state->curve_comp_error)) - bytes2 = (int)state->curve_comp_error; - } - - state->curve_comp_error -= bytes2; - - if (state->use_alt_curve) { - - if (!state->pass1_intra) { - - if (dbytes > state->average_frame) { - if (dbytes >= state->alt_curve_high) - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev); - else { - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff))); - break; - default: - case VBR_ALT_CURVE_LINEAR: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (dbytes - state->average_frame) / state->alt_curve_high_diff); - break; - case VBR_ALT_CURVE_SOFT: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_high_diff)))); - } - } - } - else { - if (dbytes <= state->alt_curve_low) - curve_temp = dbytes; - else { - switch(state->alt_curve_type) { - case VBR_ALT_CURVE_AGGRESIVE: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - sin(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff))); - break; - default: - case VBR_ALT_CURVE_LINEAR: - curve_temp = dbytes * (state->alt_curve_mid_qual - state->alt_curve_qual_dev * - (dbytes - state->average_frame) / state->alt_curve_low_diff); - break; - case VBR_ALT_CURVE_SOFT: - curve_temp = dbytes * (state->alt_curve_mid_qual + state->alt_curve_qual_dev * - (1.0 - cos(DEG2RAD * ((dbytes - state->average_frame) * 90.0 / state->alt_curve_low_diff)))); - } - } - } - - curve_temp = curve_temp * state->curve_comp_scale + state->curve_bias_bonus; - - bytes2 += ((int)curve_temp); - state->curve_comp_error += curve_temp - ((int)curve_temp); - - } - else { - state->curve_comp_error += dbytes - ((int)dbytes); - bytes2 += ((int)dbytes); - } - } - else if ((state->curve_compression_high + state->curve_compression_low) && - !state->pass1_intra) { - - if (dbytes > state->average_frame) { - curve_temp = state->curve_comp_scale * - ((double)dbytes + (state->average_frame - dbytes) * - state->curve_compression_high / 100.0); - } - else { - curve_temp = state->curve_comp_scale * - ((double)dbytes + (state->average_frame - dbytes) * - state->curve_compression_low / 100.0); - } - - bytes2 += ((int)curve_temp); - state->curve_comp_error += curve_temp - ((int)curve_temp); - } - else { - state->curve_comp_error += dbytes - ((int)dbytes); - bytes2 += ((int)dbytes); - } - - /* cap bytes2 to first pass size, lowers number of quant=1 frames */ - if (bytes2 > bytes1) { - state->curve_comp_error += bytes2 - bytes1; - bytes2 = bytes1; - } - else if (bytes2 < 1) { - state->curve_comp_error += --bytes2; - bytes2 = 1; - } - } - - state->desired_bytes2 = bytes2; - - /* Ugly dependance between getquant and getintra */ - intra = state->getintra(state); - - if(intra) { - - KFdistance = state->keyframe_locations[state->KF_idx] - - state->keyframe_locations[state->KF_idx - 1]; - - if (KFdistance < state->kftreshold) { - KFdistance = KFdistance - state->min_key_interval; - - if (KFdistance >= 0) { - - KF_min_size = bytes2 * (100 - state->kfreduction) / 100; - if (KF_min_size < 1) - KF_min_size = 1; - - bytes2 = KF_min_size + (bytes2 - KF_min_size) * KFdistance / - (state->kftreshold - state->min_key_interval); - - if (bytes2 < 1) - bytes2 = 1; - } - } - } - - /* - * Foxer: scale overflow in relation to average size, so smaller frames don't get - * too much/little bitrate - */ - overflow = (int)((double)overflow * bytes2 / state->average_frame); - - /* Foxer: reign in overflow with huge frames */ - if (labs(overflow) > labs(state->overflow)) { - overflow = state->overflow; - } - - /* Foxer: make sure overflow doesn't run away */ - if(overflow > bytes2 * state->twopass_max_overflow_improvement / 100) { - bytes2 += (overflow <= bytes2) ? bytes2 * state->twopass_max_overflow_improvement / 100 : - overflow * state->twopass_max_overflow_improvement / 100; - } - else if(overflow < bytes2 * state->twopass_max_overflow_degradation / -100) { - bytes2 += bytes2 * state->twopass_max_overflow_degradation / -100; - } - else { - bytes2 += overflow; - } - - if(bytes2 > state->max_framesize) { - capped_to_max_framesize = 1; - bytes2 = state->max_framesize; - } - - if(bytes2 < 1) { - bytes2 = 1; - } - - state->bytes1 = bytes1; - state->bytes2 = bytes2; - - /* very 'simple' quant<->filesize relationship */ - quant = state->pass1_quant * bytes1 / bytes2; - - if(quant < 1) - quant = 1; - else if(quant > 31) - quant = 31; - else if(!state->pass1_intra) { - - /* Foxer: aid desired quantizer precision by accumulating decision error */ - state->quant_error[quant] += ((double)(state->pass1_quant * bytes1) / bytes2) - quant; - - if (state->quant_error[quant] >= 1.0) { - state->quant_error[quant] -= 1.0; - quant++; - } - } - - /* we're done with credits */ - if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) { - return(quant); - } - - if(intra) { - - if (quant < state->min_iquant) - quant = state->min_iquant; - if (quant > state->max_iquant) - quant = state->max_iquant; - } - else { - - if(quant > state->max_pquant) - quant = state->max_pquant; - if(quant < state->min_pquant) - quant = state->min_pquant; - - /* subsequent frame quants can only be +- 2 */ - if(state->last_quant && capped_to_max_framesize == 0) { - if (quant > state->last_quant + 2) - quant = state->last_quant + 2; - if (quant < state->last_quant - 2) - quant = state->last_quant - 2; - } - } - - return(quant); - -} - -static int vbr_getintra_2pass2(void *sstate) -{ - - int intra; - vbr_control_t *state = sstate; - - - /* Get next intra state (fetched by update) */ - intra = state->pass1_intra; - - /* During credits, XviD will decide itself */ - if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) { - - - switch(state->credits_mode) { - default: - case VBR_CREDITS_MODE_RATE : - case VBR_CREDITS_MODE_SIZE : - intra = -1; - break; - case VBR_CREDITS_MODE_QUANT : - /* Except in this case */ - if (state->credits_quant_i == state->credits_quant_p) - intra = -1; - break; - } - - } - - /* Force I Frame when max_key_interval is reached */ - if((state->cur_frame - state->last_keyframe) > state->max_key_interval) - intra = 1; - - /* - * Force P or B Frames for frames whose distance is less than the - * requested minimum - */ - if((state->cur_frame - state->last_keyframe) < state->min_key_interval) - intra = 0; - - - /* Return the given intra mode except for first frame */ - return((state->cur_frame==0)?1:intra); - -} - -static int vbr_update_2pass2(void *sstate, - int quant, - int intra, - int header_bytes, - int total_bytes, - int kblocks, - int mblocks, - int ublocks) - - -{ - - - int next_hbytes, next_kblocks, next_mblocks, next_ublocks; - int tempdiv; - - vbr_control_t *state = sstate; - - /* - * We do not depend on getintra/quant because we have the real results - * from the xvid core - */ - - if (util_frametype(state) == FRAME_TYPE_NORMAL_MOVIE) { - - state->quant_count[quant]++; - - if (state->pass1_intra) { - - state->overflow += state->KFoverflow; - state->KFoverflow = state->desired_bytes2 - total_bytes; - - tempdiv = (state->keyframe_locations[state->KF_idx] - - state->keyframe_locations[state->KF_idx - 1]); - - /* redistribute correctly (by koepi) */ - if (tempdiv > 1) { - /* non-consecutive keyframes */ - state->KFoverflow_partial = state->KFoverflow / - (tempdiv - 1); - } - else { - state->overflow += state->KFoverflow; - state->KFoverflow = 0; - state->KFoverflow_partial = 0; - } - state->KF_idx++; - - } - else { - state->overflow += state->desired_bytes2 - total_bytes + - state->KFoverflow_partial; - state->KFoverflow -= state->KFoverflow_partial; - } - } - else { - - state->overflow += state->desired_bytes2 - total_bytes; - state->overflow += state->KFoverflow; - state->KFoverflow = 0; - state->KFoverflow_partial = 0; - } - - /* Save old quant */ - state->last_quant = quant; - - /* Update next frame data */ - fscanf(state->pass1_file, "%d %d %d %d %d %d %d\n", - &state->pass1_quant, &state->pass1_intra, &next_hbytes, - &state->pass1_bytes, &next_kblocks, &next_mblocks, - &next_ublocks); - - /* Save the last Keyframe pos */ - if(intra) - state->last_keyframe = state->cur_frame; - - /* Ok next frame */ - state->cur_frame++; - - return(0); - -} - -static int vbr_finish_2pass2(void *sstate) -{ - - vbr_control_t *state = sstate; - - if(state->pass1_file == NULL) - return(-1); - - /* Close the file */ - if(fclose(state->pass1_file) != 0) - return(-1); - - /* Free the memory */ - if(state->keyframe_locations) - free(state->keyframe_locations); - - return(0); - -} - - -/****************************************************************************** - * Fixed quant mode - Most of the functions will be dummy functions - *****************************************************************************/ - -static int vbr_init_fixedquant(void *sstate) -{ - - vbr_control_t *state = sstate; - - if(state->fixed_quant < 1) - state->fixed_quant = 1; - - if(state->fixed_quant > 31) - state->fixed_quant = 31; - - state->cur_frame = 0; - - return(0); - -} - -static int vbr_getquant_fixedquant(void *sstate) -{ - - vbr_control_t *state = sstate; - - /* Credits' frame ? */ - if(util_frametype(state) != FRAME_TYPE_NORMAL_MOVIE) { - - int quant; - - switch(state->credits_mode) { - case VBR_CREDITS_MODE_RATE: - quant = state->fixed_quant * state->credits_quant_ratio; - break; - case VBR_CREDITS_MODE_QUANT: - quant = state->credits_fixed_quant; - break; - default: - quant = state->fixed_quant; - - } - - return(quant); - - } - - /* No credit frame - return fixed quant */ - return(state->fixed_quant); - -} - -static int vbr_getintra_fixedquant(void *state) -{ - - return(-1); - -} diff --git a/core/XvidVbr.h b/core/XvidVbr.h deleted file mode 100644 index ea9d3b703..000000000 --- a/core/XvidVbr.h +++ /dev/null @@ -1,231 +0,0 @@ -/****************************************************************************** - * - * XviD VBR Library - * - * Copyright (C) 2002 Edouard Gomez <[email protected]> - * - * The curve treatment algorithm is based on work done by Foxer <email?> and - * Dirk Knop <[email protected]> for the XviD vfw dynamic library. - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - *****************************************************************************/ - -#ifndef __XVID_VBR_H__ -#define __XVID_VBR_H__ - -#define VBR_VERSION 0 - -/****************************************************************************** - * Function types used in the vbr controler - *****************************************************************************/ - -typedef int (vbr_init_function)(void *state); -typedef vbr_init_function *vbr_init_function_ptr; - -typedef int (vbr_get_quant_function)(void *state); -typedef vbr_get_quant_function *vbr_get_quant_function_ptr; - -typedef int (vbr_get_intra_function)(void *state); -typedef vbr_get_intra_function *vbr_get_intra_function_ptr; - -typedef int (vbr_update_function)(void *state, - int quant, - int intra, - int header_bytes, - int total_bytes, - int kblocks, - int mblocks, - int ublocks); -typedef vbr_update_function *vbr_update_function_ptr; - -typedef int (vbr_finish_function)(void *state); -typedef vbr_finish_function *vbr_finish_function_ptr; - -/****************************************************************************** - * The VBR CONTROLER structure - the spin of the library - *****************************************************************************/ - -typedef struct _vbr_control_t -{ - - /* All modes - specifies what VBR algorithm has to be used */ - int mode; - - /* All modes - specifies what fps the movie uses */ - float fps; - - /* All modes */ - int debug; - - /* - * For VBR_MODE_2PASS_1/2 - specifies from/to what file the vbr - * controller has to write/read stats - */ - char *filename; - - /* For VBR_MODE_2PASS_2 - Target size */ - int desired_bitrate; - - /* For VBR_MODE_2PASS_2 - Credits parameters */ - int credits_mode; - int credits_start; - int credits_start_begin; - int credits_start_end; - int credits_end; - int credits_end_begin; - int credits_end_end; - int credits_quant_ratio; - int credits_fixed_quant; - int credits_quant_i; - int credits_quant_p; - int credits_start_size; - int credits_end_size; - - /* For VBR_MODE_2PASS_2 - keyframe parameters */ - int keyframe_boost; - int kftreshold; - int kfreduction; - int min_key_interval; - int max_key_interval; - - /* For VBR_MODE_2PASS_2 - Normal curve */ - int curve_compression_high; - int curve_compression_low; - - /* For VBR_MODE_2PASS_2 - Alternate curve parameters */ - int use_alt_curve; - int alt_curve_type; - int alt_curve_low_dist; - int alt_curve_high_dist; - int alt_curve_min_rel_qual; - int alt_curve_use_auto; - int alt_curve_auto_str; - int alt_curve_use_auto_bonus_bias; - int alt_curve_bonus_bias; - int bitrate_payback_method; - int bitrate_payback_delay; - int max_iquant; - int min_iquant; - int max_pquant; - int min_pquant; - int twopass_max_bitrate; - int twopass_max_overflow_improvement; - int twopass_max_overflow_degradation; - - /* - * For VBR_MODE_FIXED_QUANT - the quantizer that has to be used for all - * frames - */ - int fixed_quant; - - /* ----------- Internal data - Do not modify ----------- */ - void *debug_file; - void *pass1_file; - - long long desired_size; - - int cur_frame; - int nb_frames; - int nb_keyframes; - - int *keyframe_locations; - int last_keyframe; - - double credits_start_curve; - double credits_end_curve; - double movie_curve; - double average_frame; - double alt_curve_low; - double alt_curve_low_diff; - double alt_curve_high; - double alt_curve_high_diff; - double alt_curve_mid_qual; - double alt_curve_qual_dev; - double curve_bias_bonus; - double curve_comp_scale; - double curve_comp_error; - - int pass1_quant; - int pass1_intra; - int pass1_bytes; - - int bytes1; - int bytes2; - int desired_bytes2; - int max_framesize; - int last_quant; - int quant_count[32]; - double quant_error[32]; - - int overflow; - int KFoverflow; - int KFoverflow_partial; - int KF_idx; - - int debug_quant_count[32]; - - /* ----------- Internal data - do not modify ----------- */ - vbr_init_function_ptr init; - vbr_get_quant_function_ptr getquant; - vbr_get_intra_function_ptr getintra; - vbr_update_function_ptr update; - vbr_finish_function_ptr finish; - -}vbr_control_t; - -/****************************************************************************** - * Constants - *****************************************************************************/ - -/* Constants for the mode member */ -#define VBR_MODE_1PASS 0x01 -#define VBR_MODE_2PASS_1 0x02 -#define VBR_MODE_2PASS_2 0x04 -#define VBR_MODE_FIXED_QUANT 0x08 - -/* Constants for the credits mode */ -#define VBR_CREDITS_MODE_RATE 0x01 -#define VBR_CREDITS_MODE_QUANT 0x02 -#define VBR_CREDITS_MODE_SIZE 0x04 - -/* Alternate curve treatment types */ -#define VBR_ALT_CURVE_SOFT 0x01 -#define VBR_ALT_CURVE_LINEAR 0x02 -#define VBR_ALT_CURVE_AGGRESIVE 0x04 - -/* Payback modes */ -#define VBR_PAYBACK_BIAS 0x01 -#define VBR_PAYBACK_PROPORTIONAL 0x02 - -/****************************************************************************** - * VBR API - *****************************************************************************/ - -extern int vbrSetDefaults(vbr_control_t *state); -extern int vbrInit(vbr_control_t *state); -extern int vbrGetQuant(vbr_control_t *state); -extern int vbrGetIntra(vbr_control_t *state); -extern int vbrUpdate(vbr_control_t *state, - int quant, - int intra, - int header_bytes, - int total_bytes, - int kblocks, - int mblocks, - int ublocks); -extern int vbrFinish(vbr_control_t *state); - -#endif |