diff options
author | handbrake <[email protected]> | 2006-01-14 13:05:49 +0000 |
---|---|---|
committer | handbrake <[email protected]> | 2006-01-14 13:05:49 +0000 |
commit | 5824c4979fbc54ae3d3015c07cbf6fa4aea7516d (patch) | |
tree | 49ba3bbe1f8d8166fa4f7f964055d4011d2deca0 /core | |
parent | f013e3544c0bdf17348d617a467af0e4fde0f545 (diff) |
HandBrake 0.5
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@7 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'core')
58 files changed, 4743 insertions, 4288 deletions
diff --git a/core/Ac3Dec.c b/core/Ac3Dec.c new file mode 100644 index 000000000..d5430d49e --- /dev/null +++ b/core/Ac3Dec.c @@ -0,0 +1,219 @@ +/* $Id: Ac3Dec.c,v 1.4 2003/11/04 20:16:44 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 <a52dec/a52.h> + +/* Local prototypes */ +static int Ac3DecWork( HBWork * ); +static int GetBytes( HBAc3Dec *, int ); + +struct HBAc3Dec +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBAudio * audio; + + /* liba52 stuff */ + a52_state_t * state; + int inFlags; + int outFlags; + float sampleLevel; + + /* Buffers */ + uint8_t ac3Frame[3840]; /* Max size of a A52 frame */ + int ac3FrameSize; /* In bytes */ + HBBuffer * ac3Buffer; + int ac3BufferPos; /* In bytes */ + int nextFrameSize; /* In bytes */ + float position; + HBBuffer * rawBuffer; +}; + +HBAc3Dec * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) +{ + HBAc3Dec * a; + if( !( a = malloc( sizeof( HBAc3Dec ) ) ) ) + { + HBLog( "HBAc3DecInit: malloc() failed, gonna crash" ); + return NULL; + } + + a->name = strdup( "Ac3Dec" ); + a->work = Ac3DecWork; + + a->handle = handle; + a->audio = audio; + + /* Init liba52 */ + a->state = a52_init( 0 ); + a->inFlags = 0; + + /* Let it do the downmixing */ + a->outFlags = A52_STEREO; + + /* Lame wants samples from -32768 to 32768 */ + a->sampleLevel = 32768.0; + + a->ac3FrameSize = 0; + a->ac3Buffer = NULL; + a->ac3BufferPos = 0; + a->nextFrameSize = 0; + a->position = 0.0; + a->rawBuffer = NULL; + + return a; +} + +void HBAc3DecClose( HBAc3Dec ** _a ) +{ + HBAc3Dec * a = *_a; + + if( a->ac3Buffer ) HBBufferClose( &a->ac3Buffer ); + if( a->rawBuffer ) HBBufferClose( &a->rawBuffer ); + a52_free( a->state ); + free( a->name ); + free( a ); + + *_a = NULL; +} + +static int Ac3DecWork( HBWork * w ) +{ + HBAc3Dec * a = (HBAc3Dec*) w; + HBAudio * audio = a->audio; + + int didSomething = 0; + + /* Push decoded buffer */ + if( a->rawBuffer ) + { + if( HBFifoPush( audio->rawFifo, &a->rawBuffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + /* Get a frame header (7 bytes) */ + if( a->ac3FrameSize < 7 ) + { + if( GetBytes( a, 7 ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + a->nextFrameSize = a52_syncinfo( a->ac3Frame, &a->inFlags, + &audio->inSampleRate, + &audio->inBitrate ); + + if( !a->nextFrameSize ) + { + HBLog( "HBAc3Dec: a52_syncinfo() failed" ); + HBErrorOccured( a->handle, HB_ERROR_A52_SYNC ); + return didSomething; + } + } + + /* Get the whole frame */ + if( a->ac3FrameSize >= 7 ) + { + sample_t * samples; + HBBuffer * rawBuffer; + int i; + + if( GetBytes( a, a->nextFrameSize ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + /* Feed liba52 */ + a52_frame( a->state, a->ac3Frame, &a->outFlags, + &a->sampleLevel, 0 ); + a->ac3FrameSize = 0; + + /* 6 blocks per frame, 256 samples per block, 2 channels */ + rawBuffer = HBBufferInit( 12 * 256 * sizeof( float ) ); + rawBuffer->position = a->position; + + for( i = 0; i < 6; i++ ) + { + /* Decode a block */ + a52_block( a->state ); + + /* Get a pointer to the raw data */ + samples = a52_samples( a->state ); + + /* Copy left channel data */ + memcpy( rawBuffer->data + i * 256 * sizeof( float ), + samples, + 256 * sizeof( float ) ); + + /* Copy right channel data */ + memcpy( rawBuffer->data + ( 6 + i ) * 256 * sizeof( float ), + 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 ) ) ) + { + return 0; + } + a->ac3BufferPos = 0; + a->position = a->ac3Buffer->position; + + if( a->ac3Buffer->last ) + { + HBDone( a->handle ); + } + } + + i = MIN( size - a->ac3FrameSize, + a->ac3Buffer->size - a->ac3BufferPos ); + memcpy( a->ac3Frame + a->ac3FrameSize, + a->ac3Buffer->data + a->ac3BufferPos, + i ); + a->ac3FrameSize += i; + a->ac3BufferPos += i; + + if( a->ac3BufferPos == a->ac3Buffer->size ) + { + HBBufferClose( &a->ac3Buffer ); + } + } + + return 1; +} + diff --git a/core/Ac3Dec.h b/core/Ac3Dec.h new file mode 100644 index 000000000..a1ecaff66 --- /dev/null +++ b/core/Ac3Dec.h @@ -0,0 +1,15 @@ +/* $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/Ac3Decoder.cpp b/core/Ac3Decoder.cpp deleted file mode 100644 index 663184e40..000000000 --- a/core/Ac3Decoder.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* $Id: Ac3Decoder.cpp,v 1.21 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Ac3Decoder.h" -#include "Fifo.h" -#include "Manager.h" - -extern "C" { -#include <a52dec/a52.h> -} - -HBAc3Decoder::HBAc3Decoder( HBManager * manager, HBAudio * audio ) -{ - fManager = manager; - fAudio = audio; - - fLock = new HBLock(); - fUsed = false; - - /* Init liba52 */ - fState = a52_init( 0 ); - fInFlags = 0; - fOutFlags = A52_STEREO; - - /* Lame wants samples from -32768 to 32768 */ - fSampleLevel = 32768.0; - - /* Max size for a A52 frame is 3840 bytes */ - fAc3Frame = new HBBuffer( 3840 ); - fAc3Frame->fSize = 0; - fAc3Buffer = NULL; - fPosInAc3Buffer = 0; - fRawBuffer = NULL; -} - -HBAc3Decoder::~HBAc3Decoder() -{ - if( fRawBuffer ) delete fRawBuffer; - if( fAc3Buffer ) delete fAc3Buffer; - delete fAc3Frame; - a52_free( fState ); - delete fLock; -} - -bool HBAc3Decoder::Work() -{ - if( !Lock() ) - { - return false; - } - - /* Push the latest decoded buffer */ - if( fRawBuffer ) - { - if( fAudio->fRawFifo->Push( fRawBuffer ) ) - { - fRawBuffer = NULL; - } - else - { - Unlock(); - return false; - } - } - - /* Get a frame header (7 bytes) */ - if( fAc3Frame->fSize < 7 ) - { - if( GetBytes( 7 ) ) - { - /* Get the size of the coming frame */ - fFrameSize = a52_syncinfo( fAc3Frame->fData, &fInFlags, - &fAudio->fInSampleRate, - &fAudio->fInBitrate ); - if( !fFrameSize ) - { - Log( "HBAc3Decoder: a52_syncinfo failed" ); - fManager->Error( HB_ERROR_A52_SYNC ); - return false; - } - } - else - { - Unlock(); - return false; - } - } - - /* In case the audio should start later than the video, - insert some silence */ - if( fAudio->fDelay > 3 * 256 * 1000 / fAudio->fInSampleRate ) - { - fRawBuffer = new HBBuffer( 12 * 256 * sizeof( float ) ); - for( uint32_t i = 0; i < 12 * 256; i++ ) - { - ((float*)fRawBuffer->fData)[i] = 0; - } - fAudio->fDelay -= 6 * 256 * 1000 / fAudio->fInSampleRate; - - Unlock(); - return true; - } - - if( fAc3Frame->fSize >= 7 ) - { - /* Get the whole frame */ - if( GetBytes( (uint32_t) fFrameSize ) ) - { - /* Feed liba52 */ - a52_frame( fState, fAc3Frame->fData, &fOutFlags, - &fSampleLevel, 0 ); - fAc3Frame->fSize = 0; - - /* 6 blocks per frame, 256 samples per block */ - fRawBuffer = new HBBuffer( 12 * 256 * sizeof( float ) ); - fRawBuffer->fPosition = fPosition; - - sample_t * samples; - for( int i = 0; i < 6; i++ ) - { - /* Decode a block */ - a52_block( fState ); - - /* Get a pointer to the raw data */ - samples = a52_samples( fState ); - - /* Copy left channel data */ - memcpy( (float*) fRawBuffer->fData + i * 256, - samples, - 256 * sizeof( float ) ); - - /* Copy right channel data */ - memcpy( (float*) fRawBuffer->fData + ( 6 + i ) * 256, - samples + 256, - 256 * sizeof( float ) ); - } - } - else - { - Unlock(); - return false; - } - } - - Unlock(); - return true; -} - -bool HBAc3Decoder::Lock() -{ - fLock->Lock(); - if( fUsed ) - { - fLock->Unlock(); - return false; - } - fUsed = true; - fLock->Unlock(); - return true; -} - -void HBAc3Decoder::Unlock() -{ - fLock->Lock(); - fUsed = false; - fLock->Unlock(); -} - -/* GetBytes() : pops buffers from the AC3 fifo until fAc3Frame - contains <size> bytes */ -bool HBAc3Decoder::GetBytes( uint32_t size ) -{ - while( fAc3Frame->fSize < size ) - { - if( !fAc3Buffer ) - { - if( !( fAc3Buffer = fAudio->fAc3Fifo->Pop() ) ) - { - return false; - } - fPosInAc3Buffer = 0; - fPosition = fAc3Buffer->fPosition; - } - - int willCopy = MIN( size - fAc3Frame->fSize, - fAc3Buffer->fSize - fPosInAc3Buffer ); - memcpy( fAc3Frame->fData + fAc3Frame->fSize, - fAc3Buffer->fData + fPosInAc3Buffer, - willCopy ); - fAc3Frame->fSize += willCopy; - fPosInAc3Buffer += willCopy; - - if( fAc3Buffer->fSize == fPosInAc3Buffer ) - { - delete fAc3Buffer; - fAc3Buffer = NULL; - } - } - - return true; -} diff --git a/core/Ac3Decoder.h b/core/Ac3Decoder.h deleted file mode 100644 index f63206b12..000000000 --- a/core/Ac3Decoder.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $Id: Ac3Decoder.h,v 1.11 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_AC3_DECODER_H -#define HB_AC3_DECODER_H - -#include "Common.h" - -class HBAc3Decoder -{ - public: - HBAc3Decoder( HBManager * manager, - HBAudio * audio ); - ~HBAc3Decoder(); - bool Work(); - - private: - bool Lock(); - void Unlock(); - bool GetBytes( uint32_t size ); - - HBManager * fManager; - HBAudio * fAudio; - - HBLock * fLock; - bool fUsed; - - /* liba52 */ - a52_state_t * fState; - int fInFlags; - int fOutFlags; - float fSampleLevel; - - /* buffers */ - HBBuffer * fAc3Frame; - HBBuffer * fAc3Buffer; - uint32_t fPosInAc3Buffer; - HBBuffer * fRawBuffer; - - float fPosition; - int fFrameSize; -}; - -#endif diff --git a/core/AviMux.c b/core/AviMux.c new file mode 100644 index 000000000..bd0551217 --- /dev/null +++ b/core/AviMux.c @@ -0,0 +1,640 @@ +/* $Id: AviMux.c,v 1.5 2003/11/06 18:35:53 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" + +/* Local structures */ +typedef struct AviMainHeader AviMainHeader; +typedef struct AviStreamHeader AviStreamHeader; +typedef struct BitmapInfo BitmapInfo; +typedef struct WaveFormatEx WaveFormatEx; + +/* Local prototypes */ +static void AviMuxThread( void * ); +static void InitAviHeaders( HBAviMux * ); +static void AddChunk( HBAviMux *, HBBuffer **, uint32_t, + AviStreamHeader * ); +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 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 +{ + uint32_t FourCC; + uint32_t BytesCount; + uint32_t MicroSecPerFrame; + uint32_t MaxBytesPerSec; + uint32_t PaddingGranularity; + uint32_t Flags; + uint32_t TotalFrames; + uint32_t InitialFrames; + uint32_t Streams; + uint32_t SuggestedBufferSize; + uint32_t Width; + uint32_t Height; + uint32_t Reserved[4]; +}; + +struct __attribute__((__packed__)) AviStreamHeader +{ + uint32_t FourCC; + uint32_t BytesCount; + uint32_t Type; + uint32_t Handler; + uint32_t Flags; + uint16_t Priority; + uint16_t Language; + uint32_t InitialFrames; + uint32_t Scale; + uint32_t Rate; + uint32_t Start; + uint32_t Length; + uint32_t SuggestedBufferSize; + uint32_t Quality; + uint32_t SampleSize; + int16_t Left; + int16_t Top; + int16_t Right; + int16_t Bottom; +}; + +struct __attribute__((__packed__)) BitmapInfo +{ + uint32_t FourCC; + uint32_t BytesCount; + uint32_t Size; + uint32_t Width; + uint32_t Height; + uint16_t Planes; + uint16_t BitCount; + uint32_t Compression; + uint32_t SizeImage; + uint32_t XPelsPerMeter; + 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 +{ + uint32_t FourCC; + uint32_t BytesCount; + uint16_t FormatTag; + uint16_t Channels; + uint32_t SamplesPerSec; + uint32_t AvgBytesPerSec; + uint16_t BlockAlign; + uint16_t BitsPerSample; + uint16_t Size; + + /* mp3 specific */ + uint16_t Id; + uint32_t Flags; + uint16_t BlockSize; + uint16_t FramesPerBlock; + uint16_t CodecDelay; +}; + +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; + HBThread * thread; +}; + +HBAviMux * HBAviMuxInit( HBHandle * handle, HBTitle * title, + HBAudio * audio, HBAudio * optAudio ) +{ + HBAviMux * a; + if( !( a = malloc( sizeof( HBAviMux ) ) ) ) + { + HBLog( "HBAviMuxInit: malloc() failed, gonna crash" ); + return NULL; + } + + a->handle = handle; + a->title = title; + a->audio = audio; + a->optAudio = optAudio; + + a->size = 0; + a->file = NULL; + a->index = HBBufferInit( 1024 * 1024 ); + a->index->size = 0; + + a->die = 0; + a->thread = HBThreadInit( "avi muxer", AviMuxThread, a, + HB_NORMAL_PRIORITY ); + return a; +} + +void HBAviMuxClose( HBAviMux ** _a ) +{ + HBAviMux * a = *_a; + + a->die = 1; + HBThreadClose( &a->thread ); + free( a ); + + *_a = NULL; +} + +static void AviMuxThread( void * _a ) +{ + HBAviMux * a = (HBAviMux*) _a; + HBTitle * title = a->title; + HBAudio * audio = a->audio; + HBAudio * optAudio = a->optAudio; + + HBBuffer * videoBuffer = NULL; + HBBuffer * audioBuffer = NULL; + HBBuffer * optAudioBuffer = NULL; + + /* Open destination file */ + HBLog( "HBAviMux: opening %s", title->file ); + if( !( a->file = fopen( title->file, "w" ) ) ) + { + HBLog( "HBAviMux: fopen() failed" ); + HBErrorOccured( a->handle, HB_ERROR_AVI_WRITE ); + return; + } + + /* Get a buffer for each track */ + videoBuffer = Pop( a, title->mpeg4Fifo ); + audioBuffer = Pop( a, audio->mp3Fifo ); + if( optAudio ) + { + optAudioBuffer = Pop( a, optAudio->mp3Fifo ); + } + + /* Failed ? Then forget it */ + if( !videoBuffer || !audioBuffer || + ( optAudio && !optAudioBuffer ) ) + { + fclose( a->file ); + a->file = NULL; + + HBLog( "HBAviMux: deleting %s", title->file ); + unlink( title->file ); + return; + } + + InitAviHeaders( a ); + + for( ;; ) + { + /* Get a buffer for each track */ + if( !videoBuffer ) + { + videoBuffer = Pop( a, title->mpeg4Fifo ); + } + if( !audioBuffer ) + { + audioBuffer = Pop( a, audio->mp3Fifo ); + } + if( optAudio && !optAudioBuffer ) + { + optAudioBuffer = Pop( a, optAudio->mp3Fifo ); + } + + if( !videoBuffer && !audioBuffer && !optAudioBuffer ) + { + /* 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 ) ) + { + AddChunk( a, &videoBuffer, FOURCC( "00dc" ), + &a->videoHeader ); + } + else if( audioBuffer && + ( !optAudioBuffer || + audioBuffer->position < optAudioBuffer->position ) ) + { + AddChunk( a, &audioBuffer, FOURCC( "01wb" ), + &a->audioHeader ); + } + else + { + AddChunk( a, &optAudioBuffer, FOURCC( "02wb" ), + &a->optAudioHeader ); + } + } + + AddIndex( a ); + + HBLog( "HBAviMux: closing %s", title->file ); + fclose( a->file ); +} + +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; + + /* AVI main header */ + memset( mainHeader, 0, sizeof( AviMainHeader ) ); + mainHeader->FourCC = FOURCC( "avih" ); + mainHeader->BytesCount = sizeof( AviMainHeader ) - 8; + mainHeader->MicroSecPerFrame = (uint64_t) 1000000 * + title->rateBase / title->rate; + mainHeader->Streams = optAudio ? 3 : 2; + mainHeader->Width = title->outWidth; + mainHeader->Height = title->outHeight; + + /* Video stream header */ + memset( videoHeader, 0, sizeof( AviStreamHeader ) ); + videoHeader->FourCC = FOURCC( "strh" ); + videoHeader->BytesCount = sizeof( AviStreamHeader ) - 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" ); + + videoHeader->Scale = title->rateBase; + videoHeader->Rate = title->rate; + + /* Video stream format */ + memset( videoFormat, 0, sizeof( BitmapInfo ) ); + videoFormat->FourCC = FOURCC( "strf" ); + videoFormat->BytesCount = sizeof( BitmapInfo ) - 8; + videoFormat->Size = sizeof( BitmapInfo ) - 8; + videoFormat->Width = title->outWidth; + videoFormat->Height = title->outHeight; + videoFormat->Planes = 1; + videoFormat->BitCount = 24; + if( title->codec == HB_CODEC_FFMPEG ) + videoFormat->Compression = FOURCC( "DX50" ); + else if( title->codec == HB_CODEC_XVID ) + videoFormat->Compression = FOURCC( "XVID" ); + + /* 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 ) + { + /* 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; + } + + hdrlBytes = 4 + sizeof( AviMainHeader ) + + ( optAudio ? 3 : 2 ) * ( 12 + sizeof( AviStreamHeader ) ) + + sizeof( BitmapInfo ) + + ( optAudio ? 2 : 1 ) * sizeof( WaveFormatEx ); + + /* Here we really start to write into the file */ + + WriteInt32( file, FOURCC( "RIFF" ) ); + WriteInt32( file, 2040 ); + WriteInt32( file, FOURCC( "AVI " ) ); + WriteInt32( file, FOURCC( "LIST" ) ); + WriteInt32( file, hdrlBytes ); + WriteInt32( file, FOURCC( "hdrl" ) ); + WriteMainHeader( file, mainHeader ); + WriteInt32( file, FOURCC( "LIST" ) ); + WriteInt32( file, 4 + sizeof( AviStreamHeader ) + + sizeof( BitmapInfo ) ); + 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 ) + { + WriteInt32( file, FOURCC( "LIST" ) ); + WriteInt32( file, 4 + sizeof( AviStreamHeader ) + + sizeof( WaveFormatEx ) ); + WriteInt32( file, FOURCC( "strl" ) ); + WriteStreamHeader( file, optAudioHeader ); + WriteWaveFormatEx( file, optAudioFormat ); + } + WriteInt32( file, FOURCC( "JUNK" ) ); + WriteInt32( file, 2008 - hdrlBytes ); + for( i = 0; i < 2008 - hdrlBytes; i++ ) + { + WriteInt8( file, 0 ); + } + WriteInt32( file, FOURCC( "LIST" ) ); + WriteInt32( file, 4 ); + WriteInt32( file, FOURCC( "movi" ) ); +} + +static void AddChunk( HBAviMux * a, HBBuffer ** _buffer, + uint32_t fourCC, AviStreamHeader * header ) +{ + HBBuffer * buffer = *_buffer; + + /* Update index */ + IndexAddInt32( a->index, fourCC ); + IndexAddInt32( a->index, buffer->keyFrame ? AVIIF_KEYFRAME : 0 ); + IndexAddInt32( a->index, 4 + a->size ); + IndexAddInt32( a->index, buffer->size ); + + /* Write the chunk to the file */ + fseek( a->file, 0, SEEK_END ); + WriteInt32( a->file, fourCC ); + WriteInt32( a->file, buffer->size ); + WriteBuffer( a->file, buffer ); + + /* Chunks must be 2-bytes aligned */ + if( buffer->size & 1 ) + { + WriteInt8( a->file, 0 ); + } + + /* Update headers */ + a->size += 8 + EVEN( buffer->size ); + header->Length++; + + /* RIFF size */ + fseek( a->file, 4, SEEK_SET ); + WriteInt32( a->file, 2040 + a->size ); + + /* AviStreamHeader's length */ + 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 ) + { + fseek( a->file, 382, SEEK_SET ); + WriteInt32( a->file, a->optAudioHeader.Length ); + } + + /* movi size */ + fseek( a->file, 2040, SEEK_SET ); + WriteInt32( a->file, 4 + a->size ); + + HBBufferClose( _buffer ); +} + +static void AddIndex( HBAviMux * a ) +{ + fseek( a->file, 0, SEEK_END ); + + WriteInt32( a->file, FOURCC( "idx1" ) ); + WriteInt32( a->file, a->index->size ); + WriteBuffer( a->file, a->index ); + + a->size += 8 + a->index->size; + fseek( a->file, 4, SEEK_SET ); + WriteInt32( a->file, 2040 + a->size ); + a->mainHeader.Flags |= AVIF_HASINDEX; + fseek( a->file, 24, SEEK_SET ); + WriteMainHeader( a->file, &a->mainHeader ); +} + +static void WriteInt8( FILE * file, uint8_t val ) +{ + fputc( val, file ); +} + +static void WriteInt16( FILE * file, uint16_t val ) +{ + fputc( val & 0xFF, file ); + fputc( val >> 8, file ); +} + +static void WriteInt32( FILE * file, uint32_t val ) +{ + fputc( val & 0xFF, file ); + fputc( ( val >> 8 ) & 0xFF, file ); + fputc( ( val >> 16 ) & 0xFF, file ); + fputc( val >> 24, file ); +} + +static void WriteBuffer( FILE * file, HBBuffer * buffer ) +{ + fwrite( buffer->data, buffer->size, 1, file ); +} + +static void WriteBitmapInfo( FILE * file, BitmapInfo * bitmapInfo ) +{ + WriteInt32( file, bitmapInfo->FourCC ); + WriteInt32( file, bitmapInfo->BytesCount ); + WriteInt32( file, bitmapInfo->Size ); + WriteInt32( file, bitmapInfo->Width ); + WriteInt32( file, bitmapInfo->Height ); + WriteInt16( file, bitmapInfo->Planes ); + WriteInt16( file, bitmapInfo->BitCount ); + WriteInt32( file, bitmapInfo->Compression ); + WriteInt32( file, bitmapInfo->SizeImage ); + WriteInt32( file, bitmapInfo->XPelsPerMeter ); + WriteInt32( file, bitmapInfo->YPelsPerMeter ); + WriteInt32( file, bitmapInfo->ClrUsed ); + WriteInt32( file, bitmapInfo->ClrImportant ); + WriteInt8( file, bitmapInfo->Blue ); + WriteInt8( file, bitmapInfo->Green ); + WriteInt8( file, bitmapInfo->Red ); + WriteInt8( file, bitmapInfo->Reserved ); +} + +static void WriteWaveFormatEx( FILE * file, WaveFormatEx * waveFormatEx ) +{ + WriteInt32( file, waveFormatEx->FourCC ); + WriteInt32( file, waveFormatEx->BytesCount ); + WriteInt16( file, waveFormatEx->FormatTag ); + WriteInt16( file, waveFormatEx->Channels ); + WriteInt32( file, waveFormatEx->SamplesPerSec ); + WriteInt32( file, waveFormatEx->AvgBytesPerSec ); + WriteInt16( file, waveFormatEx->BlockAlign ); + WriteInt16( file, waveFormatEx->BitsPerSample ); + WriteInt16( file, waveFormatEx->Size ); + WriteInt16( file, waveFormatEx->Id ); + WriteInt32( file, waveFormatEx->Flags ); + WriteInt16( file, waveFormatEx->BlockSize ); + WriteInt16( file, waveFormatEx->FramesPerBlock ); + WriteInt16( file, waveFormatEx->CodecDelay ); +} + +static void WriteMainHeader( FILE * file, AviMainHeader * mainHeader ) +{ + WriteInt32( file, mainHeader->FourCC ); + WriteInt32( file, mainHeader->BytesCount ); + WriteInt32( file, mainHeader->MicroSecPerFrame ); + WriteInt32( file, mainHeader->MaxBytesPerSec ); + WriteInt32( file, mainHeader->PaddingGranularity ); + WriteInt32( file, mainHeader->Flags ); + WriteInt32( file, mainHeader->TotalFrames ); + WriteInt32( file, mainHeader->InitialFrames ); + WriteInt32( file, mainHeader->Streams ); + WriteInt32( file, mainHeader->SuggestedBufferSize ); + WriteInt32( file, mainHeader->Width ); + WriteInt32( file, mainHeader->Height ); + WriteInt32( file, mainHeader->Reserved[0] ); + WriteInt32( file, mainHeader->Reserved[1] ); + WriteInt32( file, mainHeader->Reserved[2] ); + WriteInt32( file, mainHeader->Reserved[3] ); +} + +static void WriteStreamHeader( FILE * file, AviStreamHeader * streamHeader ) +{ + WriteInt32( file, streamHeader->FourCC ); + WriteInt32( file, streamHeader->BytesCount ); + WriteInt32( file, streamHeader->Type ); + WriteInt32( file, streamHeader->Handler ); + WriteInt32( file, streamHeader->Flags ); + WriteInt16( file, streamHeader->Priority ); + WriteInt16( file, streamHeader->Language ); + WriteInt32( file, streamHeader->InitialFrames ); + WriteInt32( file, streamHeader->Scale ); + WriteInt32( file, streamHeader->Rate ); + WriteInt32( file, streamHeader->Start ); + WriteInt32( file, streamHeader->Length ); + WriteInt32( file, streamHeader->SuggestedBufferSize ); + WriteInt32( file, streamHeader->Quality ); + WriteInt32( file, streamHeader->SampleSize ); + WriteInt16( file, streamHeader->Left ); + WriteInt16( file, streamHeader->Top ); + WriteInt16( file, streamHeader->Right ); + WriteInt16( file, streamHeader->Bottom ); +} + +static void IndexAddInt32( HBBuffer * b, uint32_t val ) +{ + if( b->size + 16 > b->alloc ) + { + HBLog( "HBAviMux: reallocing index (%d MB)", + 1 + b->alloc / 1024 / 1024 ); + HBBufferReAlloc( b, b->alloc + 1024 + 1024 ); + } + + b->data[b->size++] = val & 0xFF; + b->data[b->size++] = ( val >> 8 ) & 0xFF; + b->data[b->size++] = ( val >> 16 ) & 0xFF; + 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 new file mode 100644 index 000000000..1fccbe971 --- /dev/null +++ b/core/AviMux.h @@ -0,0 +1,15 @@ +/* $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/AviMuxer.cpp b/core/AviMuxer.cpp deleted file mode 100644 index 4a84fe8b8..000000000 --- a/core/AviMuxer.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/* $Id: AviMuxer.cpp,v 1.17 2003/10/09 23:33:36 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "AviMuxer.h" -#include "Manager.h" - -#define AVIF_HASINDEX 0x10 -#define AVIIF_KEYFRAME 0x10 - -#define FOURCC(a) ( ( a[3] << 24 ) | ( a[2] << 16 ) | ( a[1] << 8 ) | a[0] ) - -/* TODO : check return values from fputc/fwrite in case disk is full - or something */ - -void WriteInt8( FILE * file, uint8_t val ) -{ - fputc( val, file ); -} - -void WriteInt16( FILE * file, uint16_t val ) -{ - fputc( val & 0xFF, file ); - fputc( val >> 8, file ); -} - -void WriteInt32( FILE * file, uint32_t val ) -{ - fputc( val & 0xFF, file ); - fputc( ( val >> 8 ) & 0xFF, file ); - fputc( ( val >> 16 ) & 0xFF, file ); - fputc( val >> 24, file ); -} - -void WriteBuffer( FILE * file, HBBuffer * buffer ) -{ - fwrite( buffer->fData, buffer->fSize, 1, file ); -} - -void WriteBitmapInfo( FILE * file, BitmapInfo * bitmapInfo ) -{ - WriteInt32( file, bitmapInfo->FourCC ); - WriteInt32( file, bitmapInfo->BytesCount ); - WriteInt32( file, bitmapInfo->Size ); - WriteInt32( file, bitmapInfo->Width ); - WriteInt32( file, bitmapInfo->Height ); - WriteInt16( file, bitmapInfo->Planes ); - WriteInt16( file, bitmapInfo->BitCount ); - WriteInt32( file, bitmapInfo->Compression ); - WriteInt32( file, bitmapInfo->SizeImage ); - WriteInt32( file, bitmapInfo->XPelsPerMeter ); - WriteInt32( file, bitmapInfo->YPelsPerMeter ); - WriteInt32( file, bitmapInfo->ClrUsed ); - WriteInt32( file, bitmapInfo->ClrImportant ); - WriteInt8( file, bitmapInfo->Blue ); - WriteInt8( file, bitmapInfo->Green ); - WriteInt8( file, bitmapInfo->Red ); - WriteInt8( file, bitmapInfo->Reserved ); -} - -void WriteWaveFormatEx( FILE * file, WaveFormatEx * waveFormatEx ) -{ - WriteInt32( file, waveFormatEx->FourCC ); - WriteInt32( file, waveFormatEx->BytesCount ); - WriteInt16( file, waveFormatEx->FormatTag ); - WriteInt16( file, waveFormatEx->Channels ); - WriteInt32( file, waveFormatEx->SamplesPerSec ); - WriteInt32( file, waveFormatEx->AvgBytesPerSec ); - WriteInt16( file, waveFormatEx->BlockAlign ); - WriteInt16( file, waveFormatEx->BitsPerSample ); - WriteInt16( file, waveFormatEx->Size ); - WriteInt16( file, waveFormatEx->Id ); - WriteInt32( file, waveFormatEx->Flags ); - WriteInt16( file, waveFormatEx->BlockSize ); - WriteInt16( file, waveFormatEx->FramesPerBlock ); - WriteInt16( file, waveFormatEx->CodecDelay ); -} - -void WriteMainHeader( FILE * file, AviMainHeader * mainHeader ) -{ - WriteInt32( file, mainHeader->FourCC ); - WriteInt32( file, mainHeader->BytesCount ); - WriteInt32( file, mainHeader->MicroSecPerFrame ); - WriteInt32( file, mainHeader->MaxBytesPerSec ); - WriteInt32( file, mainHeader->PaddingGranularity ); - WriteInt32( file, mainHeader->Flags ); - WriteInt32( file, mainHeader->TotalFrames ); - WriteInt32( file, mainHeader->InitialFrames ); - WriteInt32( file, mainHeader->Streams ); - WriteInt32( file, mainHeader->SuggestedBufferSize ); - WriteInt32( file, mainHeader->Width ); - WriteInt32( file, mainHeader->Height ); - WriteInt32( file, mainHeader->Reserved[0] ); - WriteInt32( file, mainHeader->Reserved[1] ); - WriteInt32( file, mainHeader->Reserved[2] ); - WriteInt32( file, mainHeader->Reserved[3] ); -} - -void WriteStreamHeader( FILE * file, AviStreamHeader * streamHeader ) -{ - WriteInt32( file, streamHeader->FourCC ); - WriteInt32( file, streamHeader->BytesCount ); - WriteInt32( file, streamHeader->Type ); - WriteInt32( file, streamHeader->Handler ); - WriteInt32( file, streamHeader->Flags ); - WriteInt16( file, streamHeader->Priority ); - WriteInt16( file, streamHeader->Language ); - WriteInt32( file, streamHeader->InitialFrames ); - WriteInt32( file, streamHeader->Scale ); - WriteInt32( file, streamHeader->Rate ); - WriteInt32( file, streamHeader->Start ); - WriteInt32( file, streamHeader->Length ); - WriteInt32( file, streamHeader->SuggestedBufferSize ); - WriteInt32( file, streamHeader->Quality ); - WriteInt32( file, streamHeader->SampleSize ); - WriteInt16( file, streamHeader->Left ); - WriteInt16( file, streamHeader->Top ); - WriteInt16( file, streamHeader->Right ); - WriteInt16( file, streamHeader->Bottom ); -} - -HBAviIndex::HBAviIndex( uint32_t size ) - : HBBuffer( size ) -{ - fSize = 0; -} - -void HBAviIndex::WriteInt32( uint32_t val ) -{ - if( fSize + 16 > fAllocSize ) - { - /* Realloc if needed */ - Log( "HBAviIndex::WriteInt32() : reallocing index (%d -> %d MB)", - fAllocSize / ( 1024 * 1024 ), - 1 + fAllocSize / ( 1024 * 1024 ) ); - ReAlloc( fAllocSize + 1024 * 1024 ); - } - - fData[fSize] = val & 0xFF; - fData[fSize + 1] = ( val >> 8 ) & 0xFF; - fData[fSize + 2] = ( val >> 16 ) & 0xFF; - fData[fSize + 3] = val >> 24; - - fSize += 4; -} - -HBAviMuxer::HBAviMuxer( HBManager * manager, HBTitle * title, - HBAudio * audio1, HBAudio * audio2, - char * fileName ) - : HBThread( "avimuxer", HB_NORMAL_PRIORITY ) -{ - fManager = manager; - fTitle = title; - fAudio1 = audio1; - fAudio2 = audio2; - fFileName = strdup( fileName ); - - fVideoBuffer = NULL; - fAudio1Buffer = NULL; - fAudio2Buffer = NULL; - - fRiffBytesCount = 2040; - fMoviBytesCount = 4; - - Run(); -} - -void HBAviMuxer::DoWork() -{ - /* Open the destination file */ - if( !( fFile = fopen( fFileName, "w" ) ) ) - { - Log( "HBAviMuxer: fopen failed" ); - fManager->Error( HB_ERROR_AVI_WRITE ); - return; - } - - /* Initializations */ - memset( &fMainHeader, 0, sizeof( AviMainHeader ) ); - memset( &fVideoStreamHeader, 0, sizeof( AviStreamHeader ) ); - memset( &fAudio1StreamHeader, 0, sizeof( AviStreamHeader ) ); - memset( &fAudio2StreamHeader, 0, sizeof( AviStreamHeader ) ); - memset( &fVideoStreamFormat, 0, sizeof( BitmapInfo ) ); - memset( &fAudio1StreamFormat, 0, sizeof( WaveFormatEx ) ); - memset( &fAudio2StreamFormat, 0, sizeof( WaveFormatEx ) ); - - /* Alloc an 1 MB index (to be realloced later if needed) */ - fIndex = new HBAviIndex( 1024 * 1024 ); - - /* Main loop */ - for( ;; ) - { - while( fSuspend ) - { - Snooze( 10000 ); - } - - if( !fVideoBuffer ) - { - fVideoBuffer = Pop( fTitle->fMpeg4Fifo ); - } - if( fAudio1 && !fAudio1Buffer ) - { - fAudio1Buffer = Pop( fAudio1->fMp3Fifo ); - } - if( fAudio2 && !fAudio2Buffer ) - { - fAudio2Buffer = Pop( fAudio2->fMp3Fifo ); - } - - if( !fVideoBuffer && !fAudio1Buffer && !fAudio2Buffer ) - { - break; - } - - if( fVideoBuffer && - ( !fAudio1Buffer || - fVideoBuffer->fPosition < fAudio1Buffer->fPosition ) && - ( !fAudio2Buffer || - fVideoBuffer->fPosition < fAudio2Buffer->fPosition ) ) - { - AddVideoChunk(); - } - else if( fAudio1Buffer && - ( !fAudio2Buffer || - fAudio1Buffer->fPosition < fAudio2Buffer->fPosition ) ) - { - AddAudioChunk( 1 ); - } - else - { - AddAudioChunk( 2 ); - } - } - - /* Write the index */ - fseek( fFile, 0, SEEK_END ); - WriteInt32( fFile, FOURCC( "idx1" ) ); - WriteInt32( fFile, fIndex->fSize ); - WriteBuffer( fFile, fIndex ); - - /* Update the headers */ - fRiffBytesCount += 8 + fIndex->fSize; - fMainHeader.Flags |= AVIF_HASINDEX; - UpdateMainHeader(); - - delete fIndex; - - fclose( fFile ); -} - -bool HBAviMuxer::AddVideoChunk() -{ - fRiffBytesCount += 8 + EVEN( fVideoBuffer->fSize ); - fMoviBytesCount += 8 + EVEN( fVideoBuffer->fSize ); - - fMainHeader.MicroSecPerFrame = 1000000 * (uint64_t) fTitle->fScale / - fTitle->fRate; - fMainHeader.TotalFrames++; - fMainHeader.Width = fTitle->fOutWidth; - fMainHeader.Height = fTitle->fOutHeight; - - fVideoStreamHeader.FourCC = FOURCC( "strh" ); - fVideoStreamHeader.BytesCount = AVI_STREAM_HEADER_SIZE - 8; - fVideoStreamHeader.Type = FOURCC( "vids" ); - fVideoStreamHeader.Handler = FOURCC( "DIVX" ); - fVideoStreamHeader.Scale = fTitle->fScale; - fVideoStreamHeader.Rate = fTitle->fRate; - fVideoStreamHeader.Length++; - - fVideoStreamFormat.FourCC = FOURCC( "strf" ); - fVideoStreamFormat.BytesCount = BITMAP_INFO_SIZE - 8; - fVideoStreamFormat.Size = BITMAP_INFO_SIZE - 8; - fVideoStreamFormat.Width = fTitle->fOutWidth; - fVideoStreamFormat.Height = fTitle->fOutHeight; - fVideoStreamFormat.Planes = 1; - fVideoStreamFormat.BitCount = 24; - fVideoStreamFormat.Compression = FOURCC( "DIVX" );; - - UpdateMainHeader(); - - fseek( fFile, 0, SEEK_END ); - - /* Update the index */ - fIndex->WriteInt32( FOURCC( "00dc" ) ); - fIndex->WriteInt32( fVideoBuffer->fKeyFrame ? AVIIF_KEYFRAME : 0 ); - fIndex->WriteInt32( ftell( fFile ) - 2044 ); - fIndex->WriteInt32( fVideoBuffer->fSize ); - - /* Write the chunk */ - WriteInt32( fFile, FOURCC( "00dc" ) ); - WriteInt32( fFile, fVideoBuffer->fSize ); - WriteBuffer( fFile, fVideoBuffer ); - - /* Chunks must be 2-bytes aligned */ - if( fVideoBuffer->fSize & 1 ) - { - WriteInt8( fFile, 0 ); - } - - delete fVideoBuffer; - fVideoBuffer = NULL; - - return true; -} - -bool HBAviMuxer::AddAudioChunk( int track ) -{ - HBAudio * info; - HBBuffer * buffer; - AviStreamHeader * streamHeader; - WaveFormatEx * streamFormat; - - if( track == 1 ) - { - info = fAudio1; - buffer = fAudio1Buffer; - streamHeader = &fAudio1StreamHeader; - streamFormat = &fAudio1StreamFormat; - } - else - { - info = fAudio2; - buffer = fAudio2Buffer; - streamHeader = &fAudio2StreamHeader; - streamFormat = &fAudio2StreamFormat; - } - - fRiffBytesCount += 8 + EVEN( buffer->fSize ); - fMoviBytesCount += 8 + EVEN( buffer->fSize ); - - streamHeader->FourCC = FOURCC( "strh" ); - streamHeader->BytesCount = AVI_STREAM_HEADER_SIZE - 8; - streamHeader->Type = FOURCC( "auds" ); - streamHeader->InitialFrames = 1; - streamHeader->Scale = 1152; - streamHeader->Rate = info->fOutSampleRate; - streamHeader->Length++; - streamHeader->Quality = 0xFFFFFFFF; - - - streamFormat->FourCC = FOURCC( "strf" ); - streamFormat->BytesCount = WAVE_FORMAT_EX_SIZE - 8; - streamFormat->FormatTag = 0x55; - streamFormat->Channels = 2; - streamFormat->SamplesPerSec = info->fOutSampleRate; - streamFormat->AvgBytesPerSec = info->fOutBitrate * 1024 / 8; - streamFormat->BlockAlign = 1152; - - /* stolen from libavformat/wav.c */ - streamFormat->Size = 12; - streamFormat->Id = 1; - streamFormat->Flags = 2; - streamFormat->BlockSize = 1152; - streamFormat->FramesPerBlock = 1; - streamFormat->CodecDelay = 1393; - - UpdateMainHeader(); - - fseek( fFile, 0, SEEK_END ); - - /* Update the index */ - if( track == 1 ) - { - fIndex->WriteInt32( FOURCC( "01wb" ) ); - } - else - { - fIndex->WriteInt32( FOURCC( "02wb" ) ); - } - fIndex->WriteInt32( buffer->fKeyFrame ? AVIIF_KEYFRAME : 0 ); - fIndex->WriteInt32( ftell( fFile ) - 2044 ); - fIndex->WriteInt32( buffer->fSize ); - - /* Write the chunk */ - WriteInt32( fFile, - ( track == 1 ) ? FOURCC( "01wb" ) : FOURCC( "02wb" ) ); - WriteInt32( fFile, buffer->fSize ); - WriteBuffer( fFile, buffer ); - - /* Chunks must be 2-bytes aligned */ - if( buffer->fSize & 1 ) - { - WriteInt8( fFile, 0 ); - } - - delete buffer; - if( track == 1 ) - { - fAudio1Buffer = NULL; - } - else - { - fAudio2Buffer = NULL; - } - - return true; -} - -void HBAviMuxer::UpdateMainHeader() -{ - fMainHeader.FourCC = FOURCC( "avih" ); - fMainHeader.BytesCount = AVI_MAIN_HEADER_SIZE - 8; - fMainHeader.Streams = 1 + ( fAudio1 ? 1 : 0 ) + - ( fAudio2 ? 1 : 0 ); - - fHdrlBytesCount = 4 + AVI_MAIN_HEADER_SIZE + 12 + - AVI_STREAM_HEADER_SIZE + BITMAP_INFO_SIZE; - - if( fAudio1 ) - { - fHdrlBytesCount += 12 + AVI_STREAM_HEADER_SIZE + - WAVE_FORMAT_EX_SIZE; - } - if( fAudio2 ) - { - fHdrlBytesCount += 12 + AVI_STREAM_HEADER_SIZE + - WAVE_FORMAT_EX_SIZE; - } - - fseek( fFile, 0, SEEK_SET ); - WriteInt32( fFile, FOURCC( "RIFF" ) ); - WriteInt32( fFile, fRiffBytesCount ); - WriteInt32( fFile, FOURCC( "AVI " ) ); - WriteInt32( fFile, FOURCC( "LIST" ) ); - WriteInt32( fFile, fHdrlBytesCount ); - WriteInt32( fFile, FOURCC( "hdrl" ) ); - - WriteMainHeader( fFile, &fMainHeader ); - - int strlSize; - strlSize = 4 + AVI_STREAM_HEADER_SIZE + BITMAP_INFO_SIZE; - WriteInt32( fFile, FOURCC( "LIST" ) ); - WriteInt32( fFile, strlSize ); - WriteInt32( fFile, FOURCC( "strl" ) ); - - WriteStreamHeader( fFile, &fVideoStreamHeader ); - WriteBitmapInfo( fFile, &fVideoStreamFormat ); - - if( fAudio1 ) - { - strlSize = 4 + AVI_STREAM_HEADER_SIZE + WAVE_FORMAT_EX_SIZE; - WriteInt32( fFile, FOURCC( "LIST" ) ); - WriteInt32( fFile, strlSize ); - WriteInt32( fFile, FOURCC( "strl" ) ); - WriteStreamHeader( fFile, &fAudio1StreamHeader ); - WriteWaveFormatEx( fFile, &fAudio1StreamFormat ); - } - - if( fAudio2 ) - { - strlSize = 4 + AVI_STREAM_HEADER_SIZE + WAVE_FORMAT_EX_SIZE; - WriteInt32( fFile, FOURCC( "LIST" ) ); - WriteInt32( fFile, strlSize ); - WriteInt32( fFile, FOURCC( "strl" ) ); - WriteStreamHeader( fFile, &fAudio2StreamHeader ); - WriteWaveFormatEx( fFile, &fAudio2StreamFormat ); - } - - /* a JUNK chunk to fill the free space. - size = 2048 -/ - 12 ("RIFFxxxxAVI ") - - 8 (hdrl's "LIS1Txxxx") - - fHdrlBytesCount - - 8 ("JUNKxxxx") - - 12 ("LISTxxxxmovi) */ - int junkSize = 2008 - fHdrlBytesCount; - WriteInt32( fFile, FOURCC( "JUNK" ) ); - WriteInt32( fFile, junkSize ); - for( uint32_t i = 0; i < 2008 - fHdrlBytesCount; i++ ) - { - WriteInt8( fFile, 0 ); - } - - /* movi list */ - WriteInt32( fFile, FOURCC( "LIST" ) ); - WriteInt32( fFile, fMoviBytesCount ); - WriteInt32( fFile, FOURCC( "movi" ) ); -} diff --git a/core/AviMuxer.h b/core/AviMuxer.h deleted file mode 100644 index 842f7a87a..000000000 --- a/core/AviMuxer.h +++ /dev/null @@ -1,153 +0,0 @@ -/* $Id: AviMuxer.h,v 1.10 2003/09/30 14:38:15 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_AVI_MUXER_H -#define HB_AVI_MUXER_H - -#include "Common.h" -#include "Fifo.h" -#include "Thread.h" - -/* Misc structures used in AVI headers */ -#define BITMAP_INFO_SIZE 52 -typedef struct BitmapInfo -{ - uint32_t FourCC; - uint32_t BytesCount; - uint32_t Size; - uint32_t Width; - uint32_t Height; - uint16_t Planes; - uint16_t BitCount; - uint32_t Compression; - uint32_t SizeImage; - uint32_t XPelsPerMeter; - uint32_t YPelsPerMeter; - uint32_t ClrUsed; - uint32_t ClrImportant; - uint8_t Blue; - uint8_t Green; - uint8_t Red; - uint8_t Reserved; -} BitmapInfo; - -#define WAVE_FORMAT_EX_SIZE 38 -typedef struct WaveFormatEx -{ - uint32_t FourCC; - uint32_t BytesCount; - uint16_t FormatTag; - uint16_t Channels; - uint32_t SamplesPerSec; - uint32_t AvgBytesPerSec; - uint16_t BlockAlign; - uint16_t BitsPerSample; - uint16_t Size; - - /* mp3 specific */ - uint16_t Id; - uint32_t Flags; - uint16_t BlockSize; - uint16_t FramesPerBlock; - uint16_t CodecDelay; -} WaveFormatEx; - -#define AVI_STREAM_HEADER_SIZE 64 -typedef struct AviStreamHeader -{ - uint32_t FourCC; - uint32_t BytesCount; - uint32_t Type; - uint32_t Handler; - uint32_t Flags; - uint16_t Priority; - uint16_t Language; - uint32_t InitialFrames; - uint32_t Scale; - uint32_t Rate; - uint32_t Start; - uint32_t Length; - uint32_t SuggestedBufferSize; - uint32_t Quality; - uint32_t SampleSize; - int16_t Left; - int16_t Top; - int16_t Right; - int16_t Bottom; -} AviStreamHeader; - -#define AVI_MAIN_HEADER_SIZE 64 -typedef struct AviMainHeader -{ - uint32_t FourCC; - uint32_t BytesCount; - uint32_t MicroSecPerFrame; - uint32_t MaxBytesPerSec; - uint32_t PaddingGranularity; - uint32_t Flags; - uint32_t TotalFrames; - uint32_t InitialFrames; - uint32_t Streams; - uint32_t SuggestedBufferSize; - uint32_t Width; - uint32_t Height; - uint32_t Reserved[4]; -} AviMainHeader; - -class HBAviIndex : public HBBuffer -{ - public: - HBAviIndex( uint32_t size ); - void WriteInt32( uint32_t val ); -}; - -class HBAviMuxer : public HBThread -{ - public: - HBAviMuxer( HBManager * manager, - HBTitle * title, HBAudio * audio1, - HBAudio * audio2, - char * fileName ); - - private: - void DoWork(); - bool AddVideoChunk(); - bool AddAudioChunk( int track ); - void UpdateMainHeader(); - - HBManager * fManager; - HBTitle * fTitle; - HBAudio * fAudio1; - HBAudio * fAudio2; - char * fFileName; - - FILE * fFile; - HBBuffer * fVideoBuffer; - HBBuffer * fAudio1Buffer; - HBBuffer * fAudio2Buffer; - - /* The main header */ - AviMainHeader fMainHeader; - - /* The video track */ - AviStreamHeader fVideoStreamHeader; - BitmapInfo fVideoStreamFormat; - - /* The audio tracks */ - AviStreamHeader fAudio1StreamHeader; - WaveFormatEx fAudio1StreamFormat; - AviStreamHeader fAudio2StreamHeader; - WaveFormatEx fAudio2StreamFormat; - - uint32_t fRiffBytesCount; - uint32_t fHdrlBytesCount; - uint32_t fMoviBytesCount; - - HBAviIndex * fIndex; - -}; - -#endif diff --git a/core/Common.cpp b/core/Common.cpp deleted file mode 100644 index 4087a001d..000000000 --- a/core/Common.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* $Id: Common.cpp,v 1.31 2003/10/07 22:48:31 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#if defined( SYS_BEOS ) -# include <OS.h> -#endif - -#include "Common.h" -#include "Fifo.h" -#include "MpegDemux.h" -#include "Languages.h" - -#include <stdarg.h> -#include <time.h> -#include <sys/time.h> -#include <dvdread/ifo_types.h> -#include <dvdplay/dvdplay.h> -#include <dvdplay/info.h> -#include <dvdplay/state.h> -#include <dvdplay/nav.h> - -extern "C" { -#include <mpeg2dec/mpeg2.h> -} - -void Snooze( uint64_t time ) -{ -#if defined( SYS_BEOS ) - snooze( time ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - usleep( time ); -#endif -} - -void Log( char * log, ... ) -{ - if( !getenv( "HB_DEBUG" ) ) - { - return; - } - - char string[1024]; - - /* Show the time */ - time_t _now = time( NULL ); - struct tm * now = localtime( &_now ); - sprintf( string, "[%02d:%02d:%02d] ", - now->tm_hour, now->tm_min, now->tm_sec ); - - /* Convert the message to a string */ - va_list args; - va_start( args, log ); - int ret = vsnprintf( string + 11, 1011, log, args ); - va_end( args ); - - /* Add the end of line */ - string[ret+11] = '\n'; - string[ret+12] = '\0'; - - /* Print it */ - fprintf( stderr, "%s", string ); -} - -char * LanguageForCode( int code ) -{ - char codeString[2]; - codeString[0] = ( code >> 8 ) & 0xFF; - codeString[1] = code & 0xFF; - - iso639_lang_t * lang; - for( lang = languages; lang->engName; lang++ ) - { - if( !strncmp( lang->iso639_1, codeString, 2 ) ) - { - if( *lang->nativeName ) - return lang->nativeName; - - return lang->engName; - } - } - - return "Unknown"; -} - -uint64_t GetDate() -{ - struct timeval tv; - gettimeofday( &tv, NULL ); - return( (uint64_t) tv.tv_sec * 1000000 + (uint64_t) tv.tv_usec ); -} - -int GetCPUCount() -{ - int CPUCount = 1; - -#if defined( SYS_BEOS ) - system_info info; - get_system_info( &info ); - CPUCount = info.cpu_count; - -#elif defined( SYS_MACOSX ) - FILE * info; - char buffer[256]; - - if( ( info = popen( "/usr/sbin/sysctl hw.ncpu", "r" ) ) ) - { - if( fgets( buffer, 256, info ) ) - { - int count; - if( sscanf( buffer, "hw.ncpu: %d", &count ) == 1 ) - { - CPUCount = count; - } - else - { - Log( "GetCPUCount: sscanf() failed" ); - } - } - else - { - Log( "GetCPUCount: fgets() failed" ); - } - fclose( info ); - } - else - { - Log( "GetCPUCount: popen() failed" ); - } - -#elif defined( SYS_LINUX ) - FILE * info; - char buffer[256]; - - if( ( info = fopen( "/proc/cpuinfo", "r" ) ) ) - { - int count = 0; - while( fgets( buffer, 256, info ) ) - { - if( !memcmp( buffer, "processor", - sizeof( "processor" ) - 1 ) ) - { - count++; - } - } - CPUCount = count; - fclose( info ); - } - else - { - Log( "GetCPUCount: fopen() failed" ); - } - -#endif - CPUCount = MAX( 1, CPUCount ); - CPUCount = MIN( CPUCount, 8 ); - - return CPUCount; -} - -#define HBLIST_DEFAULT_SIZE 20 - -HBList::HBList() -{ - fItems = (void**) malloc( HBLIST_DEFAULT_SIZE * sizeof( void* ) ); - fAllocItems = HBLIST_DEFAULT_SIZE; - fNbItems = 0; -} - -HBList::~HBList() -{ - free( fItems ); -} - -uint32_t HBList::CountItems() -{ - return fNbItems; -} - -void HBList::AddItem( void * item ) -{ - if( !item ) - { - return; - } - - if( fNbItems == fAllocItems ) - { - fAllocItems += HBLIST_DEFAULT_SIZE; - fItems = (void**) realloc( fItems, fAllocItems * sizeof( void* ) ); - } - - fItems[fNbItems] = item; - - fNbItems++; -} - -void HBList::RemoveItem( void * item ) -{ - if( !item || !fNbItems ) - { - return; - } - - uint32_t i; - for( i = 0; i < fNbItems; i++ ) - { - if( fItems[i] == item ) - { - break; - } - } - - if( fItems[i] != item ) - { - Log( "HBList::RemoveItem() : item not in the list" ); - return; - } - - for( ; i < fNbItems - 1; i++ ) - { - fItems[i] = fItems[i+1]; - } - - fNbItems--; -} - -void * HBList::ItemAt( uint32_t index ) -{ - if( index < fNbItems ) - { - return fItems[index]; - } - - return NULL; -} - -HBTitle::HBTitle( char * device, int index ) -{ - fDevice = strdup( device ); - fIndex = index; - - fAudioList = new HBList(); - fPSFifo = NULL; - fMpeg2Fifo = NULL; - fRawFifo = NULL; - fMpeg4Fifo = NULL; - - fTopCrop = 0; - fBottomCrop = 0; - fLeftCrop = 0; - fRightCrop = 0; - fBitrate = 1024; - fDeinterlace = false; - fTwoPass = false; -} - -HBTitle::~HBTitle() -{ - HBAudio * audio; - - while( ( audio = (HBAudio*) fAudioList->ItemAt( 0 ) ) ) - { - fAudioList->RemoveItem( audio ); - delete audio; - } - delete fAudioList; -} - -/* Audio track */ -HBAudio::HBAudio( int id, char * description ) -{ - fId = id; - fDescription = strdup( description ); - fOutSampleRate = 44100; - fOutBitrate = 128; - - fAc3Fifo = NULL; - fRawFifo = NULL; - fMp3Fifo = NULL; -} - -HBAudio::~HBAudio() -{ - free( fDescription ); -} diff --git a/core/Common.h b/core/Common.h deleted file mode 100644 index 3c138e2a1..000000000 --- a/core/Common.h +++ /dev/null @@ -1,215 +0,0 @@ -/* $Id: Common.h,v 1.34 2003/10/13 17:49:58 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_COMMON_H -#define HB_COMMON_H - -/* Standard headers */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <inttypes.h> -typedef uint8_t byte_t; - -/* Misc structures */ -typedef struct a52_state_s a52_state_t; -typedef struct lame_global_struct lame_global_flags; -typedef struct dvdplay_s * dvdplay_ptr; -typedef struct mpeg2dec_s mpeg2dec_t; -typedef struct AVPicture AVPicture; -typedef struct AVFrame AVFrame; -typedef struct AVCodecContext AVCodecContext; -typedef struct ImgReSampleContext ImgReSampleContext; - -/* Classes */ -class HBAc3Decoder; -class HBAudio; -class HBAviIndex; -class HBAviMuxer; -class HBBuffer; -class HBDVDReader; -class HBFifo; -class HBList; -class HBLock; -class HBManager; -class HBMp3Encoder; -class HBMpeg2Decoder; -class HBMpeg4Encoder; -class HBMpegDemux; -class HBResizer; -class HBScanner; -class HBStatus; -class HBThread; -class HBTitle; -class HBWorker; - -/* Handy macros */ -#ifndef MIN -# define MIN( a, b ) ( ( (a) > (b) ) ? (b) : (a) ) -#endif -#ifndef MAX -# define MAX( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) -#endif -#define EVEN( a ) ( ( (a) & 0x1 ) ? ( (a) + 1 ) : (a) ) -#define MULTIPLE_16( a ) ( 16 * ( ( (a) + 8 ) / 16 ) ) - -#define VOUT_ASPECT_FACTOR 432000 - -/* Global prototypes */ -void Snooze( uint64_t time ); -void Log( char * log, ... ); -char * LanguageForCode( int code ); -uint64_t GetDate(); -int GetCPUCount(); - -/* Possible states */ -typedef enum -{ - HB_MODE_UNDEF = 00000, - HB_MODE_NEED_VOLUME = 00001, - HB_MODE_SCANNING = 00002, - HB_MODE_INVALID_VOLUME = 00004, - HB_MODE_READY_TO_RIP = 00010, - HB_MODE_ENCODING = 00020, - HB_MODE_SUSPENDED = 00040, - HB_MODE_STOPPING = 00100, - HB_MODE_DONE = 00200, - HB_MODE_CANCELED = 00400, - HB_MODE_ERROR = 01000 -} 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; - -class HBStatus -{ - public: - HBMode fMode; - - /* HB_MODE_SCANNING */ - char * fScannedVolume; - int fScannedTitle; - - /* HB_MODE_SCANDONE */ - HBList * fTitleList; - - /* HB_MODE_ENCODING || HB_MODE_SUSPENDED */ - float fPosition; - float fFrameRate; - uint32_t fFrames; - uint64_t fStartDate; - uint32_t fRemainingTime; /* in seconds */ - uint64_t fSuspendDate; - - /* HB_MODE_ERROR */ - HBError fError; -}; - -class HBList -{ - public: - HBList(); - ~HBList(); - uint32_t CountItems(); - void AddItem( void * item ); - void RemoveItem( void * item ); - void * ItemAt( uint32_t index ); - - private: - void ** fItems; - uint32_t fAllocItems; - uint32_t fNbItems; -}; - -class HBAudio -{ - public: - HBAudio( int id, char * description ); - ~HBAudio(); - - /* Ident */ - uint32_t fId; - char * fDescription; - - /* Settings */ - int fInSampleRate; - int fOutSampleRate; - int fInBitrate; - int fOutBitrate; - - int64_t fDelay; /* in ms */ - - /* Fifos */ - HBFifo * fAc3Fifo; - HBFifo * fRawFifo; - HBFifo * fMp3Fifo; - - /* Threads */ - HBAc3Decoder * fAc3Decoder; - HBMp3Encoder * fMp3Encoder; -}; - -class HBTitle -{ - public: - HBTitle( char * device, int index ); - ~HBTitle(); - - char * fDevice; - int fIndex; - uint64_t fLength; - - /* Video input */ - uint32_t fInWidth; - uint32_t fInHeight; - uint32_t fAspect; - uint32_t fRate; - uint32_t fScale; - - /* Video output */ - bool fDeinterlace; - uint32_t fOutWidth; - uint32_t fOutHeight; - uint32_t fOutWidthMax; - uint32_t fOutHeightMax; - uint32_t fTopCrop; - uint32_t fBottomCrop; - uint32_t fLeftCrop; - uint32_t fRightCrop; - uint32_t fBitrate; - bool fTwoPass; - - /* Audio infos */ - HBList * fAudioList; - - /* Fifos */ - HBFifo * fPSFifo; - HBFifo * fMpeg2Fifo; - HBFifo * fRawFifo; - HBFifo * fResizedFifo; - HBFifo * fMpeg4Fifo; - - /* Threads */ - HBDVDReader * fDVDReader; - HBMpegDemux * fMpegDemux; - HBMpeg2Decoder * fMpeg2Decoder; - HBResizer * fResizer; - HBMpeg4Encoder * fMpeg4Encoder; - HBAviMuxer * fAviMuxer; - HBWorker * fWorkers[4]; -}; - -#endif diff --git a/core/DVDRead.c b/core/DVDRead.c new file mode 100644 index 000000000..58e8f1031 --- /dev/null +++ b/core/DVDRead.c @@ -0,0 +1,328 @@ +/* $Id: DVDRead.c,v 1.4 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. */ + +#include "DVDRead.h" +#include "Fifo.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> + +/* Local prototypes */ +static void DVDReadThread( void * ); +static int DoPass( HBDVDRead * ); +static int Demux( HBDVDRead * ); +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; +}; + +HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * t, + HBAudio * a1, HBAudio * a2 ) +{ + HBDVDRead * d; + if( !( d = malloc( sizeof( HBDVDRead ) ) ) ) + { + HBLog( "HBDVDReadInit: malloc() failed, gonna crash" ); + return NULL; + } + + /* Initializations */ + d->handle = handle; + d->vmg = NULL; + d->title = t; + d->audio = a1; + d->optAudio = a2; + 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; + d->thread = HBThreadInit( "dvd reader", DVDReadThread, d, + HB_NORMAL_PRIORITY ); + + return d; +} + +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 ) ) ) + { + HBListRemove( d->esBufferList, buffer ); + HBBufferClose( &buffer ); + } + HBListClose( &d->esBufferList ) ; + free( d ); + + (*_d) = NULL; +} + +static void DVDReadThread( void * _d ) +{ + HBDVDRead * d = (HBDVDRead*) _d; + uint8_t dummy[DVD_VIDEO_LB_LEN]; + int i; + + /* Open the device */ + d->vmg = dvdplay_open( d->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 ); + 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++ ) + { + 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; + + 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 ); + } + } + + /* Clean up */ + dvdplay_close( d->vmg ); +} + + +static int DoPass( HBDVDRead * d ) +{ + int i; + + for( i = 0; i < d->endPosition - d->beginPosition; i++ ) + { + 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 ); + return 0; + } + + if( !Demux( d ) ) + { + return 0; + } + } + + return 1; +} + +static int Demux( HBDVDRead * d ) +{ + HBBuffer * esBuffer; + + /* Demux */ + HBPStoES( &d->psBuffer, d->esBufferList ); + + /* Push buffers */ + while( ( esBuffer = (HBBuffer*) HBListItemAt( d->esBufferList, 0 ) ) ) + { + /* First pass: trash audio buffers */ + if( d->pass == 1 && esBuffer->streamId != 0xE0 ) + { + HBListRemove( d->esBufferList, esBuffer ); + HBBufferClose( &esBuffer ); + continue; + } + + if( esBuffer->streamId == 0xE0 ) + { + if( d->videoStart < 0 ) + { + d->videoStart = esBuffer->pts / 90; + HBLog( "HBDVDRead: got first 0xE0 packet (%d)", + d->videoStart ); + } + + if( d->videoBuf ) + { + d->videoBuf->last = 0; + if( !Push( d, d->title->mpeg2Fifo, &d->videoBuf ) ) + { + return 0; + } + } + + HBListRemove( d->esBufferList, esBuffer ); + d->videoBuf = esBuffer; + } + 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; + } + + if( d->audioBuf ) + { + d->audioBuf->last = 0; + if( !Push( d, d->audio->ac3Fifo, &d->audioBuf ) ) + { + return 0; + } + } + + HBListRemove( d->esBufferList, esBuffer ); + d->audioBuf = esBuffer; + } + else if( d->optAudio && esBuffer->streamId == d->optAudio->id ) + { + if( d->optAudioStart < 0 ) + { + d->optAudioStart = esBuffer->pts / 90; + HBLog( "HBDVDRead: got first 0x%x packet (%d)", + d->optAudio->id, d->optAudioStart ); + + d->optAudio->delay = d->optAudioStart - d->videoStart; + } + + if( d->optAudioBuf ) + { + d->optAudioBuf->last = 0; + if( !Push( d, d->optAudio->ac3Fifo, &d->optAudioBuf ) ) + { + return 0; + } + } + + HBListRemove( d->esBufferList, esBuffer ); + d->optAudioBuf = esBuffer; + } + else + { + HBListRemove( d->esBufferList, esBuffer ); + HBBufferClose( &esBuffer ); + } + } + + return 1; +} + +static int Push( HBDVDRead * d, HBFifo * fifo, HBBuffer ** buffer ) +{ + for( ;; ) + { + HBCheckPaused( d->handle ); + + if( HBFifoPush( fifo, buffer ) ) + { + return 1; + } + + if( d->die ) + { + break; + } + + HBSnooze( 10000 ); + } + + return 0; +} + diff --git a/core/DVDRead.h b/core/DVDRead.h new file mode 100644 index 000000000..7a9aa7e21 --- /dev/null +++ b/core/DVDRead.h @@ -0,0 +1,16 @@ +/* $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/DVDReader.cpp b/core/DVDReader.cpp deleted file mode 100644 index c3c0e6f3e..000000000 --- a/core/DVDReader.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* $Id: DVDReader.cpp,v 1.18 2003/10/16 13:39:13 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "DVDReader.h" -#include "Manager.h" -#include "Fifo.h" - -#include <dvdread/ifo_types.h> -#include <dvdplay/dvdplay.h> -#include <dvdplay/info.h> -#include <dvdplay/state.h> -#include <dvdplay/nav.h> - -HBDVDReader::HBDVDReader( HBManager * manager, HBTitle * title ) - : HBThread( "dvdreader", HB_NORMAL_PRIORITY ) -{ - fManager = manager; - fTitle = title; - - Run(); -} - -void HBDVDReader::DoWork() -{ - /* Open the device */ - dvdplay_ptr vmg; - vmg = dvdplay_open( fTitle->fDevice, NULL, NULL ); - if( !vmg ) - { - Log( "HBDVDReader: dvdplay_open() failed" ); - fManager->Error( HB_ERROR_DVD_OPEN ); - return; - } - - bool die = false; - for( int i = 0; i < ( fTitle->fTwoPass ? 2 : 1 ); i++ ) - { - /* Open the title */ - dvdplay_start( vmg, fTitle->fIndex ); - - /* Read */ - HBBuffer * dvdBuffer; - int beginPosition = dvdplay_position( vmg ); - int endPosition = dvdplay_title_end( vmg ); - - while( dvdplay_position( vmg ) < endPosition ) - { - while( fSuspend ) - { - Snooze( 10000 ); - } - - dvdBuffer = new HBBuffer( DVD_VIDEO_LB_LEN ); - dvdBuffer->fPosition = (float) ( dvdplay_position( vmg ) - - beginPosition ) / - (float) ( endPosition - beginPosition ) ; - if( fTitle->fTwoPass ) - { - dvdBuffer->fPosition /= 2; - if( i == 1 ) - { - dvdBuffer->fPosition += 0.5; - } - } - dvdBuffer->fPass = fTitle->fTwoPass ? ( i + 1 ) : 0; - - if( dvdplay_read( vmg, dvdBuffer->fData, 1 ) < 0 ) - { - Log( "HBDVDReader: dvdplay_read() failed" ); - delete dvdBuffer; - fManager->Error( HB_ERROR_DVD_READ ); - die = true; - break; - } - - if( !Push( fTitle->fPSFifo, dvdBuffer ) ) - { - die = true; - break; - } - } - - if( die ) - { - break; - } - } - - if( !die ) - { - fManager->Done(); - } - - /* Clean up */ - dvdplay_close( vmg ); -} diff --git a/core/DVDReader.h b/core/DVDReader.h deleted file mode 100644 index b76f57566..000000000 --- a/core/DVDReader.h +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: DVDReader.h,v 1.5 2003/09/30 14:38:15 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_DVD_READER_H -#define HB_DVD_READER_H - -#include "Common.h" -#include "Thread.h" - -class HBDVDReader : public HBThread -{ - public: - HBDVDReader( HBManager * manager, HBTitle * title ); - - private: - void DoWork(); - - HBManager * fManager; - HBTitle * fTitle; -}; - -#endif diff --git a/core/FfmpegEnc.c b/core/FfmpegEnc.c new file mode 100644 index 000000000..2118c29d6 --- /dev/null +++ b/core/FfmpegEnc.c @@ -0,0 +1,230 @@ +/* $Id: FfmpegEnc.c,v 1.5 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. */ + +#include "FfmpegEnc.h" +#include "Fifo.h" +#include "Work.h" + +#include <ffmpeg/avcodec.h> + +/* Extern functions */ +void HBSetPosition( HBHandle *, float ); + +/* Local prototypes */ +static int FfmpegEncWork( HBWork * ); + +struct HBFfmpegEnc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBTitle * title; + + HBBuffer * mpeg4Buffer; + int pass; + AVCodecContext * context; + FILE * file; +}; + +HBFfmpegEnc * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) +{ + HBFfmpegEnc * f; + if( !( f = malloc( sizeof( HBFfmpegEnc ) ) ) ) + { + HBLog( "HBFfmpegEncInit: malloc() failed, gonna crash" ); + return NULL; + } + + f->name = strdup( "FfmpegEnc" ); + f->work = FfmpegEncWork; + + f->handle = handle; + f->title = title; + + f->mpeg4Buffer = NULL; + f->pass = 42; + f->context = NULL; + f->file = NULL; + + return f; +} + +void HBFfmpegEncClose( HBFfmpegEnc ** _f ) +{ + HBFfmpegEnc * f = *_f; + + if( f->context ) + { + HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", + f->pass ); + + avcodec_close( f->context ); + if( f->file ) + { + fclose( f->file ); + f->file = NULL; + } + } + free( f->name ); + free( f ); + + *_f = NULL; +} + +static int FfmpegEncWork( HBWork * w ) +{ + HBFfmpegEnc * f = (HBFfmpegEnc*) w; + HBTitle * title = f->title; + + HBBuffer * scaledBuffer; + HBBuffer * mpeg4Buffer; + AVFrame * frame; + + int didSomething = 0; + + if( f->mpeg4Buffer ) + { + if( HBFifoPush( title->mpeg4Fifo, &f->mpeg4Buffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + if( ( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + /* 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; + } + } + + f->pass = scaledBuffer->pass; + + 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 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->linesize[0] = title->outWidth; + frame->linesize[1] = title->outWidth / 2; + frame->linesize[2] = title->outWidth / 2; + + 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->keyFrame = f->context->coded_frame->key_frame; + + /* Inform the GUI about the current position */ + HBPosition( f->handle, scaledBuffer->position ); + + if( f->pass == 1 ) + { + if( f->context->stats_out ) + { + fprintf( f->file, "%s", f->context->stats_out ); + } + HBBufferClose( &mpeg4Buffer ); + } + + HBBufferClose( &scaledBuffer ); + free( frame ); + + f->mpeg4Buffer = mpeg4Buffer; + + return didSomething; +} diff --git a/core/FfmpegEnc.h b/core/FfmpegEnc.h new file mode 100644 index 000000000..8ab622011 --- /dev/null +++ b/core/FfmpegEnc.h @@ -0,0 +1,15 @@ +/* $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 new file mode 100644 index 000000000..a8f6034c0 --- /dev/null +++ b/core/Fifo.c @@ -0,0 +1,105 @@ +/* $Id: Fifo.c,v 1.2 2003/11/05 19:14:37 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" + +HBBuffer * HBBufferInit( int size ) +{ + HBBuffer * b; + if( !( b = malloc( sizeof( HBBuffer ) ) ) ) + { + HBLog( "HBBufferInit: malloc() failed, gonna crash" ); + return NULL; + } + + b->alloc = size; + b->size = size; + + if( !( b->data = malloc( size ) ) ) + { + HBLog( "HBBufferInit: malloc() failed, gonna crash" ); + free( b ); + return NULL; + } + + b->position = 0.0; + b->streamId = 0; + b->keyFrame = 0; + b->pts = 0; + b->pass = 0; + b->last = 0; + + return b; +} + +void HBBufferReAlloc( HBBuffer * b, int size ) +{ + b->alloc = size; + b->data = realloc( b->data, size ); + + if( !b->data ) + { + HBLog( "HBBufferReAlloc: realloc() failed, gonna crash soon" ); + } +} + +void HBBufferClose( HBBuffer ** b ) +{ + free( (*b)->data ); + (*b) = NULL; +} + +HBFifo * HBFifoInit( int capacity ) +{ + HBFifo * f; + if( !( f = malloc( sizeof( HBFifo ) ) ) ) + { + HBLog( "HBFifoInit: malloc() failed, gonna crash" ); + return NULL; + } + + f->capacity = capacity; + f->whereToPush = 0; + f->whereToPop = 0; + + if( !( f->buffers = malloc( ( capacity + 1 ) * sizeof( void* ) ) ) ) + { + HBLog( "HBFifoInit: malloc() failed, gonna crash" ); + free( f ); + return NULL; + } + + f->lock = HBLockInit(); + + return f; +} + +int HBFifoSize( HBFifo * f ) +{ + return ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % + ( f->capacity + 1 ); +} + +void HBFifoClose( HBFifo ** _f ) +{ + HBFifo * f = (*_f); + + HBLog( "HBFifoClose: trashing %d buffer%s", + HBFifoSize( f ), ( HBFifoSize( f ) > 1 ) ? "s" : "" ); + + while( f->whereToPush != f->whereToPop ) + { + HBBufferClose( &(f->buffers[f->whereToPop]) ); + f->whereToPop++; + f->whereToPop %= ( f->capacity + 1 ); + } + + HBLockClose( &f->lock ); + free( f->buffers ); + free( f ); + (*_f) = NULL; +} + diff --git a/core/Fifo.cpp b/core/Fifo.cpp deleted file mode 100644 index d1d051c33..000000000 --- a/core/Fifo.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* $Id: Fifo.cpp,v 1.15 2003/10/13 14:12:18 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Fifo.h" -#include "Thread.h" - -HBBuffer::HBBuffer( uint32_t size ) -{ - fAllocSize = size; - fSize = size; - fKeyFrame = false; - fData = (uint8_t*) malloc( size ); - fPosition = 0; - - if( !fData ) - { - Log( "HBBuffer::HBBuffer() : malloc() failed, gonna crash soon" ); - } -} - -HBBuffer::~HBBuffer() -{ - free( fData ); -} - -void HBBuffer::ReAlloc( uint32_t size ) -{ - fData = (uint8_t*) realloc( fData, size ); - - if( !fData ) - { - Log( "HBBuffer::ReAlloc() : realloc() failed, gonna crash soon" ); - } - - fAllocSize = size; -} - -/* Constructor */ -HBFifo::HBFifo( int capacity ) -{ - fCapacity = capacity; - - fWhereToPush = 0; - fWhereToPop = 0; - fBuffers = (HBBuffer**) malloc( ( fCapacity + 1 ) * sizeof( void* ) ); - fLock = new HBLock(); -} - -HBFifo::~HBFifo() -{ - Log( "HBFifo::~HBFifo: trashing %d buffer%s", - Size(), Size() ? "s" : "" ); - - /* Empty the fifo */ - while( fWhereToPush != fWhereToPop ) - { - HBBuffer * buffer = fBuffers[fWhereToPop]; - fWhereToPop++; - fWhereToPop %= ( fCapacity + 1 ); - delete buffer; - } - - /* Cleaning */ - free( fBuffers ); - - delete fLock; -} - -/* Size() : returns how much the fifo is currently filled */ -int HBFifo::Size() -{ - return ( fCapacity + 1 + fWhereToPush - fWhereToPop ) % - ( fCapacity + 1 ); -} - -/* Capacity() : simply returns the fifo capacity... */ -int HBFifo::Capacity() -{ - return fCapacity; -} - -/* Push() - returns immediatly (true if successful, false otherwise ) */ -bool HBFifo::Push( HBBuffer * buffer ) -{ - fLock->Lock(); - - if( Size() < fCapacity ) - { - fBuffers[fWhereToPush] = buffer; - fWhereToPush++; - fWhereToPush %= ( fCapacity + 1 ); - fLock->Unlock(); - return true; - } - - fLock->Unlock(); - return false; -} - -/* Pop() - returns immediatly (a pointer to a buffer if successful, - NULL otherwise ) */ -HBBuffer * HBFifo::Pop() -{ - fLock->Lock(); - - if( fWhereToPush != fWhereToPop ) - { - HBBuffer * buffer = fBuffers[fWhereToPop]; - fWhereToPop++; - fWhereToPop %= ( fCapacity + 1 ); - fLock->Unlock(); - return buffer; - } - - fLock->Unlock(); - return NULL; -} diff --git a/core/Fifo.h b/core/Fifo.h index 69200d30c..758125ebd 100644 --- a/core/Fifo.h +++ b/core/Fifo.h @@ -1,49 +1,81 @@ -/* $Id: Fifo.h,v 1.11 2003/09/30 14:38:15 titer Exp $ +/* $Id: Fifo.h,v 1.3 2003/11/06 13:07:52 titer Exp $ This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. + Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ #ifndef HB_FIFO_H #define HB_FIFO_H -#include "Common.h" +#include "Utils.h" +#include "Thread.h" -class HBBuffer +struct HBBuffer { - public: - HBBuffer( uint32_t size ); - ~HBBuffer(); - void ReAlloc( uint32_t size ); - - uint32_t fAllocSize; - uint32_t fSize; - uint8_t * fData; - - float fPosition; - uint32_t fStreamId; - bool fKeyFrame; - uint64_t fPTS; - uint32_t fPass; + int alloc; + int size; + uint8_t * data; + + float position; + int streamId; + int keyFrame; + uint64_t pts; + int pass; + int last; }; -class HBFifo +HBBuffer * HBBufferInit( int size ); +void HBBufferReAlloc( HBBuffer *, int size ); +void HBBufferClose( HBBuffer ** ); + +struct HBFifo { - public: - HBFifo( int capacity = 32 ); - ~HBFifo(); - - int Size(); - int Capacity(); - bool Push( HBBuffer * buffer ); - HBBuffer * Pop(); - - private: - int fCapacity; - int fWhereToPush; - int fWhereToPop; - HBBuffer ** fBuffers; - HBLock * fLock; + int capacity; + int whereToPush; + int whereToPop; + HBBuffer ** buffers; + HBLock * lock; }; +HBFifo * HBFifoInit( int capacity ); +int HBFifoSize( HBFifo * ); +static inline int HBFifoPush( HBFifo *, HBBuffer ** ); +static inline HBBuffer * HBFifoPop( HBFifo * ); +void HBFifoClose( HBFifo ** ); + +static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) +{ + HBLockLock( f->lock ); + + if( HBFifoSize( f ) < f->capacity ) + { + f->buffers[f->whereToPush] = *b; + f->whereToPush++; + f->whereToPush %= ( f->capacity + 1 ); + HBLockUnlock( f->lock ); + *b = NULL; + return 1; + } + + HBLockUnlock( f->lock ); + return 0; +} + +static inline HBBuffer * HBFifoPop( HBFifo * f ) +{ + HBLockLock( f->lock ); + + if( f->whereToPush != f->whereToPop ) + { + HBBuffer * b = f->buffers[f->whereToPop]; + f->whereToPop++; + f->whereToPop %= ( f->capacity + 1 ); + HBLockUnlock( f->lock ); + return b; + } + + HBLockUnlock( f->lock ); + return NULL; +} + #endif diff --git a/core/HandBrake.c b/core/HandBrake.c new file mode 100644 index 000000000..3f84a5757 --- /dev/null +++ b/core/HandBrake.c @@ -0,0 +1,767 @@ +/* $Id: HandBrake.c,v 1.15 2003/11/07 21:52:57 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 <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" + +/* Local prototypes */ +static void HandBrakeThread( void * ); +static void _StopRip( HBHandle * ); +static void FixPictureSettings( HBTitle * ); +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; +}; + +HBHandle * HBInit( int debug, int cpuCount ) +{ + HBHandle * h; + if( !( h = malloc( sizeof( HBHandle ) ) ) ) + { + HBLog( "HBInit: malloc() failed, gonna crash" ); + return NULL; + } + + /* See HBLog() in Utils.cpp */ + if( debug ) + { + putenv( "HB_DEBUG=1" ); + } + + /* Init libavcodec */ + avcodec_init(); + register_avcodec( &mpeg4_encoder ); + + /* Check CPU count */ + if( !cpuCount ) + { + h->cpuCount = GetCPUCount(); + HBLog( "HBInit: %d CPU%s detected", h->cpuCount, + ( h->cpuCount > 1 ) ? "s" : "" ); + } + else + { + if( cpuCount < 1 ) + { + HBLog( "HBInit: invalid CPU count (%d), using 1", + cpuCount ); + h->cpuCount = 1; + } + else if( cpuCount > 8 ) + { + HBLog( "HBInit: invalid CPU count (%d), using 8", + cpuCount ); + h->cpuCount = 8; + } + else + { + HBLog( "HBInit: user specified %d CPU%s", + cpuCount, ( cpuCount > 1 ) ? "s" : "" ); + 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->curTitle = NULL; + h->curAudio = NULL; + h->curOptAudio = NULL; + + h->pauseLock = HBLockInit(); + + h->die = 0; + h->thread = HBThreadInit( "libhb", HandBrakeThread, h, + HB_NORMAL_PRIORITY ); + + return h; +} + +int HBGetStatus( HBHandle * h, HBStatus * status ) +{ + 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; +} + +void HBScanDevice( HBHandle * h, char * device, 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 ); +} + +void HBStartRip( HBHandle * h, HBTitle * t, + HBAudio * a1, HBAudio * a2 ) +{ + 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; + } + + 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 fifos */ + t->mpeg2Fifo = HBFifoInit( 512 ); + t->rawFifo = HBFifoInit( 1 ); + t->scaledFifo = HBFifoInit( 1 ); + t->mpeg4Fifo = HBFifoInit( 1 ); + a1->ac3Fifo = HBFifoInit( 512 ); + a1->rawFifo = HBFifoInit( 1 ); + a1->mp3Fifo = HBFifoInit( 1 ); + if( a2 ) + { + a2->ac3Fifo = HBFifoInit( 512 ); + a2->rawFifo = HBFifoInit( 1 ); + a2->mp3Fifo = HBFifoInit( 1 ); + } + + /* 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 ); + } + + h->curTitle = t; + h->curAudio = a1; + h->curOptAudio = a2; +} + +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->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; +} + +uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) +{ + AVPicture pic1, pic2, pic3, pic4; + uint8_t * buf1, * buf2, * buf3, * buf4; + char fileName[1024]; + FILE * file; + ImgReSampleContext * resampleContext; + int8_t * preview, * pen; + int i; + + FixPictureSettings( t ); + + buf1 = malloc( 3 * t->inWidth * t->inHeight / 2 ); + buf2 = malloc( 3 * t->inWidth * t->inHeight / 2 ); + buf3 = malloc( 3 * t->outWidth * t->outHeight / 2 ); + buf4 = malloc( 4 * t->outWidth * t->outHeight ); + + if( !buf1 || !buf2 || !buf3 || !buf4 ) + { + HBLog( "HBGetPreview: malloc() failed, gonna crash" ); + return NULL; + } + + /* Original YUV picture */ + avpicture_fill( &pic1, buf1, PIX_FMT_YUV420P, t->inWidth, + t->inHeight ); + + /* Deinterlaced YUV picture */ + avpicture_fill( &pic2, buf2, PIX_FMT_YUV420P, + t->inWidth, t->inHeight ); + + /* Scaled YUV picture */ + avpicture_fill( &pic3, buf3, PIX_FMT_YUV420P, t->outWidth, + t->outHeight ); + + /* Scaled RGB picture ) */ + avpicture_fill( &pic4, buf4, PIX_FMT_RGBA32, t->outWidth, + t->outHeight ); + + /* Get the original image from the temp file */ + memset( fileName, 0, 1024 ); + sprintf( fileName, "/tmp/HB.%d.%d.%d", h->pid, t->index, + picture ); + file = fopen( fileName, "r" ); + if( file ) + { + fread( buf1, 3 * t->inWidth * t->inHeight / 2, 1, file ); + fclose( file ); + } + else + { + HBLog( "HBGetPreview: could not open %s", fileName ); + memset( buf1, 0, 3 * t->inWidth * t->inHeight / 2 ); + } + + /* Deinterlace if needed, and scale */ + resampleContext = + img_resample_full_init( t->outWidth, t->outHeight, + t->inWidth, t->inHeight, + t->topCrop, t->bottomCrop, + t->leftCrop, t->rightCrop ); + if( t->deinterlace ) + { + avpicture_deinterlace( &pic2, &pic1, PIX_FMT_YUV420P, + t->inWidth, t->inHeight ); + img_resample( resampleContext, &pic3, &pic2 ); + } + else + { + img_resample( resampleContext, &pic3, &pic1 ); + } + + /* Convert to RGB */ + img_convert( &pic4, PIX_FMT_RGBA32, &pic3, PIX_FMT_YUV420P, + t->outWidth, t->outHeight ); + + /* Create the final preview */ + preview = malloc( 4 * ( t->outWidthMax + 2 ) * + ( t->outHeightMax + 2 ) ); + + if( !preview ) + { + HBLog( "HBGetPreview: malloc() failed, gonna crash" ); + return NULL; + } + + /* Blank it */ + memset( preview, 0x80, + 4 * ( t->outWidthMax + 2 ) * ( t->outHeightMax + 2 ) ); + + /* Draw the picture (centered) and draw the cropping zone */ + pen = preview + ( t->outHeightMax - t->outHeight ) * + ( t->outWidthMax + 2 ) * 2 + + ( t->outWidthMax - t->outWidth ) * 2; + + memset( pen, 0xFF, 4 * ( t->outWidth + 2 ) ); + pen += 4 * ( t->outWidthMax + 2 ); + + 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 ); + pen += 4 * t->outWidth; + memset( pen, 0xFF, 4 ); + + pen = nextLine; + } + + memset( pen, 0xFF, 4 * ( t->outWidth + 2 ) ); + + /* Free memory */ + free( buf1 ); + free( buf2 ); + free( buf3 ); + free( buf4 ); + + return preview; + return NULL; +} + +void HBClose( HBHandle ** _h ) +{ + char command[1024]; + + HBHandle * h = *_h; + + h->die = 1; + HBThreadClose( &h->thread ); + + if( h->status.mode == HB_MODE_SCANNING ) + { + HBScanClose( &h->scan ); + } + else if( h->status.mode == HB_MODE_PAUSED ) + { + HBLockUnlock( h->pauseLock ); + _StopRip( h ); + } + else if( h->status.mode == HB_MODE_ENCODING ) + { + _StopRip( h ); + } + + 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; +} + +/* Following functions are called by libhb's internal threads */ +void HBCheckPaused( HBHandle * h ) +{ + HBLockLock( h->pauseLock ); + HBLockUnlock( h->pauseLock ); +} + +void HBScanning( HBHandle * h, int title ) +{ + HBLockLock( h->lock ); + h->status.scannedTitle = title; + HBLockUnlock( h->lock ); +} + +void HBScanDone( HBHandle * h, HBList * titleList ) +{ + h->status.titleList = titleList; + h->stopScan = 1; +} + +int HBGetPid( HBHandle * h ) +{ + return h->pid; +} + +void HBDone( HBHandle * h ) +{ + h->ripDone = 1; +} + +void HBPosition( HBHandle * h, float position ) +{ + if( !h->frames ) + { + h->beginDate = HBGetDate(); + h->lastFpsUpdate = h->beginDate; + } + + h->frames++; + h->framesSinceFpsUpdate++; + + HBLockLock( h->lock ); + if( position - h->status.position > 0.0001 || h->frames == 2 ) + { + HBLog( "Progress: %.2f %%", 100.0 * position ); + h->status.position = position; + + if( h->curTitle->twoPass ) + h->status.pass = ( position < 0.5 ) ? 1 : 2; + else + h->status.pass = 1; + } + 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( "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; + } + HBLockUnlock( h->lock ); +} + +void HBErrorOccured( HBHandle * h, HBError error ) +{ + if( !( h->status.mode & ( HB_MODE_ENCODING | HB_MODE_PAUSED ) ) ) + { + return; + } + + h->status.error = error; + h->error = 1; +} + +/* Local functions */ +static void HandBrakeThread( void * _h ) +{ + HBHandle * h = (HBHandle*) _h; + + h->pid = getpid(); + + while( !h->die ) + { + 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->stopRip = 0; + } + + if( h->ripDone ) + { + /* Wait a bit */ + HBSnooze( 500000 ); + + _StopRip( h ); + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_DONE; + HBLockUnlock( h->lock ); + + h->ripDone = 0; + } + + if( h->error ) + { + _StopRip( h ); + + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_ERROR; + HBLockUnlock( h->lock ); + + h->error = 0; + } + + HBSnooze( 10000 ); + } +} + +static void _StopRip( HBHandle * h ) +{ + int i; + + /* Stop threads */ + HBDVDReadClose( &h->curTitle->dvdRead ); + HBAviMuxClose( &h->curTitle->aviMux ); + for( i = 0; i < h->cpuCount; i++ ) + { + HBWorkThreadClose( &h->curTitle->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 ); + } + + /* 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 ) + { + HBFifoClose( &h->curOptAudio->ac3Fifo ); + HBFifoClose( &h->curOptAudio->rawFifo ); + HBFifoClose( &h->curOptAudio->mp3Fifo ); + } +} + +static void FixPictureSettings( HBTitle * t ) +{ + /* Sanity checks */ + t->topCrop = EVEN( t->topCrop ); + t->bottomCrop = EVEN( t->bottomCrop ); + t->leftCrop = EVEN( t->leftCrop ); + t->rightCrop = EVEN( t->rightCrop ); + + t->outWidth = MIN( t->outWidth, t->outWidthMax ); + t->outWidth = MAX( 16, t->outWidth ); + + t->outHeight = + MULTIPLE_16( (uint64_t) t->outWidth * t->inWidth * + ( t->inHeight - t->topCrop - t->bottomCrop ) * + VOUT_ASPECT_FACTOR / + ( (uint64_t) t->inHeight * + ( t->inWidth - t->leftCrop - t->rightCrop ) * + t->aspect ) ); + t->outHeight = MAX( 16, t->outHeight ); + + if( t->outHeight > t->outHeightMax ) + { + t->outHeight = t->outHeightMax; + t->outWidth = + MULTIPLE_16( (uint64_t) t->outHeight * t->inHeight * + ( t->inWidth - t->leftCrop - t->rightCrop ) * + t->aspect / + ( (uint64_t) t->inWidth * + ( t->inHeight - t->topCrop - t->bottomCrop ) * + VOUT_ASPECT_FACTOR ) ); + t->outWidth = MIN( t->outWidth, t->outWidthMax ); + t->outWidth = MAX( 16, t->outWidth ); + } +} + +static int GetCPUCount() +{ + int CPUCount = 1; + +#if defined( SYS_BEOS ) + system_info info; + get_system_info( &info ); + CPUCount = info.cpu_count; + +#elif defined( SYS_MACOSX ) + FILE * info; + char buffer[256]; + + if( ( info = popen( "/usr/sbin/sysctl hw.ncpu", "r" ) ) ) + { + if( fgets( buffer, 256, info ) ) + { + int count; + if( sscanf( buffer, "hw.ncpu: %d", &count ) == 1 ) + { + CPUCount = count; + } + else + { + HBLog( "GetCPUCount: sscanf() failed" ); + } + } + else + { + HBLog( "GetCPUCount: fgets() failed" ); + } + fclose( info ); + } + else + { + HBLog( "GetCPUCount: popen() failed" ); + } + +#elif defined( SYS_LINUX ) + FILE * info; + char buffer[256]; + + if( ( info = popen( "grep -c '^processor' /proc/cpuinfo", "r" ) ) ) + { + if( fgets( buffer, 256, info ) ) + { + int count; + if( sscanf( buffer, "%d", &count ) == 1 ) + { + CPUCount = count; + } + else + { + HBLog( "GetCPUCount: sscanf() failed" ); + } + } + else + { + HBLog( "GetCPUCount: fgets() failed" ); + } + fclose( info ); + } + else + { + HBLog( "GetCPUCount: fopen() failed" ); + } + +#elif defined( SYS_CYGWIN ) + /* TODO */ + CPUCount = 1; + +#endif + CPUCount = MAX( 1, CPUCount ); + CPUCount = MIN( CPUCount, 8 ); + + return CPUCount; +} + diff --git a/core/HandBrake.h b/core/HandBrake.h new file mode 100644 index 000000000..35ec0fc0a --- /dev/null +++ b/core/HandBrake.h @@ -0,0 +1,55 @@ +/* $Id: HandBrake.h,v 1.3 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_HANDBRAKE_H +#define HB_HANDBRAKE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Utils.h" + +/* 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 * ); + +/* Launch a thread which scans the specified device and title. Use + title = 0 to scan all titles. Returns immediately */ +void HBScanDevice( HBHandle *, char * device, int title ); + +/* Start ripping the specified title with specified audio tracks. + Returns immediatly */ +void HBStartRip( HBHandle *, HBTitle *, HBAudio *, HBAudio * ); + +/* Suspend rip. Returns immediatly */ +void HBPauseRip( HBHandle * ); + +/* Resume rip. Returns immediatly */ +void HBResumeRip( HBHandle * ); + +/* Cancel rip. Returns immediatly */ +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 ) */ +uint8_t * HBGetPreview( HBHandle *, HBTitle *, int picture ); + +/* Clean up things */ +void HBClose( HBHandle ** ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/HandBrakeInternal.h b/core/HandBrakeInternal.h new file mode 100644 index 000000000..7c10512c9 --- /dev/null +++ b/core/HandBrakeInternal.h @@ -0,0 +1,35 @@ +/* $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/Languages.h b/core/Languages.h index 21a5e1487..7949688c9 100644 --- a/core/Languages.h +++ b/core/Languages.h @@ -1,7 +1,7 @@ -/* $Id: Languages.h,v 1.2 2003/09/30 14:38:15 titer Exp $ +/* $Id: Languages.h,v 1.1 2003/11/03 12:08:01 titer Exp $ This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. + Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ #ifndef HB_LANGUAGES_H @@ -14,7 +14,7 @@ typedef struct iso639_lang_t char * iso639_1; /* ISO-639-1 (2 characters) code */ } iso639_lang_t; -iso639_lang_t languages[] = +static iso639_lang_t languages[] = { { "Afar", "", "aa" }, { "Abkhazian", "", "ab" }, { "Afrikaans", "", "af" }, diff --git a/core/MadDec.c b/core/MadDec.c new file mode 100644 index 000000000..deecfeebd --- /dev/null +++ b/core/MadDec.c @@ -0,0 +1,9 @@ +/* $Id: MadDec.c,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. */ + +#include "MadDec.h" +#include "Fifo.h" + diff --git a/core/MadDec.h b/core/MadDec.h new file mode 100644 index 000000000..b1624338f --- /dev/null +++ b/core/MadDec.h @@ -0,0 +1,15 @@ +/* $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/Manager.cpp b/core/Manager.cpp deleted file mode 100644 index 908aa08fd..000000000 --- a/core/Manager.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/* $Id: Manager.cpp,v 1.70 2003/10/16 13:36:17 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Ac3Decoder.h" -#include "AviMuxer.h" -#include "DVDReader.h" -#include "Fifo.h" -#include "Manager.h" -#include "Mp3Encoder.h" -#include "Mpeg2Decoder.h" -#include "Mpeg4Encoder.h" -#include "MpegDemux.h" -#include "Resizer.h" -#include "Scanner.h" -#include "Worker.h" - -#include <ffmpeg/avcodec.h> - -/* Public methods */ - -HBManager::HBManager( bool debug, int cpuCount ) - : HBThread( "manager", HB_NORMAL_PRIORITY ) -{ - /* See Log() in Common.cpp */ - if( debug ) - { - putenv( "HB_DEBUG=1" ); - } - - /* Check CPU count */ - if( !cpuCount ) - { - fCPUCount = GetCPUCount(); - Log( "HBManager::HBManager: %d CPU%s detected", fCPUCount, - ( fCPUCount > 1 ) ? "s" : "" ); - } - else - { - fCPUCount = cpuCount; - if( fCPUCount < 1 ) - { - Log( "HBManager::HBManager: invalid CPU count (%d), " - "using 1", fCPUCount ); - fCPUCount = 1; - } - else if( fCPUCount > 8 ) - { - Log( "HBManager::HBManager: invalid CPU count (%d), " - "using 8", fCPUCount ); - fCPUCount = 8; - } - Log( "HBManager::HBManager: user specified %d CPU%s", - fCPUCount, ( fCPUCount > 1 ) ? "s" : "" ); - } - - /* Init ffmpeg's libavcodec */ - avcodec_init(); -// register_avcodec( &mpeg4_encoder ); - avcodec_register_all(); - - /* Initialization */ - fStopScan = false; - fStopRip = false; - fRipDone = false; - fError = false; - - fScanner = NULL; - - fStatusLock = new HBLock(); - fStatus.fMode = HB_MODE_NEED_VOLUME; - fNeedUpdate = true; - - fCurTitle = NULL; - fCurAudio1 = NULL; - fCurAudio2 = NULL; - - Run(); -} - -HBManager::~HBManager() -{ - /* Stop ripping if needed */ - fStatusLock->Lock(); - if( fStatus.fMode == HB_MODE_ENCODING ) - { - fStatusLock->Unlock(); - - StopRip(); - while( fStopRip ) - { - Snooze( 10000 ); - } - } - else - { - fStatusLock->Unlock(); - } - - /* Stop scanning if needed */ - if( fScanner ) - { - delete fScanner; - } - - /* Remove temp files */ - char command[1024]; memset( command, 0, 1024 ); - sprintf( command, "rm -f /tmp/HB.%d.*", GetPid() ); - system( command ); - - delete fStatusLock; -} - -void HBManager::DoWork() -{ - while( !fDie ) - { - if( fStopScan ) - { - /* Destroy the thread */ - delete fScanner; - fScanner = NULL; - - /* Update interface */ - fStatusLock->Lock(); - if( fStatus.fTitleList && fStatus.fTitleList->CountItems() ) - { - fStatus.fMode = HB_MODE_READY_TO_RIP; - } - else - { - fStatus.fMode = HB_MODE_INVALID_VOLUME; - } - fNeedUpdate = true; - fStatusLock->Unlock(); - - fStopScan = false; - } - - if( fStopRip || fError || fRipDone ) - { - if( fRipDone ) - { - /* Wait a bit */ - while( fCurTitle->fPSFifo->Size() ) - { - Snooze( 10000 ); - } - while( fCurTitle->fMpeg2Fifo->Size() && - ( !fCurAudio1 || fCurAudio1->fAc3Fifo->Size() ) && - ( !fCurAudio2 || fCurAudio2->fAc3Fifo->Size() ) ) - { - Snooze( 10000 ); - } - Snooze( 500000 ); - } - else - { - fStatusLock->Lock(); - fStatus.fMode = HB_MODE_STOPPING; - fNeedUpdate = true; - fStatusLock->Unlock(); - } - - /* Stop threads */ - delete fCurTitle->fDVDReader; - delete fCurTitle->fAviMuxer; - for( int i = 0; i < fCPUCount; i++ ) - { - delete fCurTitle->fWorkers[i]; - } - - /* Clean up */ - delete fCurTitle->fMpegDemux; - delete fCurTitle->fMpeg2Decoder; - delete fCurTitle->fResizer; - delete fCurTitle->fMpeg4Encoder; - - if( fCurAudio1 ) - { - delete fCurAudio1->fAc3Decoder; - delete fCurAudio1->fMp3Encoder; - } - - if( fCurAudio2 ) - { - delete fCurAudio2->fAc3Decoder; - delete fCurAudio2->fMp3Encoder; - } - - /* Destroy fifos */ - delete fCurTitle->fPSFifo; - delete fCurTitle->fMpeg2Fifo; - delete fCurTitle->fRawFifo; - delete fCurTitle->fResizedFifo; - delete fCurTitle->fMpeg4Fifo; - - if( fCurAudio1 ) - { - delete fCurAudio1->fAc3Fifo; - delete fCurAudio1->fRawFifo; - delete fCurAudio1->fMp3Fifo; - } - - if( fCurAudio2 ) - { - delete fCurAudio2->fAc3Fifo; - delete fCurAudio2->fRawFifo; - delete fCurAudio2->fMp3Fifo; - } - - /* Update interface */ - fStatusLock->Lock(); - fStatus.fMode = fStopRip ? HB_MODE_CANCELED : - ( fError ? HB_MODE_ERROR : HB_MODE_DONE ); - fNeedUpdate = true; - fStatusLock->Unlock(); - - fStopRip = false; - fError = false; - fRipDone = false; - } - - Snooze( 10000 ); - } -} - -bool HBManager::NeedUpdate() -{ - fStatusLock->Lock(); - if( fNeedUpdate ) - { - fNeedUpdate = false; - fStatusLock->Unlock(); - return true; - } - fStatusLock->Unlock(); - - return false; -} - -HBStatus HBManager::GetStatus() -{ - fStatusLock->Lock(); - HBStatus status = fStatus; - fStatusLock->Unlock(); - - return status; -} - -void HBManager::ScanVolumes( char * device ) -{ - if( !( fStatus.fMode & - ( HB_MODE_NEED_VOLUME | HB_MODE_INVALID_VOLUME ) ) ) - { - Log( "HBManager::ScanVolumes : current mode is %d, aborting", - fStatus.fMode ); - return; - } - - fScanner = new HBScanner( this, device ); - - fStatusLock->Lock(); - fStatus.fMode = HB_MODE_SCANNING; - fStatus.fScannedVolume = strdup( device ); - fStatus.fScannedTitle = 0; - fNeedUpdate = true; - fStatusLock->Unlock(); -} - -void HBManager::StartRip( HBTitle * title, HBAudio * audio1, - HBAudio * audio2, char * file ) -{ - if( !title || !file ) - { - Log( "HBManager::StartRip : error (title = %p, file = %s)", - title, file ); - return; - } - - if( !( fStatus.fMode & ( HB_MODE_READY_TO_RIP | HB_MODE_DONE | - HB_MODE_CANCELED | HB_MODE_ERROR ) ) ) - { - Log( "HBManager::StartRip : current mode is %d, aborting", - fStatus.fMode ); - return; - } - - FixPictureSettings( title ); - - Log( "HBManager::StartRip:" ); - Log( "- device: %s, title: %d", title->fDevice, title->fIndex ); - Log( "- video: %dx%d->%dx%d, bitrate=%d, 2-pass=%s, deinterlace=%s", - title->fInWidth, title->fInHeight, - title->fOutWidth, title->fOutHeight, - title->fBitrate, title->fTwoPass ? "yes" : "no", - title->fDeinterlace ? "yes" : "no" ); - Log( "- cropping: top=%d, bottom=%d, left=%d, right=%d", - title->fTopCrop, title->fBottomCrop, - title->fLeftCrop, title->fRightCrop ); - if( audio1 ) - { - Log( "- audio 1: lang = %s (%x), bitrate = %d", - audio1->fDescription, audio1->fId, audio1->fOutBitrate ); - } - if( audio2 ) - { - Log( "- audio 2: lang = %s (%x), bitrate = %d", - audio2->fDescription, audio2->fId, audio2->fOutBitrate ); - } - - /* Create fifos */ - title->fPSFifo = new HBFifo( 256 ); - title->fMpeg2Fifo = new HBFifo( 256 ); - title->fRawFifo = new HBFifo( 4 ); - title->fResizedFifo = new HBFifo( 4 ); - title->fMpeg4Fifo = new HBFifo( 4 ); - if( audio1 ) - { - audio1->fAc3Fifo = new HBFifo( 256 ); - audio1->fRawFifo = new HBFifo( 4 ); - audio1->fMp3Fifo = new HBFifo( 4 ); - } - if( audio2 ) - { - audio2->fAc3Fifo = new HBFifo( 256 ); - audio2->fRawFifo = new HBFifo( 4 ); - audio2->fMp3Fifo = new HBFifo( 4 ); - } - - /* Create decoders & encoders objects */ - title->fMpegDemux = new HBMpegDemux( this, title, audio1, - audio2 ); - title->fMpeg2Decoder = new HBMpeg2Decoder( this, title ); - title->fResizer = new HBResizer( this, title ); - title->fMpeg4Encoder = new HBMpeg4Encoder( this, title ); - if( audio1 ) - { - audio1->fAc3Decoder = new HBAc3Decoder( this, audio1 ); - audio1->fMp3Encoder = new HBMp3Encoder( this, audio1 ); - } - if( audio2 ) - { - audio2->fAc3Decoder = new HBAc3Decoder( this, audio2 ); - audio2->fMp3Encoder = new HBMp3Encoder( this, audio2 ); - } - - /* Create and launch the threads */ - title->fDVDReader = new HBDVDReader( this, title ); - title->fAviMuxer = new HBAviMuxer( this, title, audio1, audio2, - file ); - for( int i = 0; i < fCPUCount; i++ ) - { - title->fWorkers[i] = new HBWorker( title, audio1, audio2 ); - } - - fCurTitle = title; - fCurAudio1 = audio1; - fCurAudio2 = audio2; - - fStatusLock->Lock(); - fStatus.fMode = HB_MODE_ENCODING; - fStatus.fPosition = 0; - fStatus.fFrameRate = 0; - fStatus.fFrames = 0; - fStatus.fStartDate = 0; - fStatus.fRemainingTime = 0; - fStatus.fSuspendDate = 0; - fNeedUpdate = true; - fStatusLock->Unlock(); -} - -void HBManager::SuspendRip() -{ - if( fStatus.fMode != HB_MODE_ENCODING ) - { - Log( "HBManager::SuspendRip : current mode is %d, aborting", - fStatus.fMode ); - return; - } - - fCurTitle->fDVDReader->Suspend(); - fCurTitle->fAviMuxer->Suspend(); - for( int i = 0; i < fCPUCount; i++ ) - { - fCurTitle->fWorkers[i]->Suspend(); - } - - fStatusLock->Lock(); - fStatus.fMode = HB_MODE_SUSPENDED; - fStatus.fSuspendDate = GetDate(); - fNeedUpdate = true; - fStatusLock->Unlock(); -} - -void HBManager::ResumeRip() -{ - if( fStatus.fMode != HB_MODE_SUSPENDED ) - { - Log( "HBManager::ResumeRip : current mode is %d, aborting", - fStatus.fMode ); - return; - } - - fCurTitle->fDVDReader->Resume(); - fCurTitle->fAviMuxer->Resume(); - for( int i = 0; i < fCPUCount; i++ ) - { - fCurTitle->fWorkers[i]->Resume(); - } - - fStatusLock->Lock(); - fStatus.fMode = HB_MODE_ENCODING; - fStatus.fStartDate += GetDate() - fStatus.fSuspendDate; - fNeedUpdate = true; - fStatusLock->Unlock(); -} - -void HBManager::StopRip() -{ - if( !( fStatus.fMode & ( HB_MODE_ENCODING | HB_MODE_SUSPENDED ) ) ) - { - Log( "HBManager::StopRip : current mode is %d, aborting", - fStatus.fMode ); - return; - } - - /* Stop the threads */ - fStopRip = true; -} - -#define fInWidth title->fInWidth -#define fInHeight title->fInHeight -#define fAspect title->fAspect -#define fDeinterlace title->fDeinterlace -#define fOutWidth title->fOutWidth -#define fOutHeight title->fOutHeight -#define fOutWidthMax title->fOutWidthMax -#define fOutHeightMax title->fOutHeightMax -#define fTopCrop title->fTopCrop -#define fBottomCrop title->fBottomCrop -#define fLeftCrop title->fLeftCrop -#define fRightCrop title->fRightCrop - -void HBManager::FixPictureSettings( HBTitle * title ) -{ - /* Sanity checks */ - fTopCrop = EVEN( fTopCrop ); - fBottomCrop = EVEN( fBottomCrop ); - fLeftCrop = EVEN( fLeftCrop ); - fRightCrop = EVEN( fRightCrop ); - - fOutWidth = MIN( fOutWidth, fOutWidthMax ); - fOutWidth = MAX( 16, fOutWidth ); - - fOutHeight = MULTIPLE_16( (uint64_t) fOutWidth * fInWidth * - ( fInHeight - fTopCrop - fBottomCrop ) * - VOUT_ASPECT_FACTOR / - ( (uint64_t) fInHeight * - ( fInWidth - fLeftCrop - fRightCrop ) * - fAspect ) ); - fOutHeight = MAX( 16, fOutHeight ); - - if( fOutHeight > fOutHeightMax ) - { - fOutHeight = fOutHeightMax; - fOutWidth = MULTIPLE_16( (uint64_t) fOutHeight * fInHeight * - ( fInWidth - fLeftCrop - fRightCrop ) * - fAspect / - ( (uint64_t) fInWidth * - ( fInHeight - fTopCrop - fBottomCrop ) * - VOUT_ASPECT_FACTOR ) ); - fOutWidth = MIN( fOutWidth, fOutWidthMax ); - fOutWidth = MAX( 16, fOutWidth ); - } -} - -uint8_t * HBManager::GetPreview( HBTitle * title, uint32_t image ) -{ - FixPictureSettings( title ); - - AVPicture pic1, pic2, pic3, pic4; - uint8_t * buf1, * buf2, * buf3, * buf4; - - /* Original YUV picture */ - buf1 = (uint8_t*) malloc( 3 * fInWidth * fInHeight / 2 ); - avpicture_fill( &pic1, buf1, PIX_FMT_YUV420P, fInWidth, - fInHeight ); - - /* Deinterlaced YUV picture */ - buf2 = (uint8_t*) malloc( 3 * fInWidth * fInHeight / 2 ); - avpicture_fill( &pic2, buf2, PIX_FMT_YUV420P, - fInWidth, fInHeight ); - - /* Resized YUV picture */ - buf3 = (uint8_t*) malloc( 3 * fOutWidth * fOutHeight / 2 ); - avpicture_fill( &pic3, buf3, PIX_FMT_YUV420P, fOutWidth, - fOutHeight ); - - /* Resized RGB picture ) */ - buf4 = (uint8_t*) malloc( 4 * fOutWidth * fOutHeight ); - avpicture_fill( &pic4, buf4, PIX_FMT_RGBA32, fOutWidth, - fOutHeight ); - - /* Get the original image from the temp file */ - char fileName[1024]; memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.%x.%d", GetPid(), (uint32_t) title, - image); - FILE * file = fopen( fileName, "r" ); - fread( buf1, 3 * fInWidth * fInHeight / 2, 1, file ); - fclose( file ); - - /* Deinterlace if needed, and resize */ - ImgReSampleContext * resampleContext = - img_resample_full_init( fOutWidth, fOutHeight, - fInWidth, fInHeight, - fTopCrop, fBottomCrop, - fLeftCrop, fRightCrop ); - if( fDeinterlace ) - { - avpicture_deinterlace( &pic2, &pic1, PIX_FMT_YUV420P, - fInWidth, fInHeight ); - img_resample( resampleContext, &pic3, &pic2 ); - } - else - { - img_resample( resampleContext, &pic3, &pic1 ); - } - - /* Convert to RGB */ - img_convert( &pic4, PIX_FMT_RGBA32, &pic3, PIX_FMT_YUV420P, - fOutWidth, fOutHeight ); - - /* Create the final preview */ - uint8_t * preview = (uint8_t*) malloc( 4 * ( fOutWidthMax + 2 ) * - ( fOutHeightMax + 2 ) ); - - /* Blank it */ - memset( preview, 0, - 4 * ( fOutWidthMax + 2 ) * ( fOutHeightMax + 2 ) ); - - /* Draw the picture (centered) and draw the cropping zone */ - uint32_t leftOffset = 1 + ( fOutWidthMax - fOutWidth ) / 2; - uint32_t topOffset = 1 + ( fOutHeightMax - fOutHeight ) / 2; - - memset( preview + 4 * ( ( fOutWidthMax + 2 ) * ( topOffset - 1 ) + - leftOffset - 1 ), - 0xFF, 4 * ( fOutWidth + 2 ) ); - - for( uint32_t i = 0; i < fOutHeight; i++ ) - { - memset( preview + 4 * ( ( fOutWidthMax + 2 ) * - ( i + topOffset ) + leftOffset - 1 ), - 0xFF, 4 ); - memcpy( preview + 4 * ( ( fOutWidthMax + 2 ) * - ( i + topOffset ) + leftOffset ), - buf4 + 4 * fOutWidth * i, - 4 * fOutWidth ); - memset( preview + 4 * ( ( fOutWidthMax + 2 ) * - ( i + topOffset ) + leftOffset + - fOutWidth ), - 0xFF, 4 ); - } - - memset( preview + 4 * ( ( fOutWidthMax + 2 ) * - ( topOffset + fOutHeight ) + - leftOffset - 1 ), - 0xFF, 4 * ( fOutWidth + 2 ) ); - - /* Free memory */ - free( buf1 ); - free( buf2 ); - free( buf3 ); - free( buf4 ); - - return preview; -} - -#undef fInWidth -#undef fInHeight -#undef fAspect -#undef fDeinterlace -#undef fOutWidth -#undef fOutHeight -#undef fOutWidthMax -#undef fOutHeightMax -#undef fTopCrop -#undef fBottomCrop -#undef fLeftCrop -#undef fRightCrop - -void HBManager::Scanning( char * volume, int title ) -{ - fStatusLock->Lock(); - fStatus.fMode = HB_MODE_SCANNING; - fStatus.fScannedVolume = volume; - fStatus.fScannedTitle = title; - fNeedUpdate = true; - fStatusLock->Unlock(); -} - -void HBManager::ScanDone( HBList * titleList ) -{ - fStatus.fTitleList = titleList;; - fStopScan = true; -} - -/* Called by the DVD reader */ -void HBManager::Done() -{ - fRipDone = true; -} - -void HBManager::Error( HBError error ) -{ - if( fStatus.fMode != HB_MODE_ENCODING ) - { - return; - } - - fStatus.fError = error; - fError = true; -} - -void HBManager::SetPosition( float pos ) -{ - if( !fStatus.fStartDate ) - { - fStatus.fStartDate = GetDate(); - } - - fStatus.fFrames++; - - if( ( pos - fStatus.fPosition ) * 10000 < 1 ) - { - return; - } - - fStatusLock->Lock(); - fStatus.fPosition = pos; - fStatus.fFrameRate = (float) fStatus.fFrames / - ( ( (float) ( GetDate() - fStatus.fStartDate ) ) / 1000000 ) ; - fStatus.fRemainingTime = - (uint32_t) ( (float) ( GetDate() - fStatus.fStartDate ) * - ( 1 - fStatus.fPosition ) / - ( 1000000 * fStatus.fPosition ) ); - fNeedUpdate = true; - fStatusLock->Unlock(); -} - diff --git a/core/Manager.h b/core/Manager.h deleted file mode 100644 index dc885e5f5..000000000 --- a/core/Manager.h +++ /dev/null @@ -1,64 +0,0 @@ -/* $Id: Manager.h,v 1.32 2003/10/08 22:20:36 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MANAGER_H -#define HB_MANAGER_H - -#include "Common.h" -#include "Thread.h" - -class HBManager : public HBThread -{ - public: - HBManager( bool debug = false, - int cpuCount = 0 ); - ~HBManager(); - void DoWork(); - - /* Methods called by the interface */ - bool NeedUpdate(); - HBStatus GetStatus(); - void ScanVolumes( char * device ); - void StartRip( HBTitle * title, HBAudio * audio1, - HBAudio * audio2, char * file ); - void SuspendRip(); - void ResumeRip(); - void StopRip(); - uint8_t * GetPreview( HBTitle * title, uint32_t image ); - - /* Methods called by the working threads */ - void Scanning( char * volume, int title ); - void ScanDone( HBList * titleList ); - void Done(); - void Error( HBError error ); - void SetPosition( float pos ); - - private: - void FixPictureSettings( HBTitle * title ); - - int fPid; - int fCPUCount; - - /* Booleans used in DoWork() */ - bool fStopScan; - volatile bool fStopRip; - bool fRipDone; - bool fError; - - /* Scanner thread */ - HBScanner * fScanner; - - /* Status infos */ - HBLock * fStatusLock; - bool fNeedUpdate; - HBStatus fStatus; - - HBTitle * fCurTitle; - HBAudio * fCurAudio1; - HBAudio * fCurAudio2; -}; - -#endif diff --git a/core/Mp3Enc.c b/core/Mp3Enc.c new file mode 100644 index 000000000..70693467f --- /dev/null +++ b/core/Mp3Enc.c @@ -0,0 +1,281 @@ +/* $Id: Mp3Enc.c,v 1.5 2003/11/07 21:52:57 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 <lame/lame.h> + +/* Local prototypes */ +static int Mp3EncWork( HBWork * ); +static int GetBytes( HBMp3Enc * ); + +struct HBMp3Enc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBAudio * audio; + lame_global_flags * globalFlags; + HBBuffer * rawBuffer; + int rawBufferPos; + float position; + int samplesNeeded; + int samplesGot; + float * left; + float * right; + HBBuffer * mp3Buffer; +}; + +HBMp3Enc * HBMp3EncInit( HBHandle * handle, HBAudio * audio ) +{ + HBMp3Enc * m; + if( !( m = malloc( sizeof( HBMp3Enc ) ) ) ) + { + HBLog( "HBMp3EncInit: malloc() failed, gonna crash" ); + return NULL; + } + + 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; +} + +void HBMp3EncClose( HBMp3Enc ** _m ) +{ + HBMp3Enc * m = *_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 ); + free( m->name ); + free( m ); + + *_m = NULL; +} + +static int Mp3EncWork( HBWork * w ) +{ + HBMp3Enc * m = (HBMp3Enc*) w; + HBAudio * audio = m->audio; + + HBBuffer * mp3Buffer; + int ret; + + int didSomething = 0; + + if( !m->globalFlags ) + { + int i; + + /* Get a first buffer so we know that audio->inSampleRate is + correct */ + if( ( m->rawBuffer = HBFifoPop( audio->rawFifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + m->rawBufferPos = 0; + m->position = m->rawBuffer->position; + + /* The idea is to have exactly one mp3 frame (i.e. 1152 samples) by + output buffer. As we are resampling from inSampleRate to + 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 / 2; + + HBLog( "HBMp3Enc: opening lame (%d->%d Hz, %d kbps)", + audio->inSampleRate, audio->outSampleRate, + audio->outBitrate ); + m->globalFlags = lame_init(); + lame_set_in_samplerate( m->globalFlags, audio->inSampleRate ); + lame_set_out_samplerate( m->globalFlags, audio->outSampleRate ); + lame_set_brate( m->globalFlags, audio->outBitrate ); + + if( lame_init_params( m->globalFlags ) == -1 ) + { + HBLog( "HBMp3Enc: lame_init_params() failed" ); + HBErrorOccured( m->handle, HB_ERROR_MP3_INIT ); + return didSomething; + } + + m->left = malloc( m->samplesNeeded * sizeof( float ) ); + m->right = malloc( m->samplesNeeded * sizeof( float ) ); + + if( !m->left || !m->right ) + { + HBLog( "HBMp3Enc: malloc() failed, gonna crash" ); + } + + for( i = 0; i < m->samplesNeeded; i++ ) + { + m->left[i] = 0.0; + m->right[i] = 0.0; + } + } + + /* Push encoded buffer */ + if( m->mp3Buffer ) + { + if( HBFifoPush( audio->mp3Fifo, &m->mp3Buffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + /* A/V synchro fix in case audio doesn't start at the same time + than video */ + if( audio->delay > 0 ) + { + /* Audio starts later - insert some silence */ + int length = m->samplesNeeded * 1000 / audio->inSampleRate; + + if( audio->delay > length ) + { + HBLog( "HBMp3Enc: adding %d ms of silence", length ); + m->samplesGot = m->samplesNeeded; + audio->delay -= length; + } + else + { + audio->delay = 0; + } + } + else if( audio->delay < 0 ) + { + /* Audio starts sooner - trash some */ + int length = m->samplesNeeded * 1000 / audio->inSampleRate; + + if( - audio->delay > length ) + { + if( GetBytes( m ) ) + { + didSomething = 1; + HBLog( "HBMp3Enc: trashing %d ms", length ); + m->samplesGot = 0; + audio->delay += length; + return didSomething; + } + else + { + return didSomething; + } + } + else + { + audio->delay = 0; + } + } + + /* Get new samples */ + if( GetBytes( m ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + m->samplesGot = 0; + + mp3Buffer = HBBufferInit( LAME_MAXMP3BUFFER ); + ret = lame_encode_buffer_float( m->globalFlags, m->left, + m->right, m->samplesNeeded, + mp3Buffer->data, + mp3Buffer->size ); + + if( ret < 0 ) + { + /* Error */ + HBLog( "HBMp3Enc: lame_encode_buffer_float() failed (%d)", + ret ); + HBErrorOccured( m->handle, HB_ERROR_MP3_ENCODE ); + HBBufferClose( &mp3Buffer ); + } + else if( ret == 0 ) + { + /* No error, but nothing encoded */ + HBBufferClose( &mp3Buffer ); + } + else + { + /* Encoding was successful */ + mp3Buffer->size = ret; + mp3Buffer->keyFrame = 1; + mp3Buffer->position = m->position; + + m->mp3Buffer = mp3Buffer; + } + + return didSomething; +} + +static int GetBytes( HBMp3Enc * m ) +{ + while( m->samplesGot < m->samplesNeeded ) + { + int i; + + if( !m->rawBuffer ) + { + if( !( m->rawBuffer = HBFifoPop( m->audio->rawFifo ) ) ) + { + return 0; + } + + m->rawBufferPos = 0; + m->position = m->rawBuffer->position; + } + + i = MIN( m->samplesNeeded - m->samplesGot, + ( m->rawBuffer->size / 2 - + m->rawBufferPos ) / sizeof( float ) ); + + memcpy( m->left + m->samplesGot, + m->rawBuffer->data + m->rawBufferPos, + i * sizeof( float ) ); + memcpy( m->right + m->samplesGot, + m->rawBuffer->data + m->rawBuffer->size / 2 + + m->rawBufferPos, + i * sizeof( float ) ); + + m->samplesGot += i; + m->rawBufferPos += i * sizeof( float ); + + if( m->rawBufferPos == m->rawBuffer->size / 2 ) + { + HBBufferClose( &m->rawBuffer ); + } + } + + return 1; +} diff --git a/core/Mp3Enc.h b/core/Mp3Enc.h new file mode 100644 index 000000000..db02f4f44 --- /dev/null +++ b/core/Mp3Enc.h @@ -0,0 +1,15 @@ +/* $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/Mp3Encoder.cpp b/core/Mp3Encoder.cpp deleted file mode 100644 index 96ae8c568..000000000 --- a/core/Mp3Encoder.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* $Id: Mp3Encoder.cpp,v 1.14 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Mp3Encoder.h" -#include "Manager.h" -#include "Fifo.h" - -#include <lame/lame.h> - -HBMp3Encoder::HBMp3Encoder( HBManager * manager, HBAudio * audio ) -{ - fManager = manager; - fAudio = audio; - - fLock = new HBLock(); - fUsed = false; - - fRawBuffer = NULL; - fPosInBuffer = 0; - fSamplesNb = 0; - fLeftSamples = NULL; - fRightSamples = NULL; - - fPosition = 0; - fInitDone = false; - fMp3Buffer = NULL; -} - -bool HBMp3Encoder::Work() -{ - if( !Lock() ) - { - return false; - } - - if( !fInitDone ) - { - /* Wait for a first buffer so we know fAudio->fInSampleRate - is correct */ - if( !fAudio->fRawFifo->Size() ) - { - Unlock(); - return false; - } - - /* The idea is to have exactly one mp3 frame (i.e. 1152 samples) by - output buffer. As we are resampling from fInSampleRate to - fOutSampleRate, we will give ( 1152 * fInSampleRate ) / - ( 2 * fOutSampleRate ) to libmp3lame so we are sure we will - never get more than 1 frame at a time */ - fCount = ( 1152 * fAudio->fInSampleRate ) / - ( 2 * fAudio->fOutSampleRate ); - - /* Init libmp3lame */ - fGlobalFlags = lame_init(); - lame_set_in_samplerate( fGlobalFlags, fAudio->fInSampleRate ); - lame_set_out_samplerate( fGlobalFlags, fAudio->fOutSampleRate ); - lame_set_brate( fGlobalFlags, fAudio->fOutBitrate ); - - if( lame_init_params( fGlobalFlags ) == -1 ) - { - Log( "HBMp3Encoder: lame_init_params() failed" ); - fManager->Error( HB_ERROR_MP3_INIT ); - return false; - } - - fLeftSamples = (float*) malloc( fCount * sizeof( float ) ); - fRightSamples = (float*) malloc( fCount * sizeof( float ) ); - - fInitDone = true; - } - - if( fMp3Buffer ) - { - if( fAudio->fMp3Fifo->Push( fMp3Buffer ) ) - { - fMp3Buffer = NULL; - } - else - { - Unlock(); - return false; - } - } - - /* Get new samples */ - if( GetSamples() ) - { - fSamplesNb = 0; - - fMp3Buffer = new HBBuffer( LAME_MAXMP3BUFFER ); - int ret = lame_encode_buffer_float( fGlobalFlags, fLeftSamples, - fRightSamples, fCount, - fMp3Buffer->fData, - fMp3Buffer->fSize ); - - if( ret < 0 ) - { - Log( "HBMp3Encoder: lame_encode_buffer_float() failed " - "(%d)", ret ); - fManager->Error( HB_ERROR_MP3_ENCODE ); - return false; - } - else if( ret > 0 ) - { - /* We got something, send it to the muxer */ - fMp3Buffer->fSize = ret; - fMp3Buffer->fKeyFrame = true; - fMp3Buffer->fPosition = fPosition; - } - else - { - delete fMp3Buffer; - fMp3Buffer = NULL; - } - } - else - { - Unlock(); - return false; - } - - Unlock(); - return true; -} - -bool HBMp3Encoder::Lock() -{ - fLock->Lock(); - if( fUsed ) - { - fLock->Unlock(); - return false; - } - fUsed = true; - fLock->Unlock(); - return true; -} - -void HBMp3Encoder::Unlock() -{ - fLock->Lock(); - fUsed = false; - fLock->Unlock(); -} - -bool HBMp3Encoder::GetSamples() -{ - while( fSamplesNb < fCount ) - { - if( !fRawBuffer ) - { - if( !( fRawBuffer = fAudio->fRawFifo->Pop() ) ) - { - return false; - } - - fPosInBuffer = 0; - fPosition = fRawBuffer->fPosition; - } - - int willCopy = MIN( fCount - fSamplesNb, 6 * 256 - fPosInBuffer ); - - memcpy( fLeftSamples + fSamplesNb, - (float*) fRawBuffer->fData + fPosInBuffer, - willCopy * sizeof( float ) ); - memcpy( fRightSamples + fSamplesNb, - (float*) fRawBuffer->fData + 6 * 256 + fPosInBuffer, - willCopy * sizeof( float ) ); - - fSamplesNb += willCopy; - fPosInBuffer += willCopy; - - if( fPosInBuffer == 6 * 256 ) - { - delete fRawBuffer; - fRawBuffer = NULL; - } - } - - return true; -} diff --git a/core/Mp3Encoder.h b/core/Mp3Encoder.h deleted file mode 100644 index fb8348961..000000000 --- a/core/Mp3Encoder.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id: Mp3Encoder.h,v 1.9 2003/10/07 22:48:31 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MP3_ENCODER_H -#define HB_MP3_ENCODER_H - -#include "Common.h" - -class HBMp3Encoder -{ - public: - HBMp3Encoder( HBManager * manager, - HBAudio * audio ); - bool Work(); - - private: - bool Lock(); - void Unlock(); - bool GetSamples(); - - HBManager * fManager; - HBAudio * fAudio; - - HBLock * fLock; - bool fUsed; - - HBBuffer * fRawBuffer; - uint32_t fPosInBuffer; /* in samples */ - uint32_t fSamplesNb; - float * fLeftSamples; - float * fRightSamples; - - float fPosition; - lame_global_flags * fGlobalFlags; - bool fInitDone; - HBBuffer * fMp3Buffer; - uint32_t fCount; -}; - -#endif diff --git a/core/Mpeg2Dec.c b/core/Mpeg2Dec.c new file mode 100644 index 000000000..d6ce22b3f --- /dev/null +++ b/core/Mpeg2Dec.c @@ -0,0 +1,195 @@ +/* $Id: Mpeg2Dec.c,v 1.3 2003/11/06 12:33:11 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 <mpeg2dec/mpeg2.h> + +/* Local prototypes */ +static int Mpeg2DecWork( HBWork * ); + +struct HBMpeg2Dec +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBTitle * title; + HBList * rawBufferList; + int pass; + mpeg2dec_t * libmpeg2; + const mpeg2_info_t * info; + int lateField; +}; + +HBMpeg2Dec * HBMpeg2DecInit( HBHandle * handle, HBTitle * title ) +{ + HBMpeg2Dec * m ; + if( !( m = malloc( sizeof( HBMpeg2Dec ) ) ) ) + { + HBLog( "HBMpeg2Dec: malloc() failed, gonna crash" ); + return NULL; + } + + m->name = strdup( "Mpeg2Dec" ); + m->work = Mpeg2DecWork; + + m->handle = handle; + m->title = title; + + m->rawBufferList = HBListInit(); + m->pass = 42; + m->libmpeg2 = NULL; + m->info = NULL; + m->lateField = 0; + + return m; +} + +void HBMpeg2DecClose( HBMpeg2Dec ** _m ) +{ + HBBuffer * buffer; + + HBMpeg2Dec * m = *_m; + + if( m->libmpeg2 ) + { + HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", m->pass ); + mpeg2_close( m->libmpeg2 ); + } + while( ( buffer = HBListItemAt( m->rawBufferList, 0 ) ) ) + { + HBListRemove( m->rawBufferList, buffer ); + HBBufferClose( &buffer ); + } + HBListClose( &m->rawBufferList ); + free( m->name ); + free( m ); + + *_m = NULL; +} + +static int Mpeg2DecWork( HBWork * w ) +{ + HBMpeg2Dec * m = (HBMpeg2Dec*) w; + HBTitle * title = m->title; + HBBuffer * mpeg2Buffer; + HBBuffer * rawBuffer; + HBBuffer * tmpBuffer; + mpeg2_state_t state; + + int didSomething = 0; + + /* Push decoded buffers */ + while( ( rawBuffer = (HBBuffer*) + HBListItemAt( m->rawBufferList, 0 ) ) ) + { + tmpBuffer = rawBuffer; + if( HBFifoPush( title->rawFifo, &rawBuffer ) ) + { + didSomething = 1; + HBListRemove( m->rawBufferList, tmpBuffer ); + } + else + { + return didSomething; + } + } + + /* Get a new buffer to decode */ + if( ( mpeg2Buffer = HBFifoPop( title->mpeg2Fifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + /* Init or re-init if needed */ + if( mpeg2Buffer->pass != m->pass ) + { + if( m->libmpeg2 ) + { + HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", m->pass ); + mpeg2_close( m->libmpeg2 ); + } + + m->pass = mpeg2Buffer->pass; + + HBLog( "HBMpeg2Dec: opening libmpeg2 (pass %d)", m->pass ); + m->libmpeg2 = mpeg2_init(); + m->info = mpeg2_info( m->libmpeg2 ); + m->lateField = 0; + } + + /* Decode */ + mpeg2_buffer( m->libmpeg2, mpeg2Buffer->data, + mpeg2Buffer->data + mpeg2Buffer->size ); + + for( ;; ) + { + state = mpeg2_parse( m->libmpeg2 ); + + if( state == STATE_BUFFER ) + { + break; + } + else if( ( state == STATE_SLICE || state == STATE_END ) && + m->info->display_fbuf ) + { + rawBuffer = HBBufferInit( 3 * title->inWidth * + title->outWidth ); + + /* TODO: make libmpeg2 write directly in our buffer */ + memcpy( rawBuffer->data, m->info->display_fbuf->buf[0], + title->inWidth * title->inHeight ); + memcpy( rawBuffer->data + title->inWidth * title->inHeight, + m->info->display_fbuf->buf[1], + title->inWidth * title->inHeight / 4 ); + memcpy( rawBuffer->data + title->inWidth * title->inHeight + + title->inWidth * title->inHeight / 4, + m->info->display_fbuf->buf[2], + title->inWidth * title->inHeight / 4 ); + + rawBuffer->position = mpeg2Buffer->position; + rawBuffer->pass = mpeg2Buffer->pass; + + HBListAdd( m->rawBufferList, rawBuffer ); + + /* 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; + tmpBuffer->last = rawBuffer->last; + memcpy( tmpBuffer->data, rawBuffer->data, + tmpBuffer->size ); + HBListAdd( m->rawBufferList, tmpBuffer ); + } + m->lateField = !m->lateField; + } + } + else if( state == STATE_INVALID ) + { + /* Shouldn't happen on a DVD */ + HBLog( "HBMpeg2Dec: STATE_INVALID" ); + } + } + + if( mpeg2Buffer->last ) + { + HBDone( m->handle ); + } + + HBBufferClose( &mpeg2Buffer ); + + return didSomething; +} diff --git a/core/Mpeg2Dec.h b/core/Mpeg2Dec.h new file mode 100644 index 000000000..af7f18c44 --- /dev/null +++ b/core/Mpeg2Dec.h @@ -0,0 +1,15 @@ +/* $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/Mpeg2Decoder.cpp b/core/Mpeg2Decoder.cpp deleted file mode 100644 index a9b6a5373..000000000 --- a/core/Mpeg2Decoder.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* $Id: Mpeg2Decoder.cpp,v 1.22 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Mpeg2Decoder.h" -#include "Manager.h" -#include "Fifo.h" - -extern "C" { -#include <mpeg2dec/mpeg2.h> -} -#include <ffmpeg/avcodec.h> - -HBMpeg2Decoder::HBMpeg2Decoder( HBManager * manager, HBTitle * title ) -{ - fManager = manager; - fTitle = title; - - fLock = new HBLock(); - fUsed = false; - - fPass = 42; - fRawBuffer = NULL; - fRawBufferList = new HBList(); - fHandle = NULL; -} - -bool HBMpeg2Decoder::Work() -{ - if( !Lock() ) - { - return false; - } - - /* Push decoded buffers */ - while( ( fRawBuffer = - (HBBuffer*) fRawBufferList->ItemAt( 0 ) ) ) - { - if( fTitle->fRawFifo->Push( fRawBuffer ) ) - { - fRawBufferList->RemoveItem( fRawBuffer ); - } - else - { - Unlock(); - return false; - } - } - - /* Get a new buffer to decode */ - if( ( fMpeg2Buffer = fTitle->fMpeg2Fifo->Pop() ) ) - { - /* (Re)init if needed */ - if( fMpeg2Buffer->fPass != fPass ) - { - fPass = fMpeg2Buffer->fPass; - Init(); - } - - /* Do the job */ - DecodeBuffer(); - } - else - { - Unlock(); - return false; - } - - Unlock(); - return true; -} - -bool HBMpeg2Decoder::Lock() -{ - fLock->Lock(); - if( fUsed ) - { - fLock->Unlock(); - return false; - } - fUsed = true; - fLock->Unlock(); - return true; -} - -void HBMpeg2Decoder::Unlock() -{ - fLock->Lock(); - fUsed = false; - fLock->Unlock(); -} - -void HBMpeg2Decoder::Init() -{ - if( fHandle ) - { - mpeg2_close( fHandle ); - } - - fLateField = false; - - fHandle = mpeg2_init(); -} - -void HBMpeg2Decoder::DecodeBuffer() -{ - const mpeg2_info_t * info = mpeg2_info( fHandle ); - - /* Feed libmpeg2 */ - mpeg2_buffer( fHandle, fMpeg2Buffer->fData, - fMpeg2Buffer->fData + fMpeg2Buffer->fSize ); - - mpeg2_state_t state; - for( ;; ) - { - state = mpeg2_parse( fHandle ); - - if( state == STATE_BUFFER ) - { - break; - } - else if( ( state == STATE_SLICE || state == STATE_END ) && - info->display_fbuf ) - { - fRawBuffer = new HBBuffer( 3 * fTitle->fInWidth * - fTitle->fInHeight / 2 ); - - /* TODO : make libmpeg2 write directly in our buffer */ - memcpy( fRawBuffer->fData, - info->display_fbuf->buf[0], - fTitle->fInWidth * fTitle->fInHeight ); - memcpy( fRawBuffer->fData + fTitle->fInWidth * - fTitle->fInHeight, - info->display_fbuf->buf[1], - fTitle->fInWidth * fTitle->fInHeight / 4 ); - memcpy( fRawBuffer->fData + fTitle->fInWidth * - fTitle->fInHeight + fTitle->fInWidth * - fTitle->fInHeight / 4, - info->display_fbuf->buf[2], - fTitle->fInWidth * fTitle->fInHeight / 4 ); - - fRawBuffer->fPosition = fMpeg2Buffer->fPosition; - fRawBuffer->fPass = fMpeg2Buffer->fPass; - - fRawBufferList->AddItem( fRawBuffer ); - - /* NTSC pulldown kludge */ - if( info->display_picture->nb_fields == 3 ) - { - if( fLateField ) - { - HBBuffer * pulldownBuffer; - pulldownBuffer = new HBBuffer( fRawBuffer->fSize ); - pulldownBuffer->fPosition = fRawBuffer->fPosition; - pulldownBuffer->fPass = fRawBuffer->fPass; - memcpy( pulldownBuffer->fData, fRawBuffer->fData, - pulldownBuffer->fSize ); - fRawBufferList->AddItem( pulldownBuffer ); - } - fLateField = !fLateField; - } - } - else if( state == STATE_INVALID ) - { - /* Shouldn't happen on a DVD */ - Log( "HBMpeg2Decoder: STATE_INVALID" ); - } - } - - delete fMpeg2Buffer; - fMpeg2Buffer = NULL; -} - diff --git a/core/Mpeg2Decoder.h b/core/Mpeg2Decoder.h deleted file mode 100644 index 6e20509a2..000000000 --- a/core/Mpeg2Decoder.h +++ /dev/null @@ -1,40 +0,0 @@ -/* $Id: Mpeg2Decoder.h,v 1.16 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MPEG2_DECODER_H -#define HB_MPEG2_DECODER_H - -#include "Common.h" - -class HBMpeg2Decoder -{ - public: - HBMpeg2Decoder( HBManager * manager, - HBTitle * title ); - bool Work(); - - private: - bool Lock(); - void Unlock(); - - void Init(); - void DecodeBuffer(); - - HBManager * fManager; - HBTitle * fTitle; - - HBLock * fLock; - bool fUsed; - - uint32_t fPass; - HBBuffer * fMpeg2Buffer; - HBBuffer * fRawBuffer; - HBList * fRawBufferList; - mpeg2dec_t * fHandle; - bool fLateField; -}; - -#endif diff --git a/core/Mpeg4Encoder.cpp b/core/Mpeg4Encoder.cpp deleted file mode 100644 index bf5821a4c..000000000 --- a/core/Mpeg4Encoder.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* $Id: Mpeg4Encoder.cpp,v 1.25 2003/10/14 15:23:56 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Mpeg4Encoder.h" -#include "Manager.h" -#include "Fifo.h" - -#include <ffmpeg/avcodec.h> - -HBMpeg4Encoder::HBMpeg4Encoder( HBManager * manager, HBTitle * title ) -{ - fManager = manager; - fTitle = title; - - fLock = new HBLock(); - fUsed = false; - - fPass = 42; - fMpeg4Buffer = NULL; - fFile = NULL; - fFrame = avcodec_alloc_frame(); - fLog = NULL; -} - -bool HBMpeg4Encoder::Work() -{ - if( !Lock() ) - { - return false; - } - - if( fMpeg4Buffer ) - { - if( fTitle->fMpeg4Fifo->Push( fMpeg4Buffer ) ) - { - fMpeg4Buffer = NULL; - } - else - { - Unlock(); - return false; - } - } - - if( ( fResizedBuffer = fTitle->fResizedFifo->Pop() ) ) - { - if( fResizedBuffer->fPass != fPass ) - { - fPass = fResizedBuffer->fPass; - Init(); - } - - fManager->SetPosition( fResizedBuffer->fPosition ); - EncodeBuffer(); - } - else - { - Unlock(); - return false; - } - - Unlock(); - return true; -} - -bool HBMpeg4Encoder::Lock() -{ - fLock->Lock(); - if( fUsed ) - { - fLock->Unlock(); - return false; - } - fUsed = true; - fLock->Unlock(); - return true; -} - -void HBMpeg4Encoder::Unlock() -{ - fLock->Lock(); - fUsed = false; - fLock->Unlock(); -} - -void HBMpeg4Encoder::Init() -{ - /* Clean up if needed */ - if( fFile ) - { - fclose( fFile ); - } - - AVCodec * codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); - if( !codec ) - { - Log( "HBMpeg4Encoder: avcodec_find_encoder() failed" ); - fManager->Error( HB_ERROR_MPEG4_INIT ); - return; - } - - fContext = avcodec_alloc_context(); - fContext->bit_rate = 1024 * fTitle->fBitrate; - fContext->bit_rate_tolerance = 10240 * fTitle->fBitrate; - fContext->width = fTitle->fOutWidth; - fContext->height = fTitle->fOutHeight; - fContext->frame_rate = fTitle->fRate; - fContext->frame_rate_base = fTitle->fScale; - fContext->gop_size = 10 * fTitle->fRate / fTitle->fScale; - - if( fPass == 1 ) - { - fContext->flags |= CODEC_FLAG_PASS1; - - char fileName[1024]; memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", fManager->GetPid() ); - fFile = fopen( fileName, "w" ); - } - else if( fPass == 2 ) - { - fContext->flags |= CODEC_FLAG_PASS2; - - char fileName[1024]; memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", fManager->GetPid() ); - fFile = fopen( fileName, "r" ); - fseek( fFile, 0, SEEK_END ); - uint32_t size = ftell( fFile ); - fLog = (char*) malloc( size + 1 ); - fseek( fFile, 0, SEEK_SET ); - fread( fLog, size, 1, fFile ); - fclose( fFile ); - fLog[size] = '\0'; - fContext->stats_in = fLog; - } - - if( avcodec_open( fContext, codec ) < 0 ) - { - Log( "HBMpeg4Encoder: avcodec_open() failed" ); - fManager->Error( HB_ERROR_MPEG4_INIT ); - return; - } -} - -void HBMpeg4Encoder::EncodeBuffer() -{ - fFrame->data[0] = fResizedBuffer->fData; - fFrame->data[1] = fFrame->data[0] + fTitle->fOutWidth * - fTitle->fOutHeight; - fFrame->data[2] = fFrame->data[1] + fTitle->fOutWidth * - fTitle->fOutHeight / 4; - fFrame->linesize[0] = fTitle->fOutWidth; - fFrame->linesize[1] = fTitle->fOutWidth / 2; - fFrame->linesize[2] = fTitle->fOutWidth / 2; - - fMpeg4Buffer = new HBBuffer( 3 * fTitle->fOutWidth * - fTitle->fOutHeight / 2 ); - /* Should be really too much... */ - - fMpeg4Buffer->fPosition = fResizedBuffer->fPosition; - fMpeg4Buffer->fSize = - avcodec_encode_video( fContext, fMpeg4Buffer->fData, - fMpeg4Buffer->fAllocSize, fFrame ); - fMpeg4Buffer->fKeyFrame = ( fContext->coded_frame->key_frame != 0 ); - - if( fResizedBuffer->fPass == 1 ) - { - if( fContext->stats_out ) - { - fprintf( fFile, "%s", fContext->stats_out ); - } - delete fMpeg4Buffer; - fMpeg4Buffer = NULL; - } - - delete fResizedBuffer; - fResizedBuffer = NULL; -} - diff --git a/core/Mpeg4Encoder.h b/core/Mpeg4Encoder.h deleted file mode 100644 index 3d20f315a..000000000 --- a/core/Mpeg4Encoder.h +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id: Mpeg4Encoder.h,v 1.11 2003/10/08 11:56:40 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MPEG4_ENCODER_H -#define HB_MPEG4_ENCODER_H - -#include "Common.h" - -class HBMpeg4Encoder -{ - public: - HBMpeg4Encoder( HBManager * manager, - HBTitle * title ); - bool Work(); - - private: - bool Lock(); - void Unlock(); - - void Init(); - void EncodeBuffer(); - - HBManager * fManager; - HBTitle * fTitle; - - HBLock * fLock; - bool fUsed; - - uint32_t fPass; - HBBuffer * fResizedBuffer; - AVCodecContext * fContext; - AVFrame * fFrame; - FILE * fFile; - char * fLog; - HBBuffer * fMpeg4Buffer; -}; - -#endif diff --git a/core/MpegDemux.cpp b/core/MpegDemux.cpp deleted file mode 100644 index 249ee2738..000000000 --- a/core/MpegDemux.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/* $Id: MpegDemux.cpp,v 1.20 2003/10/16 13:36:17 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "MpegDemux.h" -#include "Manager.h" -#include "Fifo.h" - -extern "C" { -#include <a52dec/a52.h> -} - -HBMpegDemux::HBMpegDemux( HBManager * manager, HBTitle * title, - HBAudio * audio1, HBAudio * audio2 ) -{ - fManager = manager; - fTitle = title; - fAudio1 = audio1; - fAudio2 = audio2; - - fLock = new HBLock(); - fUsed = false; - - fPSBuffer = NULL; - fESBuffer = NULL; - fESBufferList = NULL; - - fFirstVideoPTS = -1; - fFirstAudio1PTS = -1; - fFirstAudio2PTS = -1; -} - -HBMpegDemux::~HBMpegDemux() -{ - /* Free memory */ - if( fESBufferList ) - { - while( ( fESBuffer = (HBBuffer*) fESBufferList->ItemAt( 0 ) ) ) - { - fESBufferList->RemoveItem( fESBuffer ); - delete fESBuffer; - } - } - delete fLock; -} - -bool HBMpegDemux::Work() -{ - if( !Lock() ) - { - return false; - } - - /* Push waiting buffers */ - if( fESBufferList ) - { - for( uint32_t i = 0; i < fESBufferList->CountItems(); ) - { - fESBuffer = (HBBuffer*) fESBufferList->ItemAt( i ); - - if( fESBuffer->fPass == 1 && fESBuffer->fStreamId != 0xE0 ) - { - fESBufferList->RemoveItem( fESBuffer ); - delete fESBuffer; - continue; - } - - /* Look for a decoder for this ES */ - - if( fESBuffer->fStreamId == 0xE0 ) - { - if( fFirstVideoPTS < 0 ) - { - fFirstVideoPTS = fESBuffer->fPTS; - Log( "HBMpegDemux: got first 0xE0 packet (%lld)", - fFirstVideoPTS ); - } - if( fTitle->fMpeg2Fifo->Push( fESBuffer ) ) - { - fESBufferList->RemoveItem( fESBuffer ); - } - else - { - i++; - } - } - else if( fAudio1 && - fESBuffer->fStreamId == fAudio1->fId ) - { - if( fFirstAudio1PTS < 0 ) - { - fFirstAudio1PTS = fESBuffer->fPTS; - Log( "HBMpegDemux: got first 0x%x packet (%lld)", - fAudio1->fId, fFirstAudio1PTS ); - - fAudio1->fDelay = - ( fFirstAudio1PTS - fFirstVideoPTS ) / 90; - } - if( fAudio1->fAc3Fifo->Push( fESBuffer ) ) - { - fESBufferList->RemoveItem( fESBuffer ); - } - else - { - i++; - } - } - else if( fAudio2 && - fESBuffer->fStreamId == fAudio2->fId ) - { - if( fFirstAudio2PTS < 0 ) - { - fFirstAudio2PTS = fESBuffer->fPTS; - Log( "HBMpegDemux: got first 0x%x packet (%lld)", - fAudio2->fId, fFirstAudio2PTS ); - - fAudio2->fDelay = - ( fFirstAudio2PTS - fFirstVideoPTS ) / 90; - } - if( fAudio2->fAc3Fifo->Push( fESBuffer ) ) - { - fESBufferList->RemoveItem( fESBuffer ); - } - else - { - i++; - } - } - else - { - fESBufferList->RemoveItem( fESBuffer ); - delete fESBuffer; - } - } - - if( !fESBufferList->CountItems() ) - { - delete fESBufferList; - fESBufferList = NULL; - } - else - { - Unlock(); - return false; - } - } - - /* Get a PS packet */ - if( ( fPSBuffer = fTitle->fPSFifo->Pop() ) ) - { - /* Get the ES data in it */ - PStoES( fPSBuffer, &fESBufferList ); - } - else - { - Unlock(); - return false; - } - - Unlock(); - return true; -} - -bool HBMpegDemux::Lock() -{ - fLock->Lock(); - if( fUsed ) - { - fLock->Unlock(); - return false; - } - fUsed = true; - fLock->Unlock(); - return true; -} - -void HBMpegDemux::Unlock() -{ - fLock->Lock(); - fUsed = false; - fLock->Unlock(); -} - -bool PStoES( HBBuffer * psBuffer, HBList ** _esBufferList ) -{ -#define psData (psBuffer->fData) - - uint32_t pos = 0; - - /* pack_header */ - if( psData[pos] != 0 || psData[pos+1] != 0 || - psData[pos+2] != 0x1 || psData[pos+3] != 0xBA ) - { - Log( "PStoES: not a PS packet (%02x%02x%02x%02x)", - psData[pos] << 24, psData[pos+1] << 16, - psData[pos+2] << 8, psData[pos+3] ); - delete psBuffer; - (*_esBufferList) = NULL; - return false; - } - pos += 4; /* pack_start_code */ - pos += 9; /* pack_header */ - pos += 1 + ( psData[pos] & 0x7 ); /* stuffing bytes */ - - /* system_header */ - if( psData[pos] == 0 && psData[pos+1] == 0 && - psData[pos+2] == 0x1 && psData[pos+3] == 0xBB ) - { - uint32_t header_length; - - pos += 4; /* system_header_start_code */ - header_length = ( psData[pos] << 8 ) + psData[pos+1]; - pos += 2 + header_length; - } - - HBList * esBufferList = new HBList(); - HBBuffer * esBuffer; - - /* PES */ - while( pos + 6 < psBuffer->fSize && - psData[pos] == 0 && psData[pos+1] == 0 && psData[pos+2] == 0x1 ) - { - uint32_t streamId; - uint32_t PES_packet_length; - uint32_t PES_packet_end; - uint32_t PES_header_data_length; - uint32_t PES_header_end; - bool hasPTS; - uint64_t PTS = 0; - - pos += 3; /* packet_start_code_prefix */ - streamId = psData[pos]; - pos += 1; - - PES_packet_length = ( psData[pos] << 8 ) + psData[pos+1]; - pos += 2; /* PES_packet_length */ - PES_packet_end = pos + PES_packet_length; - - if( streamId != 0xE0 && streamId != 0xBD ) - { - /* Not interesting */ - pos = PES_packet_end; - continue; - } - - hasPTS = ( ( psData[pos+1] >> 6 ) & 0x2 ); - pos += 2; /* Required headers */ - - PES_header_data_length = psData[pos]; - pos += 1; - PES_header_end = pos + PES_header_data_length; - - if( hasPTS ) - { - PTS = ( ( ( (uint64_t) psData[pos] >> 1 ) & 0x7 ) << 30 ) + - ( psData[pos+1] << 22 ) + - ( ( psData[pos+2] >> 1 ) << 15 ) + - ( psData[pos+3] << 7 ) + - ( psData[pos+4] >> 1 ); - } - - pos = PES_header_end; - - if( streamId == 0xBD ) - { - /* A52: don't ask */ - streamId |= ( psData[pos] << 8 ); - pos += 4; - } - - /* Sanity check */ - if( pos >= PES_packet_end ) - { - Log( "PStoES: pos >= PES_packet_end" ); - pos = PES_packet_end; - continue; - } - - /* Here we hit we ES payload */ - esBuffer = new HBBuffer( PES_packet_end - pos ); - - esBuffer->fPosition = psBuffer->fPosition; - esBuffer->fPass = psBuffer->fPass; - esBuffer->fStreamId = streamId; - esBuffer->fPTS = PTS; - memcpy( esBuffer->fData, psBuffer->fData + pos, - PES_packet_end - pos ); - - esBufferList->AddItem( esBuffer ); - - pos = PES_packet_end; - } - - delete psBuffer; - - if( !esBufferList->CountItems() ) - { - delete esBufferList; - esBufferList = NULL; - } - - (*_esBufferList) = esBufferList; - return true; - -#undef psData -} diff --git a/core/MpegDemux.h b/core/MpegDemux.h deleted file mode 100644 index 187a08de9..000000000 --- a/core/MpegDemux.h +++ /dev/null @@ -1,43 +0,0 @@ -/* $Id: MpegDemux.h,v 1.11 2003/10/09 13:24:48 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MPEG_DEMUX_H -#define HB_MPEG_DEMUX_H - -#include "Common.h" - -bool PStoES( HBBuffer * psBuffer, HBList ** _esBufferList ); - -class HBMpegDemux -{ - public: - HBMpegDemux( HBManager * manager, HBTitle * title, - HBAudio * audio1, HBAudio * audio2 ); - ~HBMpegDemux(); - bool Work(); - - private: - bool Lock(); - void Unlock(); - - HBManager * fManager; - HBTitle * fTitle; - HBAudio * fAudio1; - HBAudio * fAudio2; - - HBLock * fLock; - bool fUsed; - - HBBuffer * fPSBuffer; - HBBuffer * fESBuffer; - HBList * fESBufferList; - - int64_t fFirstVideoPTS; - int64_t fFirstAudio1PTS; - int64_t fFirstAudio2PTS; -}; - -#endif diff --git a/core/Resizer.cpp b/core/Resizer.cpp deleted file mode 100644 index c49a39bf3..000000000 --- a/core/Resizer.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* $Id: Resizer.cpp,v 1.9 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Resizer.h" -#include "Manager.h" -#include "Fifo.h" - -#include <ffmpeg/avcodec.h> - -HBResizer::HBResizer( HBManager * manager, HBTitle * title ) -{ - fManager = manager; - fTitle = title; - - /* Lock */ - fLock = new HBLock(); - fUsed = false; - - /* Init libavcodec */ - fResampleContext = - img_resample_full_init( fTitle->fOutWidth, fTitle->fOutHeight, - fTitle->fInWidth, fTitle->fInHeight, - fTitle->fTopCrop, fTitle->fBottomCrop, - fTitle->fLeftCrop, fTitle->fRightCrop ); - - /* Buffers & pictures */ - fRawBuffer = NULL; - fDeinterlacedBuffer = new HBBuffer( 3 * fTitle->fInWidth * - fTitle->fInHeight / 2 ); - fResizedBuffer = NULL; - fRawPicture = (AVPicture*) malloc( sizeof( AVPicture ) ); - fDeinterlacedPicture = (AVPicture*) malloc( sizeof( AVPicture ) ); - fResizedPicture = (AVPicture*) malloc( sizeof( AVPicture ) ); - - avpicture_fill( fDeinterlacedPicture, fDeinterlacedBuffer->fData, - PIX_FMT_YUV420P, fTitle->fInWidth, - fTitle->fInHeight ); -} - -HBResizer::~HBResizer() -{ - /* Free memory */ - free( fResizedPicture ); - free( fDeinterlacedPicture ); - free( fRawPicture ); - if( fResizedBuffer ) delete fResizedBuffer; - delete fDeinterlacedBuffer; - img_resample_close( fResampleContext ); - delete fLock; -} - -bool HBResizer::Work() -{ - if( !Lock() ) - { - return false; - } - - /* Push the latest resized buffer */ - if( fResizedBuffer ) - { - if( fTitle->fResizedFifo->Push( fResizedBuffer ) ) - { - fResizedBuffer = NULL; - } - else - { - Unlock(); - return false; - } - } - - /* Get a new raw picture */ - if( ( fRawBuffer = fTitle->fRawFifo->Pop() ) ) - { - /* Do the job */ - avpicture_fill( fRawPicture, fRawBuffer->fData, - PIX_FMT_YUV420P, fTitle->fInWidth, - fTitle->fInHeight ); - - fResizedBuffer = new HBBuffer( 3 * fTitle->fOutWidth * - fTitle->fOutHeight / 2 ); - fResizedBuffer->fPosition = fRawBuffer->fPosition; - fResizedBuffer->fPass = fRawBuffer->fPass; - avpicture_fill( fResizedPicture, fResizedBuffer->fData, - PIX_FMT_YUV420P, fTitle->fOutWidth, - fTitle->fOutHeight ); - - if( fTitle->fDeinterlace ) - { - avpicture_deinterlace( fDeinterlacedPicture, fRawPicture, - PIX_FMT_YUV420P, - fTitle->fInWidth, - fTitle->fInHeight ); - img_resample( fResampleContext, fResizedPicture, - fDeinterlacedPicture ); - } - else - { - img_resample( fResampleContext, fResizedPicture, - fRawPicture ); - } - delete fRawBuffer; - fRawBuffer = NULL; - } - else - { - Unlock(); - return false; - } - - Unlock(); - return true; -} - -bool HBResizer::Lock() -{ - fLock->Lock(); - if( fUsed ) - { - fLock->Unlock(); - return false; - } - fUsed = true; - fLock->Unlock(); - return true; -} - -void HBResizer::Unlock() -{ - fLock->Lock(); - fUsed = false; - fLock->Unlock(); -} - diff --git a/core/Resizer.h b/core/Resizer.h deleted file mode 100644 index f6d4a4568..000000000 --- a/core/Resizer.h +++ /dev/null @@ -1,38 +0,0 @@ -/* $Id: Resizer.h,v 1.5 2003/10/07 22:48:31 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_RESIZER_H -#define HB_RESIZER_H - -#include "Common.h" - -class HBResizer -{ - public: - HBResizer( HBManager * manager, HBTitle * title ); - ~HBResizer(); - bool Work(); - - private: - bool Lock(); - void Unlock(); - - HBManager * fManager; - HBTitle * fTitle; - - HBLock * fLock; - bool fUsed; - - ImgReSampleContext * fResampleContext; - HBBuffer * fRawBuffer; - HBBuffer * fDeinterlacedBuffer; - HBBuffer * fResizedBuffer; - AVPicture * fRawPicture; - AVPicture * fDeinterlacedPicture; - AVPicture * fResizedPicture; -}; - -#endif diff --git a/core/Scale.c b/core/Scale.c new file mode 100644 index 000000000..7e9295962 --- /dev/null +++ b/core/Scale.c @@ -0,0 +1,139 @@ +/* $Id: Scale.c,v 1.4 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. */ + +#include "Fifo.h" +#include "Scale.h" +#include "Work.h" + +#include <ffmpeg/avcodec.h> + +/* Local prototypes */ +static int ScaleWork( HBWork * ); + +struct HBScale +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBTitle * title; + + ImgReSampleContext * context; + AVPicture rawPicture; + HBBuffer * deintBuffer; + AVPicture deintPicture; + HBBuffer * scaledBuffer; + AVPicture scaledPicture; +}; + +HBScale * HBScaleInit( HBHandle * handle, HBTitle * title ) +{ + HBScale * s; + if( !( s = malloc( sizeof( HBScale ) ) ) ) + { + HBLog( "HBScaleInit: malloc() failed, gonna crash" ); + return NULL; + } + + s->name = strdup( "Scale" ); + s->work = ScaleWork; + + s->handle = handle; + s->title = title; + + /* Init libavcodec */ + s->context = + img_resample_full_init( title->outWidth, title->outHeight, + title->inWidth, title->inHeight, + title->topCrop, title->bottomCrop, + title->leftCrop, title->rightCrop ); + + /* Allocate a constant buffer used for deinterlacing */ + 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; + + return s; +} + +void HBScaleClose( HBScale ** _s ) +{ + HBScale * s = *_s; + + img_resample_close( s->context ); + HBBufferClose( &s->deintBuffer ); + free( s->name ); + free( s ); + + *_s = NULL; +} + +static int ScaleWork( HBWork * w ) +{ + HBScale * s = (HBScale*) w; + HBTitle * title = s->title; + HBBuffer * rawBuffer; + + int didSomething = 0; + + /* Push scaled buffer */ + if( s->scaledBuffer ) + { + if( HBFifoPush( title->scaledFifo, &s->scaledBuffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + /* Get a new raw picture */ + if( ( rawBuffer = HBFifoPop( title->rawFifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + /* 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; + + /* libavcodec stuff */ + avpicture_fill( &s->rawPicture, rawBuffer->data, PIX_FMT_YUV420P, + title->inWidth, title->inHeight ); + avpicture_fill( &s->scaledPicture, s->scaledBuffer->data, + PIX_FMT_YUV420P, title->outWidth, + title->outHeight ); + + /* Do the job */ + if( title->deinterlace ) + { + avpicture_deinterlace( &s->deintPicture, &s->rawPicture, + PIX_FMT_YUV420P, title->inWidth, + title->inHeight ); + img_resample( s->context, &s->scaledPicture, + &s->deintPicture ); + } + else + { + img_resample( s->context, &s->scaledPicture, &s->rawPicture ); + } + + /* Free memory */ + HBBufferClose( &rawBuffer ); + + return didSomething; +} + diff --git a/core/Scale.h b/core/Scale.h new file mode 100644 index 000000000..cf06ad661 --- /dev/null +++ b/core/Scale.h @@ -0,0 +1,15 @@ +/* $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 new file mode 100644 index 000000000..83f2fc098 --- /dev/null +++ b/core/Scan.c @@ -0,0 +1,395 @@ +/* $Id: Scan.c,v 1.4 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. */ + +#include "Fifo.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 <mpeg2dec/mpeg2.h> + +/* Local prototypes */ +static void ScanThread( void * ); +static HBTitle * ScanTitle( HBScan *, dvdplay_ptr vmg, int index ); +static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, + HBTitle * title, int which ); +static char * LanguageForCode( int code ); + +struct HBScan +{ + HBHandle * handle; + char * device; + int title; + int die; + HBThread * thread; +}; + +HBScan * HBScanInit( HBHandle * handle, char * device, int title ) +{ + HBScan * s; + if( !( s = malloc( sizeof( HBScan ) ) ) ) + { + HBLog( "HBScanInit: malloc() failed, gonna crash" ); + return NULL; + } + + s->handle = handle; + s->device = strdup( device ); + s->title = title; + s->die = 0; + s->thread = HBThreadInit( "scan", ScanThread, s, + HB_NORMAL_PRIORITY ); + + return s; +} + +void HBScanClose( HBScan ** _s ) +{ + HBScan * s = *_s; + + s->die = 1; + HBThreadClose( &s->thread ); + + free( s->device ); + free( s ); + *_s = NULL; +} + +static void ScanThread( void * _s ) +{ + 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 ); + return; + } + + /* Detect titles */ + for( i = ( s->title ? s->title - 1 : 0 ); + i < ( s->title ? s->title : dvdplay_title_nr( vmg ) ); + i++ ) + { + if( s->die ) + { + break; + } + + if( !( title = ScanTitle( s, vmg, i + 1 ) ) ) + { + continue; + } + + HBListAdd( titleList, title ); + } + + HBLog( "HBScan: closing device %s", s->device ); + dvdplay_close( vmg ); + + HBScanDone( s->handle, titleList ); +} + +static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) +{ + 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 ); + + 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 ); + + /* Discard titles under 10 seconds */ + if( title->length < 10 ) + { + HBLog( "HBScan: ignoring title %d (too short)", index ); + HBTitleClose( &title ); + return NULL; + } + + /* Detect languages */ + dvdplay_audio_info( vmg, &audio_nr, &foo ); + + for( i = 0; i < audio_nr; i++ ) + { + int id; + int j; + + if( s->die ) + { + break; + } + + id = dvdplay_audio_id( vmg, i ); + + if( id < 1 ) + { + continue; + } + + if( ( id & 0xFF ) != 0xBD ) + { + HBLog( "HBScan: non-AC3 audio track detected, ignoring" ); + continue; + } + + /* Check if we don't already found an track with the same id */ + audio = NULL; + for( j = 0; j < HBListCountItems( title->audioList ); j++ ) + { + audio = (HBAudio*) HBListItemAt( title->audioList, j ); + if( id == audio->id ) + { + break; + } + else + { + audio = NULL; + } + } + + if( audio ) + { + HBLog( "HBScan: discarding duplicate track %x", id ); + continue; + } + + attr = dvdplay_audio_attr( vmg, j ); + audio = HBAudioInit( id, LanguageForCode( attr->lang_code ) ); + HBLog( "HBScan: new language (%x, %s)", id, audio->language ); + HBListAdd( title->audioList, audio ); + } + + /* Discard titles with no audio tracks */ + if( !HBListCountItems( 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 */ + dvdplay_read( vmg, dummy, 1 ); + + + for( i = 0; i < 10; i++ ) + { + if( s->die ) + { + break; + } + + if( !DecodeFrame( s, vmg, title, i ) ) + { + HBLog( "HBScan: ignoring title %d (could not decode)", + index ); + HBTitleClose( &title ); + return NULL; + } + } + + if( title->inHeight * title->aspect > + title->inWidth * VOUT_ASPECT_FACTOR ) + { + title->outWidthMax = title->inWidth; + title->outHeightMax = MULTIPLE_16( (uint64_t)title->inWidth * + VOUT_ASPECT_FACTOR / title->aspect ); + } + else + { + title->outWidthMax = MULTIPLE_16( (uint64_t)title->inHeight * + title->aspect / VOUT_ASPECT_FACTOR ); + title->outHeightMax = title->inHeight; + } + + /* Default picture size */ + title->outWidth = title->outWidthMax; + title->outHeight = title->outHeightMax; + + return title; +} + +static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, + HBTitle * title, int which ) +{ + int titleFirst = dvdplay_title_first( vmg ); + int titleEnd = dvdplay_title_end( vmg ); + int pictureStart = ( which + 1 ) * ( titleEnd - titleFirst ) / 11; + int pictureEnd = titleFirst + ( which + 2 ) * + ( titleEnd - titleFirst ) / 11; + + mpeg2dec_t * handle; + const mpeg2_info_t * info; + mpeg2_state_t state; + char fileName[1024]; + FILE * file; + + HBList * esBufferList = HBListInit(); + HBBuffer * psBuffer = NULL; + HBBuffer * esBuffer = NULL; + + /* Seek to the right place */ + dvdplay_seek( vmg, pictureStart ); + + /* Init libmpeg2 */ + 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 ), + 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 ) ) + { + psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); + if( dvdplay_read( vmg, psBuffer->data, 1 ) != 1 || + !HBPStoES( &psBuffer, esBufferList ) ) + { + HBLog( "HBScan: failed to get a valid PS " + "packet" ); + CLEANUP; + return 0; + } + + if( dvdplay_position( vmg ) >= pictureEnd ) + { + HBLog( "HBScan: gone too far, aborting" ); + CLEANUP; + return 0; + } + } + + esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ); + HBListRemove( esBufferList, esBuffer ); + + if( esBuffer->streamId != 0xE0 ) + { + HBBufferClose( &esBuffer ); + } + } + + /* 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; + } + else if( ( state == STATE_SLICE || state == STATE_END ) && + ( info->display_fbuf ) && + ( info->display_picture->flags & PIC_MASK_CODING_TYPE ) + == PIC_FLAG_CODING_TYPE_I ) + { + /* Write the raw picture to a file */ + fwrite( info->display_fbuf->buf[0], + title->inWidth * title->inHeight, 1, file ); + fwrite( info->display_fbuf->buf[1], + title->inWidth * title->inHeight / 4, 1, file ); + fwrite( info->display_fbuf->buf[2], + title->inWidth * title->inHeight / 4, 1, file ); + break; + } + else if( state == STATE_INVALID ) + { + /* Reset libmpeg2 */ + mpeg2_close( handle ); + handle = mpeg2_init(); + } + } + + CLEANUP; + + return 1; + +#undef CLEANUP +} + +static char * LanguageForCode( int code ) +{ + char codeString[2]; + iso639_lang_t * lang; + + codeString[0] = ( code >> 8 ) & 0xFF; + codeString[1] = code & 0xFF; + + for( lang = languages; lang->engName; lang++ ) + { + if( !strncmp( lang->iso639_1, codeString, 2 ) ) + { + if( *lang->nativeName ) + { + return lang->nativeName; + } + + return lang->engName; + } + } + + return "Unknown"; +} + diff --git a/core/Scan.h b/core/Scan.h new file mode 100644 index 000000000..5cc8542e7 --- /dev/null +++ b/core/Scan.h @@ -0,0 +1,15 @@ +/* $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/Scanner.cpp b/core/Scanner.cpp deleted file mode 100644 index 44ff6be3a..000000000 --- a/core/Scanner.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/* $Id: Scanner.cpp,v 1.23 2003/10/13 14:12:18 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Scanner.h" -#include "Manager.h" -#include "Fifo.h" -#include "MpegDemux.h" - -#include <dvdread/ifo_types.h> -#include <dvdplay/dvdplay.h> -#include <dvdplay/info.h> -#include <dvdplay/state.h> -#include <dvdplay/nav.h> - -extern "C" { -#include <mpeg2dec/mpeg2.h> -} - -HBScanner::HBScanner( HBManager * manager, char * device ) - : HBThread( "scanner", HB_NORMAL_PRIORITY ) -{ - fManager = manager; - fDevice = strdup( device ); - - Run(); -} - -void HBScanner::DoWork() -{ - Log( "HBScanner: opening device %s", fDevice ); - - dvdplay_ptr vmg; - vmg = dvdplay_open( fDevice, NULL, NULL ); - if( !vmg ) - { - Log( "HBScanner: dvdplay_open() failed (%s)", - fDevice ); - fManager->ScanDone( NULL ); - return; - } - - /* Detect titles */ - HBList * titleList = new HBList(); - HBTitle * title; - for( int i = 0; i < dvdplay_title_nr( vmg ); i++ ) - { - if( fDie ) - { - break; - } - - Log( "HBScanner: scanning title %d", i + 1 ); - fManager->Scanning( fDevice, i + 1 ); - - title = new HBTitle( fDevice, i + 1 ); - - if( ScanTitle( title, vmg ) ) - { - titleList->AddItem( title ); - } - else - { - Log( "HBScanner: ignoring title %d", i + 1 ); - delete title; - } - } - - Log( "HBScanner: closing device %s", fDevice ); - dvdplay_close( vmg ); - - fManager->ScanDone( titleList ); -} - -bool HBScanner::ScanTitle( HBTitle * title, dvdplay_ptr vmg ) -{ - dvdplay_start( vmg, title->fIndex ); - - /* Length */ - title->fLength = dvdplay_title_time( vmg ); - Log( "HBScanner::ScanTitle: title length is %lld seconds", - title->fLength ); - - /* Discard titles under 10 seconds */ - if( title->fLength < 10 ) - { - return false; - } - - /* Detect languages */ - int audio_nr, foo; - dvdplay_audio_info( vmg, &audio_nr, &foo ); - - audio_attr_t * attr; - HBAudio * audio; - for( int i = 0; i < audio_nr; i++ ) - { - if( fDie ) - { - break; - } - - int id = dvdplay_audio_id( vmg, i ); - - if( id < 1 ) - { - continue; - } - - if( ( id & 0xFF ) != 0xBD ) - { - Log( "HBScanner::ScanTitle: non-AC3 audio track " - "detected, ignoring" ); - continue; - } - - /* Check if we don't already found an track with the same id */ - audio = NULL; - for( uint32_t j = 0; j < title->fAudioList->CountItems(); j++ ) - { - audio = (HBAudio*) title->fAudioList->ItemAt( j ); - if( (uint32_t) id == audio->fId ) - { - break; - } - else - { - audio = NULL; - } - } - - if( audio ) - { - Log( "HBScanner::ScanTitle: discarding duplicate track %x", - id ); - continue; - } - - attr = dvdplay_audio_attr( vmg, i ); - audio = new HBAudio( id, LanguageForCode( attr->lang_code ) ); - Log( "HBScanner::ScanTitle: new language (%x, %s)", - id, audio->fDescription ); - title->fAudioList->AddItem( audio ); - } - - /* Discard titles with no audio tracks */ - if( !title->fAudioList->CountItems() ) - { - return false; - } - - /* Kludge : libdvdplay wants we to read a first block before seeking */ - uint8_t dummyBuf[DVD_VIDEO_LB_LEN]; - dvdplay_read( vmg, dummyBuf, 1 ); - - for( int i = 0; i < 10; i++ ) - { - if( fDie ) - { - break; - } - - if( !DecodeFrame( title, vmg, i ) ) - { - return false; - } - } - - if( title->fInHeight * title->fAspect > - title->fInWidth * VOUT_ASPECT_FACTOR ) - { - title->fOutWidthMax = title->fInWidth; - title->fOutHeightMax = MULTIPLE_16( (uint64_t)title->fInWidth * - VOUT_ASPECT_FACTOR / title->fAspect ); - } - else - { - title->fOutWidthMax = MULTIPLE_16( (uint64_t)title->fInHeight * - title->fAspect / VOUT_ASPECT_FACTOR ); - title->fOutHeightMax = title->fInHeight; - } - - /* Default picture size */ - title->fOutWidth = title->fOutWidthMax; - title->fOutHeight = title->fOutHeightMax; - - return true; -} -bool HBScanner::DecodeFrame( HBTitle * title, dvdplay_ptr vmg, int i ) -{ - /* Seek to the right place */ - int titleFirst = dvdplay_title_first ( vmg ); - int titleEnd = dvdplay_title_end( vmg ); - - dvdplay_seek( vmg, ( i + 1 ) * ( titleEnd - titleFirst ) / 11 ) ; - - /* Init libmpeg2 */ - mpeg2dec_t * handle = mpeg2_init(); - const mpeg2_info_t * info = mpeg2_info( handle ); - mpeg2_state_t state; - - /* Init the destination file */ - char fileName[1024]; - memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.%x.%d", fManager->GetPid(), - (uint32_t) title, i ); - FILE * file = fopen( fileName, "w" ); - - HBList * esBufferList = NULL; - HBBuffer * psBuffer = NULL; - HBBuffer * esBuffer = NULL; - - for( ;; ) - { - state = mpeg2_parse( handle ); - - if( state == STATE_BUFFER ) - { - /* Free the previous buffer */ - if( esBuffer ) - { - delete esBuffer; - esBuffer = NULL; - } - - /* Get a new one */ - while( !esBuffer ) - { - while( !esBufferList ) - { - psBuffer = new HBBuffer( DVD_VIDEO_LB_LEN ); - if( dvdplay_read( vmg, psBuffer->fData, 1 ) != 1 || - !PStoES( psBuffer, &esBufferList ) ) - { - Log( "HBScanner::DecodeFrame: failed to get " - "a valid PS packet" ); - mpeg2_close( handle ); - fclose( file ); - return false; - } - } - - esBuffer = (HBBuffer*) esBufferList->ItemAt( 0 ); - esBufferList->RemoveItem( esBuffer ); - if( !esBufferList->CountItems() ) - { - delete esBufferList; - esBufferList = NULL; - } - - if( esBuffer->fStreamId != 0xE0 ) - { - delete esBuffer; - esBuffer = NULL; - } - } - - /* Feed libmpeg2 */ - mpeg2_buffer( handle, esBuffer->fData, - esBuffer->fData + esBuffer->fSize ); - } - else if( state == STATE_SEQUENCE ) - { - /* Get size & framerate info */ - title->fInWidth = info->sequence->width; - title->fInHeight = info->sequence->height; - title->fAspect = (uint64_t)info->sequence->display_width * - info->sequence->pixel_width * VOUT_ASPECT_FACTOR / - ( info->sequence->display_height * - info->sequence->pixel_height ); - title->fRate = 27000000; - title->fScale = info->sequence->frame_period; - } - else if( ( state == STATE_SLICE || state == STATE_END ) && - ( info->display_fbuf ) && - ( info->display_picture->flags & PIC_MASK_CODING_TYPE ) - == PIC_FLAG_CODING_TYPE_I ) - { - /* Write the raw picture to a file */ - fwrite( info->display_fbuf->buf[0], - title->fInWidth * title->fInHeight, 1, file ); - fwrite( info->display_fbuf->buf[1], - title->fInWidth * title->fInHeight / 4, 1, file ); - fwrite( info->display_fbuf->buf[2], - title->fInWidth * title->fInHeight / 4, 1, file ); - break; - } - else if( state == STATE_INVALID ) - { - /* Reset libmpeg2 */ - mpeg2_close( handle ); - handle = mpeg2_init(); - } - } - - mpeg2_close( handle ); - - fclose( file ); - - return true; -} diff --git a/core/Scanner.h b/core/Scanner.h deleted file mode 100644 index dbdb587c4..000000000 --- a/core/Scanner.h +++ /dev/null @@ -1,27 +0,0 @@ -/* $Id: Scanner.h,v 1.5 2003/09/30 21:21:32 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_SCANNER_H -#define HB_SCANNER_H - -#include "Common.h" -#include "Thread.h" - -class HBScanner : public HBThread -{ - public: - HBScanner( HBManager * manager, char * device ); - - private: - void DoWork(); - bool ScanTitle( HBTitle * title, dvdplay_ptr vmg ); - bool DecodeFrame( HBTitle * title, dvdplay_ptr vmg, int i ); - - HBManager * fManager; - char * fDevice; -}; - -#endif diff --git a/core/Thread.c b/core/Thread.c new file mode 100644 index 000000000..77caa0ee5 --- /dev/null +++ b/core/Thread.c @@ -0,0 +1,138 @@ +/* $Id: Thread.c,v 1.4 2003/11/06 15:51:36 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" + +struct HBThread +{ + char * name; + int priority; + void (*function) ( void * ); + void * arg; + +#if defined( SYS_BEOS ) + int thread; +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + pthread_t thread; +#elif defined( SYS_CYGWIN ) + /* TODO */ + int thread; +#endif +}; + +#ifndef SYS_CYGWIN +static void ThreadFunc( void * t ); +#endif + +HBThread * HBThreadInit( char * name, void (* function)(void *), + void * arg, int priority ) +{ + HBThread * t; + if( !( t = malloc( sizeof( HBThread ) ) ) ) + { + HBLog( "HBThreadInit: malloc() failed, gonna crash" ); + return NULL; + } + + t->name = strdup( name ); + t->priority = priority; + t->function = function; + t->arg = arg; + +#if defined( SYS_BEOS ) + t->thread = spawn_thread( (int32 (*)( void * )) ThreadFunc, + name, priority, t ); + resume_thread( t->thread ); +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + pthread_create( &t->thread, NULL, + (void * (*)( void * )) ThreadFunc, t ); +#elif defined( SYS_CYGWIN ) + /* TODO */ + t->thread = 0; +#endif + + HBLog( "HBThreadInit: thread %d started (\"%s\")", + t->thread, t->name ); + + return t; +} + +#ifndef SYS_CYGWIN +static void ThreadFunc( void * _t ) +{ + HBThread * t = (HBThread*) _t; + +#if defined( SYS_MACOSX ) + struct sched_param param; + memset( ¶m, 0, sizeof( struct sched_param ) ); + param.sched_priority = t->priority; + if( pthread_setschedparam( pthread_self(), SCHED_OTHER, ¶m ) ) + { + HBLog( "HBThreadInit: couldn't set thread priority" ); + } +#endif + + t->function( t->arg ); +} +#endif + +void HBThreadClose( HBThread ** _t ) +{ + HBThread * t = *_t; + +#if defined( SYS_BEOS ) + long exitValue; + wait_for_thread( t->thread, &exitValue ); +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + pthread_join( t->thread, NULL ); +#elif defined( SYS_CYGWIN ) + /* TODO */ +#endif + + HBLog( "HBThreadClose: thread %d stopped (\"%s\")", + t->thread, t->name ); + + free( t->name ); + free( t ); + *_t = NULL; +} + +HBLock * HBLockInit() +{ + HBLock * l; + if( !( l = malloc( sizeof( HBLock ) ) ) ) + { + HBLog( "HBLockInit: malloc() failed, gonna crash" ); + return NULL; + } + +#if defined( SYS_BEOS ) + l->sem = create_sem( 1, "sem" ); +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + pthread_mutex_init( &l->mutex, NULL ); +#elif defined( SYS_CYGWIN ) + /* TODO */ +#endif + + return l; +} + +void HBLockClose( HBLock ** _l ) +{ + HBLock * l = *_l; + +#if defined( SYS_BEOS ) + delete_sem( l->sem ); +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + pthread_mutex_destroy( &l->mutex ); +#elif defined( SYS_CYGWIN ) + /* TODO */ +#endif + free( l ); + + *_l = NULL; +} + diff --git a/core/Thread.cpp b/core/Thread.cpp deleted file mode 100644 index c52f7506a..000000000 --- a/core/Thread.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id: Thread.cpp,v 1.24 2003/10/14 14:35:20 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#if defined( SYS_BEOS ) -# include <OS.h> -# include <Locker.h> -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) -# include <pthread.h> -#endif - -#include "Thread.h" -#include "Fifo.h" - -HBThread::HBThread( char * name, int priority ) -{ - fName = strdup( name ); - fPriority = priority; - fDie = false; - fSuspend = false; -} - -HBThread::~HBThread() -{ - fDie = true; - fSuspend = false; - -#if defined( SYS_BEOS ) - long exit_value; - wait_for_thread( fThread, &exit_value ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_join( fThread, NULL ); -#endif - - Log( "HBThread: thread %d stopped (\"%s\")", fThread, fName ); - free( fName ); -} - -void HBThread::Suspend() -{ - fSuspend = true; -} - -void HBThread::Resume() -{ - fSuspend = false; -} - -int HBThread::GetPid() -{ - return fPid; -} - -void HBThread::Run() -{ -#if defined( SYS_BEOS ) - fThread = spawn_thread( (int32 (*)(void *)) ThreadFunc, - fName, fPriority, this ); - resume_thread( fThread ); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_create( &fThread, NULL, - (void * (*)(void *)) ThreadFunc, this ); -#endif - - Log( "HBThread: thread %d started (\"%s\")", - fThread, fName ); -} - -bool HBThread::Push( HBFifo * fifo, HBBuffer * buffer ) -{ - while( !fDie ) - { - if( fifo->Push( buffer ) ) - { - return true; - } - - Snooze( 10000 ); - } - - delete buffer; - return false; -} - -HBBuffer * HBThread::Pop( HBFifo * fifo ) -{ - HBBuffer * buffer; - - while( !fDie ) - { - if( ( buffer = fifo->Pop() ) ) - { - return buffer; - } - - Snooze( 10000 ); - } - - return NULL; -} - -void HBThread::ThreadFunc( HBThread * _this ) -{ -#if defined( SYS_MACOSX ) - struct sched_param param; - memset( ¶m, 0, sizeof( struct sched_param ) ); - param.sched_priority = _this->fPriority; - if ( pthread_setschedparam( pthread_self(), SCHED_OTHER, ¶m ) ) - { - Log( "HBThread: couldn't set thread priority" ); - } -#endif - - _this->fPid = (int) getpid(); - - _this->DoWork(); -} - -void HBThread::DoWork() -{ -} - - -HBLock::HBLock() -{ -#if defined( SYS_BEOS ) - fLocker = new BLocker(); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_mutex_init( &fMutex, NULL ); -#endif -} - -HBLock::~HBLock() -{ -#if defined( SYS_BEOS ) - delete fLocker; -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_mutex_destroy( &fMutex ); -#endif -} - -void HBLock::Lock() -{ -#if defined( SYS_BEOS ) - fLocker->Lock(); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_mutex_lock( &fMutex ); -#endif -} - -void HBLock::Unlock() -{ -#if defined( SYS_BEOS ) - fLocker->Unlock(); -#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_mutex_unlock( &fMutex ); -#endif -} diff --git a/core/Thread.h b/core/Thread.h index 0a09fabc9..58700aae1 100644 --- a/core/Thread.h +++ b/core/Thread.h @@ -1,13 +1,19 @@ -/* $Id: Thread.h,v 1.19 2003/10/09 16:03:51 titer Exp $ +/* $Id: Thread.h,v 1.3 2003/11/06 15:51:36 titer Exp $ This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. + Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ #ifndef HB_THREAD_H #define HB_THREAD_H -#include "Common.h" +#if defined( SYS_BEOS ) +# include <OS.h> +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) +# include <pthread.h> +#endif + +#include "Utils.h" #if defined( SYS_BEOS ) # define HB_LOW_PRIORITY 5 @@ -15,63 +21,52 @@ #elif defined( SYS_MACOSX ) # define HB_LOW_PRIORITY 0 # define HB_NORMAL_PRIORITY 31 -#elif defined( SYS_LINUX ) +#elif defined( SYS_LINUX ) || defined( SYS_CYGWIN ) /* Actually unused */ # define HB_LOW_PRIORITY 0 # define HB_NORMAL_PRIORITY 0 #endif -class HBThread -{ - public: - HBThread( char * name, - int priority = HB_LOW_PRIORITY ); - virtual ~HBThread(); - void Suspend(); - void Resume(); - int GetPid(); - - protected: - void Run(); - bool Push( HBFifo * fifo, HBBuffer * buffer ); - HBBuffer * Pop( HBFifo * fifo ); - - volatile bool fDie; - volatile bool fSuspend; - - private: - static void ThreadFunc( HBThread * _this ); - virtual void DoWork(); - - char * fName; - int fPriority; +HBThread * HBThreadInit( char * name, void (* function)(void *), + void * arg, int priority ); +void HBThreadClose( HBThread ** ); +struct HBLock +{ #if defined( SYS_BEOS ) - int fThread; + sem_id sem; #elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_t fThread; + pthread_mutex_t mutex; +#elif defined( SYS_CYGWIN ) + /* TODO */ #endif - int fPid; }; +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 ) -class BLocker; + acquire_sem( l->sem ); +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + pthread_mutex_lock( &l->mutex ); +#elif defined( SYS_CYGWIN ) + /* TODO */ #endif +} -class HBLock +static inline void HBLockUnlock( HBLock * l ) { - public: - HBLock(); - ~HBLock(); - void Lock(); - void Unlock(); - - private: #if defined( SYS_BEOS ) - BLocker * fLocker; + release_sem( l->sem ); #elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) - pthread_mutex_t fMutex; + pthread_mutex_unlock( &l->mutex ); +#elif defined( SYS_CYGWIN ) + /* TODO */ #endif -}; +} #endif diff --git a/core/Utils.c b/core/Utils.c new file mode 100644 index 000000000..5f35ec3ae --- /dev/null +++ b/core/Utils.c @@ -0,0 +1,352 @@ +/* $Id: Utils.c,v 1.6 2003/11/06 15:51:36 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 <stdarg.h> +#include <time.h> +#include <sys/time.h> + +#include "Utils.h" +#include "Fifo.h" + +struct HBList +{ + void ** items; + int allocItems; + int nbItems; +}; + +void HBSnooze( int time ) +{ +#if defined( SYS_BEOS ) + snooze( time ); +#elif defined( SYS_MACOSX ) || defined( SYS_LINUX ) + usleep( time ); +#elif defined( SYS_CYGWIN ) + /* TODO */ +#endif +} + +void HBLog( char * log, ... ) +{ + char string[81]; + time_t _now; + struct tm * now; + va_list args; + int ret; + + if( !getenv( "HB_DEBUG" ) ) + { + return; + } + + /* Show the time */ + _now = time( NULL ); + 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 ); + va_end( args ); + + /* Add the end of line */ + string[ret+11] = '\n'; + string[ret+12] = '\0'; + + /* Print it */ + fprintf( stderr, "%s", string ); +} + +uint64_t HBGetDate() +{ +#ifndef SYS_CYGWIN + struct timeval tv; + gettimeofday( &tv, NULL ); + return( (uint64_t) tv.tv_sec * 1000000 + (uint64_t) tv.tv_usec ); +#else + return 0; +#endif +} + +/* Basic MPEG demuxer - only works with DVDs ! (2048 bytes packets) */ +int HBPStoES( HBBuffer ** _psBuffer, HBList * esBufferList ) +{ + HBBuffer * psBuffer = *_psBuffer; + HBBuffer * esBuffer; + int pos = 0; + +#define d (psBuffer->data) + + /* pack_header */ + if( d[pos] != 0 || d[pos+1] != 0 || + d[pos+2] != 0x1 || d[pos+3] != 0xBA ) + { + HBLog( "HBPStoES: not a PS packet (%02x%02x%02x%02x)", + d[pos] << 24, d[pos+1] << 16, + d[pos+2] << 8, d[pos+3] ); + HBBufferClose( _psBuffer ); + return 0; + } + pos += 4; /* pack_start_code */ + pos += 9; /* pack_header */ + pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */ + + /* system_header */ + if( d[pos] == 0 && d[pos+1] == 0 && + d[pos+2] == 0x1 && d[pos+3] == 0xBB ) + { + int header_length; + + pos += 4; /* system_header_start_code */ + header_length = ( d[pos] << 8 ) + d[pos+1]; + pos += 2 + header_length; + } + + /* PES */ + 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 hasPTS; + uint64_t PTS = 0; + + pos += 3; /* packet_start_code_prefix */ + streamId = d[pos]; + pos += 1; + + PES_packet_length = ( d[pos] << 8 ) + d[pos+1]; + pos += 2; /* PES_packet_length */ + PES_packet_end = pos + PES_packet_length; + + if( streamId != 0xE0 && streamId != 0xBD ) + { + /* Not interesting */ + pos = PES_packet_end; + continue; + } + + hasPTS = ( ( d[pos+1] >> 6 ) & 0x2 ) ? 1 : 0; + pos += 2; /* Required headers */ + + PES_header_d_length = d[pos]; + pos += 1; + PES_header_end = pos + PES_header_d_length; + + if( hasPTS ) + { + PTS = ( ( ( (uint64_t) d[pos] >> 1 ) & 0x7 ) << 30 ) + + ( d[pos+1] << 22 ) + + ( ( d[pos+2] >> 1 ) << 15 ) + + ( d[pos+3] << 7 ) + + ( d[pos+4] >> 1 ); + } + + pos = PES_header_end; + + if( streamId == 0xBD ) + { + /* A52: don't ask */ + streamId |= ( d[pos] << 8 ); + pos += 4; + } + + /* 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 ); + + esBuffer->position = psBuffer->position; + esBuffer->pass = psBuffer->pass; + esBuffer->streamId = streamId; + esBuffer->pts = PTS; + memcpy( esBuffer->data, d + pos, + PES_packet_end - pos ); + + HBListAdd( esBufferList, esBuffer ); + + pos = PES_packet_end; + } + + HBBufferClose( _psBuffer ); + + return 1; +} + +#define HBLIST_DEFAULT_SIZE 20 +HBList * HBListInit() +{ + HBList * l; + if( !( l = malloc( sizeof( HBList ) ) ) ) + { + HBLog( "HBListInit: malloc() failed, gonna crash" ); + return NULL; + } + + if( !( l->items = malloc( HBLIST_DEFAULT_SIZE * sizeof( void* ) ) ) ) + { + HBLog( "HBListInit: malloc() failed, gonna crash" ); + free( l ); + return NULL; + } + + l->allocItems = HBLIST_DEFAULT_SIZE; + l->nbItems = 0; + + return l; +} + +int HBListCountItems( HBList * l ) +{ + return l->nbItems; +} + +void HBListAdd( HBList * l, void * item ) +{ + if( !item ) + { + return; + } + + if( l->nbItems == l->allocItems ) + { + l->allocItems += HBLIST_DEFAULT_SIZE; + l->items = realloc( l->items, + l->allocItems * sizeof( void* ) ); + } + + l->items[l->nbItems] = item; + (l->nbItems)++; +} + +void HBListRemove( HBList * l, void * item ) +{ + int i; + + if( !item || !l->nbItems ) + { + return; + } + + for( i = 0; i < l->nbItems; i++ ) + { + if( l->items[i] == item ) + { + break; + } + } + + if( l->items[i] != item ) + { + HBLog( "HBListRemove: specified item is not in the list" ); + return; + } + + for( ; i < l->nbItems - 1; i++ ) + { + l->items[i] = l->items[i+1]; + } + + (l->nbItems)--; +} + +void * HBListItemAt( HBList * l, int index ) +{ + if( index < 0 || index >= l->nbItems ) + { + return NULL; + } + + return l->items[index]; +} + +void HBListClose( HBList ** _l ) +{ + HBList * l = *_l; + + free( l->items ); + free( l ); + + *_l = NULL; +} + +HBTitle * HBTitleInit( char * device, int index ) +{ + HBTitle * t = calloc( sizeof( HBTitle ), 1 ); + + t->device = strdup( device ); + t->index = index; + + 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 ) ) ) + { + HBListRemove( t->audioList, audio ); + HBAudioClose( &audio ); + } + HBListClose( &t->audioList ); + + if( t->file ) free( t->file ); + free( t->device ); + free( t ); + + *_t = NULL; +} + +HBAudio * HBAudioInit( int id, char * language ) +{ + HBAudio * a; + if( !( a = malloc( sizeof( HBAudio ) ) ) ) + { + HBLog( "HBAudioInit: malloc() 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; + + return a; +} + +void HBAudioClose( HBAudio ** _a ) +{ + HBAudio * a = *_a; + + free( a->language ); + free( a ); + + *_a = NULL; +} + diff --git a/core/Utils.h b/core/Utils.h new file mode 100644 index 000000000..ba1a9101e --- /dev/null +++ b/core/Utils.h @@ -0,0 +1,213 @@ +/* $Id: Utils.h,v 1.6 2003/11/07 21:22:17 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_UTILS_H +#define HB_UTILS_H + +/* Standard headers */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <inttypes.h> +typedef uint8_t byte_t; +#ifdef SYS_BEOS +# include <OS.h> +#endif + +/* Handy macros */ +#ifndef MIN +#define MIN( a, b ) ( ( (a) > (b) ) ? (b) : (a) ) +#endif +#ifndef MAX +#define MAX( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) +#endif +#ifndef EVEN +#define EVEN( a ) ( ( (a) & 0x1 ) ? ( (a) + 1 ) : (a) ) +#endif +#ifndef MULTIPLE_16 +#define MULTIPLE_16( a ) ( 16 * ( ( (a) + 8 ) / 16 ) ) +#endif +#ifndef VOUT_ASPECT_FACTOR +#define VOUT_ASPECT_FACTOR 432000 +#endif + +typedef struct HBAc3Dec HBAc3Dec; +typedef struct HBAudio HBAudio; +typedef struct HBAviMux HBAviMux; +typedef struct HBBuffer HBBuffer; +typedef struct HBDVDRead HBDVDRead; +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 HBWork HBWork; +typedef struct HBWorkThread HBWorkThread; +typedef struct HBXvidEnc HBXvidEnc; + +/* Misc functions which may be used from anywhere */ +void HBSnooze( int time ); +void HBLog( char * log, ... ); +uint64_t HBGetDate(); +int HBPStoES( HBBuffer ** psBuffer, HBList * esBufferList ); + +/* HBList functions */ +HBList * HBListInit(); +int HBListCountItems( HBList * ); +void HBListAdd( HBList *, void * item ); +void HBListRemove( HBList *, void * item ); +void * HBListItemAt( HBList *, int index ); +void HBListClose( HBList ** ); + +/* HBTitle function */ +HBTitle * HBTitleInit(); +void HBTitleClose( HBTitle ** ); + +/* HBAudio functions */ +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; + +/* Possible codecs */ +typedef enum +{ + HB_CODEC_FFMPEG = 0, + HB_CODEC_XVID +} HBCodec; + +struct HBStatus +{ + HBMode mode; + + /* HB_MODE_SCANNING */ + int scannedTitle; + + /* 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 */ + + /* HB_MODE_ERROR */ + HBError error; +}; + +struct HBTitle +{ + char * device; + int index; + int length; + char * file; + + /* Video input */ + 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; + + /* Fifos */ + HBFifo * mpeg2Fifo; + HBFifo * rawFifo; + HBFifo * scaledFifo; + HBFifo * mpeg4Fifo; + + /* Threads */ + HBDVDRead * dvdRead; + HBMpeg2Dec * mpeg2Dec; + HBScale * scale; + HBFfmpegEnc * ffmpegEnc; + HBXvidEnc * xvidEnc; + HBAviMux * aviMux; + HBWorkThread * workThreads[8]; +}; + +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; +}; + + + +#endif diff --git a/core/Work.c b/core/Work.c new file mode 100644 index 000000000..b15e50839 --- /dev/null +++ b/core/Work.c @@ -0,0 +1,187 @@ +/* $Id: Work.c,v 1.4 2003/11/06 12:33:11 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" + +/* Local prototypes */ +static void WorkThread( void * t ); + +struct HBWork +{ + HB_WORK_COMMON_MEMBERS +}; + +struct HBWorkThread +{ + HBHandle * handle; + + HBList * workList; + int firstThread; + + int die; + HBThread * thread; +}; + +HBWorkThread * HBWorkThreadInit( HBHandle * handle, HBTitle * title, + HBAudio * audio, HBAudio * optAudio, + int firstThread ) +{ + int i; + HBWork * w; + + HBWorkThread * t; + if( !( t = malloc( sizeof( HBWorkThread ) ) ) ) + { + HBLog( "HBWorkThreadInit: malloc() failed, gonna crash" ); + return NULL; + } + + t->handle = handle; + + /* 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 */ + t->workList = HBListInit(); + HBListAdd( t->workList, title->mpeg2Dec ); + HBListAdd( t->workList, title->scale ); + + 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 ) + { + HBListAdd( t->workList, optAudio->ac3Dec ); + HBListAdd( t->workList, optAudio->mp3Enc ); + } + + t->firstThread = firstThread; + + /* Work objects are not thread-safe, so let's init locks so each + one can not be called anymore when it's doing something. This + is done by the first worker thread (see HBStartRip) */ + if( t->firstThread ) + { + for( i = 0; i < HBListCountItems( t->workList ); i++ ) + { + w = (HBWork*) HBListItemAt( t->workList, i ); + w->lock = HBLockInit(); + w->used = 0; + w->time = 0; + } + } + + /* Actually launch the thread */ + t->die = 0; + t->thread = HBThreadInit( "work thread", WorkThread, t, + HB_LOW_PRIORITY ); + + return t; +} + +void HBWorkThreadClose( HBWorkThread ** _t ) +{ + HBWorkThread * t = (*_t); + HBWork * w; + + /* Stop the thread */ + t->die = 1; + HBThreadClose( &t->thread ); + + /* Destroy locks, show stats */ + if( t->firstThread ) + { + int i; + uint64_t total = 0; + + for( i = 0; i < HBListCountItems( t->workList ); i++ ) + { + w = (HBWork*) HBListItemAt( t->workList, i ); + HBLockClose( &w->lock ); + total += w->time; + } + + for( i = 0; i < HBListCountItems( t->workList ); i++ ) + { + w = (HBWork*) HBListItemAt( t->workList, i ); + HBLog( "HBWorkThreadClose: %- 9s = %05.2f %%", w->name, + 100.0 * w->time / total ); + } + + } + + /* Free memory */ + HBListClose( &t->workList ); + free( t ); + + (*_t) = NULL; +} + +static void WorkThread( void * _t ) +{ + HBWorkThread * t = (HBWorkThread*) _t; + HBWork * w; + int didSomething, i; + uint64_t date; + + for( ;; ) + { + HBCheckPaused( t->handle ); + + didSomething = 0; + + for( i = 0; i < HBListCountItems( t->workList ); i++ ) + { + if( t->die ) + { + break; + } + + w = (HBWork*) HBListItemAt( t->workList, i ); + + /* 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; + } + + /* Unlock */ + HBLockLock( w->lock ); + w->used = 0; + HBLockUnlock( w->lock ); + } + + if( t->die ) + { + break; + } + + /* If nothing could be done, wait a bit to prevent a useless + CPU-consuming loop */ + if( !didSomething ) + { + HBSnooze( 10000 ); + } + } +} + diff --git a/core/Work.h b/core/Work.h new file mode 100644 index 000000000..8d3cfba15 --- /dev/null +++ b/core/Work.h @@ -0,0 +1,27 @@ +/* $Id: Work.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_WORK_H +#define HB_WORK_H + +#include "HandBrakeInternal.h" + +#define HB_WORK_COMMON_MEMBERS \ + char * name; \ + HBLock * lock; \ + int used; \ + uint64_t time; \ + int (*work) ( HBWork * ); + +void HBWorkLock( HBWork * ); +void HBWorkWork( HBWork * ); +void HBWorkUnlock( HBWork * ); + +HBWorkThread * HBWorkThreadInit( HBHandle *, HBTitle *, HBAudio *, + HBAudio *, int firstThread ); +void HBWorkThreadClose( HBWorkThread ** ); + +#endif diff --git a/core/Worker.cpp b/core/Worker.cpp deleted file mode 100644 index 4310e46f4..000000000 --- a/core/Worker.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* $Id: Worker.cpp,v 1.11 2003/10/16 13:36:17 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Ac3Decoder.h" -#include "Mp3Encoder.h" -#include "Mpeg2Decoder.h" -#include "Mpeg4Encoder.h" -#include "MpegDemux.h" -#include "Resizer.h" -#include "Worker.h" - -HBWorker::HBWorker( HBTitle * title, HBAudio * audio1, - HBAudio * audio2 ) - : HBThread( "worker") -{ - fTitle = title; - fAudio1 = audio1; - fAudio2 = audio2; - - Run(); -} - -void HBWorker::DoWork() -{ - bool didSomething; - uint64_t mpegDemux = 0; - uint64_t mpeg2Decoder = 0; - uint64_t resizer = 0; - uint64_t mpeg4Encoder = 0; - uint64_t ac3Decoder1 = 0; - uint64_t mp3Encoder1 = 0; - uint64_t ac3Decoder2 = 0; - uint64_t mp3Encoder2 = 0; - uint64_t tmpDate; - - for( ;; ) - { - while( fSuspend ) - { - Snooze( 10000 ); - } - - didSomething = false; - - tmpDate = GetDate(); - if( fTitle->fMpegDemux->Work() ) - { - mpegDemux += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - - tmpDate = GetDate(); - if( fTitle->fMpeg2Decoder->Work() ) - { - mpeg2Decoder += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - - tmpDate = GetDate(); - if( fTitle->fResizer->Work() ) - { - resizer += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - - tmpDate = GetDate(); - if( fTitle->fMpeg4Encoder->Work() ) - { - mpeg4Encoder += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - - if( fAudio1 ) - { - tmpDate = GetDate(); - if( fAudio1->fAc3Decoder->Work() ) - { - ac3Decoder1 += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - - tmpDate = GetDate(); - if( fAudio1->fMp3Encoder->Work() ) - { - mp3Encoder1 += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - } - - if( fAudio2 ) - { - tmpDate = GetDate(); - if( fAudio2->fAc3Decoder->Work() ) - { - ac3Decoder2 += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - - tmpDate = GetDate(); - if( fAudio2->fMp3Encoder->Work() ) - { - mp3Encoder2 += ( GetDate() - tmpDate ); - didSomething = true; - } - - if( fDie ) break; - } - - if( !didSomething ) - { - Snooze( 10000 ); - } - } - - tmpDate = mpegDemux + mpeg2Decoder + resizer + mpeg4Encoder + - ac3Decoder1 + mp3Encoder1 + ac3Decoder2 + mp3Encoder2; - Log( "HBWorker stopped. CPU utilization:" ); - Log( "- MPEG demuxer: %.2f %%", 100.0 * mpegDemux / tmpDate ); - Log( "- MPEG-2 decoder: %.2f %%", 100.0 * mpeg2Decoder / tmpDate ); - Log( "- Resizer: %.2f %%", 100.0 * resizer / tmpDate ); - Log( "- MPEG-4 encoder: %.2f %%", 100.0 * mpeg4Encoder / tmpDate ); - if( fAudio1 ) - { - Log( "- AC3 decoder 1: %.2f %%", 100.0 * ac3Decoder1 / tmpDate ); - Log( "- MP3 encoder 1: %.2f %%", 100.0 * mp3Encoder1 / tmpDate ); - } - if( fAudio2 ) - { - Log( "- AC3 decoder 2: %.2f %%", 100.0 * ac3Decoder2 / tmpDate ); - Log( "- MP3 encoder 2: %.2f %%", 100.0 * mp3Encoder2 / tmpDate ); - } -} - diff --git a/core/Worker.h b/core/Worker.h deleted file mode 100644 index 5df8f648b..000000000 --- a/core/Worker.h +++ /dev/null @@ -1,28 +0,0 @@ -/* $Id: Worker.h,v 1.3 2003/10/16 13:36:17 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://beos.titer.org/handbrake/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_WORKER_H -#define HB_WORKER_H - -#include "Common.h" -#include "Thread.h" - -class HBWorker : public HBThread -{ - public: - HBWorker( HBTitle * title, HBAudio * audio1, - HBAudio * audio2 ); - void WaitUntilDone(); - - private: - void DoWork(); - - HBTitle * fTitle; - HBAudio * fAudio1; - HBAudio * fAudio2; -}; - -#endif diff --git a/core/XvidEnc.c b/core/XvidEnc.c new file mode 100644 index 000000000..8f16ad4ba --- /dev/null +++ b/core/XvidEnc.c @@ -0,0 +1,170 @@ +/* $Id: XvidEnc.c,v 1.5 2003/11/05 19:14:37 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 "XvidEnc.h" +#include "Fifo.h" +#include "Work.h" + +#include <xvid.h> + +/* Local prototypes */ +static int XvidEncWork( HBWork * ); + +struct HBXvidEnc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBTitle * title; + + void * xvid; + HBBuffer * mpeg4Buffer; + int pass; +}; + +HBXvidEnc * HBXvidEncInit( HBHandle * handle, HBTitle * title ) +{ + HBXvidEnc * x; + if( !( x = malloc( sizeof( HBXvidEnc ) ) ) ) + { + HBLog( "HBXvidEncInit: malloc() failed, gonna crash" ); + return NULL; + } + + x->name = strdup( "XvidEnc" ); + x->work = XvidEncWork; + + x->handle = handle; + x->title = title; + + x->xvid = NULL; + x->mpeg4Buffer = NULL; + x->pass = 42; + + return x; +} + +void HBXvidEncClose( HBXvidEnc ** _x ) +{ + HBXvidEnc * x = *_x; + free( x ); + *_x = NULL; +} + +static int XvidEncWork( HBWork * w ) +{ + HBXvidEnc * x = (HBXvidEnc*) w; + HBTitle * title = x->title; + HBBuffer * scaledBuffer; + HBBuffer * mpeg4Buffer; + XVID_ENC_FRAME xframe; + + int didSomething = 0; + + if( x->mpeg4Buffer ) + { + if( HBFifoPush( title->mpeg4Fifo, &x->mpeg4Buffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + if( ( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + /* Init or re-init if needed */ + if( scaledBuffer->pass != x->pass ) + { + XVID_INIT_PARAM xinit; + XVID_ENC_PARAM xparam; + + x->pass = scaledBuffer->pass;; + + HBLog( "HBXvidEnc: opening libxvidcore (pass %d)", x->pass ); + + xinit.cpu_flags = 0; + xvid_init( NULL, 0, &xinit, NULL ); + + xparam.width = title->outWidth; + xparam.height = title->outHeight; + + xparam.fincr = title->rateBase; + xparam.fbase = title->rate; + + xparam.rc_bitrate = title->bitrate * 1000; + + /* 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; + } + + /* TODO implement 2-pass encoding */ + if( x->pass == 1 ) + { + HBPosition( x->handle, scaledBuffer->position ); + HBBufferClose( &scaledBuffer ); + return didSomething; + } + + mpeg4Buffer = HBBufferInit( title->outWidth * + title->outHeight * 3 / 2 ); + mpeg4Buffer->position = scaledBuffer->position; + + xframe.general = XVID_H263QUANT | XVID_HALFPEL | XVID_INTER4V; + xframe.motion = PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | + PMV_EXTSEARCH16 | PMV_EARLYSTOP8 | + PMV_HALFPELREFINE8 | PMV_HALFPELDIAMOND8 | + PMV_USESQUARES16; + xframe.bitstream = mpeg4Buffer->data; + + xframe.image = scaledBuffer->data; + xframe.colorspace = XVID_CSP_I420; + + xframe.quant_intra_matrix = NULL; + xframe.quant_inter_matrix = NULL; + xframe.quant = 0; + xframe.intra = -1; + + xframe.hint.hintstream = NULL; + + if( xvid_encore( x->xvid, XVID_ENC_ENCODE, &xframe, NULL ) ) + { + HBLog( "HBXvidEnc: xvid_encore() failed" ); + } + + mpeg4Buffer->size = xframe.length; + mpeg4Buffer->keyFrame = xframe.intra; + + /* Inform the GUI about the current position */ + HBPosition( x->handle, scaledBuffer->position ); + + HBBufferClose( &scaledBuffer ); + x->mpeg4Buffer = mpeg4Buffer; + + return didSomething; +} + diff --git a/core/XvidEnc.h b/core/XvidEnc.h new file mode 100644 index 000000000..01cb6f4d4 --- /dev/null +++ b/core/XvidEnc.h @@ -0,0 +1,15 @@ +/* $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 |