diff options
author | handbrake <[email protected]> | 2006-01-14 13:34:42 +0000 |
---|---|---|
committer | handbrake <[email protected]> | 2006-01-14 13:34:42 +0000 |
commit | d35a2a23fe450c88925128b9db7c63a5f1ed395d (patch) | |
tree | ed7f6b0e4b1f118b0209c606448b693b822020fb /core | |
parent | 60925e41e540e9c79b522f4864296bc425fcc9e4 (diff) |
HandBrake 0.6.2
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@15 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'core')
-rw-r--r-- | core/Ac3Dec.c | 186 | ||||
-rw-r--r-- | core/AviMux.c | 571 | ||||
-rw-r--r-- | core/DVDRead.c | 45 | ||||
-rw-r--r-- | core/FaacEnc.c | 180 | ||||
-rw-r--r-- | core/FfmpegEnc.c | 175 | ||||
-rw-r--r-- | core/Fifo.c | 15 | ||||
-rw-r--r-- | core/Fifo.h | 84 | ||||
-rw-r--r-- | core/HBInternal.h | 25 | ||||
-rw-r--r-- | core/HandBrake.c | 108 | ||||
-rw-r--r-- | core/Jamfile | 15 | ||||
-rw-r--r-- | core/LpcmDec.c | 139 | ||||
-rw-r--r-- | core/MadDec.c | 8 | ||||
-rw-r--r-- | core/Mp3Enc.c | 251 | ||||
-rw-r--r-- | core/Mp4Mux.c | 270 | ||||
-rw-r--r-- | core/Mpeg2Dec.c | 128 | ||||
-rw-r--r-- | core/MpgaDec.c | 132 | ||||
-rw-r--r-- | core/Mux.c | 228 | ||||
-rw-r--r-- | core/Mux.h | 21 | ||||
-rw-r--r-- | core/OgmMux.c | 531 | ||||
-rw-r--r-- | core/Resample.c | 159 | ||||
-rw-r--r-- | core/Scale.c | 194 | ||||
-rw-r--r-- | core/Scan.c | 327 | ||||
-rw-r--r-- | core/Thread.c | 12 | ||||
-rw-r--r-- | core/Utils.c | 31 | ||||
-rw-r--r-- | core/Utils.h | 70 | ||||
-rw-r--r-- | core/VorbisEnc.c | 222 | ||||
-rw-r--r-- | core/Work.c | 7 | ||||
-rw-r--r-- | core/X264Enc.c | 126 | ||||
-rw-r--r-- | core/XvidEnc.c | 234 |
29 files changed, 2207 insertions, 2287 deletions
diff --git a/core/Ac3Dec.c b/core/Ac3Dec.c index 3fb4cc0ae..ef805588c 100644 --- a/core/Ac3Dec.c +++ b/core/Ac3Dec.c @@ -1,4 +1,4 @@ -/* $Id: Ac3Dec.c,v 1.13 2004/03/08 11:32:48 titer Exp $ +/* $Id: Ac3Dec.c,v 1.17 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,7 +9,7 @@ /* liba52 */ #include "a52dec/a52.h" -typedef struct HBAc3Dec +struct HBWork { HB_WORK_COMMON_MEMBERS @@ -24,195 +24,131 @@ typedef struct HBAc3Dec /* 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; + int hasSync; + int nextFrameSize; +}; /* Local prototypes */ static int Ac3DecWork( HBWork * ); -static int GetBytes( HBAc3Dec *, int ); HBWork * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) { - HBAc3Dec * a; - if( !( a = malloc( sizeof( HBAc3Dec ) ) ) ) + HBWork * w; + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) { HBLog( "HBAc3DecInit: malloc() failed, gonna crash" ); return NULL; } - a->name = strdup( "Ac3Dec" ); - a->work = Ac3DecWork; + w->name = strdup( "Ac3Dec" ); + w->work = Ac3DecWork; - a->handle = handle; - a->audio = audio; + w->handle = handle; + w->audio = audio; /* Init liba52 */ - a->state = a52_init( 0 ); - a->inFlags = 0; + w->state = a52_init( 0 ); /* Let it do the downmixing */ - a->outFlags = A52_STEREO; - - if( audio->outCodec == HB_CODEC_MP3 ) - /* Lame wants 16 bits samples */ - a->sampleLevel = 32768.0; - else if( audio->outCodec == HB_CODEC_AAC ) - /* Faac wants 24 bits samples */ - a->sampleLevel = 8388608.0; - else if( audio->outCodec == HB_CODEC_VORBIS ) - /* Vorbis wants FIXME bits samples */ - a->sampleLevel = 32768.0; - - a->ac3FrameSize = 0; - a->ac3Buffer = NULL; - a->ac3BufferPos = 0; - a->nextFrameSize = 0; - a->position = 0.0; - a->rawBuffer = NULL; - - return (HBWork*) a; + w->outFlags = A52_STEREO; + + /* 16 bits samples */ + w->sampleLevel = 32768.0; + + return w; } -void HBAc3DecClose( HBWork ** _a ) +void HBAc3DecClose( HBWork ** _w ) { - HBAc3Dec * a = (HBAc3Dec*) *_a; + HBWork * w = *_w; - if( a->ac3Buffer ) HBBufferClose( &a->ac3Buffer ); - if( a->rawBuffer ) HBBufferClose( &a->rawBuffer ); - a52_free( a->state ); - free( a->name ); - free( a ); + a52_free( w->state ); + free( w->name ); + free( w ); - *_a = NULL; + *_w = NULL; } static int Ac3DecWork( HBWork * w ) { - HBAc3Dec * a = (HBAc3Dec*) w; - HBAudio * audio = a->audio; + HBAudio * audio = w->audio; - int didSomething = 0; + float position; - /* Push decoded buffer */ - if( a->rawBuffer ) + if( HBFifoIsHalfFull( audio->rawFifo ) ) { - if( HBFifoPush( audio->rawFifo, &a->rawBuffer ) ) - { - didSomething = 1; - } - else - { - return didSomething; - } + return 0; } /* Get a frame header (7 bytes) */ - if( a->ac3FrameSize < 7 ) + if( !w->hasSync ) { - if( GetBytes( a, 7 ) ) + if( !HBFifoGetBytes( audio->inFifo, w->ac3Frame, 7, + &position ) ) { - didSomething = 1; - } - else - { - return didSomething; + return 0; } - a->nextFrameSize = a52_syncinfo( a->ac3Frame, &a->inFlags, + /* Check the header */ + w->nextFrameSize = a52_syncinfo( w->ac3Frame, &w->inFlags, &audio->inSampleRate, &audio->inBitrate ); - if( !a->nextFrameSize ) + if( !w->nextFrameSize ) { HBLog( "HBAc3Dec: a52_syncinfo() failed" ); - HBErrorOccured( a->handle, HB_ERROR_A52_SYNC ); - return didSomething; + HBErrorOccured( w->handle, HB_ERROR_A52_SYNC ); + return 0; } + + w->hasSync = 1; } /* Get the whole frame */ - if( a->ac3FrameSize >= 7 ) + if( w->hasSync ) { sample_t * samples; HBBuffer * rawBuffer; int i; - if( GetBytes( a, a->nextFrameSize ) ) - { - didSomething = 1; - } - else + if( !HBFifoGetBytes( audio->inFifo, w->ac3Frame + 7, + w->nextFrameSize - 7, &position ) ) { - return didSomething; + return 0; } + w->hasSync = 0; + /* Feed liba52 */ - a52_frame( a->state, a->ac3Frame, &a->outFlags, - &a->sampleLevel, 0 ); - a->ac3FrameSize = 0; + a52_frame( w->state, w->ac3Frame, &w->outFlags, + &w->sampleLevel, 0 ); /* 6 blocks per frame, 256 samples per block, 2 channels */ - rawBuffer = HBBufferInit( 12 * 256 * sizeof( float ) ); - rawBuffer->position = a->position; - rawBuffer->samples = 6 * 256; - rawBuffer->left = (float*) rawBuffer->data; - rawBuffer->right = rawBuffer->left + 6 * 256; + rawBuffer = HBBufferInit( 3072 * sizeof( float ) ); + rawBuffer->position = position; for( i = 0; i < 6; i++ ) { - /* Decode a block */ - a52_block( a->state ); + int j; - /* Get a pointer to the raw data */ - samples = a52_samples( a->state ); - - /* Copy left channel data */ - memcpy( rawBuffer->left + i * 256, samples, - 256 * sizeof( float ) ); - - /* Copy right channel data */ - memcpy( rawBuffer->right + i * 256, samples + 256, - 256 * sizeof( float ) ); - } - - a->rawBuffer = rawBuffer; - } - - return didSomething; -} + /* Decode a block */ + a52_block( w->state ); -static int GetBytes( HBAc3Dec * a, int size ) -{ - int i; + /* Get a pointer to the float samples */ + samples = a52_samples( w->state ); - while( a->ac3FrameSize < size ) - { - if( !a->ac3Buffer ) - { - if( !( a->ac3Buffer = HBFifoPop( a->audio->inFifo ) ) ) + /* Interleave samples */ + for( j = 0; j < 256; j++ ) { - return 0; + rawBuffer->dataf[512*i+2*j] = samples[j]; + rawBuffer->dataf[512*i+2*j+1] = samples[256+j]; } - a->ac3BufferPos = 0; - a->position = a->ac3Buffer->position; } - 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 ) + /* Send decoded data to the resampler */ + if( !HBFifoPush( audio->rawFifo, &rawBuffer ) ) { - HBBufferClose( &a->ac3Buffer ); + HBLog( "HBAc3Dec: HBFifoPush failed" ); } } diff --git a/core/AviMux.c b/core/AviMux.c index 444d77adc..c0209dd49 100644 --- a/core/AviMux.c +++ b/core/AviMux.c @@ -1,4 +1,4 @@ -/* $Id: AviMux.c,v 1.17 2004/03/16 16:11:29 titer Exp $ +/* $Id: AviMux.c,v 1.24 2004/05/12 18:02:35 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,33 +6,12 @@ #include "HBInternal.h" -int64_t videoFrames; -int64_t videoBytes; -int64_t audioFrames; -int64_t audioBytes; - -/* Local prototypes */ -static void AviMuxThread( void * ); -static void InitAviHeaders( HBAviMux * ); -static void AddChunk( HBAviMux *, HBBuffer *, uint32_t, - HBAviStreamHeader * ); -static void AddIndex( HBAviMux * ); -static void WriteInt8( FILE *, uint8_t ); -static void WriteInt16( FILE *, uint16_t ); -static void WriteInt32( FILE *, uint32_t ); -static void WriteBuffer( FILE *, HBBuffer * ); -static void WriteMainHeader( FILE *, HBAviMainHeader * ); -static void WriteStreamHeader( FILE *, HBAviStreamHeader * ); -static void WriteHBBitmapInfo( FILE *, HBBitmapInfo * ); -static void WriteHBWaveFormatEx( FILE *, HBWaveFormatEx * ); -static void IndexAddInt32( HBBuffer * buffer, uint32_t ); - #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__)) HBAviMainHeader +typedef struct __attribute__((__packed__)) { uint32_t FourCC; uint32_t BytesCount; @@ -47,9 +26,10 @@ struct __attribute__((__packed__)) HBAviMainHeader uint32_t Width; uint32_t Height; uint32_t Reserved[4]; -}; -struct __attribute__((__packed__)) HBAviStreamHeader +} HBAviMainHeader; + +typedef struct __attribute__((__packed__)) { uint32_t FourCC; uint32_t BytesCount; @@ -70,9 +50,10 @@ struct __attribute__((__packed__)) HBAviStreamHeader int16_t Top; int16_t Right; int16_t Bottom; -}; -struct __attribute__((__packed__)) HBBitmapInfo +} HBAviStreamHeader; + +typedef struct __attribute__((__packed__)) { uint32_t FourCC; uint32_t BytesCount; @@ -87,9 +68,10 @@ struct __attribute__((__packed__)) HBBitmapInfo uint32_t YPelsPerMeter; uint32_t ClrUsed; uint32_t ClrImportant; -}; -struct __attribute__((__packed__)) HBWaveFormatEx +} HBBitmapInfo; + +typedef struct __attribute__((__packed__)) { uint32_t FourCC; uint32_t BytesCount; @@ -107,10 +89,13 @@ struct __attribute__((__packed__)) HBWaveFormatEx uint16_t BlockSize; uint16_t FramesPerBlock; uint16_t CodecDelay; -}; -struct HBAviMux +} HBWaveFormatEx; + +struct HBMux { + HB_MUX_COMMON_MEMBERS + HBHandle * handle; HBTitle * title; @@ -119,284 +104,191 @@ struct HBAviMux FILE * file; HBBuffer * index; - - volatile int die; - HBThread * thread; }; -HBAviMux * HBAviMuxInit( HBHandle * handle, HBTitle * title ) +typedef struct { - HBAviMux * a; - if( !( a = malloc( sizeof( HBAviMux ) ) ) ) - { - HBLog( "HBAviMuxInit: malloc() failed, gonna crash" ); - return NULL; - } - - a->handle = handle; - a->title = title; - - videoFrames = 0; - videoBytes = 0; - audioFrames = 0; - audioBytes = 0; + HBAviMainHeader mainHeader; + HBAviStreamHeader videoHeader; + HBBitmapInfo videoFormat; - a->size = 0; - a->file = NULL; - a->index = HBBufferInit( 1024 * 1024 ); - a->index->size = 0; +} AviVideoMuxData; - a->die = 0; - a->thread = HBThreadInit( "avi muxer", AviMuxThread, a, - HB_NORMAL_PRIORITY ); - return a; -} - -void HBAviMuxClose( HBAviMux ** _a ) +typedef struct { - HBAviMux * a = *_a; - FILE * file; - long size; - - a->die = 1; - HBThreadClose( &a->thread ); - -#ifndef HB_CYGWIN - file = fopen( a->title->file, "r" ); -#else - file = fopen( a->title->file, "rb" ); -#endif - if( file ) - { - fseek( file, 0, SEEK_END ); - size = ftell( file ); - fclose( file ); - - HBLog( "HBAviMux: videoFrames=%lld, %lld bytes", - videoFrames, videoBytes ); - HBLog( "HBAviMux: audioFrames=%lld, %lld bytes", - audioFrames, audioBytes ); - HBLog( "HBAviMux: overhead=%.2f bytes / frame", - ( (float) size - videoBytes - audioBytes ) / - ( videoFrames + audioFrames ) ); - } + uint32_t fourCC; + HBAviStreamHeader audioHeader; + HBWaveFormatEx audioFormat; - free( a ); +} AviAudioMuxData; - *_a = NULL; -} - -static void AviMuxThread( void * _a ) +/* Local prototypes */ +static int AviStart( HBMux * ); +static int AviMuxVideo( HBMux *, void *, HBBuffer *); +static int AviMuxAudio( HBMux *, void *, HBBuffer *); +static int AviEnd( HBMux * ); + +static void AddChunk( HBMux *, HBBuffer *, uint32_t, + HBAviStreamHeader * ); +static void AddIndex( HBMux * ); +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 *, HBAviMainHeader * ); +static void WriteStreamHeader( FILE *, HBAviStreamHeader * ); +static void WriteHBBitmapInfo( FILE *, HBBitmapInfo * ); +static void WriteHBWaveFormatEx( FILE *, HBWaveFormatEx * ); +static void IndexAddInt32( HBBuffer * buffer, uint32_t ); + +HBMux * HBAviMuxInit( HBHandle * handle, HBTitle * title ) { - HBAviMux * a = (HBAviMux*) _a; - HBTitle * title = a->title; - int audioCount = HBListCount( title->ripAudioList ); - - HBAudio * audio; - HBBuffer * buffer; + HBMux * m; + HBAudio * audio; int i; - /* Open destination file */ - HBLog( "HBAviMux: opening %s", title->file ); -#ifndef HB_CYGWIN - if( !( a->file = fopen( title->file, "w" ) ) ) -#else - if( !( a->file = fopen( title->file, "wb" ) ) ) -#endif - { - HBLog( "HBAviMux: fopen() failed" ); - HBErrorOccured( a->handle, HB_ERROR_AVI_WRITE ); - return; - } - - /* Wait until we have one encoded frame for each track */ - while( !a->die && !HBFifoSize( title->outFifo ) ) + if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) { - HBSnooze( 10000 ); + HBLog( "HBAviMux: malloc() failed, gonna crash" ); + return NULL; } - for( i = 0; i < audioCount; i++ ) + m->start = AviStart; + m->muxVideo = AviMuxVideo; + m->muxAudio = AviMuxAudio; + m->end = AviEnd; + m->handle = handle; + m->title = title; + + m->file = NULL; + m->index = HBBufferInit( 1024 * 1024 ); + m->index->size = 0; + + /* Alloc muxer data */ + title->muxData = calloc( sizeof( AviVideoMuxData ), 1 ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - audio = HBListItemAt( title->ripAudioList, i ); - while( !a->die && !HBFifoSize( audio->outFifo ) ) - { - HBSnooze( 10000 ); - } + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + audio->muxData = calloc( sizeof( AviAudioMuxData ), 1 ); } - if( a->die ) - { - fclose( a->file ); - a->file = NULL; - - HBLog( "HBAviMux: deleting %s", title->file ); - unlink( title->file ); - return; - } + return m; +} - InitAviHeaders( a ); +void HBAviMuxClose( HBMux ** _m ) +{ + HBMux * m = *_m; + HBTitle * title = m->title; + HBAudio * audio; + int i; - for( ;; ) + /* Free muxer data */ + free( title->muxData ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - /* Wait until we have one encoded frame for each track */ - if( !HBFifoWait( title->outFifo ) ) - { - a->die = 1; - } - for( i = 0; i < audioCount; i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - if( !HBFifoWait( audio->outFifo ) ) - { - a->die = 1; - break; - } - } - - if( a->die ) - { - break; - } - - /* Interleave frames in the same order than they were in the - original MPEG stream */ - audio = NULL; - for( i = 0; i < audioCount; i++ ) - { - HBAudio * otherAudio; - otherAudio = HBListItemAt( title->ripAudioList, i ); - if( !audio || HBFifoPosition( otherAudio->outFifo ) < - HBFifoPosition( audio->outFifo ) ) - { - audio = otherAudio; - } - } - - if( audio == NULL || - HBFifoPosition( title->outFifo ) < HBFifoPosition( audio->outFifo ) ) - { - buffer = HBFifoPop( title->outFifo ); - AddChunk( a, buffer, FOURCC( "00dc" ), title->aviVideoHeader ); - videoFrames++; - videoBytes += buffer->size; - HBBufferClose( &buffer ); - } - else - { - buffer = HBFifoPop( audio->outFifo ); - AddChunk( a, buffer, audio->aviFourCC, audio->aviAudioHeader ); - audioFrames++; - audioBytes += buffer->size; - HBBufferClose( &buffer ); - } + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + free( audio->muxData ); } - AddIndex( a ); + HBBufferClose( &m->index ); - HBLog( "HBAviMux: closing %s", title->file ); - fclose( a->file ); + free( m ); + + *_m = NULL; } -static void InitAviHeaders( HBAviMux * a ) +#define mh videoMuxData->mainHeader +#define vh videoMuxData->videoHeader +#define vf videoMuxData->videoFormat +#define ah audioMuxData->audioHeader +#define af audioMuxData->audioFormat +static int AviStart( HBMux * m ) { - HBTitle * title = a->title; - FILE * file = a->file; - int audioCount = HBListCount( title->ripAudioList ); - - HBAudio * audio; - HBAviMainHeader * mainHeader; - HBAviStreamHeader * videoHeader; - HBBitmapInfo * videoFormat; - HBAviStreamHeader * audioHeader; - HBWaveFormatEx * audioFormat; - int hdrlBytes; - int i; - - /* AVI main header */ - mainHeader = calloc( sizeof( HBAviMainHeader ), 1 ); + HBTitle * title = m->title; + int audioCount = HBListCount( title->ripAudioList ); + AviVideoMuxData * videoMuxData = (AviVideoMuxData *) title->muxData; + AviAudioMuxData * audioMuxData; + HBAudio * audio; + int hdrlBytes; + int i; - mainHeader->FourCC = FOURCC( "avih" ); - mainHeader->BytesCount = sizeof( HBAviMainHeader ) - 8; - mainHeader->MicroSecPerFrame = (uint64_t) 1000000 * - title->rateBase / title->rate; - mainHeader->Streams = 1 + audioCount; - mainHeader->Width = title->outWidth; - mainHeader->Height = title->outHeight; + /* Open destination file */ + HBLog( "HBAviMux: opening %s", title->file ); + if( !( m->file = fopen( title->file, "wb" ) ) ) + { + HBLog( "HBAviMux: fopen() failed" ); + HBErrorOccured( m->handle, HB_ERROR_AVI_WRITE ); + return 1; + } - title->aviMainHeader = mainHeader; + /* AVI main header */ + mh.FourCC = FOURCC( "avih" ); + mh.BytesCount = sizeof( HBAviMainHeader ) - 8; + mh.MicroSecPerFrame = (uint64_t) 1000000 * title->rateBase / + title->rate; + mh.Streams = 1 + audioCount; + mh.Width = title->outWidth; + mh.Height = title->outHeight; /* Video stream header */ - videoHeader = calloc( sizeof( HBAviStreamHeader ), 1 ); - - videoHeader->FourCC = FOURCC( "strh" ); - videoHeader->BytesCount = sizeof( HBAviStreamHeader ) - 8; - videoHeader->Type = FOURCC( "vids" ); + vh.FourCC = FOURCC( "strh" ); + vh.BytesCount = sizeof( HBAviStreamHeader ) - 8; + vh.Type = FOURCC( "vids" ); if( title->codec == HB_CODEC_FFMPEG ) - videoHeader->Handler = FOURCC( "divx" ); + vh.Handler = FOURCC( "divx" ); else if( title->codec == HB_CODEC_XVID ) - videoHeader->Handler = FOURCC( "xvid" ); + vh.Handler = FOURCC( "xvid" ); else if( title->codec == HB_CODEC_X264 ) - videoHeader->Handler = FOURCC( "H264" ); - - videoHeader->Scale = title->rateBase; - videoHeader->Rate = title->rate; + vh.Handler = FOURCC( "h264" ); - title->aviVideoHeader = videoHeader; + vh.Scale = title->rateBase; + vh.Rate = title->rate; /* Video stream format */ - videoFormat = calloc( sizeof( HBBitmapInfo ), 1 ); - - videoFormat->FourCC = FOURCC( "strf" ); - videoFormat->BytesCount = sizeof( HBBitmapInfo ) - 8; - videoFormat->Size = sizeof( HBBitmapInfo ) - 8; - videoFormat->Width = title->outWidth; - videoFormat->Height = title->outHeight; - videoFormat->Planes = 1; - videoFormat->BitCount = 24; + vf.FourCC = FOURCC( "strf" ); + vf.BytesCount = sizeof( HBBitmapInfo ) - 8; + vf.Size = sizeof( HBBitmapInfo ) - 8; + vf.Width = title->outWidth; + vf.Height = title->outHeight; + vf.Planes = 1; + vf.BitCount = 24; if( title->codec == HB_CODEC_FFMPEG ) - videoFormat->Compression = FOURCC( "DX50" ); + vf.Compression = FOURCC( "DX50" ); else if( title->codec == HB_CODEC_XVID ) - videoFormat->Compression = FOURCC( "XVID" ); + vf.Compression = FOURCC( "XVID" ); else if( title->codec == HB_CODEC_X264 ) - videoFormat->Compression = FOURCC( "H264" ); - - title->aviVideoFormat = videoFormat; + vf.Compression = FOURCC( "H264" ); for( i = 0; i < audioCount; i++ ) { - audio = HBListItemAt( title->ripAudioList, i ); + audio = HBListItemAt( title->ripAudioList, i ); + audioMuxData = (AviAudioMuxData *) audio->muxData; /* Audio stream header */ - audioHeader = calloc( sizeof( HBAviStreamHeader ), 1 ); - - audioHeader->FourCC = FOURCC( "strh" ); - audioHeader->BytesCount = sizeof( HBAviStreamHeader ) - 8; - audioHeader->Type = FOURCC( "auds" ); - audioHeader->InitialFrames = 1; - audioHeader->Scale = 1152; - audioHeader->Rate = audio->outSampleRate; - audioHeader->Quality = 0xFFFFFFFF; - - audio->aviAudioHeader = audioHeader; + ah.FourCC = FOURCC( "strh" ); + ah.BytesCount = sizeof( HBAviStreamHeader ) - 8; + ah.Type = FOURCC( "auds" ); + ah.InitialFrames = 1; + ah.Scale = 1; + ah.Rate = audio->outBitrate * 1000 / 8; + ah.SampleSize = 1; + ah.Quality = 0xFFFFFFFF; /* Audio stream format */ - audioFormat = calloc( sizeof( HBWaveFormatEx ), 1 ); - - audioFormat->FourCC = FOURCC( "strf" ); - audioFormat->BytesCount = sizeof( HBWaveFormatEx ) - 8; - audioFormat->FormatTag = 0x55; - audioFormat->Channels = 2; - audioFormat->SamplesPerSec = audio->outSampleRate; - audioFormat->AvgBytesPerSec = audio->outBitrate * 1024 / 8; - audioFormat->BlockAlign = 1152; - audioFormat->Size = 12; - audioFormat->Id = 1; - audioFormat->Flags = 2; - audioFormat->BlockSize = 1152; - audioFormat->FramesPerBlock = 1; - audioFormat->CodecDelay = 1393; - - audio->aviAudioFormat = audioFormat; + af.FourCC = FOURCC( "strf" ); + af.BytesCount = sizeof( HBWaveFormatEx ) - 8; + af.FormatTag = 0x55; + af.Channels = 2; + af.SamplesPerSec = audio->outSampleRate; + af.AvgBytesPerSec = audio->outBitrate * 1000 / 8; + af.BlockAlign = 1; + af.Size = 12; + af.Id = 1; + af.Flags = 2; + af.BlockSize = 1152 * af.AvgBytesPerSec / + audio->outSampleRate; + af.FramesPerBlock = 1; + af.CodecDelay = 1393; } hdrlBytes = 4 + sizeof( HBAviMainHeader ) + ( 1 + audioCount ) * @@ -405,114 +297,147 @@ static void InitAviHeaders( HBAviMux * a ) /* 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, title->aviMainHeader ); - WriteInt32( file, FOURCC( "LIST" ) ); - WriteInt32( file, 4 + sizeof( HBAviStreamHeader ) + - sizeof( HBBitmapInfo ) ); - WriteInt32( file, FOURCC( "strl" ) ); - WriteStreamHeader( file, title->aviVideoHeader ); - WriteHBBitmapInfo( file, title->aviVideoFormat ); + WriteInt32( m->file, FOURCC( "RIFF" ) ); + WriteInt32( m->file, 2040 ); + WriteInt32( m->file, FOURCC( "AVI " ) ); + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, hdrlBytes ); + WriteInt32( m->file, FOURCC( "hdrl" ) ); + WriteMainHeader( m->file, &mh ); + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, 4 + sizeof( HBAviStreamHeader ) + + sizeof( HBBitmapInfo ) ); + WriteInt32( m->file, FOURCC( "strl" ) ); + WriteStreamHeader( m->file, &vh ); + WriteHBBitmapInfo( m->file, &vf ); for( i = 0; i < audioCount; i++ ) { char fourCC[5]; audio = HBListItemAt( title->ripAudioList, i ); + audioMuxData = (AviAudioMuxData *) audio->muxData; snprintf( fourCC, 5, "%02dwb", i + 1 ); - audio->aviFourCC = FOURCC( fourCC ); + audioMuxData->fourCC = FOURCC( fourCC ); - WriteInt32( file, FOURCC( "LIST" ) ); - WriteInt32( file, 4 + sizeof( HBAviStreamHeader ) + + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, 4 + sizeof( HBAviStreamHeader ) + sizeof( HBWaveFormatEx ) ); - WriteInt32( file, FOURCC( "strl" ) ); - WriteStreamHeader( file, audio->aviAudioHeader ); - WriteHBWaveFormatEx( file, audio->aviAudioFormat ); + WriteInt32( m->file, FOURCC( "strl" ) ); + WriteStreamHeader( m->file, &ah ); + WriteHBWaveFormatEx( m->file, &af ); } - WriteInt32( file, FOURCC( "JUNK" ) ); - WriteInt32( file, 2008 - hdrlBytes ); + WriteInt32( m->file, FOURCC( "JUNK" ) ); + WriteInt32( m->file, 2008 - hdrlBytes ); for( i = 0; i < 2008 - hdrlBytes; i++ ) { - WriteInt8( file, 0 ); + WriteInt8( m->file, 0 ); } - WriteInt32( file, FOURCC( "LIST" ) ); - WriteInt32( file, 4 ); - WriteInt32( file, FOURCC( "movi" ) ); + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, 4 ); + WriteInt32( m->file, FOURCC( "movi" ) ); + + return 0; +} + +static int AviMuxVideo( HBMux * m, void * _muxData, HBBuffer * buffer ) +{ + AviVideoMuxData * muxData = (AviVideoMuxData *) _muxData; + AddChunk( m, buffer, FOURCC( "00dc" ), &muxData->videoHeader ); + return 0; +} + +static int AviMuxAudio( HBMux * m, void * _muxData, HBBuffer * buffer ) +{ + AviAudioMuxData * muxData = (AviAudioMuxData *) _muxData; + AddChunk( m, buffer, muxData->fourCC, &muxData->audioHeader ); + return 0; +} + +static int AviEnd( HBMux * m ) +{ + AddIndex( m ); + fclose( m->file ); + return 0; } +#undef mh +#undef vh +#undef vf +#undef ah +#undef af -static void AddChunk( HBAviMux * a, HBBuffer * buffer, +static void AddChunk( HBMux * m, HBBuffer * buffer, uint32_t fourCC, HBAviStreamHeader * header ) { - HBTitle * title = a->title; + HBTitle * title = m->title; + AviVideoMuxData * videoMuxData = (AviVideoMuxData *) title->muxData; + AviAudioMuxData * audioMuxData; HBAudio * audio; int i; /* 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 ); + IndexAddInt32( m->index, fourCC ); + IndexAddInt32( m->index, buffer->keyFrame ? AVIIF_KEYFRAME : 0 ); + IndexAddInt32( m->index, 4 + m->size ); + IndexAddInt32( m->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 ); + fseek( m->file, 0, SEEK_END ); + WriteInt32( m->file, fourCC ); + WriteInt32( m->file, buffer->size ); + WriteBuffer( m->file, buffer ); /* Chunks must be 2-bytes aligned */ if( buffer->size & 1 ) { - WriteInt8( a->file, 0 ); + WriteInt8( m->file, 0 ); } /* Update headers */ - a->size += 8 + EVEN( buffer->size ); + m->size += 8 + EVEN( buffer->size ); header->Length++; /* RIFF size */ - fseek( a->file, 4, SEEK_SET ); - WriteInt32( a->file, 2040 + a->size ); + fseek( m->file, 4, SEEK_SET ); + WriteInt32( m->file, 2040 + m->size ); /* HBAviStreamHeader's lengths */ - fseek( a->file, 140, SEEK_SET ); - WriteInt32( a->file, title->aviVideoHeader->Length ); + fseek( m->file, 140, SEEK_SET ); + WriteInt32( m->file, videoMuxData->videoHeader.Length ); for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); - fseek( a->file, 268 + i * 114, SEEK_SET ); - WriteInt32( a->file, audio->aviAudioHeader->Length ); + audioMuxData = (AviAudioMuxData *) audio->muxData; + fseek( m->file, 268 + i * 114, SEEK_SET ); + WriteInt32( m->file, audioMuxData->audioHeader.Length ); } /* movi size */ - fseek( a->file, 2040, SEEK_SET ); - WriteInt32( a->file, 4 + a->size ); + fseek( m->file, 2040, SEEK_SET ); + WriteInt32( m->file, 4 + m->size ); } -static void AddIndex( HBAviMux * a ) +static void AddIndex( HBMux * m ) { - HBTitle * title = a->title; + HBTitle * title = m->title; + AviVideoMuxData * videoMuxData = (AviVideoMuxData *) title->muxData; - fseek( a->file, 0, SEEK_END ); + fseek( m->file, 0, SEEK_END ); - WriteInt32( a->file, FOURCC( "idx1" ) ); - WriteInt32( a->file, a->index->size ); - WriteBuffer( a->file, a->index ); + WriteInt32( m->file, FOURCC( "idx1" ) ); + WriteInt32( m->file, m->index->size ); + WriteBuffer( m->file, m->index ); - a->size += 8 + a->index->size; - fseek( a->file, 4, SEEK_SET ); - WriteInt32( a->file, 2040 + a->size ); - title->aviMainHeader->Flags |= AVIF_HASINDEX; - fseek( a->file, 24, SEEK_SET ); - WriteMainHeader( a->file, title->aviMainHeader ); + m->size += 8 + m->index->size; + fseek( m->file, 4, SEEK_SET ); + WriteInt32( m->file, 2040 + m->size ); + videoMuxData->mainHeader.Flags |= AVIF_HASINDEX; + fseek( m->file, 24, SEEK_SET ); + WriteMainHeader( m->file, &videoMuxData->mainHeader ); } static void WriteInt8( FILE * file, uint8_t val ) @@ -554,12 +479,6 @@ static void WriteHBBitmapInfo( FILE * file, HBBitmapInfo * bitmapInfo ) WriteInt32( file, bitmapInfo->YPelsPerMeter ); WriteInt32( file, bitmapInfo->ClrUsed ); WriteInt32( file, bitmapInfo->ClrImportant ); -#if 0 - WriteInt8( file, bitmapInfo->Blue ); - WriteInt8( file, bitmapInfo->Green ); - WriteInt8( file, bitmapInfo->Red ); - WriteInt8( file, bitmapInfo->Reserved ); -#endif } static void WriteHBWaveFormatEx( FILE * file, HBWaveFormatEx * waveFormatEx ) diff --git a/core/DVDRead.c b/core/DVDRead.c index 08e5139f8..4c36f3942 100644 --- a/core/DVDRead.c +++ b/core/DVDRead.c @@ -1,4 +1,4 @@ -/* $Id: DVDRead.c,v 1.10 2004/02/29 11:21:34 titer Exp $ +/* $Id: DVDRead.c,v 1.13 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,12 +6,7 @@ #include "HBInternal.h" -/* libdvdplay */ -#include "dvdread/ifo_types.h" -#include "dvdplay/dvdplay.h" -#include "dvdplay/info.h" -#include "dvdplay/state.h" -#include "dvdplay/nav.h" +#include "dvdread/dvd_reader.h" /* Local prototypes */ static void DVDReadThread( void * ); @@ -23,7 +18,8 @@ struct HBDVDRead { HBHandle * handle; - dvdplay_ptr vmg; + dvd_reader_t * reader; + dvd_file_t * file; HBTitle * title; int beginPosition; int endPosition; @@ -46,7 +42,8 @@ HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * title ) /* Initializations */ d->handle = handle; - d->vmg = NULL; + d->reader = NULL; + d->file = NULL; d->title = title; d->beginPosition = 0; d->endPosition = 0; @@ -92,27 +89,20 @@ static void DVDReadThread( void * _d ) int i; /* Open the device */ - d->vmg = dvdplay_open( title->device, NULL, NULL ); - if( !d->vmg ) + d->reader = DVDOpen( title->device ); + if( !d->reader ) { - HBLog( "HBDVDRead: dvdplay_open() failed" ); + HBLog( "HBDVDRead: DVDOpen() failed" ); HBErrorOccured( d->handle, HB_ERROR_DVD_OPEN ); return; } /* Open the title */ - dvdplay_start( d->vmg, title->index ); - d->beginPosition = dvdplay_title_first( d->vmg ); - d->endPosition = dvdplay_title_end( d->vmg ); - - HBLog( "HBDVDRead: starting, blocks: %d to %d", - d->beginPosition, d->endPosition ); + d->file = DVDOpenFile( d->reader, title->vts_id, DVD_READ_TITLE_VOBS ); /* Do the job */ for( i = 0; i < ( title->twoPass ? 2 : 1 ); i++ ) { - dvdplay_start( d->vmg, title->index ); - HBLog( "HBDVDRead: starting pass %d of %d", i + 1, title->twoPass ? 2 : 1 ); @@ -131,7 +121,8 @@ static void DVDReadThread( void * _d ) } /* Clean up */ - dvdplay_close( d->vmg ); + DVDCloseFile( d->file ); + DVDClose( d->reader ); } @@ -139,11 +130,11 @@ static int DoPass( HBDVDRead * d ) { int i; - for( i = 0; i < d->endPosition - d->beginPosition; i++ ) + for( i = d->title->startBlock; i < d->title->endBlock; i++ ) { d->psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); - d->psBuffer->position = - (float) i / ( d->endPosition - d->beginPosition ); + d->psBuffer->position = (float) ( i - d->title->startBlock ) / + ( d->title->endBlock - d->title->startBlock ); if( d->pass ) { @@ -156,9 +147,9 @@ static int DoPass( HBDVDRead * d ) } d->psBuffer->pass = d->pass; - if( dvdplay_read( d->vmg, d->psBuffer->data, 1 ) < 0 ) + if( DVDReadBlocks( d->file, i, 1, d->psBuffer->data ) < 0 ) { - HBLog( "HBDVDRead: dvdplay_read() failed" ); + HBLog( "HBDVDRead: DVDReadBlocks() failed" ); HBErrorOccured( d->handle, HB_ERROR_DVD_READ ); HBBufferClose( &d->psBuffer ); return 0; @@ -195,6 +186,7 @@ static int Demux( HBDVDRead * d ) continue; } + /* Video */ if( esBuffer->streamId == 0xE0 ) { if( title->start < 0 ) @@ -212,6 +204,7 @@ static int Demux( HBDVDRead * d ) continue; } + /* Audio or whatever */ for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); diff --git a/core/FaacEnc.c b/core/FaacEnc.c index b55a9deb6..689e6e18f 100644 --- a/core/FaacEnc.c +++ b/core/FaacEnc.c @@ -1,4 +1,4 @@ -/* $Id: FaacEnc.c,v 1.15 2004/02/18 17:07:20 titer Exp $ +/* $Id: FaacEnc.c,v 1.20 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,7 +9,7 @@ /* libfaac */ #include "faac.h" -typedef struct HBFaacEnc +struct HBWork { HB_WORK_COMMON_MEMBERS @@ -19,193 +19,119 @@ typedef struct HBFaacEnc faacEncHandle * faac; unsigned long inputSamples; unsigned long maxOutputBytes; - int32_t * inputBuffer; - unsigned long samplesGot; - HBBuffer * rawBuffer; - int rawBufferPos; /* in bytes */ - float position; - HBBuffer * aacBuffer; - - /* Stats */ - int64_t samples; - int64_t bytes; -} HBFaacEnc; + float * inputBuffer; +}; /* Local prototypes */ static int FaacEncWork( HBWork * ); -static int GetSamples( HBFaacEnc * ); HBWork * HBFaacEncInit( HBHandle * handle, HBAudio * audio ) { - HBFaacEnc * f; - if( !( f = calloc( sizeof( HBFaacEnc ), 1 ) ) ) + HBWork * w; + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) { HBLog( "HBFaacEncInit: malloc() failed, gonna crash" ); return NULL; } - f->name = strdup( "FaacEnc" ); - f->work = FaacEncWork; + w->name = strdup( "FaacEnc" ); + w->work = FaacEncWork; - f->handle = handle; - f->audio = audio; + w->handle = handle; + w->audio = audio; - return (HBWork*) f; + return w; } -void HBFaacEncClose( HBWork ** _f ) +void HBFaacEncClose( HBWork ** _w ) { - HBFaacEnc * f = (HBFaacEnc*) *_f; + HBWork * w = *_w; - if( f->faac ) + if( w->faac ) { - faacEncClose( f->faac ); - free( f->inputBuffer ); + faacEncClose( w->faac ); + free( w->inputBuffer ); } - if( f->samples ) - { - int64_t bytes = 128 * f->audio->outBitrate * f->samples / - f->audio->outSampleRate; - float bitrate = (float) f->bytes * f->audio->inSampleRate / - f->samples / 128; - - HBLog( "HBFaacEnc: %lld samples encoded (%lld bytes), %.2f kbps", - f->samples, f->bytes, bitrate ); - HBLog( "HBFaacEnc: error is %lld bytes", f->bytes - bytes ); - } - - free( f->name ); - free( f ); + free( w->name ); + free( w ); - *_f = NULL; + *_w = NULL; } static int FaacEncWork( HBWork * w ) { - HBFaacEnc * f = (HBFaacEnc*) w; - HBAudio * audio = f->audio; + HBAudio * audio = w->audio; - int didSomething = 0; + HBBuffer * aacBuffer; + float position; - if( !f->faac ) + if( !w->faac ) { faacEncConfigurationPtr config; - /* Get a first buffer so we know that audio->inSampleRate is - correct */ - if( ( f->rawBuffer = HBFifoPop( audio->rawFifo ) ) ) - { - didSomething = 1; - } - else + if( !HBFifoSize( audio->resampleFifo ) ) { - return didSomething; + return 0; } - f->rawBufferPos = 0; - f->position = f->rawBuffer->position; HBLog( "HBFaacEnc: opening libfaac (%x)", audio->id ); - /* No resampling */ - audio->outSampleRate = audio->inSampleRate; - - f->faac = faacEncOpen( audio->outSampleRate, 2, - &f->inputSamples, &f->maxOutputBytes ); - f->inputBuffer = malloc( f->inputSamples * sizeof( int32_t ) ); - config = faacEncGetCurrentConfiguration( f->faac ); + w->faac = faacEncOpen( audio->outSampleRate, 2, + &w->inputSamples, &w->maxOutputBytes ); + w->inputBuffer = malloc( w->inputSamples * sizeof( float ) ); + config = faacEncGetCurrentConfiguration( w->faac ); config->mpegVersion = MPEG4; config->aacObjectType = LOW; config->allowMidside = 1; config->useLfe = 0; config->useTns = 0; - config->bitRate = audio->outBitrate * 512; + config->bitRate = audio->outBitrate * 500; /* per channel */ config->bandWidth = 0; config->outputFormat = 0; - faacEncSetConfiguration( f->faac, config ); - faacEncGetDecoderSpecificInfo( f->faac, &audio->esConfig, - &audio->esConfigLength ); - } - - /* Push encoded buffer */ - if( f->aacBuffer ) - { - if( HBFifoPush( audio->outFifo, &f->aacBuffer ) ) + config->inputFormat = FAAC_INPUT_FLOAT; + if( !faacEncSetConfiguration( w->faac, config ) ) { - didSomething = 1; + HBLog( "HBFaacEnc: faacEncSetConfiguration failed" ); } - else + if( faacEncGetDecoderSpecificInfo( w->faac, &audio->esConfig, + &audio->esConfigLength ) < 0 ) { - return didSomething; + HBLog( "HBFaacEnc: faacEncGetDecoderSpecificInfo failed" ); } } - if( GetSamples( f ) ) + if( HBFifoIsHalfFull( audio->outFifo ) ) { - didSomething = 1; + return 0; } - else + + if( !HBFifoGetBytes( audio->resampleFifo, + (uint8_t *) w->inputBuffer, + w->inputSamples * sizeof( float ), + &position ) ) { - return didSomething; + return 0; } - f->samplesGot = 0; - - f->aacBuffer = HBBufferInit( f->maxOutputBytes ); - f->aacBuffer->position = f->position; - f->aacBuffer->size = faacEncEncode( f->faac, f->inputBuffer, - f->inputSamples, f->aacBuffer->data, f->maxOutputBytes ); + aacBuffer = HBBufferInit( w->maxOutputBytes ); + aacBuffer->position = position; + aacBuffer->size = faacEncEncode( w->faac, (int32_t*)w->inputBuffer, + w->inputSamples, aacBuffer->data, w->maxOutputBytes ); - f->samples += f->inputSamples / 2; - - if( !f->aacBuffer->size ) + if( !aacBuffer->size ) { - HBBufferClose( &f->aacBuffer ); + HBBufferClose( &aacBuffer ); } - else if( f->aacBuffer->size < 0 ) + else if( aacBuffer->size < 0 ) { HBLog( "HBFaacEnc: faacEncEncode() failed" ); } else { - f->bytes += f->aacBuffer->size; - } - - return didSomething; -} - -static int GetSamples( HBFaacEnc * f ) -{ - while( f->samplesGot < f->inputSamples ) - { - int i, copy; - - if( !f->rawBuffer ) - { - if( !( f->rawBuffer = HBFifoPop( f->audio->rawFifo ) ) ) - { - return 0; - } - - f->rawBufferPos = 0; - f->position = f->rawBuffer->position; - } - - copy = MIN( f->inputSamples - f->samplesGot, - ( f->rawBuffer->samples - f->rawBufferPos ) * 2 ); - - for( i = 0; i < copy; i += 2 ) - { - f->inputBuffer[f->samplesGot++] = - f->rawBuffer->left[f->rawBufferPos]; - f->inputBuffer[f->samplesGot++] = - f->rawBuffer->right[f->rawBufferPos]; - f->rawBufferPos++; - } - - if( f->rawBufferPos == f->rawBuffer->samples ) + if( !HBFifoPush( audio->outFifo, &aacBuffer ) ) { - HBBufferClose( &f->rawBuffer ); + HBLog( "HBFaacEnc: HBFifoPush failed" ); } } diff --git a/core/FfmpegEnc.c b/core/FfmpegEnc.c index 7d909a7a3..ae474d00b 100644 --- a/core/FfmpegEnc.c +++ b/core/FfmpegEnc.c @@ -1,4 +1,4 @@ -/* $Id: FfmpegEnc.c,v 1.19 2004/03/01 21:36:36 titer Exp $ +/* $Id: FfmpegEnc.c,v 1.26 2004/05/12 18:02:35 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,120 +9,89 @@ /* libavcodec */ #include "ffmpeg/avcodec.h" -typedef struct HBFfmpegEnc +struct HBWork { HB_WORK_COMMON_MEMBERS HBHandle * handle; HBTitle * title; - HBBuffer * mpeg4Buffer; int pass; AVCodecContext * context; FILE * file; - - /* Stats */ - int frames; - int64_t bytes; -} HBFfmpegEnc; +}; /* Local prototypes */ static int FfmpegEncWork( HBWork * ); -static int InitAvcodec( HBFfmpegEnc * ); -static void CloseAvcodec( HBFfmpegEnc * ); +static int InitAvcodec( HBWork * ); +static void CloseAvcodec( HBWork * ); HBWork * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) { - HBFfmpegEnc * f; - if( !( f = calloc( sizeof( HBFfmpegEnc ), 1 ) ) ) + HBWork * w; + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) { HBLog( "HBFfmpegEncInit: malloc() failed, gonna crash" ); return NULL; } - f->name = strdup( "FfmpegEnc" ); - f->work = FfmpegEncWork; + w->name = strdup( "FfmpegEnc" ); + w->work = FfmpegEncWork; - f->handle = handle; - f->title = title; - f->pass = 42; + w->handle = handle; + w->title = title; + w->pass = 42; - return (HBWork*) f; + return w; } -void HBFfmpegEncClose( HBWork ** _f ) +void HBFfmpegEncClose( HBWork ** _w ) { - HBFfmpegEnc * f = (HBFfmpegEnc*) *_f; + HBWork * w = *_w; - if( f->context ) + if( w->context ) { - CloseAvcodec( f ); + CloseAvcodec( w ); } - /* Stats */ - if( f->frames ) - { - float bitrate = (float) f->bytes * f->title->rate / - f->frames / f->title->rateBase / 128; - int64_t bytes = (int64_t) f->frames * f->title->bitrate * 128 * - f->title->rateBase / f->title->rate; - - HBLog( "HBFfmpegEnc: %d frames encoded (%lld bytes), %.2f kbps", - f->frames, f->bytes, bitrate ); - HBLog( "HBFfmpegEnc: error is %lld bytes", f->bytes - bytes ); - } - free( f->name ); - free( f ); + free( w->name ); + free( w ); - *_f = NULL; + *_w = NULL; } static int FfmpegEncWork( HBWork * w ) { - HBFfmpegEnc * f = (HBFfmpegEnc*) w; - HBTitle * title = f->title; + HBTitle * title = w->title; HBBuffer * scaledBuffer; HBBuffer * mpeg4Buffer; AVFrame * frame; - int didSomething = 0; - - if( f->mpeg4Buffer ) + if( HBFifoIsHalfFull( title->outFifo ) ) { - if( HBFifoPush( title->outFifo, &f->mpeg4Buffer ) ) - { - didSomething = 1; - } - else - { - return didSomething; - } + return 0; } - if( ( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) + if( !( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) { - didSomething = 1; - } - else - { - return didSomething; + return 0; } /* Init or re-init if needed */ - if( scaledBuffer->pass != f->pass ) + if( scaledBuffer->pass != w->pass ) { - if( f->context ) + if( w->context ) { - CloseAvcodec( f ); + CloseAvcodec( w ); } - - f->pass = scaledBuffer->pass; - - if( !InitAvcodec( f ) ) + + w->pass = scaledBuffer->pass; + + if( !InitAvcodec( w ) ) { - HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); - return didSomething; + HBErrorOccured( w->handle, HB_ERROR_MPEG4_INIT ); + return 0; } } @@ -139,49 +108,48 @@ static int FfmpegEncWork( HBWork * w ) mpeg4Buffer = HBBufferInit( 3 * title->outWidth * title->outHeight / 2 ); mpeg4Buffer->position = scaledBuffer->position; - mpeg4Buffer->size = avcodec_encode_video( f->context, + mpeg4Buffer->size = avcodec_encode_video( w->context, mpeg4Buffer->data, mpeg4Buffer->alloc, frame ); - mpeg4Buffer->keyFrame = f->context->coded_frame->key_frame; + mpeg4Buffer->keyFrame = w->context->coded_frame->key_frame; /* Inform the GUI about the current position */ - HBPosition( f->handle, scaledBuffer->position ); + HBPosition( w->handle, scaledBuffer->position ); - if( f->pass == 1 ) + if( w->pass == 1 ) { - if( f->context->stats_out ) + if( w->context->stats_out ) { - fprintf( f->file, "%s", f->context->stats_out ); + fprintf( w->file, "%s", w->context->stats_out ); } HBBufferClose( &mpeg4Buffer ); } else { - f->mpeg4Buffer = mpeg4Buffer; - - /* Stats */ - f->frames++; - f->bytes += mpeg4Buffer->size; + if( !HBFifoPush( title->outFifo, &mpeg4Buffer ) ) + { + HBLog( "HBFfmpegEnc: HBFifoPush failed" ); + } } HBBufferClose( &scaledBuffer ); free( frame ); - return didSomething; + return 1; } -static int InitAvcodec( HBFfmpegEnc * f ) +static int InitAvcodec( HBWork * w ) { AVCodec * codec; AVCodecContext * context; - HBTitle * title = f->title; + HBTitle * title = w->title; - HBLog( "HBFfmpegEnc: opening libavcodec (pass %d)", f->pass ); + HBLog( "HBFfmpegEnc: opening libavcodec (pass %d)", w->pass ); codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); if( !codec ) { HBLog( "HBFfmpegEnc: avcodec_find_encoder() failed" ); - HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); + HBErrorOccured( w->handle, HB_ERROR_MPEG4_INIT ); return 0; } @@ -194,20 +162,25 @@ static int InitAvcodec( HBFfmpegEnc * f ) context->frame_rate_base = title->rateBase; context->gop_size = 10 * title->rate / title->rateBase; - if( title->mux == HB_MUX_MP4 && f->pass != 1 ) + if( title->mux == HB_MUX_MP4 && w->pass != 1 ) { context->flags |= CODEC_FLAG_GLOBAL_HEADER; } - if( f->pass ) + if( w->pass ) { char fileName[1024]; memset( fileName, 0, 1024 ); +#ifndef HB_CYGWIN sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", - HBGetPid( f->handle ) ); + HBGetPid( w->handle ) ); +#else + sprintf( fileName, "C:\\HB.%d.ffmpeg.log", + HBGetPid( w->handle ) ); +#endif - if( f->pass == 1 ) + if( w->pass == 1 ) { - f->file = fopen( fileName, "w" ); + w->file = fopen( fileName, "wb" ); context->flags |= CODEC_FLAG_PASS1; } else @@ -216,7 +189,7 @@ static int InitAvcodec( HBFfmpegEnc * f ) int size; char * log; - file = fopen( fileName, "r" ); + file = fopen( fileName, "rb" ); fseek( file, 0, SEEK_END ); size = ftell( file ); fseek( file, 0, SEEK_SET ); @@ -245,7 +218,7 @@ static int InitAvcodec( HBFfmpegEnc * f ) return 0; } - if( title->mux == HB_MUX_MP4 && f->pass != 1 ) + if( title->mux == HB_MUX_MP4 && w->pass != 1 ) { /* UGLY */ title->esConfig = malloc( 15 ); @@ -253,30 +226,30 @@ static int InitAvcodec( HBFfmpegEnc * f ) memcpy( title->esConfig, context->extradata + 15, 15 ); } - f->context = context; + w->context = context; return 1; } -static void CloseAvcodec( HBFfmpegEnc * f ) +static void CloseAvcodec( HBWork * w ) { HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", - f->pass ); + w->pass ); - if( f->context->stats_in ) + if( w->context->stats_in ) { - free( f->context->stats_in ); + free( w->context->stats_in ); } - avcodec_close( f->context ); - if( f->file ) + avcodec_close( w->context ); + if( w->file ) { - fclose( f->file ); - f->file = NULL; + fclose( w->file ); + w->file = NULL; } - if( f->title->esConfig ) + if( w->title->esConfig ) { - free( f->title->esConfig ); - f->title->esConfig = NULL; - f->title->esConfigLength = 0; + free( w->title->esConfig ); + w->title->esConfig = NULL; + w->title->esConfigLength = 0; } } diff --git a/core/Fifo.c b/core/Fifo.c index 5c32c59a1..ae0c412da 100644 --- a/core/Fifo.c +++ b/core/Fifo.c @@ -1,4 +1,4 @@ -/* $Id: Fifo.c,v 1.14 2004/03/17 10:35:06 titer Exp $ +/* $Id: Fifo.c,v 1.17 2004/04/27 19:30:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -14,7 +14,7 @@ HBBuffer * HBBufferInit( int size ) HBBuffer * b; if( !( b = calloc( sizeof( HBBuffer ), 1 ) ) ) { - HBLog( "HBBufferInit: malloc() failed, gonna crash" ); + HBLog( "HBBuffer: malloc() failed, gonna crash" ); return NULL; } @@ -31,10 +31,11 @@ HBBuffer * HBBufferInit( int size ) b->data = b->dataOrig + 15; b->data -= (long) b->data & 15; #endif + b->dataf = (float*) b->data; if( !b->data ) { - HBLog( "HBBufferInit: malloc() failed, gonna crash" ); + HBLog( "HBBuffer: malloc() failed, gonna crash" ); free( b ); return NULL; } @@ -57,7 +58,7 @@ void HBBufferReAlloc( HBBuffer * b, int size ) if( !b->data ) { - HBLog( "HBBufferReAlloc: realloc() failed, gonna crash soon" ); + HBLog( "HBBuffer: realloc() failed, gonna crash soon" ); } } @@ -80,7 +81,7 @@ HBFifo * HBFifoInit( int capacity ) HBFifo * f; if( !( f = malloc( sizeof( HBFifo ) ) ) ) { - HBLog( "HBFifoInit: malloc() failed, gonna crash" ); + HBLog( "HBFifo: malloc() failed, gonna crash" ); return NULL; } @@ -91,7 +92,7 @@ HBFifo * HBFifoInit( int capacity ) if( !( f->buffers = malloc( ( capacity + 1 ) * sizeof( void* ) ) ) ) { - HBLog( "HBFifoInit: malloc() failed, gonna crash" ); + HBLog( "HBFifo: malloc() failed, gonna crash" ); free( f ); return NULL; } @@ -114,7 +115,7 @@ void HBFifoClose( HBFifo ** _f ) { HBFifo * f = (*_f); - HBLog( "HBFifoClose: trashing %d buffer%s", + HBLog( "HBFifo: trashing %d buffer%s", HBFifoSize( f ), ( HBFifoSize( f ) > 1 ) ? "s" : "" ); while( f->whereToPush != f->whereToPop ) diff --git a/core/Fifo.h b/core/Fifo.h index 264a7eeb3..26c4b5581 100644 --- a/core/Fifo.h +++ b/core/Fifo.h @@ -1,4 +1,4 @@ -/* $Id: Fifo.h,v 1.13 2004/03/17 10:35:06 titer Exp $ +/* $Id: Fifo.h,v 1.16 2004/04/27 22:02:59 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -19,23 +19,22 @@ struct HBBuffer #if defined( HB_CYGWIN ) uint8_t * dataOrig; #endif + float * dataf; float position; int pass; /* Only used for PStoES */ - int streamId; + uint32_t streamId; uint64_t pts; /* NTSC suxx */ int repeat; - /* Only used for raw audio buffers */ - int samples; /* Number of samples for each track */ - float * left; - float * right; - /* Only used for MPEG-4, MP3 and AAC buffers */ int keyFrame; + + /* Use for bitstreams */ + int _pos; }; HBBuffer * HBBufferInit( int size ); @@ -55,10 +54,13 @@ struct HBFifo HBFifo * HBFifoInit( int capacity ); static inline int HBFifoSize( HBFifo * ); +static inline int HBFifoIsHalfFull( HBFifo * ); static inline int HBFifoPush( HBFifo *, HBBuffer ** ); static inline HBBuffer * HBFifoPop( HBFifo * ); static inline int HBFifoWait( HBFifo * ); static inline float HBFifoPosition( HBFifo * ); +static inline int HBFifoGetBytes( HBFifo * f, uint8_t *, int, + float * position ); void HBFifoDie( HBFifo * ); void HBFifoClose( HBFifo ** ); @@ -72,6 +74,16 @@ static inline int HBFifoSize( HBFifo * f ) return size; } +static inline int HBFifoIsHalfFull( HBFifo * f ) +{ + int size; + HBLockLock( f->lock ); + size = ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % + ( f->capacity + 1 ); + HBLockUnlock( f->lock ); + return ( 2 * size > f->capacity ); +} + static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) { HBLockLock( f->lock ); @@ -144,4 +156,62 @@ static inline float HBFifoPosition( HBFifo * f ) return pos; } +static inline int HBFifoGetBytes( HBFifo * f, uint8_t * data, int nb, + float * position ) +{ + int whereToPop, bytes = 0; + HBBuffer * buffer; + HBLockLock( f->lock ); + + /* Do we have enough? */ + for( whereToPop = f->whereToPop; ; whereToPop++ ) + { + whereToPop %= ( f->capacity + 1 ); + if( f->whereToPush == whereToPop ) + { + /* We hit the end of the fifo */ + break; + } + + bytes += f->buffers[whereToPop]->size - + f->buffers[whereToPop]->_pos; + + if( bytes >= nb ) + { + break; + } + } + + if( bytes < nb ) + { + /* Not enough data */ + HBLockUnlock( f->lock ); + return 0; + } + + for( bytes = 0; bytes < nb; ) + { + int copy; + + buffer = f->buffers[f->whereToPop]; + copy = MIN( nb - bytes, buffer->size - buffer->_pos ); + + memcpy( data + bytes, buffer->data + buffer->_pos, copy ); + (*position) = buffer->position; + + buffer->_pos += copy; + bytes += copy; + + if( buffer->_pos == buffer->size ) + { + HBBufferClose( &buffer ); + f->whereToPop++; + f->whereToPop %= ( f->capacity + 1 ); + } + } + + HBLockUnlock( f->lock ); + return 1; +} + #endif diff --git a/core/HBInternal.h b/core/HBInternal.h index a8adb4d44..4fa45f8b0 100644 --- a/core/HBInternal.h +++ b/core/HBInternal.h @@ -1,4 +1,4 @@ -/* $Id: HBInternal.h,v 1.5 2004/03/08 11:32:48 titer Exp $ +/* $Id: HBInternal.h,v 1.10 2004/05/12 17:21:24 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,9 +9,16 @@ #include "HandBrake.h" #include "Fifo.h" +#include "Mux.h" #include "Thread.h" #include "Work.h" +#ifndef HB_CYGWIN +#define LLD "%lld" +#else +#define LLD "%I64d" +#endif + /* Demuxer */ HBDVDRead * HBDVDReadInit( HBHandle *, HBTitle * ); void HBDVDReadClose( HBDVDRead ** ); @@ -23,13 +30,17 @@ HBWork * HBAc3DecInit( HBHandle *, HBAudio * ); void HBAc3DecClose( HBWork ** ); HBWork * HBLpcmDecInit( HBHandle *, HBAudio * ); void HBLpcmDecClose( HBWork ** ); -HBWork * HBMadDecInit( HBHandle *, HBAudio * ); -void HBMadDecClose( HBWork ** ); +HBWork * HBMpgaDecInit( HBHandle *, HBAudio * ); +void HBMpgaDecClose( HBWork ** ); /* Scaler */ HBWork * HBScaleInit( HBHandle *, HBTitle * ); void HBScaleClose( HBWork ** ); +/* Resampler */ +HBWork * HBResampleInit( HBHandle *, HBAudio * ); +void HBResampleClose( HBWork ** ); + /* Encoders */ HBWork * HBFfmpegEncInit( HBHandle *, HBTitle * ); void HBFfmpegEncClose( HBWork ** ); @@ -44,14 +55,6 @@ void HBFaacEncClose( HBWork ** ); HBWork * HBVorbisEncInit ( HBHandle *, HBAudio * ); void HBVorbisEncClose( HBWork ** ); -/* Muxers */ -HBAviMux * HBAviMuxInit( HBHandle *, HBTitle * ); -void HBAviMuxClose( HBAviMux ** ); -HBMp4Mux * HBMp4MuxInit( HBHandle *, HBTitle * ); -void HBMp4MuxClose( HBMp4Mux ** ); -HBOgmMux * HBOgmMuxInit( HBHandle *, HBTitle * ); -void HBOgmMuxClose( HBOgmMux ** ); - /* Scanner */ HBScan * HBScanInit( HBHandle *, const char * device, int title ); void HBScanClose( HBScan ** ); diff --git a/core/HandBrake.c b/core/HandBrake.c index 9c88b37c6..6d16b4640 100644 --- a/core/HandBrake.c +++ b/core/HandBrake.c @@ -1,4 +1,4 @@ -/* $Id: HandBrake.c,v 1.47 2004/03/21 22:58:41 titer Exp $ +/* $Id: HandBrake.c,v 1.58 2004/05/12 18:02:35 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -48,11 +48,6 @@ struct HBHandle HBHandle * HBInit( int debug, int cpuCount ) { HBHandle * h; - if( !( h = calloc( sizeof( HBHandle ), 1 ) ) ) - { - HBLog( "HBInit: malloc() failed, gonna crash" ); - return NULL; - } /* See HBLog() in Utils.cpp */ if( debug ) @@ -60,9 +55,18 @@ HBHandle * HBInit( int debug, int cpuCount ) putenv( "HB_DEBUG=1" ); } + HBLog( "HBInit: starting HandBrake " HB_VERSION ); + + if( !( h = calloc( sizeof( HBHandle ), 1 ) ) ) + { + HBLog( "HBInit: malloc() failed, gonna crash" ); + return NULL; + } + /* Init libavcodec */ avcodec_init(); register_avcodec( &mpeg4_encoder ); + register_avcodec( &mp2_decoder ); /* Check CPU count */ if( !cpuCount ) @@ -131,9 +135,9 @@ void HBStartRip( HBHandle * h, HBTitle * title ) /* Video fifos */ title->inFifo = HBFifoInit( 2048 ); - title->rawFifo = HBFifoInit( 1 ); - title->scaledFifo = HBFifoInit( 1 ); - title->outFifo = HBFifoInit( 1 ); + title->rawFifo = HBFifoInit( 32 ); + title->scaledFifo = HBFifoInit( 32 ); + title->outFifo = HBFifoInit( 32 ); /* Video work objects */ title->decoder = HBMpeg2DecInit( h, title ); @@ -150,15 +154,20 @@ void HBStartRip( HBHandle * h, HBTitle * title ) audio = HBListItemAt( title->ripAudioList, i ); /* Audio fifos */ - audio->inFifo = HBFifoInit( 2048 ); - audio->rawFifo = HBFifoInit( 1 ); - audio->outFifo = HBFifoInit( 4 ); /* At least 4 for Vorbis */ + audio->inFifo = HBFifoInit( 2048 ); + audio->rawFifo = HBFifoInit( 32 ); + audio->resampleFifo = HBFifoInit( 32 ); + audio->outFifo = HBFifoInit( 32 ); /* Audio work objects */ if( audio->inCodec == HB_CODEC_AC3 ) audio->decoder = HBAc3DecInit( h, audio ); else if( audio->inCodec == HB_CODEC_LPCM ) audio->decoder = HBLpcmDecInit( h, audio ); + else if( audio->inCodec == HB_CODEC_MPGA ) + audio->decoder = HBMpgaDecInit( h, audio ); + + audio->resample = HBResampleInit( h, audio ); if( audio->outCodec == HB_CODEC_MP3 ) audio->encoder = HBMp3EncInit( h, audio ); @@ -171,12 +180,7 @@ void HBStartRip( HBHandle * h, HBTitle * title ) /* Create threads */ title->dvdRead = HBDVDReadInit( h, title ); - if( title->mux == HB_MUX_AVI ) - title->aviMux = HBAviMuxInit( h, title ); - else if( title->mux == HB_MUX_MP4 ) - title->mp4Mux = HBMp4MuxInit( h, title ); - else if( title->mux == HB_MUX_OGM ) - title->ogmMux = HBOgmMuxInit( h, title ); + title->muxThread = HBMuxThreadInit( h, title ); for( i = 0; i < h->cpuCount; i++ ) { @@ -254,9 +258,9 @@ uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) /* Get the original image from the temp file */ memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.%d.%d", h->pid, t->index, + sprintf( fileName, "/tmp/HB.%d.%d.%d", h->pid, t->title, picture ); - file = fopen( fileName, "r" ); + file = fopen( fileName, "rb" ); if( file ) { fread( buf1, 3 * t->inWidth * t->inHeight / 2, 1, file ); @@ -341,49 +345,49 @@ int HBGetBitrateForSize( HBTitle * title, int size, int muxer, { int64_t available; int overheadPerFrame; - int sampleRate; int samplesPerFrame; + int length; switch( muxer ) { + /* Overhead are max seen values */ case HB_MUX_MP4: - overheadPerFrame = 5; /* hopefully */ - sampleRate = 48000; /* No resampling */ + overheadPerFrame = 6; samplesPerFrame = 1024; /* AAC */ break; case HB_MUX_AVI: - overheadPerFrame = 24; - sampleRate = 44100; /* Resampling */ + overheadPerFrame = 26; samplesPerFrame = 1152; /* MP3 */ break; case HB_MUX_OGM: overheadPerFrame = 0; /* XXX */ - sampleRate = 48000; /* No resampling */ samplesPerFrame = 1024; /* Vorbis */ break; default: return 0; } - /* Actually target 1 MB less */ - available = (int64_t) ( size - 1 ) * 1024 * 1024; + length = 3600 * title->hours + 60 * title->minutes + + title->seconds + 1; + + available = (int64_t) size * 1024 * 1024; /* Audio data */ - available -= audioCount * title->length * audioBitrate * 128; + available -= audioCount * length * audioBitrate * 1000 / 8; /* Video headers */ - available -= (int64_t) title->length * title->rate * + available -= (int64_t) length * title->rate * overheadPerFrame / title->rateBase; /* Audio headers */ - available -= (int64_t) audioCount * title->length * sampleRate * + available -= (int64_t) audioCount * length * 44100 * overheadPerFrame / samplesPerFrame; if( available < 0 ) { return 0; } - return( available / ( 128 * title->length ) ); + return( available / ( 128 * length ) ); } void HBClose( HBHandle ** _h ) @@ -413,9 +417,11 @@ void HBClose( HBHandle ** _h ) } } +#ifndef HB_CYGWIN memset( command, 0, 1024 ); sprintf( command, "rm -f /tmp/HB.%d.*", h->pid ); system( command ); +#endif HBLockClose( &h->lock ); HBLockClose( &h->pauseLock ); @@ -442,7 +448,6 @@ void HBScanDone( HBHandle * h, HBList * titleList ) h->stopScan = 1; h->titleList = titleList; HBLockUnlock( h->lock ); - h->cb.scanDone( h->cb.data, titleList ); } int HBGetPid( HBHandle * h ) @@ -522,6 +527,7 @@ static void HandBrakeThread( void * _h ) HBScanClose( &h->scan ); h->stopScan = 0; HBLockUnlock( h->lock ); + h->cb.scanDone( h->cb.data, h->titleList ); continue; } @@ -537,10 +543,9 @@ static void HandBrakeThread( void * _h ) if( h->ripDone ) { HBTitle * title = h->curTitle; - HBAudio * audio; - int i, ok = 0; - /* Wait until we're done with the decoding of one track */ + /* Wait until we're done with the video track */ + uint64_t waitStart = HBGetDate(); for( ;; ) { if( !HBFifoSize( title->inFifo ) && @@ -549,26 +554,21 @@ static void HandBrakeThread( void * _h ) { break; } - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); - if( !HBFifoSize( title->inFifo ) && - !HBFifoSize( title->rawFifo ) ) - { - ok = 1; - break; - } - } - if( ok ) + + /* XXX Deadlock workaround */ + if( HBGetDate() - waitStart > 30000000 ) { + HBLog( "Waited too long, stopping now" ); break; } + HBSnooze( 5000 ); } HBSnooze( 500000 ); _StopRip( h ); h->ripDone = 0; + h->error = 0; HBLockUnlock( h->lock ); h->cb.ripDone( h->cb.data, HB_SUCCESS ); continue; @@ -577,9 +577,9 @@ static void HandBrakeThread( void * _h ) if( h->error ) { _StopRip( h ); - h->error = 0; HBLockUnlock( h->lock ); h->cb.ripDone( h->cb.data, h->error ); + h->error = 0; continue; } @@ -615,12 +615,7 @@ static void _StopRip( HBHandle * h ) } /* Stop mux thread */ - if( title->mux == HB_MUX_AVI ) - HBAviMuxClose( &title->aviMux ); - else if( title->mux == HB_MUX_MP4 ) - HBMp4MuxClose( &title->mp4Mux ); - else if( title->mux == HB_MUX_OGM ) - HBOgmMuxClose( &title->ogmMux ); + HBMuxThreadClose( &title->muxThread ); /* Clean up */ HBMpeg2DecClose( &title->decoder ); @@ -645,6 +640,10 @@ static void _StopRip( HBHandle * h ) HBAc3DecClose( &audio->decoder ); else if( audio->inCodec == HB_CODEC_LPCM ) HBLpcmDecClose( &audio->decoder ); + else if( audio->inCodec == HB_CODEC_MPGA ) + HBMpgaDecClose( &audio->decoder ); + + HBResampleClose( &audio->resample ); if( audio->outCodec == HB_CODEC_MP3 ) HBMp3EncClose( &audio->encoder ); @@ -656,6 +655,7 @@ static void _StopRip( HBHandle * h ) /* Audio fifos */ HBFifoClose( &audio->inFifo ); HBFifoClose( &audio->rawFifo ); + HBFifoClose( &audio->resampleFifo ); HBFifoClose( &audio->outFifo ); HBListRemove( title->ripAudioList, audio ); diff --git a/core/Jamfile b/core/Jamfile index 992dc5cf8..3c683531b 100644 --- a/core/Jamfile +++ b/core/Jamfile @@ -1,4 +1,4 @@ -# $Id: Jamfile,v 1.7 2004/03/29 00:28:42 titer Exp $ +# $Id: Jamfile,v 1.12 2004/04/27 19:42:24 titer Exp $ # # This file is part of the HandBrake source code. # Homepage: <http://handbrake.m0k.org/>. @@ -8,21 +8,21 @@ SubDir TOP core ; LIBHB_SRC = Ac3Dec.c AviMux.c DVDRead.c FaacEnc.c FfmpegEnc.c Fifo.c HandBrake.c - LpcmDec.c MadDec.c Mp3Enc.c Mp4Mux.c Mpeg2Dec.c OgmMux.c Scale.c - Scan.c Thread.c Utils.c VorbisEnc.c Work.c X264Enc.c XvidEnc.c ; + LpcmDec.c Mp3Enc.c Mp4Mux.c Mpeg2Dec.c MpgaDec.c Mux.c OgmMux.c + Resample.c Scale.c Scan.c Thread.c Utils.c VorbisEnc.c Work.c + X264Enc.c XvidEnc.c ; Library libhb : $(LIBHB_SRC) ; # Sadly, we might want to debug our code -ObjectCcFlags $(LIBHB_SRC) : -g -Wall ; +ObjectCcFlags $(LIBHB_SRC) : -g -Wall -W ; # Needed includes ObjectHdrs Ac3Dec.c : $(TOP)/contrib/liba52 ; ObjectHdrs FfmpegEnc.c HandBrake.c - Scale.c : $(TOP)/contrib/libavcodec ; -ObjectHdrs DVDRead.c - Scan.c : $(TOP)/contrib/libdvdplay ; + MpgaDec.c + Scale.c : $(TOP)/contrib/libavcodec ; ObjectHdrs DVDRead.c Scan.c : $(TOP)/contrib/libdvdread ; ObjectHdrs FaacEnc.c : $(TOP)/contrib/libfaac ; @@ -30,6 +30,7 @@ ObjectHdrs Mp3Enc.c : $(TOP)/contrib/libmp3lame ; ObjectHdrs Mp4Mux.c : $(TOP)/contrib/libmp4v2 ; ObjectHdrs Mpeg2Dec.c Scan.c : $(TOP)/contrib/libmpeg2 ; +ObjectHdrs Resample.c : $(TOP)/contrib/libsamplerate ; ObjectHdrs OgmMux.c VorbisEnc.c : $(TOP)/contrib/libogg ; ObjectHdrs VorbisEnc.c : $(TOP)/contrib/libvorbis ; diff --git a/core/LpcmDec.c b/core/LpcmDec.c index 519b4868a..425f429d9 100644 --- a/core/LpcmDec.c +++ b/core/LpcmDec.c @@ -1,4 +1,4 @@ -/* $Id: LpcmDec.c,v 1.3 2004/03/29 00:29:41 titer Exp $ +/* $Id: LpcmDec.c,v 1.10 2004/05/10 16:50:32 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,7 +6,7 @@ #include "HBInternal.h" -typedef struct HBLpcmDec +struct HBWork { HB_WORK_COMMON_MEMBERS @@ -14,102 +14,60 @@ typedef struct HBLpcmDec HBAudio * audio; int initDone; - int channels; - float sampleLevel; - HBBuffer * rawBuffer; -} HBLpcmDec; +}; /* Local prototypes */ static int LpcmDecWork( HBWork * ); HBWork * HBLpcmDecInit( HBHandle * handle, HBAudio * audio ) { - HBLpcmDec * l; - if( !( l = calloc( sizeof( HBLpcmDec ), 1 ) ) ) + HBWork * w; + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) { HBLog( "HBLpcmDecInit: malloc() failed, gonna crash" ); return NULL; } - l->name = strdup( "LpcmDec" ); - l->work = LpcmDecWork; + w->name = strdup( "LpcmDec" ); + w->work = LpcmDecWork; - l->handle = handle; - l->audio = audio; + w->handle = handle; + w->audio = audio; - if( audio->outCodec & ( HB_CODEC_MP3 | HB_CODEC_VORBIS ) ) - { - /* 16 bits samples */ - l->sampleLevel = 1.0; - } - else if( audio->outCodec & HB_CODEC_AAC ) - { - /* 24 bits samples */ - l->sampleLevel = 256.0; - } - - return (HBWork*) l; -} - -void HBLpcmDecClose( HBWork ** _l ) -{ - HBLpcmDec * l = (HBLpcmDec*) *_l; - - /* Clean up */ - if( l->rawBuffer ) - { - HBBufferClose( &l->rawBuffer ); - } - free( l->name ); - free( l ); - - *_l = NULL; + return w; } -#ifndef HB_MACOSX -static int16_t Swap16( int16_t * p ) +void HBLpcmDecClose( HBWork ** _w ) { - uint8_t tmp[2]; - - tmp[0] = ((uint8_t*)p)[1]; - tmp[1] = ((uint8_t*)p)[0]; - - return *(int16_t*)tmp; + HBWork * w = *_w; + free( w->name ); + free( w ); + *_w = NULL; } -#endif static int LpcmDecWork( HBWork * w ) { - HBLpcmDec * l = (HBLpcmDec*) w; - HBAudio * audio = l->audio; - HBBuffer * lpcmBuffer; - int16_t * int16data; + HBAudio * audio = w->audio; - int i; - int samples; - int didSomething = 0; + HBBuffer * lpcmBuffer; + HBBuffer * rawBuffer; + uint8_t * samples_u8; + float * samples_f; + int samples_nr, i; - /* Push decoded buffer */ - if( l->rawBuffer ) + if( HBFifoIsHalfFull( audio->rawFifo ) ) { - if( HBFifoPush( audio->rawFifo, &l->rawBuffer ) ) - { - didSomething = 1; - } - else - { - return 0; - } + return 0; } /* Get a new LPCM buffer */ lpcmBuffer = HBFifoPop( audio->inFifo ); if( !lpcmBuffer ) { - return didSomething; + return 0; } - if( !l->initDone ) + if( !w->initDone ) { /* SampleRate */ switch( ( lpcmBuffer->data[4] >> 4 ) & 0x3 ) @@ -121,45 +79,46 @@ static int LpcmDecWork( HBWork * w ) audio->inSampleRate = 32000; break; default: - HBLog( "LpcmDec: unknown samplerate (%d)", + HBLog( "HBLpcmDec: unknown samplerate (%d)", ( lpcmBuffer->data[4] >> 4 ) & 0x3 ); } - HBLog( "LpcmDec: samplerate = %d Hz", audio->inSampleRate ); - /* Channels */ - HBLog( "LpcmDec: %d channels", - ( lpcmBuffer->data[4] & 0x7 ) + 1 ); + /* We hope there are 2 channels */ + HBLog( "HBLpcmDec: samplerate: %d Hz, channels: %d", + audio->inSampleRate, ( lpcmBuffer->data[4] & 0x7 ) + 1 ); - l->initDone = 1; + w->initDone = 1; } if( lpcmBuffer->data[5] != 0x80 ) { - HBLog( "LpcmDec: no frame synx (%02x�", lpcmBuffer->data[5] ); + HBLog( "HBLpcmDec: no frame sync (%02x)", lpcmBuffer->data[5] ); } - samples = ( lpcmBuffer->size - 6 ) / sizeof( int16_t ) / 2; - int16data = (int16_t*) ( lpcmBuffer->data + 6 ); - - l->rawBuffer = HBBufferInit( samples * sizeof( float ) * 2 ); - l->rawBuffer->left = (float*) l->rawBuffer->data; - l->rawBuffer->right = l->rawBuffer->left + samples; - l->rawBuffer->position = lpcmBuffer->position; - l->rawBuffer->samples = samples; + /* Allocate raw buffer */ + samples_nr = ( lpcmBuffer->size - 6 ) / sizeof( int16_t ); + rawBuffer = HBBufferInit( samples_nr * sizeof( float ) ); + rawBuffer->position = lpcmBuffer->position; - for( i = 0; i < samples; i++ ) + /* Big endian int16 -> float conversion (happy casting) */ + samples_u8 = lpcmBuffer->data + 6; + samples_f = rawBuffer->dataf; + for( i = 0; i < samples_nr; i++ ) { -#ifdef HB_MACOSX - l->rawBuffer->left[i] = (float) int16data[2*i] * l->sampleLevel; - l->rawBuffer->right[i] = (float) int16data[2*i+1] * l->sampleLevel; -#else - l->rawBuffer->left[i] = (float) Swap16(&int16data[2*i]) * l->sampleLevel; - l->rawBuffer->right[i] = (float) Swap16(&int16data[2*i+1]) * l->sampleLevel; -#endif + samples_f[0] = (float) (int16_t) + ( ( ( (uint16_t) samples_u8[0] ) << 8 ) + + (uint16_t) samples_u8[1] ); + samples_u8 += 2; + samples_f += 1; } HBBufferClose( &lpcmBuffer ); + if( !HBFifoPush( audio->rawFifo, &rawBuffer ) ) + { + HBLog( "HBLpcmDec: HBFifoPush failed" ); + } + return 1; } diff --git a/core/MadDec.c b/core/MadDec.c deleted file mode 100644 index da79ad886..000000000 --- a/core/MadDec.c +++ /dev/null @@ -1,8 +0,0 @@ -/* $Id: MadDec.c,v 1.2 2003/12/26 20:03:27 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - diff --git a/core/Mp3Enc.c b/core/Mp3Enc.c index bd62df4ae..c1aae34fe 100644 --- a/core/Mp3Enc.c +++ b/core/Mp3Enc.c @@ -1,4 +1,4 @@ -/* $Id: Mp3Enc.c,v 1.13 2004/01/21 17:59:33 titer Exp $ +/* $Id: Mp3Enc.c,v 1.23 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,226 +9,110 @@ /* libmp3lame */ #include "lame/lame.h" -typedef struct HBMp3Enc +struct HBWork { HB_WORK_COMMON_MEMBERS HBHandle * handle; HBAudio * audio; lame_global_flags * globalFlags; - HBBuffer * rawBuffer; - int rawBufferPos; - float position; - int inputSamples; - int samplesGot; - float * left; - float * right; - HBBuffer * mp3Buffer; - - /* Stats */ - int64_t samples; - int64_t bytes; -} HBMp3Enc; +}; /* Local prototypes */ static int Mp3EncWork( HBWork * ); -static int GetSamples( HBMp3Enc * ); HBWork * HBMp3EncInit( HBHandle * handle, HBAudio * audio ) { - HBMp3Enc * m; - if( !( m = calloc( sizeof( HBMp3Enc ), 1 ) ) ) + HBWork * w; + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) { HBLog( "HBMp3EncInit: malloc() failed, gonna crash" ); return NULL; } - m->name = strdup( "Mp3Enc" ); - m->work = Mp3EncWork; + w->name = strdup( "Mp3Enc" ); + w->work = Mp3EncWork; - m->handle = handle; - m->audio = audio; + w->handle = handle; + w->audio = audio; - return (HBWork*) m; + return w; } -void HBMp3EncClose( HBWork ** _m ) +void HBMp3EncClose( HBWork ** _w ) { - HBMp3Enc * m = (HBMp3Enc*) *_m; - - if( m->globalFlags ) lame_close( m->globalFlags ); - if( m->rawBuffer ) HBBufferClose( &m->rawBuffer ); - if( m->left ) free( m->left ); - if( m->right ) free( m->right ); - if( m->mp3Buffer ) HBBufferClose( &m->mp3Buffer ); + HBWork * w = *_w; - if( m->samples ) - { - int64_t bytes = 128 * m->audio->outBitrate * m->samples / - m->audio->inSampleRate; - float bitrate = (float) m->bytes * m->audio->inSampleRate / - m->samples / 128; + if( w->globalFlags ) lame_close( w->globalFlags ); - HBLog( "HBMp3Enc: %lld samples encoded (%lld bytes), %.2f kbps", - m->samples, m->bytes, bitrate ); - HBLog( "HBFaacEnc: error is %lld bytes", m->bytes - bytes ); - } - - free( m->name ); - free( m ); - - *_m = NULL; + free( w->name ); + free( w ); + *_w = NULL; } static int Mp3EncWork( HBWork * w ) { - HBMp3Enc * m = (HBMp3Enc*) w; - HBAudio * audio = m->audio; + HBAudio * audio = w->audio; HBBuffer * mp3Buffer; int ret; - int didSomething = 0; + float samples_f[1152 * 2]; + int16_t samples_s16[1152 * 2]; + float position; + int i; - if( !m->globalFlags ) + if( !w->globalFlags ) { - int i; - - /* Get a first buffer so we know that audio->inSampleRate is - correct */ - if( ( m->rawBuffer = HBFifoPop( audio->rawFifo ) ) ) + if( !HBFifoSize( audio->resampleFifo ) ) { - didSomething = 1; + return 0; } - 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 */ - audio->outSampleRate = 44100; - m->inputSamples = 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; - } + HBLog( "HBMp3Enc: opening lame (%d kbps)", audio->outBitrate ); - m->left = malloc( m->inputSamples * sizeof( float ) ); - m->right = malloc( m->inputSamples * sizeof( float ) ); + w->globalFlags = lame_init(); + lame_set_brate( w->globalFlags, audio->outBitrate ); - if( !m->left || !m->right ) - { - HBLog( "HBMp3Enc: malloc() failed, gonna crash" ); - } + /* No resampling there - it's been done before */ + lame_set_in_samplerate( w->globalFlags, audio->outSampleRate ); + lame_set_out_samplerate( w->globalFlags, audio->outSampleRate ); - for( i = 0; i < m->inputSamples; i++ ) + if( lame_init_params( w->globalFlags ) == -1 ) { - m->left[i] = 0.0; - m->right[i] = 0.0; + HBLog( "HBMp3Enc: lame_init_params() failed" ); + HBErrorOccured( w->handle, HB_ERROR_MP3_INIT ); + return 0; } } - /* Push encoded buffer */ - if( m->mp3Buffer ) + if( HBFifoIsHalfFull( audio->outFifo ) ) { - if( HBFifoPush( audio->outFifo, &m->mp3Buffer ) ) - { - didSomething = 1; - } - else - { - return didSomething; - } + return 0; } - /* A/V synchro fix in case audio doesn't start at the same time - than video */ - if( audio->delay > 0 ) + if( !HBFifoGetBytes( audio->resampleFifo, (uint8_t*) samples_f, + 1152 * 2 * sizeof( float ), &position ) ) { - /* Audio starts later - insert some silence */ - int length = m->inputSamples * 1000 / audio->inSampleRate; - - if( audio->delay > length ) - { - HBLog( "HBMp3Enc: adding %d ms of silence", length ); - m->samplesGot = m->inputSamples; - audio->delay -= length; - } - else - { - audio->delay = 0; - } + return 0; } - else if( audio->delay < 0 ) - { - /* Audio starts sooner - trash some */ - int length = m->inputSamples * 1000 / audio->inSampleRate; - if( - audio->delay > length ) - { - if( GetSamples( 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( GetSamples( m ) ) + /* float -> s16 */ + for( i = 0; i < 1152 * 2; i++ ) { - didSomething = 1; + samples_s16[i] = samples_f[i]; } - else - { - return didSomething; - } - - m->samplesGot = 0; mp3Buffer = HBBufferInit( LAME_MAXMP3BUFFER ); - ret = lame_encode_buffer_float( m->globalFlags, m->left, - m->right, m->inputSamples, - mp3Buffer->data, - mp3Buffer->size ); - /* Stats */ - m->samples += m->inputSamples; + ret = lame_encode_buffer_interleaved( w->globalFlags, + samples_s16, 1152, mp3Buffer->data, LAME_MAXMP3BUFFER ); if( ret < 0 ) { /* Error */ HBLog( "HBMp3Enc: lame_encode_buffer_float() failed (%d)", ret ); - HBErrorOccured( m->handle, HB_ERROR_MP3_ENCODE ); + HBErrorOccured( w->handle, HB_ERROR_MP3_ENCODE ); HBBufferClose( &mp3Buffer ); } else if( ret == 0 ) @@ -241,51 +125,14 @@ static int Mp3EncWork( HBWork * w ) /* Encoding was successful */ mp3Buffer->size = ret; mp3Buffer->keyFrame = 1; - mp3Buffer->position = m->position; - m->mp3Buffer = mp3Buffer; + mp3Buffer->position = position; - /* Stats */ - m->bytes += ret; - } - - return didSomething; -} - -static int GetSamples( HBMp3Enc * m ) -{ - while( m->samplesGot < m->inputSamples ) - { - 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->inputSamples - m->samplesGot, - m->rawBuffer->samples - m->rawBufferPos ); - - memcpy( m->left + m->samplesGot, - m->rawBuffer->left + m->rawBufferPos, - i * sizeof( float ) ); - memcpy( m->right + m->samplesGot, - m->rawBuffer->right + m->rawBufferPos, - i * sizeof( float ) ); - - m->samplesGot += i; - m->rawBufferPos += i; - - if( m->rawBufferPos == m->rawBuffer->samples ) + if( !HBFifoPush( audio->outFifo, &mp3Buffer ) ) { - HBBufferClose( &m->rawBuffer ); + HBLog( "HBMp3Enc: HBFifoPush failed" ); } } return 1; } + diff --git a/core/Mp4Mux.c b/core/Mp4Mux.c index c545c96fc..d48c1adc6 100644 --- a/core/Mp4Mux.c +++ b/core/Mp4Mux.c @@ -1,4 +1,4 @@ -/* $Id: Mp4Mux.c,v 1.24 2004/03/08 13:42:29 titer Exp $ +/* $Id: Mp4Mux.c,v 1.31 2004/05/13 21:10:56 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,191 +9,170 @@ /* libmp4v2 */ #include "mp4.h" -int64_t videoFrames; -int64_t videoBytes; -int64_t audioFrames; -int64_t audioBytes; - -/* Local prototypes */ -static void Mp4MuxThread( void * ); - -struct HBMp4Mux +struct HBMux { + HB_MUX_COMMON_MEMBERS + HBHandle * handle; HBTitle * title; - volatile int die; - HBThread * thread; + MP4FileHandle file; + + /* QuickTime sync workaround */ + int sampleRate; + uint64_t frames; + uint64_t date; + }; -HBMp4Mux * HBMp4MuxInit( HBHandle * handle, HBTitle * title ) +typedef struct +{ + int track; + +} Mp4MuxData; + +/* Local prototypes */ +static int Mp4Start( HBMux * ); +static int Mp4MuxVideo( HBMux *, void *, HBBuffer *); +static int Mp4MuxAudio( HBMux *, void *, HBBuffer *); +static int Mp4End( HBMux * ); + +HBMux * HBMp4MuxInit( HBHandle * handle, HBTitle * title ) { - HBMp4Mux * m; - if( !( m = malloc( sizeof( HBMp4Mux ) ) ) ) + HBMux * m; + HBAudio * audio; + int i; + + if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) { - HBLog( "HBMp4MuxInit: malloc() failed, gonna crash" ); + HBLog( "HBMp4Mux: malloc() failed, gonna crash" ); return NULL; } - - videoFrames = 0; - videoBytes = 0; - audioFrames = 0; - audioBytes = 0; + m->start = Mp4Start; + m->muxVideo = Mp4MuxVideo; + m->muxAudio = Mp4MuxAudio; + m->end = Mp4End; m->handle = handle; m->title = title; - m->die = 0; - m->thread = HBThreadInit( "mp4 muxer", Mp4MuxThread, m, - HB_NORMAL_PRIORITY ); + /* Alloc muxer data */ + title->muxData = calloc( sizeof( Mp4MuxData ), 1 ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + audio->muxData = calloc( sizeof( Mp4MuxData ), 1 ); + } + return m; } -void HBMp4MuxClose( HBMp4Mux ** _m ) +void HBMp4MuxClose( HBMux ** _m ) { - HBMp4Mux * m = *_m; - FILE * file; - long size; - - m->die = 1; - HBThreadClose( &m->thread ); - - file = fopen( m->title->file, "r" ); - if( file ) + HBMux * m = *_m; + HBTitle * title = m->title; + HBAudio * audio; + int i; + + /* Free muxer data */ + free( title->muxData ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - fseek( file, 0, SEEK_END ); - size = ftell( file ); - fclose( file ); - - HBLog( "HBMp4Mux: videoFrames=%lld, %lld bytes", - videoFrames, videoBytes ); - HBLog( "HBMp4Mux: audioFrames=%lld, %lld bytes", - audioFrames, audioBytes ); - HBLog( "HBMp4Mux: overhead=%.2f bytes / frame", - ( (float) size - videoBytes - audioBytes ) / - ( videoFrames + audioFrames ) ); + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + free( audio->muxData ); } free( m ); - *_m = NULL; } -static void Mp4MuxThread( void * _m ) +static int Mp4Start( HBMux * m ) { - HBMp4Mux * m = (HBMp4Mux*) _m; - HBTitle * title = m->title; - HBAudio * audio; - HBBuffer * buffer; - char tmpFile[1024]; + HBTitle * title = m->title; + HBAudio * audio; + Mp4MuxData * muxData; + int i; - int audioCount = HBListCount( m->title->ripAudioList ); - int i; + /* Create file */ + m->file = MP4Create( title->file, 0, 0 ); - MP4FileHandle file; - - /* Wait until we have one encoded frame for each track */ - while( !m->die && !HBFifoSize( title->outFifo ) ) + /* Add video track */ + muxData = (Mp4MuxData *) title->muxData; + if( HBListCount( title->ripAudioList ) ) { - HBSnooze( 10000 ); + /* QuickTime sync workaround */ + audio = (HBAudio *) HBListItemAt( title->ripAudioList, 0 ); + m->sampleRate = audio->outSampleRate; + MP4SetTimeScale( m->file, m->sampleRate ); + muxData->track = MP4AddVideoTrack( m->file, m->sampleRate, + MP4_INVALID_DURATION, title->outWidth, title->outHeight, + MP4_MPEG4_VIDEO_TYPE ); } - for( i = 0; i < audioCount; i++ ) + else { - audio = HBListItemAt( title->ripAudioList, i ); - while( !m->die && !HBFifoSize( audio->outFifo ) ) - { - HBSnooze( 10000 ); - } + MP4SetTimeScale( m->file, 90000 ); + muxData->track = MP4AddVideoTrack( m->file, 90000, + (uint64_t) 90000 * title->rateBase / title->rate, + title->outWidth, title->outHeight, + MP4_MPEG4_VIDEO_TYPE ); } + MP4SetVideoProfileLevel( m->file, 0x03 ); + MP4SetTrackESConfiguration( m->file, muxData->track, + title->esConfig, title->esConfigLength ); - if( m->die ) + /* Add audio tracks */ + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - return; + audio = HBListItemAt( title->ripAudioList, i ); + muxData = (Mp4MuxData *) audio->muxData; + muxData->track = MP4AddAudioTrack( m->file, + audio->outSampleRate, 1024, MP4_MPEG4_AUDIO_TYPE ); + MP4SetAudioProfileLevel( m->file, 0x0F ); + MP4SetTrackESConfiguration( m->file, muxData->track, + audio->esConfig, audio->esConfigLength ); } - /* Write file headers */ - file = MP4Create( title->file, 0, 0 ); - MP4SetTimeScale( file, 90000 ); - title->track = MP4AddVideoTrack( file, 90000, - MP4_INVALID_DURATION, - title->outWidth, title->outHeight, - MP4_MPEG4_VIDEO_TYPE ); - MP4SetVideoProfileLevel( file, 0x03 ); - MP4SetTrackESConfiguration( file, title->track, title->esConfig, - title->esConfigLength ); - - for( i = 0; i < audioCount; i++ ) + return 0; +} + +static int Mp4MuxVideo( HBMux * m, void * _muxData, HBBuffer * buffer ) +{ + Mp4MuxData * muxData = (Mp4MuxData *) _muxData; + HBTitle * title = m->title; + + if( HBListCount( title->ripAudioList ) ) { - audio = HBListItemAt( title->ripAudioList, i ); - audio->track = MP4AddAudioTrack( file, audio->outSampleRate, - 1024, MP4_MPEG4_AUDIO_TYPE ); - MP4SetAudioProfileLevel( file, 0x0F ); - MP4SetTrackESConfiguration( file, audio->track, audio->esConfig, - audio->esConfigLength ); + /* QuickTime sync workaround */ + int dur = (uint64_t) m->sampleRate * ( ++m->frames ) * + title->rateBase / title->rate - m->date; + MP4WriteSample( m->file, muxData->track, buffer->data, buffer->size, + dur, 0, buffer->keyFrame ); + m->date += dur; } - - for( ;; ) + else { - /* Wait until we have one encoded frame for each track */ - if( !HBFifoWait( title->outFifo ) ) - { - m->die = 1; - break; - } - for( i = 0; i < audioCount; i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - if( !HBFifoWait( audio->outFifo ) ) - { - m->die = 1; - break; - } - } - - if( m->die ) - { - break; - } - - /* Interleave frames in the same order than they were in the - original MPEG stream */ - audio = NULL; - for( i = 0; i < audioCount; i++ ) - { - HBAudio * otherAudio; - otherAudio = HBListItemAt( title->ripAudioList, i ); - if( !audio || HBFifoPosition( otherAudio->outFifo ) < - HBFifoPosition( audio->outFifo ) ) - { - audio = otherAudio; - } - } - - if( !audio || HBFifoPosition( title->outFifo ) < - HBFifoPosition( audio->outFifo ) ) - { - buffer = HBFifoPop( title->outFifo ); - MP4WriteSample( file, title->track, buffer->data, - buffer->size, - (uint64_t) 90000 * title->rateBase / title->rate, - 0, buffer->keyFrame ); - videoFrames++; - videoBytes += buffer->size; - HBBufferClose( &buffer ); - } - else - { - buffer = HBFifoPop( audio->outFifo ); - MP4WriteSample( file, audio->track, buffer->data, - buffer->size, MP4_INVALID_DURATION, - 0, buffer->keyFrame ); - audioFrames++; - audioBytes += buffer->size; - HBBufferClose( &buffer ); - } + MP4WriteSample( m->file, muxData->track, buffer->data, + buffer->size, MP4_INVALID_DURATION, 0, + buffer->keyFrame ); } + return 0; +} + +static int Mp4MuxAudio( HBMux * m, void * _muxData, HBBuffer * buffer ) +{ + Mp4MuxData * muxData = (Mp4MuxData *) _muxData; + + MP4WriteSample( m->file, muxData->track, buffer->data, buffer->size, + MP4_INVALID_DURATION, 0, buffer->keyFrame ); + return 0; +} + +static int Mp4End( HBMux * m ) +{ + HBTitle * title = m->title; + char tmpFile[1024]; - MP4Close( file ); + MP4Close( m->file ); HBLog( "HBMp4Mux: making the file ISMA compliant" ); if( !MP4MakeIsmaCompliant( title->file, 0 /*MP4_DETAILS_ALL*/, 1 ) ) @@ -213,5 +192,6 @@ static void Mp4MuxThread( void * _m ) { rename( tmpFile, title->file ); } + return 0; } diff --git a/core/Mpeg2Dec.c b/core/Mpeg2Dec.c index ea3ffa2e4..043c416dc 100644 --- a/core/Mpeg2Dec.c +++ b/core/Mpeg2Dec.c @@ -1,4 +1,4 @@ -/* $Id: Mpeg2Dec.c,v 1.12 2004/01/16 19:04:04 titer Exp $ +/* $Id: Mpeg2Dec.c,v 1.15 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -8,170 +8,144 @@ #include "mpeg2dec/mpeg2.h" -typedef struct HBMpeg2Dec +struct HBWork { HB_WORK_COMMON_MEMBERS HBHandle * handle; HBTitle * title; - HBList * rawBufferList; int pass; mpeg2dec_t * libmpeg2; const mpeg2_info_t * info; int lateField; -} HBMpeg2Dec; +}; /* Local prototypes */ static int Mpeg2DecWork( HBWork * ); HBWork * HBMpeg2DecInit( HBHandle * handle, HBTitle * title ) { - HBMpeg2Dec * m ; - if( !( m = malloc( sizeof( HBMpeg2Dec ) ) ) ) + HBWork * w ; + if( !( w = malloc( sizeof( HBWork ) ) ) ) { HBLog( "HBMpeg2Dec: malloc() failed, gonna crash" ); return NULL; } - m->name = strdup( "Mpeg2Dec" ); - m->work = Mpeg2DecWork; + w->name = strdup( "Mpeg2Dec" ); + w->work = Mpeg2DecWork; - m->handle = handle; - m->title = title; + w->handle = handle; + w->title = title; - m->rawBufferList = HBListInit(); - m->pass = 42; - m->libmpeg2 = NULL; - m->info = NULL; - m->lateField = 0; + w->pass = 42; + w->libmpeg2 = NULL; + w->info = NULL; + w->lateField = 0; - return (HBWork*) m; + return w; } -void HBMpeg2DecClose( HBWork ** _m ) +void HBMpeg2DecClose( HBWork ** _w ) { - HBBuffer * buffer; + HBWork * w = *_w; - HBMpeg2Dec * m = (HBMpeg2Dec*) *_m; - - if( m->libmpeg2 ) - { - HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", m->pass ); - mpeg2_close( m->libmpeg2 ); - } - while( ( buffer = HBListItemAt( m->rawBufferList, 0 ) ) ) + if( w->libmpeg2 ) { - HBListRemove( m->rawBufferList, buffer ); - HBBufferClose( &buffer ); + HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", w->pass ); + mpeg2_close( w->libmpeg2 ); } - HBListClose( &m->rawBufferList ); - free( m->name ); - free( m ); + free( w->name ); + free( w ); - *_m = NULL; + *_w = NULL; } static int Mpeg2DecWork( HBWork * w ) { - HBMpeg2Dec * m = (HBMpeg2Dec*) w; - HBTitle * title = m->title; + HBTitle * title = w->title; HBBuffer * mpeg2Buffer; HBBuffer * rawBuffer; - HBBuffer * tmpBuffer; mpeg2_state_t state; - int didSomething = 0; - - /* Push decoded buffers */ - while( ( rawBuffer = (HBBuffer*) - HBListItemAt( m->rawBufferList, 0 ) ) ) + if( HBFifoIsHalfFull( title->rawFifo ) ) { - tmpBuffer = rawBuffer; - if( HBFifoPush( title->rawFifo, &rawBuffer ) ) - { - didSomething = 1; - HBListRemove( m->rawBufferList, tmpBuffer ); - } - else - { - return didSomething; - } + return 0; } /* Get a new buffer to decode */ - if( ( mpeg2Buffer = HBFifoPop( title->inFifo ) ) ) - { - didSomething = 1; - } - else + if( !( mpeg2Buffer = HBFifoPop( title->inFifo ) ) ) { - return didSomething; + return 0; } /* Init or re-init if needed */ - if( mpeg2Buffer->pass != m->pass ) + if( mpeg2Buffer->pass != w->pass ) { - if( m->libmpeg2 ) + if( w->libmpeg2 ) { - HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", m->pass ); - mpeg2_close( m->libmpeg2 ); + HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", w->pass ); + mpeg2_close( w->libmpeg2 ); } - m->pass = mpeg2Buffer->pass; + w->pass = mpeg2Buffer->pass; - HBLog( "HBMpeg2Dec: opening libmpeg2 (pass %d)", m->pass ); + HBLog( "HBMpeg2Dec: opening libmpeg2 (pass %d)", w->pass ); #ifdef HB_NOMMX mpeg2_accel( 0 ); #endif - m->libmpeg2 = mpeg2_init(); - m->info = mpeg2_info( m->libmpeg2 ); - m->lateField = 0; + w->libmpeg2 = mpeg2_init(); + w->info = mpeg2_info( w->libmpeg2 ); + w->lateField = 0; } /* Decode */ - mpeg2_buffer( m->libmpeg2, mpeg2Buffer->data, + mpeg2_buffer( w->libmpeg2, mpeg2Buffer->data, mpeg2Buffer->data + mpeg2Buffer->size ); for( ;; ) { - state = mpeg2_parse( m->libmpeg2 ); + state = mpeg2_parse( w->libmpeg2 ); if( state == STATE_BUFFER ) { break; } else if( ( state == STATE_SLICE || state == STATE_END ) && - m->info->display_fbuf ) + w->info->display_fbuf ) { rawBuffer = HBBufferInit( 3 * title->inWidth * title->inHeight ); /* TODO: make libmpeg2 write directly in our buffer */ - memcpy( rawBuffer->data, m->info->display_fbuf->buf[0], + memcpy( rawBuffer->data, w->info->display_fbuf->buf[0], title->inWidth * title->inHeight ); memcpy( rawBuffer->data + title->inWidth * title->inHeight, - m->info->display_fbuf->buf[1], + w->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], + w->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( w->info->display_picture->nb_fields == 3 ) { - rawBuffer->repeat = m->lateField; - m->lateField = !m->lateField; + rawBuffer->repeat = w->lateField; + w->lateField = !w->lateField; } else { rawBuffer->repeat = 0; } + + if( !HBFifoPush( title->rawFifo, &rawBuffer ) ) + { + HBLog( "HBMpeg2Dec: HBFifoPush failed" ); + } } else if( state == STATE_INVALID ) { @@ -182,5 +156,5 @@ static int Mpeg2DecWork( HBWork * w ) HBBufferClose( &mpeg2Buffer ); - return didSomething; + return 1; } diff --git a/core/MpgaDec.c b/core/MpgaDec.c new file mode 100644 index 000000000..e397a7234 --- /dev/null +++ b/core/MpgaDec.c @@ -0,0 +1,132 @@ +/* $Id: MpgaDec.c,v 1.3 2004/05/02 16:25: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. */ + +#include "HBInternal.h" + +#include "ffmpeg/avcodec.h" + +struct HBWork +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBAudio * audio; + + AVCodecContext * context; +}; + +/* Local prototypes */ +static int MpgaDecWork( HBWork * ); + +HBWork * HBMpgaDecInit( HBHandle * handle, HBAudio * audio ) +{ + HBWork * w; + AVCodec * codec; + + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) + { + HBLog( "HBMpgaDecInit: malloc() failed, gonna crash" ); + return NULL; + } + + w->name = strdup( "MpgaDec" ); + w->work = MpgaDecWork; + + w->handle = handle; + w->audio = audio; + + codec = avcodec_find_decoder( CODEC_ID_MP2 ); + if( !codec ) + { + HBLog( "HBMpgaDec: avcodec_find_decoder failed" ); + } + + w->context = avcodec_alloc_context(); + if( !w->context ) + { + HBLog( "HBMpgaDec: avcodec_alloc_context failed" ); + } + + if( avcodec_open( w->context, codec ) < 0 ) + { + HBLog( "HBMpgaDec: avcodec_open failed" ); + } + + return w; +} + +void HBMpgaDecClose( HBWork ** _w ) +{ + HBWork * w = *_w; + + avcodec_close( w->context ); + free( w->name ); + free( w ); + *_w = NULL; +} + +static int MpgaDecWork( HBWork * w ) +{ + HBAudio * audio = w->audio; + + HBBuffer * mpgaBuffer; + HBBuffer * rawBuffer; + + int out_size, len, pos; + short buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; + + if( HBFifoIsHalfFull( audio->rawFifo ) ) + { + return 0; + } + + /* Get a new mpeg buffer */ + mpgaBuffer = HBFifoPop( audio->inFifo ); + if( !mpgaBuffer ) + { + return 0; + } + + pos = 0; + while( pos < mpgaBuffer->size ) + { + len = avcodec_decode_audio( w->context, buffer, &out_size, + mpgaBuffer->data + pos, + mpgaBuffer->size - pos ); + pos += len; + + if( !audio->inSampleRate ) + { + audio->inSampleRate = w->context->sample_rate; + HBLog( "HBMpgaDec: samplerate = %d", audio->inSampleRate ); + } + + if( out_size ) + { + int i; + rawBuffer = HBBufferInit( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE ); + rawBuffer->position = mpgaBuffer->position; + + /* s16 -> float */ + for( i = 0; i < out_size / 2; i++ ) + { + rawBuffer->dataf[i] = buffer[i]; + } + + rawBuffer->size = out_size * 2; + + if( !HBFifoPush( audio->rawFifo, &rawBuffer ) ) + { + HBLog( "HBMpgaDec: HBFifoPush failed" ); + } + } + } + + HBBufferClose( &mpgaBuffer ); + + return 1; +} + diff --git a/core/Mux.c b/core/Mux.c new file mode 100644 index 000000000..c9449e7ff --- /dev/null +++ b/core/Mux.c @@ -0,0 +1,228 @@ +/* $Id: Mux.c,v 1.9 2004/05/25 17:36:40 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 <sys/types.h> +#include <sys/stat.h> + +#include "HBInternal.h" + +HBMux * HBAviMuxInit( HBHandle * handle, HBTitle * title ); +void HBAviMuxClose( HBMux ** ); +HBMux * HBMp4MuxInit( HBHandle * handle, HBTitle * title ); +void HBMp4MuxClose( HBMux ** ); +HBMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ); +void HBOgmMuxClose( HBMux ** ); + +/* Local prototypes */ +static void MuxThread( void * t ); + +struct HBMux +{ + HB_MUX_COMMON_MEMBERS +}; + +struct HBMuxThread +{ + HBHandle * handle; + HBTitle * title; + HBMux * mux; + + uint64_t videoFrames; + uint64_t videoBytes; + uint64_t audioFrames; + uint64_t audioBytes; + + volatile int die; + HBThread * thread; +}; + +HBMuxThread * HBMuxThreadInit( HBHandle * handle, HBTitle * title ) +{ + HBMuxThread * t; + if( !( t = calloc( sizeof( HBMuxThread ), 1 ) ) ) + { + HBLog( "HBMuxThreadInit: malloc() failed, gonna crash" ); + return NULL; + } + t->handle = handle; + t->title = title; + + /* Init muxer */ + if( title->mux == HB_MUX_AVI ) + t->mux = HBAviMuxInit( handle, title ); + else if( title->mux == HB_MUX_MP4 ) + t->mux = HBMp4MuxInit( handle, title ); + else if( title->mux == HB_MUX_OGM ) + t->mux = HBOgmMuxInit( handle, title ); + + /* Launch the thread */ + t->thread = HBThreadInit( "mux thread", MuxThread, t, + HB_NORMAL_PRIORITY ); + + return t; +} + +void HBMuxThreadClose( HBMuxThread ** _t ) +{ + HBMuxThread * t = (*_t); + HBTitle * title = t->title; + struct stat sb; + + /* Stop the thread */ + t->die = 1; + HBThreadClose( &t->thread ); + + /* Close muxer */ + if( title->mux == HB_MUX_AVI ) + HBAviMuxClose( &t->mux ); + else if( title->mux == HB_MUX_MP4 ) + HBMp4MuxClose( &t->mux ); + else if( title->mux == HB_MUX_OGM ) + HBOgmMuxClose( &t->mux ); + + /* Stats */ + if( !stat( title->file, &sb ) ) + { + uint64_t overhead; + HBAudio * audio; + + overhead = (uint64_t) sb.st_size - t->videoBytes - t->audioBytes; + HBLog( "HBMuxThread: file size: "LLD" bytes", + (uint64_t) sb.st_size ); + HBLog( "HBMuxThread: video data: "LLD" bytes ("LLD" frames)", + t->videoBytes, t->videoFrames ); + HBLog( "HBMuxThread: audio data: "LLD" bytes ("LLD" frames)", + t->audioBytes, t->audioFrames ); + HBLog( "HBMuxThread: overhead: "LLD" bytes (%.2f bytes per " + "frame)", overhead, (float) overhead / ( t->videoFrames + + t->audioFrames ) ); + + HBLog( "HBMuxThread: video bitrate: %.2f kbps", + (float) t->videoBytes * title->rate / t->videoFrames / + title->rateBase / 128 ); + HBLog( "HBMuxThread: video error: "LLD" bytes", t->videoBytes - + t->videoFrames * title->bitrate * 128 * title->rateBase / + title->rate ); + + /* FIXME - handle multi-audio encoding */ + audio = (HBAudio *) HBListItemAt( title->ripAudioList, 0 ); + if( audio ) + { + int samplesPerFrame = ( audio->outCodec == HB_CODEC_MP3 ? + 1152 : 1024 ); + HBLog( "HBMuxThread: audio bitrate: %.2f kbps", + (float) t->audioBytes * audio->outSampleRate / + t->audioFrames / samplesPerFrame / 125 ); + HBLog( "HBMuxThread: audio error: "LLD" bytes", + t->audioBytes - audio->outBitrate * t->audioFrames * + 125 * samplesPerFrame / audio->outSampleRate ); + } + } + + free( t ); + + *_t = NULL; +} + +static int MuxWait( HBTitle * title ) +{ + int i; + HBAudio * audio; + + if( !HBFifoWait( title->outFifo ) ) + { + return 0; + } + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + if( !HBFifoWait( audio->outFifo ) ) + { + return 0; + } + } + return 1; +} + +static void MuxThread( void * _t ) +{ + HBMuxThread * t = (HBMuxThread*) _t; + HBTitle * title = t->title; + HBMux * m = t->mux; + HBAudio * audio; + HBBuffer * buffer; + int i; + + /* Remove the file if already existing */ + unlink( title->file ); + + /* Wait until we have at least one video frame and 3 audio frames + for each track (Vorbis...) */ + if( !HBFifoWait( title->outFifo ) ) + { + return; + } + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = HBListItemAt( title->ripAudioList, i ); + while( !t->die && HBFifoSize( audio->outFifo ) < 3 ) + { + HBSnooze( 10000 ); + } + if( t->die ) + { + return; + } + } + + m->start( m ); + + /* Mux */ + for( ;; ) + { + /* Wait until we have one frame for each track */ + if( !MuxWait( title ) ) + { + break; + } + + /* Interleave frames in the same order than they were in the + original MPEG stream */ + audio = NULL; + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + HBAudio * otherAudio; + otherAudio = HBListItemAt( title->ripAudioList, i ); + if( !audio || HBFifoPosition( otherAudio->outFifo ) < + HBFifoPosition( audio->outFifo ) ) + { + audio = otherAudio; + } + } + if( !audio || HBFifoPosition( title->outFifo ) < + HBFifoPosition( audio->outFifo ) ) + { + /* Video */ + buffer = HBFifoPop( title->outFifo ); + m->muxVideo( m, title->muxData, buffer ); + t->videoBytes += buffer->size; + t->videoFrames++; + HBBufferClose( &buffer ); + } + else + { + /* Audio */ + buffer = HBFifoPop( audio->outFifo ); + m->muxAudio( m, audio->muxData, buffer ); + t->audioBytes += buffer->size; + t->audioFrames++; + HBBufferClose( &buffer ); + } + } + + m->end( m ); +} + diff --git a/core/Mux.h b/core/Mux.h new file mode 100644 index 000000000..fbd1fd98f --- /dev/null +++ b/core/Mux.h @@ -0,0 +1,21 @@ +/* $Id: Mux.h,v 1.2 2004/05/02 16:25: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_MUX_H +#define HB_MUX_H + +#define HB_MUX_COMMON_MEMBERS \ + int (*start) ( HBMux * ); \ + int (*muxVideo) ( HBMux *, void *, HBBuffer * ); \ + int (*muxAudio) ( HBMux *, void *, HBBuffer * ); \ + int (*end) ( HBMux * ); + +typedef struct HBMux HBMux; + +HBMuxThread * HBMuxThreadInit( HBHandle *, HBTitle * ); +void HBMuxThreadClose( HBMuxThread ** ); + +#endif diff --git a/core/OgmMux.c b/core/OgmMux.c index fef1ae01b..e99a494f5 100644 --- a/core/OgmMux.c +++ b/core/OgmMux.c @@ -1,4 +1,4 @@ -/* $Id: OgmMux.c,v 1.7 2004/03/08 11:32:48 titer Exp $ +/* $Id: OgmMux.c,v 1.13 2004/05/13 21:10:56 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -8,209 +8,26 @@ #include <ogg/ogg.h> -static void OgmMuxThread( void * ); -static int OgmStart( HBOgmMux * ); -static int OgmFlush( HBOgmMux *, int ); -static int OgmEnd( HBOgmMux * ); +static int OgmStart( HBMux * ); +static int OgmMux( HBMux *, void *, HBBuffer * ); +static int OgmEnd( HBMux * ); -struct HBOgmMux +struct HBMux { - HBHandle *handle; - HBTitle *title; + HB_MUX_COMMON_MEMBERS - volatile int die; - HBThread *thread; - - FILE *file; - - int i_tk; - struct - { - HBFifo *fifo; - - int codec; - - ogg_stream_state os; - int i_packet_no; - - } tk[100]; /* The first who set more than 100 stream !! */ + HBHandle * handle; + HBTitle * title; + FILE * file; }; -HBOgmMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ) -{ - HBOgmMux *ogm = malloc( sizeof( HBOgmMux ) ); - - ogm->handle = handle; - ogm->title = title; - - ogm->file = NULL; - ogm->i_tk = 0; - - ogm->die = 0; - ogm->thread = HBThreadInit( "ogm muxer", OgmMuxThread, ogm, HB_NORMAL_PRIORITY ); - return ogm; -} - -void HBOgmMuxClose( HBOgmMux ** _ogm ) -{ - HBOgmMux *ogm = *_ogm; - - ogm->die = 1; - HBThreadClose( &ogm->thread ); - - free( ogm ); - - *_ogm = NULL; -} - -static int OgmDataWait( HBOgmMux *ogm ) -{ - int i; - - for( i = 0; i < ogm->i_tk; i++ ) - { - while( !ogm->die && HBFifoSize( ogm->tk[i].fifo ) <= 0 ) - { - HBSnooze( 10000 ); - } - } - return ogm->die ? -1 : 0; -} - -static void OgmMuxThread( void * _this ) +typedef struct { - HBOgmMux *ogm = _this; - - HBTitle *title = ogm->title; - - int i; - - /* Open output file */ - if( ( ogm->file = fopen( title->file, "w" ) ) == NULL ) - { - HBLog( "HBOgmMux: failed to open `%s'", title->file ); - /* FIXME */ - HBErrorOccured( ogm->handle, HB_ERROR_AVI_WRITE ); - return; - } - HBLog( "HBOgmMux: `%s' opened", title->file ); - - - /* Wait for data in each fifo */ - HBLog( "HBOgmMux: waiting video/audio data" ); - if( OgmDataWait( ogm ) < 0 ) - { - HBLog( "HBOgmMux: exiting" ); - fclose( ogm->file ); - unlink( title->file ); - return; - } - - if( OgmStart( ogm ) < 0 ) - { - HBLog( "HBOgmMux: failed to write headers" ); - fclose( ogm->file ); - unlink( title->file ); - return; - } + int codec; + ogg_stream_state os; + int i_packet_no; - HBLog( "HBOgmMux: headers written" ); - - for( ;; ) - { - HBBuffer *buffer; - ogg_packet op; - int i_tk; - - /* Wait data */ - if( OgmDataWait( ogm ) < 0 ) - { - break; - } - - /* Choose the right track to write (interleaved data) */ - for( i = 0, i_tk = -1; i < ogm->i_tk; i++ ) - { - if( i_tk < 0 || - HBFifoPosition( ogm->tk[i].fifo ) < HBFifoPosition( ogm->tk[i_tk].fifo ) ) - { - i_tk = i; - } - } - - buffer = HBFifoPop( ogm->tk[i_tk].fifo ); - - switch( ( ogm->tk[i_tk].codec ) ) - { - case HB_CODEC_FFMPEG: - case HB_CODEC_XVID: - case HB_CODEC_X264: - op.bytes = buffer->size + 1; - op.packet = malloc( op.bytes ); - op.packet[0] = buffer->keyFrame ? 0x08 : 0x00; - memcpy( &op.packet[1], buffer->data, buffer->size ); - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = ogm->tk[i_tk].i_packet_no; - op.packetno = ogm->tk[i_tk].i_packet_no++; - break; - case HB_CODEC_MP3: - op.bytes = buffer->size + 1; - op.packet = malloc( op.bytes ); - op.packet[0] = 0x08; - memcpy( &op.packet[1], buffer->data, buffer->size ); - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = ogm->tk[i_tk].i_packet_no * 1152; - op.packetno = ogm->tk[i_tk].i_packet_no++; - break; - case HB_CODEC_VORBIS: - memcpy( &op, buffer->data, sizeof( ogg_packet ) ); - - op.packet = malloc( op.bytes ); - memcpy( op.packet, buffer->data + sizeof( ogg_packet ), op.bytes ); - break; - - default: - HBLog( "HBOgmMux: unhandled codec" ); - op.bytes = 0; - op.packet = NULL; - break; - } - - if( op.packet ) - { - ogg_stream_packetin( &ogm->tk[i_tk].os, &op ); - - for( ;; ) - { - ogg_page og; - if( ogg_stream_pageout( &ogm->tk[i_tk].os, &og ) == 0 ) - { - break; - } - - if( fwrite( og.header, og.header_len, 1, ogm->file ) <= 0 || - fwrite( og.body, og.body_len, 1, ogm->file ) <= 0 ) - { - HBLog( "HBOgmMux: write failed" ); - break; - } - } - free( op.packet ); - } - - HBBufferClose( &buffer ); - } - - if( OgmEnd( ogm ) < 0 ) - { - HBLog( "HBOgmMux: flush failed" ); - } - - fclose( ogm->file ); - HBLog( "HBOgmMux: `%s' closed", title->file ); -} +} OgmMuxData; typedef struct __attribute__((__packed__)) { @@ -268,17 +85,66 @@ static void _SetQWLE( uint8_t *p, uint64_t i_qw ) SetDWLE( p+4, ( i_qw >> 32)&0xffffffff ); } -static int OgmFlush( HBOgmMux *ogm, int i_tk ) +HBMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ) +{ + HBMux * m; + HBAudio * audio; + int i; + + if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) + { + HBLog( "HBOgmMux: malloc failed, gonna crash" ); + return NULL; + } + m->start = OgmStart; + m->muxVideo = OgmMux; + m->muxAudio = OgmMux; + m->end = OgmEnd; + + m->handle = handle; + m->title = title; + + /* Alloc muxer data */ + title->muxData = calloc( sizeof( OgmMuxData ), 1 ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + audio->muxData = calloc( sizeof( OgmMuxData ), 1 ); + } + + return m; +} + +void HBOgmMuxClose( HBMux ** _m ) +{ + HBMux * m = *_m; + HBTitle * title = m->title; + HBAudio * audio; + int i; + + /* Free muxer data */ + free( title->muxData ); + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + free( audio->muxData ); + } + + free( m ); + *_m = NULL; +} + +static int OgmFlush( HBMux * m, OgmMuxData * muxData ) { for( ;; ) { ogg_page og; - if( ogg_stream_flush( &ogm->tk[i_tk].os, &og ) == 0 ) + if( ogg_stream_flush( &muxData->os, &og ) == 0 ) { break; } - if( fwrite( og.header, og.header_len, 1, ogm->file ) <= 0 || - fwrite( og.body, og.body_len, 1, ogm->file ) <= 0 ) + if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || + fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) { return -1; } @@ -286,92 +152,87 @@ static int OgmFlush( HBOgmMux *ogm, int i_tk ) return 0; } -static int OgmStart( HBOgmMux *ogm ) +static int OgmStart( HBMux * m ) { - HBTitle *title = ogm->title; - int i; + HBTitle * title = m->title; + HBAudio * audio; + OgmMuxData * muxData; + ogg_packet op; + ogg_stream_header_t h; + int i; - ogg_packet op; + /* Open output file */ + if( ( m->file = fopen( title->file, "wb" ) ) == NULL ) + { + HBLog( "HBOgmMux: failed to open `%s'", title->file ); + /* FIXME */ + HBErrorOccured( m->handle, HB_ERROR_AVI_WRITE ); + return -1; + } + HBLog( "HBOgmMux: `%s' opened", title->file ); - /* Init track */ - ogm->tk[0].codec = title->codec; - ogm->tk[0].fifo = title->outFifo; - ogm->tk[0].i_packet_no = 0; - ogg_stream_init (&ogm->tk[0].os, 0 ); + /* Init tracks */ - for( i = 1; i < HBListCount( title->ripAudioList ) + 1; i++ ) + /* Video */ + muxData = (OgmMuxData *) title->muxData; + muxData->codec = title->codec; + muxData->i_packet_no = 0; + ogg_stream_init( &muxData->os, 0 ); + + /* Audio */ + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - HBAudio *audio = HBListItemAt( title->ripAudioList, i - 1 ); + HBAudio * audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + muxData = (OgmMuxData *) audio->muxData; - ogm->tk[i].codec = audio->outCodec; - ogm->tk[i].fifo = audio->outFifo; - ogm->tk[i].i_packet_no = 0; - ogg_stream_init (&ogm->tk[i].os, i ); + muxData->codec = audio->outCodec; + muxData->i_packet_no = 0; + ogg_stream_init( &muxData->os, i + 1 ); } - ogm->i_tk = 1 + HBListCount( title->ripAudioList ); - /* Wait data for each track */ - for( i = 0; i < ogm->i_tk; i++ ) + /* First pass: all b_o_s packets */ + + /* Video */ + muxData = (OgmMuxData *) title->muxData; + memset( &h, 0, sizeof( ogg_stream_header_t ) ); + h.i_packet_type = 0x01; + memcpy( h.stream_type, "video ", 8 ); + if( muxData->codec == HB_CODEC_X264 ) { - while( !ogm->die && - ( ( ogm->tk[i].codec == HB_CODEC_VORBIS && HBFifoSize( ogm->tk[i].fifo ) <= 3 ) || - HBFifoSize( ogm->tk[i].fifo ) <= 0 ) ) - { - HBSnooze( 10000 ); - } + memcpy( h.sub_type, "H264", 4 ); } - - if( ogm->die ) + else { - return -1; + memcpy( h.sub_type, "XVID", 4 ); } - - /* First pass: all b_o_s packets */ - for( i = 0; i < ogm->i_tk; i++ ) + SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); + SetQWLE( &h.i_time_unit, (int64_t)10*1000*1000*(int64_t)title->rateBase/(int64_t)title->rate ); + SetQWLE( &h.i_samples_per_unit, 1 ); + SetDWLE( &h.i_default_len, 0 ); + SetDWLE( &h.i_buffer_size, 1024*1024 ); + SetWLE ( &h.i_bits_per_sample, 0 ); + SetDWLE( &h.header.video.i_width, title->outWidth ); + SetDWLE( &h.header.video.i_height, title->outHeight ); + op.packet = (char*)&h; + op.bytes = sizeof( ogg_stream_header_t ); + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = muxData->i_packet_no++; + ogg_stream_packetin( &muxData->os, &op ); + OgmFlush( m, muxData ); + + /* Audio */ + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - ogg_stream_header_t h; - + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + muxData = (OgmMuxData *) audio->muxData; memset( &h, 0, sizeof( ogg_stream_header_t ) ); - - switch( ogm->tk[i].codec ) + switch( muxData->codec ) { - case HB_CODEC_FFMPEG: - case HB_CODEC_XVID: - case HB_CODEC_X264: - h.i_packet_type = 0x01; - memcpy( h.stream_type, "video ", 8 ); - if( ogm->tk[i].codec == HB_CODEC_X264 ) - { - memcpy( h.sub_type, "H264", 4 ); - } - else - { - memcpy( h.sub_type, "XVID", 4 ); - } - - SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); - SetQWLE( &h.i_time_unit, (int64_t)10*1000*1000*(int64_t)title->rateBase/(int64_t)title->rate ); - SetQWLE( &h.i_samples_per_unit, 1 ); - SetDWLE( &h.i_default_len, 0 ); - SetDWLE( &h.i_buffer_size, 1024*1024 ); - SetWLE ( &h.i_bits_per_sample, 0 ); - SetDWLE( &h.header.video.i_width, title->outWidth ); - SetDWLE( &h.header.video.i_height, title->outHeight ); - - op.packet = (char*)&h; - op.bytes = sizeof( ogg_stream_header_t ); - op.b_o_s = 1; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = ogm->tk[i].i_packet_no++; - ogg_stream_packetin( &ogm->tk[i].os, &op ); - break; - case HB_CODEC_MP3: { - HBAudio *audio = HBListItemAt( title->ripAudioList, i - 1 ); - h.i_packet_type = 0x01; memcpy( h.stream_type, "audio ", 8 ); memcpy( h.sub_type, "55 ", 4 ); @@ -385,87 +246,151 @@ static int OgmStart( HBOgmMux *ogm ) SetDWLE( &h.header.audio.i_channels, 2 ); SetDWLE( &h.header.audio.i_block_align, 0 ); - SetDWLE( &h.header.audio.i_avgbytespersec, audio->outBitrate / 8 ); - + SetDWLE( &h.header.audio.i_avgbytespersec, + audio->outBitrate / 8 ); op.packet = (char*)&h; op.bytes = sizeof( ogg_stream_header_t ); op.b_o_s = 1; op.e_o_s = 0; op.granulepos = 0; - op.packetno = ogm->tk[i].i_packet_no++; - ogg_stream_packetin( &ogm->tk[i].os, &op ); + op.packetno = muxData->i_packet_no++; + ogg_stream_packetin( &muxData->os, &op ); break; } case HB_CODEC_VORBIS: { - HBBuffer *h = HBFifoPop( ogm->tk[i].fifo ); + HBBuffer *h = HBFifoPop( audio->outFifo ); memcpy( &op, h->data, sizeof( ogg_packet ) ); op.packet = h->data + sizeof( ogg_packet ); - ogg_stream_packetin( &ogm->tk[i].os, &op ); + ogg_stream_packetin( &muxData->os, &op ); break; } - case HB_CODEC_AAC: - break; default: - HBLog( "unhandled codec" ); + HBLog( "HBOgmMux: unhandled codec" ); break; } - OgmFlush( ogm, i ); + OgmFlush( m, muxData ); } /* second pass: all non b_o_s packets */ - for( i = 0; i < ogm->i_tk; i++ ) + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) { - if( ogm->tk[i].codec == HB_CODEC_VORBIS ) + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + if( audio->outCodec == HB_CODEC_VORBIS ) { HBBuffer *h; int j; + muxData = (OgmMuxData *) audio->muxData; for( j = 0; j < 2; j++ ) { - HBFifoWait( ogm->tk[i].fifo ); - h = HBFifoPop( ogm->tk[i].fifo ); + h = HBFifoPop( audio->outFifo ); memcpy( &op, h->data, sizeof( ogg_packet ) ); op.packet = h->data + sizeof( ogg_packet ); - ogg_stream_packetin( &ogm->tk[i].os, &op ); + ogg_stream_packetin( &muxData->os, &op ); - OgmFlush( ogm, i ); + OgmFlush( m, muxData ); } } -#if 0 - else + } + + HBLog( "HBOgmMux: headers written" ); + return 0; +} + +static int OgmMux( HBMux * m, void * _muxData, HBBuffer * buffer ) +{ + OgmMuxData * muxData = (OgmMuxData *) _muxData; + ogg_packet op; + + switch( muxData->codec ) + { + case HB_CODEC_FFMPEG: + case HB_CODEC_XVID: + case HB_CODEC_X264: + op.bytes = buffer->size + 1; + op.packet = malloc( op.bytes ); + op.packet[0] = buffer->keyFrame ? 0x08 : 0x00; + memcpy( &op.packet[1], buffer->data, buffer->size ); + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = muxData->i_packet_no; + op.packetno = muxData->i_packet_no++; + break; + case HB_CODEC_MP3: + op.bytes = buffer->size + 1; + op.packet = malloc( op.bytes ); + op.packet[0] = 0x08; + memcpy( &op.packet[1], buffer->data, buffer->size ); + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = muxData->i_packet_no * 1152; + op.packetno = muxData->i_packet_no++; + break; + case HB_CODEC_VORBIS: + memcpy( &op, buffer->data, sizeof( ogg_packet ) ); + op.packet = malloc( op.bytes ); + memcpy( op.packet, buffer->data + sizeof( ogg_packet ), op.bytes ); + break; + + default: + HBLog( "HBOgmMux: unhandled codec" ); + op.bytes = 0; + op.packet = NULL; + break; + } + + if( op.packet ) + { + ogg_stream_packetin( &muxData->os, &op ); + + for( ;; ) { - /* Home made commentary */ - op.packet = "\003Handbrake"; - op.bytes = strlen( "\003Handbrake" );; - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = ogm->tk[i].i_packet_no++; - - ogg_stream_packetin( &ogm->tk[i].os, &op ); - OgmFlush( ogm, i ); + ogg_page og; + if( ogg_stream_pageout( &muxData->os, &og ) == 0 ) + { + break; + } + + if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || + fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) + { + HBLog( "HBOgmMux: write failed" ); + break; + } } -#endif + free( op.packet ); } - return 0; } -static int OgmEnd( HBOgmMux *ogm ) +static int OgmEnd( HBMux * m ) { - int i; + HBTitle * title = m->title; + HBAudio * audio; + OgmMuxData * muxData; + int i; - for( i = 0; i < ogm->i_tk; i++ ) + muxData = (OgmMuxData *) title->muxData; + if( OgmFlush( m, muxData ) < 0 ) { - if( OgmFlush( ogm, i ) < 0 ) + return -1; + } + for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) + { + audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); + muxData = (OgmMuxData *) audio->muxData; + if( OgmFlush( m, muxData ) < 0 ) { return -1; } } + + fclose( m->file ); + HBLog( "HBOgmMux: `%s' closed", title->file ); return 0; } diff --git a/core/Resample.c b/core/Resample.c new file mode 100644 index 000000000..f3632b371 --- /dev/null +++ b/core/Resample.c @@ -0,0 +1,159 @@ +/* $Id: Resample.c,v 1.4 2004/05/02 16:25: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. */ + +#include "HBInternal.h" + +#include "samplerate.h" + +struct HBWork +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBAudio * audio; + + float * samples; + SRC_STATE * state; + SRC_DATA data; + + uint64_t in; + uint64_t out; +}; + +/* Local prototypes */ +static int ResampleWork( HBWork * ); + +HBWork * HBResampleInit( HBHandle * handle, HBAudio * audio ) +{ + HBWork * w; + if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) + { + HBLog( "HBResampleInit: malloc() failed, gonna crash" ); + return NULL; + } + + w->name = strdup( "Resample" ); + w->work = ResampleWork; + + w->handle = handle; + w->audio = audio; + + return w; +} + +void HBResampleClose( HBWork ** _w ) +{ + HBWork * w = *_w; + + if( w->samples ) free( w->samples ); + if( w->state ) src_delete( w->state ); + + free( w->name ); + free( w ); + *_w = NULL; +} + +static int ResampleWork( HBWork * w ) +{ + HBAudio * audio = w->audio; + + HBBuffer * resampleBuffer; + float position; + + if( HBFifoIsHalfFull( audio->resampleFifo ) ) + { + return 0; + } + + /* Initialization */ + if( !w->samples ) + { + int error; + + /* Until a first packet comes, audio->inSampleRate is + undefined */ + if( !HBFifoSize( audio->rawFifo ) ) + { + return 0; + } + + /* No, the user can't choose. 44100 Hz, take it or leave it */ + audio->outSampleRate = 44100; + HBLog( "HBResample: in = %d Hz, out = %d Hz", + audio->inSampleRate, audio->outSampleRate ); + + /* Buffer in which we'll pop the samples from the decoder */ + w->samples = malloc( audio->inSampleRate * 2 * + sizeof( float ) / 10 ); + + /* Init libsamplerate */ + w->state = src_new( SRC_SINC_FASTEST, 2, &error ); + + /* Prepare the SRC_DATA structure */ + w->data.data_in = w->samples; + w->data.input_frames = audio->inSampleRate / 10; + w->data.output_frames = audio->outSampleRate / 10; + w->data.src_ratio = (double) audio->outSampleRate / + (double) audio->inSampleRate; + w->data.end_of_input = 0; + } + + /* Fix A/V synchro in case the audio track starts later than the + video */ + if( audio->delay > 0 ) + { + HBLog( "HBResample: adding %d ms of silence", audio->delay ); + + resampleBuffer = HBBufferInit( audio->delay * + audio->outSampleRate * 2 * sizeof( float ) / 1000 ); + memset( resampleBuffer->data, 0, resampleBuffer->size ); + if( !HBFifoPush( audio->resampleFifo, &resampleBuffer ) ) + { + HBLog( "HBResample: HBFifoPush failed" ); + } + + audio->delay = 0; + return 1; + } + + /* Get samples from the decoder */ + if( !HBFifoGetBytes( audio->rawFifo, (uint8_t *) w->samples, + audio->inSampleRate * 2 * sizeof( float ) / 10, + &position ) ) + { + return 0; + } + + /* Init resampled buffer */ + resampleBuffer = HBBufferInit( audio->outSampleRate * 2 * + sizeof( float ) / 10 ); + resampleBuffer->position = position; + + /* Resample */ + w->data.data_out = resampleBuffer->dataf; + if( src_process( w->state, &w->data ) ) + { + HBLog( "HBResample: src_process failed" ); + } + resampleBuffer->size = w->data.output_frames_gen * 2 * + sizeof( float ); + + if( w->data.input_frames_used != w->data.input_frames ) + { + /* Here we're basically f*cked */ + HBLog( "HBResample: ohoh, %d/%d used", + w->data.input_frames_used, w->data.input_frames ); + } + + /* Send resampled data to the encoder */ + if( !HBFifoPush( audio->resampleFifo, &resampleBuffer ) ) + { + HBLog( "HBResample: HBFifoPush failed" ); + } + + return 1; +} + diff --git a/core/Scale.c b/core/Scale.c index 527882539..2908d6456 100644 --- a/core/Scale.c +++ b/core/Scale.c @@ -1,4 +1,4 @@ -/* $Id: Scale.c,v 1.10 2004/03/08 11:32:48 titer Exp $ +/* $Id: Scale.c,v 1.14 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,13 +6,9 @@ #include "HBInternal.h" -#define USE_FFMPEG - -#ifdef USE_FFMPEG #include "ffmpeg/avcodec.h" -#endif -typedef struct HBScale +struct HBWork { HB_WORK_COMMON_MEMBERS @@ -20,114 +16,74 @@ typedef struct HBScale HBTitle * title; HBBuffer * deintBuffer; - HBList * scaledBufferList; -#ifdef USE_FFMPEG ImgReSampleContext * context; AVPicture rawPicture; AVPicture deintPicture; AVPicture scaledPicture; -#endif -} HBScale; +}; /* Local prototypes */ static int ScaleWork( HBWork * ); -#ifndef USE_FFMPEG -static void Deinterlace( uint8_t * in, uint8_t * out, int w, int h, - int tcrop, int bcrop, int lcrop, int rcrop ); -static void Resample( uint8_t * in, uint8_t * out, int oldw, int oldh, - int neww, int newh, int tcrop, int bcrop, - int lcrop, int rcrop ); -#endif HBWork * HBScaleInit( HBHandle * handle, HBTitle * title ) { - HBScale * s; - if( !( s = malloc( sizeof( HBScale ) ) ) ) + HBWork * w; + if( !( w = malloc( sizeof( HBWork ) ) ) ) { HBLog( "HBScaleInit: malloc() failed, gonna crash" ); return NULL; } - s->name = strdup( "Scale" ); - s->work = ScaleWork; + w->name = strdup( "Scale" ); + w->work = ScaleWork; - s->handle = handle; - s->title = title; + w->handle = handle; + w->title = title; /* Allocate a constant buffer used for deinterlacing */ - s->deintBuffer = HBBufferInit( 3 * title->inWidth * - title->inHeight / 2 ); + w->deintBuffer = HBBufferInit( 3 * title->inWidth * + title->inHeight / 2 ); -#ifdef USE_FFMPEG - avpicture_fill( &s->deintPicture, s->deintBuffer->data, + avpicture_fill( &w->deintPicture, w->deintBuffer->data, PIX_FMT_YUV420P, title->inWidth, title->inHeight ); /* Init libavcodec */ - s->context = + w->context = img_resample_full_init( title->outWidth, title->outHeight, title->inWidth, title->inHeight, title->topCrop, title->bottomCrop, title->leftCrop, title->rightCrop ); -#endif - - s->scaledBufferList = HBListInit(); - return (HBWork*) s; + return w; } -void HBScaleClose( HBWork ** _s ) +void HBScaleClose( HBWork ** _w ) { - HBScale * s = (HBScale*) *_s; - -#ifdef USE_FFMPEG - img_resample_close( s->context ); -#endif - HBListClose( &s->scaledBufferList ); - HBBufferClose( &s->deintBuffer ); - free( s->name ); - free( s ); + HBWork * w = *_w; - *_s = NULL; + img_resample_close( w->context ); + HBBufferClose( &w->deintBuffer ); + free( w->name ); + free( w ); + *_w = NULL; } static int ScaleWork( HBWork * w ) { - HBScale * s = (HBScale*) w; - HBTitle * title = s->title; + HBTitle * title = w->title; HBBuffer * rawBuffer; HBBuffer * scaledBuffer; HBBuffer * tmpBuffer; -#ifndef USE_FFMPEG - uint8_t * in, * out; - int plane, shift; -#endif - int didSomething = 0; - - /* Push scaled buffer(s) */ - while( ( scaledBuffer = (HBBuffer*) - HBListItemAt( s->scaledBufferList, 0 ) ) ) + if( HBFifoIsHalfFull( title->scaledFifo ) ) { - tmpBuffer = scaledBuffer; - if( HBFifoPush( title->scaledFifo, &scaledBuffer ) ) - { - didSomething = 1; - HBListRemove( s->scaledBufferList, tmpBuffer ); - } - else - { - return didSomething; - } + return 0; } /* Get a new raw picture */ - if( ( rawBuffer = HBFifoPop( title->rawFifo ) ) ) - { - didSomething = 1; - } - else + if( !( rawBuffer = HBFifoPop( title->rawFifo ) ) ) { - return didSomething; + return 0; } /* Allocate new buffer for the scaled picture */ @@ -136,62 +92,26 @@ static int ScaleWork( HBWork * w ) scaledBuffer->position = rawBuffer->position; scaledBuffer->pass = rawBuffer->pass; -#ifdef USE_FFMPEG /* libavcodec stuff */ - avpicture_fill( &s->rawPicture, rawBuffer->data, PIX_FMT_YUV420P, + avpicture_fill( &w->rawPicture, rawBuffer->data, PIX_FMT_YUV420P, title->inWidth, title->inHeight ); - avpicture_fill( &s->scaledPicture, scaledBuffer->data, + avpicture_fill( &w->scaledPicture, scaledBuffer->data, PIX_FMT_YUV420P, title->outWidth, title->outHeight ); /* Do the job */ if( title->deinterlace ) { - avpicture_deinterlace( &s->deintPicture, &s->rawPicture, + avpicture_deinterlace( &w->deintPicture, &w->rawPicture, PIX_FMT_YUV420P, title->inWidth, title->inHeight ); - img_resample( s->context, &s->scaledPicture, - &s->deintPicture ); + img_resample( w->context, &w->scaledPicture, + &w->deintPicture ); } else { - img_resample( s->context, &s->scaledPicture, &s->rawPicture ); - } -#else - if( title->deinterlace ) - { - in = rawBuffer->data; - out = s->deintBuffer->data; - for( plane = 0; plane < 3; plane++ ) - { - shift = plane ? 1 : 0; - Deinterlace( in, out, title->inWidth >> shift, - title->inHeight >> shift, - title->topCrop >> shift, - title->bottomCrop >> shift, - title->leftCrop >> shift, - title->rightCrop >> shift ); - in += title->inWidth * title->inHeight >> ( 2 * shift ); - out += title->inWidth * title->inHeight >> ( 2 * shift ); - } - } - - in = title->deinterlace ? s->deintBuffer->data : rawBuffer->data; - out = scaledBuffer->data; - for( plane = 0; plane < 3; plane++ ) - { - shift = plane ? 1 : 0; - Resample( in, out, title->inWidth >> shift, - title->inHeight >> shift, title->outWidth >> shift, - title->outHeight >> shift, title->topCrop >> shift, - title->bottomCrop >> shift, title->leftCrop >> shift, - title->rightCrop >> shift ); - in += title->inWidth * title->inHeight >> ( 2 * shift ); - out += title->outWidth * title->outHeight >> ( 2 * shift );; + img_resample( w->context, &w->scaledPicture, &w->rawPicture ); } -#endif - - HBListAdd( s->scaledBufferList, scaledBuffer ); if( rawBuffer->repeat ) { @@ -201,52 +121,20 @@ static int ScaleWork( HBWork * w ) memcpy( tmpBuffer->data, scaledBuffer->data, scaledBuffer->size ); - HBListAdd( s->scaledBufferList, tmpBuffer ); - } - - /* Free memory */ - HBBufferClose( &rawBuffer ); - - return didSomething; -} - -#ifndef USE_FFMPEG -static void Deinterlace( uint8_t * in, uint8_t * out, int w, int h, - int tcrop, int bcrop, int lcrop, int rcrop ) -{ - int i, j; - - /* First line */ - if( !tcrop ) - { - memcpy( out, in + lcrop, w - lcrop - rcrop ); - } - - /* Merge lines */ - for( i = MAX( 1, tcrop ); i < h - bcrop; i++ ) - { - for( j = lcrop; j < w - rcrop; j++ ) + if( !HBFifoPush( title->scaledFifo, &tmpBuffer ) ) { - out[i*w+j] = ( in[(i-1)*w+j] + in[i*w+j] ) / 2; + HBLog( "HBScale: HBFifoPush failed" ); } } -} -static void Resample( uint8_t * in, uint8_t * out, int oldw, int oldh, - int neww, int newh, int tcrop, int bcrop, - int lcrop, int rcrop ) -{ - int i, j; - int cropw = oldw - lcrop - rcrop; - int croph = oldh - tcrop - bcrop; - for( i = 0; i < newh; i++ ) + if( !HBFifoPush( title->scaledFifo, &scaledBuffer ) ) { - for( j = 0; j < neww; j++ ) - { - out[i*neww+j] = in[(tcrop+i*croph/newh)*oldw + - lcrop+j*cropw/neww]; - } + HBLog( "HBScale: HBFifoPush failed" ); } + + /* Free memory */ + HBBufferClose( &rawBuffer ); + + return 1; } -#endif diff --git a/core/Scan.c b/core/Scan.c index 8f19a138d..9315e59d0 100644 --- a/core/Scan.c +++ b/core/Scan.c @@ -1,4 +1,4 @@ -/* $Id: Scan.c,v 1.15 2004/03/08 11:32:48 titer Exp $ +/* $Id: Scan.c,v 1.26 2004/05/12 18:02:35 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -7,18 +7,15 @@ #include "HBInternal.h" #include "Languages.h" -#include "dvdread/ifo_types.h" -#include "dvdplay/dvdplay.h" -#include "dvdplay/info.h" -#include "dvdplay/state.h" -#include "dvdplay/nav.h" +#include "dvdread/ifo_read.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, +static HBTitle * ScanTitle( HBScan *, dvd_reader_t * reader, + ifo_handle_t * vmg, int index ); +static int DecodeFrame( HBScan * s, dvd_file_t * dvdFile, HBTitle * title, int which ); static char * LanguageForCode( int code ); @@ -29,6 +26,7 @@ struct HBScan int title; volatile int die; HBThread * thread; + HBList * titleList; }; HBScan * HBScanInit( HBHandle * handle, const char * device, int title ) @@ -64,40 +62,47 @@ void HBScanClose( HBScan ** _s ) static void ScanThread( void * _s ) { - HBScan * s = (HBScan*) _s; - dvdplay_ptr vmg; - HBList * titleList = HBListInit(); - HBTitle * title; - int i; + int i; + HBScan * s = (HBScan*) _s; + HBList * titleList = HBListInit(); + HBTitle * title; + dvd_reader_t * reader; + ifo_handle_t * vmg; + + s->titleList = titleList; HBLog( "HBScan: opening device %s", s->device ); - vmg = dvdplay_open( s->device, NULL, NULL ); - if( !vmg ) + reader = DVDOpen( s->device ); + if( !reader ) { - HBLog( "HBScan: dvdplay_open() failed (%s)", s->device ); + HBLog( "HBScan: DVDOpen() failed (%s)", s->device ); HBListClose( &titleList ); HBScanDone( s->handle, NULL ); return; } + vmg = ifoOpen( reader, 0 ); + /* Detect titles */ i = s->title ? ( s->title - 1 ) : 0; while( !s->die ) { - if( ( title = ScanTitle( s, vmg, i + 1 ) ) ) + if( ( title = ScanTitle( s, reader, vmg, i + 1 ) ) ) { HBListAdd( titleList, title ); } - if( s->title || i == dvdplay_title_nr( vmg ) - 1 ) + if( s->title || i == vmg->tt_srpt->nr_of_srpts - 1 ) { break; } i++; } + ifoClose( vmg ); + HBLog( "HBScan: closing device %s", s->device ); - dvdplay_close( vmg ); + DVDClose( reader ); if( s->die ) { @@ -117,27 +122,102 @@ static void ScanThread( void * _s ) HBScanDone( s->handle, titleList ); } -static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) + +static unsigned int convert_bcd( unsigned int i_x ) +{ + int y = 0, z = 1; + + for( ; i_x ; ) + { + y += z * ( i_x & 0xf ); + i_x = i_x >> 4; + z = z * 10; + } + + return y; +} + +static HBTitle * ScanTitle( HBScan * s, dvd_reader_t * reader, + ifo_handle_t * vmg, int index ) { HBTitle * title; - int audio_nr, foo; - audio_attr_t * attr; + HBTitle * title2; HBAudio * audio; - int i; - uint8_t dummy[DVD_VIDEO_LB_LEN]; + int i, audio_nr; + int ttn; + ifo_handle_t * vts; + int pgc_id, pgn, cell; + pgc_t * pgc; + dvd_file_t * dvdFile; - HBScanning( s->handle, index, dvdplay_title_nr( vmg ) ); + HBScanning( s->handle, index, vmg->tt_srpt->nr_of_srpts ); title = HBTitleInit( s->device, index ); - dvdplay_start( vmg, index ); - /* Length */ - title->length = dvdplay_title_time( vmg ); - HBLog( "HBScan: title %d: length is %d seconds", index, - title->length ); + /* VTS in which our title is */ + title->vts_id = vmg->tt_srpt->title[index-1].title_set_nr; + + vts = ifoOpen( reader, title->vts_id ); + if( !vts ) + { + HBLog( "HBScan: ifoOpen failed (vts %d)", title->vts_id ); + HBTitleClose( &title ); + return NULL; + } + + /* Position of the title in the VTS */ + ttn = vmg->tt_srpt->title[index-1].vts_ttn; + + /* Get pgc */ + pgc_id = vts->vts_ptt_srpt->title[ttn-1].ptt[0].pgcn; + pgn = vts->vts_ptt_srpt->title[ttn-1].ptt[0].pgn; + pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; + + /* Start block */ + cell = pgc->program_map[pgn-1] - 1; + title->startBlock = pgc->cell_playback[cell].first_sector; + + /* End block */ + cell = pgc->nr_of_cells - 1; + title->endBlock = pgc->cell_playback[cell].last_sector; + + HBLog( "HBScan: vts=%d, ttn=%d, blocks %d to %d", title->vts_id, + ttn, title->startBlock, title->endBlock ); + + /* I've seen a DVD with strictly identical titles. Check this here, + and ignore it if redundant */ + title2 = NULL; + for( i = 0; i < HBListCount( s->titleList ); i++ ) + { + title2 = (HBTitle*) HBListItemAt( s->titleList, i ); + if( title->vts_id == title2->vts_id && + title->startBlock == title2->startBlock && + title->endBlock == title2->endBlock ) + { + break; + } + else + { + title2 = NULL; + } + } + if( title2 ) + { + HBLog( "HBScan: title %d is duplicate with title %d", + index, title2->title ); + HBTitleClose( &title ); + return NULL; + } + + /* Get time */ + title->hours = convert_bcd( pgc->playback_time.hour ); + title->minutes = convert_bcd( pgc->playback_time.minute ); + title->seconds = convert_bcd( pgc->playback_time.second ); + HBLog( "HBScan: title %d: length is %02d:%02d:%02d", index, + title->hours, title->minutes, title->seconds ); /* Discard titles under 10 seconds */ - if( title->length < 10 ) + if( !title->hours && !title->minutes && title->seconds < 10 ) { HBLog( "HBScan: ignoring title %d (too short)", index ); HBTitleClose( &title ); @@ -145,36 +225,57 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) } /* Detect languages */ - dvdplay_audio_info( vmg, &audio_nr, &foo ); + audio_nr = vts->vtsi_mat->nr_of_vts_audio_streams; for( i = 0; i < audio_nr; i++ ) { - int id, j, codec; + uint32_t id = 0; + int j, codec; + int audio_format = vts->vtsi_mat->vts_audio_attr[i].audio_format; + int lang_code = vts->vtsi_mat->vts_audio_attr[i].lang_code; + int audio_control = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i]; + int i_position; if( s->die ) { break; } - id = dvdplay_audio_id( vmg, i ); - - if( id < 1 ) + if( !( audio_control & 0x8000 ) ) { continue; } - if( ( id & 0xF0FF ) == 0x80BD ) - { - codec = HB_CODEC_AC3; - } - else if( ( id & 0xF0FF ) == 0xA0BD ) + i_position = ( audio_control & 0x7F00 ) >> 8; + + switch( audio_format ) { - codec = HB_CODEC_LPCM; + case 0x00: /* A52 */ + codec = HB_CODEC_AC3; + id = ( ( 0x80 + i_position ) << 8 ) | 0xbd; + break; + + case 0x02: + case 0x03: + codec = HB_CODEC_MPGA; + id = 0xc0 + i_position; + break; + + case 0x04: /* LPCM */ + codec = HB_CODEC_LPCM; + id = ( ( 0xa0 + i_position ) << 8 ) | 0xbd; + break; + + default: + codec = 0; + id = 0; + HBLog( "HBScan: title %d: unknown audio codec (%x), " + "ignoring", index, audio_format ); + break; } - else + + if( !id ) { - HBLog( "HBScan: title %d: unknown audio codec (%x), " - "ignoring", index, id ); continue; } @@ -200,8 +301,7 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) continue; } - attr = dvdplay_audio_attr( vmg, j ); - audio = HBAudioInit( id, LanguageForCode( attr->lang_code ) ); + audio = HBAudioInit( id, LanguageForCode( lang_code ), codec ); audio->inCodec = codec; HBLog( "HBScan: title %d: new language (%x, %s)", index, id, audio->language ); @@ -216,8 +316,15 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) return NULL; } - /* Kludge : libdvdplay wants us to read a first block before seeking */ - dvdplay_read( vmg, dummy, 1 ); + ifoClose( vts ); + + dvdFile = DVDOpenFile( reader, title->vts_id, DVD_READ_TITLE_VOBS ); + if( !dvdFile ) + { + HBLog( "HBScan: DVDOpenFile failed" ); + HBTitleClose( &title ); + return NULL; + } for( i = 0; i < 10; i++ ) { @@ -226,7 +333,7 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) break; } - if( !DecodeFrame( s, vmg, title, i ) ) + if( !DecodeFrame( s, dvdFile, title, i ) ) { HBLog( "HBScan: ignoring title %d (could not decode)", index ); @@ -235,6 +342,8 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) } } + DVDCloseFile( dvdFile ); + /* Handle ratio */ if( title->inHeight * title->aspect > title->inWidth * VOUT_ASPECT_FACTOR ) @@ -257,41 +366,88 @@ static HBTitle * ScanTitle( HBScan * s, dvdplay_ptr vmg, int index ) return title; } -static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, +static HBBuffer * GetBuffer( HBList * esBufferList, + dvd_file_t * dvdFile, + int * pictureStart, int pictureEnd ) +{ + HBBuffer * esBuffer = NULL; + HBBuffer * psBuffer = NULL; + + while( !esBuffer ) + { + while( !HBListCount( esBufferList ) ) + { + psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); + if( DVDReadBlocks( dvdFile, (*pictureStart)++, 1, + psBuffer->data ) != 1 ) + { + HBLog( "HBScan: DVDReadBlocks() failed" ); + HBBufferClose( &psBuffer ); + return NULL; + } + if( !HBPStoES( &psBuffer, esBufferList ) ) + { + HBLog( "HBScan: HBPStoES() failed" ); + return NULL; + } + if( *pictureStart >= pictureEnd ) + { + HBLog( "HBScan: gone too far, aborting" ); + return NULL; + } + } + + esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ); + HBListRemove( esBufferList, esBuffer ); + + if( esBuffer->streamId != 0xE0 ) + { + HBBufferClose( &esBuffer ); + } + } + + return esBuffer; +} + +static int DecodeFrame( HBScan * s, dvd_file_t * dvdFile, 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; + int pictureStart = title->startBlock + ( which + 1 ) * + ( title->endBlock - title->startBlock ) / 11; + int pictureEnd = title->startBlock + ( which + 2 ) * + ( title->endBlock - title->startBlock ) / 11; mpeg2dec_t * handle; const mpeg2_info_t * info; mpeg2_state_t state; char fileName[1024]; FILE * file; - int ret = 1; + int ret = 0; HBList * esBufferList = HBListInit(); - HBBuffer * psBuffer = NULL; HBBuffer * esBuffer = NULL; - /* Seek to the right place */ - dvdplay_seek( vmg, pictureStart ); /* Init libmpeg2 */ -#ifdef HB_NOMMX - mpeg2_accel( 0 ); -#endif handle = mpeg2_init(); info = mpeg2_info( handle ); /* Init the destination file */ memset( fileName, 0, 1024 ); +#ifndef HB_CYGWIN sprintf( fileName, "/tmp/HB.%d.%d.%d", HBGetPid( s->handle ), - title->index, which ); - file = fopen( fileName, "w" ); + title->title, which ); +#else + sprintf( fileName, "C:\\HB.%d.%d.%d", HBGetPid( s->handle ), + title->title, which ); +#endif + file = fopen( fileName, "wb" ); + if( !file ) + { + HBLog( "HBScan: fopen failed" ); + HBListClose( &esBufferList ); + return 0; + } for( ;; ) { @@ -306,43 +462,10 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, } /* Get a new one */ - while( !esBuffer ) - { - while( !HBListCount( 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" ); - break; - } - - if( dvdplay_position( vmg ) >= pictureEnd ) - { - HBLog( "HBScan: gone too far, aborting" ); - break; - } - } - - if( !HBListCount( esBufferList ) ) - { - break; - } - - esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ); - HBListRemove( esBufferList, esBuffer ); - - if( esBuffer->streamId != 0xE0 ) - { - HBBufferClose( &esBuffer ); - } - } - + esBuffer = GetBuffer( esBufferList, dvdFile, &pictureStart, + pictureEnd ); if( !esBuffer ) { - ret = 0; break; } @@ -413,7 +536,7 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, } #undef Y #undef DARK - + /* Write the raw picture to a file */ fwrite( info->display_fbuf->buf[0], title->inWidth * title->inHeight, 1, file ); @@ -421,6 +544,7 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, title->inWidth * title->inHeight / 4, 1, file ); fwrite( info->display_fbuf->buf[2], title->inWidth * title->inHeight / 4, 1, file ); + ret = 1; break; } else if( state == STATE_INVALID ) @@ -440,7 +564,6 @@ static int DecodeFrame( HBScan * s, dvdplay_ptr vmg, HBBufferClose( &esBuffer ); } HBListClose( &esBufferList ); - if( psBuffer ) HBBufferClose( &psBuffer ); if( esBuffer ) HBBufferClose( &esBuffer ); mpeg2_close( handle ); fclose( file ); diff --git a/core/Thread.c b/core/Thread.c index 8c63b2423..9379223f0 100644 --- a/core/Thread.c +++ b/core/Thread.c @@ -1,4 +1,4 @@ -/* $Id: Thread.c,v 1.13 2004/03/16 16:14:03 titer Exp $ +/* $Id: Thread.c,v 1.14 2004/04/27 19:30:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -46,7 +46,7 @@ static void ThreadFunc( void * _t ) param.sched_priority = t->priority; if( pthread_setschedparam( pthread_self(), SCHED_OTHER, ¶m ) ) { - HBLog( "HBThreadInit: couldn't set thread priority" ); + HBLog( "HBThread: couldn't set thread priority" ); } #endif @@ -61,7 +61,7 @@ HBThread * HBThreadInit( char * name, void (* function)(void *), HBThread * t; if( !( t = malloc( sizeof( HBThread ) ) ) ) { - HBLog( "HBThreadInit: malloc() failed, gonna crash" ); + HBLog( "HBThread: malloc() failed, gonna crash" ); return NULL; } t->name = strdup( name ); @@ -82,7 +82,7 @@ HBThread * HBThreadInit( char * name, void (* function)(void *), (LPTHREAD_START_ROUTINE) ThreadFunc, t, 0, NULL ); #endif - HBLog( "HBThreadInit: thread %d started (\"%s\")", + HBLog( "HBThread: thread %d started (\"%s\")", t->thread, t->name ); return t; @@ -102,7 +102,7 @@ void HBThreadClose( HBThread ** _t ) WaitForSingleObject( t->thread, INFINITE ); #endif - HBLog( "HBThreadClose: thread %d stopped (\"%s\")", + HBLog( "HBThread: thread %d stopped (\"%s\")", t->thread, t->name ); /* Clean up */ @@ -120,7 +120,7 @@ HBLock * HBLockInit() HBLock * l; if( !( l = malloc( sizeof( HBLock ) ) ) ) { - HBLog( "HBLockInit: malloc() failed, gonna crash" ); + HBLog( "HBLock: malloc() failed, gonna crash" ); return NULL; } diff --git a/core/Utils.c b/core/Utils.c index 81aeebea5..45ebf7bd4 100644 --- a/core/Utils.c +++ b/core/Utils.c @@ -1,4 +1,4 @@ -/* $Id: Utils.c,v 1.16 2004/03/08 11:32:48 titer Exp $ +/* $Id: Utils.c,v 1.20 2004/05/12 17:21:24 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -14,6 +14,19 @@ #include "Utils.h" #include "Fifo.h" +#ifdef HB_CYGWIN +int gettimeofday( struct timeval * tv, struct timezone * tz ) +{ + tv->tv_sec = 0; + tv->tv_usec = 0; + return 0; +} +void bcopy( const void * src, void * dest, size_t n ) +{ + memcpy( dest, src, n ); +} +#endif + struct HBList { void ** items; @@ -126,7 +139,8 @@ int HBPStoES( HBBuffer ** _psBuffer, HBList * esBufferList ) pos += 2; /* PES_packet_length */ PES_packet_end = pos + PES_packet_length; - if( streamId != 0xE0 && streamId != 0xBD ) + if( streamId != 0xE0 && streamId != 0xBD && + ( streamId & 0xC0 ) != 0xC0 ) { /* Not interesting */ pos = PES_packet_end; @@ -303,7 +317,7 @@ HBTitle * HBTitleInit( char * device, int index ) } t->device = strdup( device ); - t->index = index; + t->title = index; t->codec = HB_CODEC_FFMPEG; t->mux = HB_MUX_MP4; @@ -336,7 +350,7 @@ void HBTitleClose( HBTitle ** _t ) *_t = NULL; } -HBAudio * HBAudioInit( int id, char * language ) +HBAudio * HBAudioInit( int id, char * language, int codec ) { HBAudio * a; if( !( a = calloc( sizeof( HBAudio ), 1 ) ) ) @@ -346,19 +360,20 @@ HBAudio * HBAudioInit( int id, char * language ) } a->id = id; - a->language = strdup( language ); a->start = -1; + a->inCodec = codec; + memset( a->language, 0, 512 ); + snprintf( a->language, 511, "%s (%s)", language, + ( codec == HB_CODEC_AC3 ) ? "AC3" : ( ( codec == + HB_CODEC_LPCM ? "LPCM" : "MPEG" ) ) ); 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 index 2d1a06b92..fce20e557 100644 --- a/core/Utils.h +++ b/core/Utils.h @@ -1,4 +1,4 @@ -/* $Id: Utils.h,v 1.23 2004/03/08 11:32:48 titer Exp $ +/* $Id: Utils.h,v 1.30 2004/05/04 12:50:52 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -48,21 +48,13 @@ typedef struct HBTitle HBTitle; typedef struct HBThread HBThread; /* (De)Muxers */ -typedef struct HBAviMux HBAviMux; -typedef struct HBOgmMux HBOgmMux; typedef struct HBDVDRead HBDVDRead; -typedef struct HBMp4Mux HBMp4Mux; typedef struct HBScan HBScan; typedef struct HBWork HBWork; +typedef struct HBMuxThread HBMuxThread; typedef struct HBWorkThread HBWorkThread; -/* AVI stuff */ -typedef struct HBAviMainHeader HBAviMainHeader; -typedef struct HBAviStreamHeader HBAviStreamHeader; -typedef struct HBBitmapInfo HBBitmapInfo; -typedef struct HBWaveFormatEx HBWaveFormatEx; - /* Misc functions which may be used from anywhere */ void HBSnooze( int time ); void HBLog( char * log, ... ); @@ -82,7 +74,7 @@ HBTitle * HBTitleInit(); void HBTitleClose( HBTitle ** ); /* HBAudio functions */ -HBAudio * HBAudioInit( int id, char * language ); +HBAudio * HBAudioInit( int id, char * language, int codec ); void HBAudioClose( HBAudio ** ); #define HB_SUCCESS 0x00 @@ -96,15 +88,16 @@ void HBAudioClose( HBAudio ** ); #define HB_ERROR_MPEG4_INIT 0x80 /* Possible codecs */ -#define HB_CODEC_MPEG2 0x00 -#define HB_CODEC_FFMPEG 0x01 -#define HB_CODEC_XVID 0x02 -#define HB_CODEC_AC3 0x04 -#define HB_CODEC_LPCM 0x08 -#define HB_CODEC_MP3 0x10 -#define HB_CODEC_AAC 0x20 -#define HB_CODEC_X264 0x40 -#define HB_CODEC_VORBIS 0x80 +#define HB_CODEC_MPEG2 0x000 +#define HB_CODEC_FFMPEG 0x001 +#define HB_CODEC_XVID 0x002 +#define HB_CODEC_AC3 0x004 +#define HB_CODEC_LPCM 0x008 +#define HB_CODEC_MP3 0x010 +#define HB_CODEC_AAC 0x020 +#define HB_CODEC_X264 0x040 +#define HB_CODEC_VORBIS 0x080 +#define HB_CODEC_MPGA 0x100 /* Possible muxers */ #define HB_MUX_AVI 0x00 @@ -115,8 +108,13 @@ struct HBTitle { /* DVD info */ char * device; - int index; - int length; + int title; + int vts_id; + int startBlock; + int endBlock; + int hours; + int minutes; + int seconds; /* Audio infos */ HBList * audioList; @@ -156,16 +154,13 @@ struct HBTitle char * file; int mux; + /* Muxer data */ + void * muxData; + /* MP4 muxer specific */ - int track; uint8_t * esConfig; int esConfigLength; - /* AVI muxer specific */ - HBAviMainHeader * aviMainHeader; - HBAviStreamHeader * aviVideoHeader; - HBBitmapInfo * aviVideoFormat; - /* Fifos */ HBFifo * inFifo; HBFifo * rawFifo; @@ -174,10 +169,8 @@ struct HBTitle /* Threads */ HBDVDRead * dvdRead; - HBAviMux * aviMux; - HBMp4Mux * mp4Mux; - HBOgmMux * ogmMux; HBWorkThread * workThreads[8]; + HBMuxThread * muxThread; /* Work objects */ HBWork * decoder; @@ -189,7 +182,7 @@ struct HBAudio { /* Ident */ uint32_t id; - char * language; + char language[512]; /* Settings */ int inCodec; @@ -208,22 +201,19 @@ struct HBAudio uint8_t * esConfig; unsigned long esConfigLength; - /* MP4 track id */ - int track; - - /* AVI stuff */ - uint32_t aviFourCC; - HBAviStreamHeader * aviAudioHeader; - HBWaveFormatEx * aviAudioFormat; + /* Muxer data */ + void * muxData; /* Fifos */ HBFifo * inFifo; HBFifo * rawFifo; + HBFifo * resampleFifo; HBFifo * outFifo; /* Work objects */ HBWork * decoder; - HBWork * encoder;; + HBWork * resample; + HBWork * encoder; }; #endif diff --git a/core/VorbisEnc.c b/core/VorbisEnc.c index c75b36850..8b7b10f8f 100644 --- a/core/VorbisEnc.c +++ b/core/VorbisEnc.c @@ -1,4 +1,4 @@ -/* $Id: VorbisEnc.c,v 1.5 2004/03/08 11:32:49 titer Exp $ +/* $Id: VorbisEnc.c,v 1.9 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -11,7 +11,7 @@ #define OGGVORBIS_FRAME_SIZE 1024 -typedef struct HBVorbisEnc +struct HBWork { HB_WORK_COMMON_MEMBERS @@ -23,60 +23,46 @@ typedef struct HBVorbisEnc vorbis_comment vc; vorbis_dsp_state vd; vorbis_block vb; + float position; - HBBuffer *rawBuffer; - int rawBufferPos; /* in bytes */ - float position; int32_t * inputBuffer; - unsigned long samplesGot; - unsigned long inputSamples; - HBBuffer *vorbisBuffer; - - HBBuffer *header[3]; -} HBVorbisEnc; +}; /* Local prototypes */ static int VorbisEncWork( HBWork * ); -static int GetSamples( HBVorbisEnc * ); -HBWork *HBVorbisEncInit ( HBHandle *handle, HBAudio *audio ) +HBWork * HBVorbisEncInit ( HBHandle * handle, HBAudio * audio ) { - HBVorbisEnc *enc = malloc( sizeof( HBVorbisEnc ) ); - - enc->name = strdup( "VorbisEnc" ); - enc->work = VorbisEncWork; + HBWork * w = calloc( sizeof( HBWork ), 1 ); - enc->handle = handle; - enc->audio = audio; + w->name = strdup( "VorbisEnc" ); + w->work = VorbisEncWork; - enc->inited = 0; - enc->rawBuffer = NULL; - enc->inputSamples = 2 * OGGVORBIS_FRAME_SIZE; - enc->inputBuffer = malloc( 2 * OGGVORBIS_FRAME_SIZE * sizeof( int32_t ) ); - enc->samplesGot = 0; + w->handle = handle; + w->audio = audio; - enc->vorbisBuffer = NULL; + w->inputBuffer = malloc( 2 * OGGVORBIS_FRAME_SIZE * sizeof( int32_t ) ); - return (HBWork*) enc; + return w; } -void HBVorbisEncClose( HBWork **_enc ) +void HBVorbisEncClose( HBWork ** _w ) { - HBVorbisEnc *enc = (HBVorbisEnc*) *_enc; + HBWork * w = *_w; - if( enc->inited ) + if( w->inited ) { - vorbis_block_clear( &enc->vb ); - vorbis_dsp_clear( &enc->vd ); - vorbis_comment_clear( &enc->vc ); - vorbis_info_clear( &enc->vi ); + vorbis_block_clear( &w->vb ); + vorbis_dsp_clear( &w->vd ); + vorbis_comment_clear( &w->vc ); + vorbis_info_clear( &w->vi ); } - free( enc->name ); - free( enc ); + free( w->name ); + free( w ); - *_enc = NULL; + *_w = NULL; } static HBBuffer *PacketToBuffer( ogg_packet *op ) @@ -89,170 +75,98 @@ static HBBuffer *PacketToBuffer( ogg_packet *op ) return buf; } -static int VorbisEncWork( HBWork *w ) +static int VorbisEncWork( HBWork * w ) { - HBVorbisEnc *enc = (HBVorbisEnc*)w; - HBAudio *audio = enc->audio; - int didSomething = 0; + HBAudio * audio = w->audio; float **buffer; int i; + float inputBuffer[OGGVORBIS_FRAME_SIZE * 2]; + HBBuffer * vorbisBuffer; + if( HBFifoIsHalfFull( audio->outFifo ) ) + { + return 0; + } - if( !enc->inited ) + if( !w->inited ) { ogg_packet header[3]; - /* Get a first buffer so we know that audio->inSampleRate is correct */ - if( ( enc->rawBuffer = HBFifoPop( audio->rawFifo ) ) == NULL ) + if( !HBFifoSize( audio->resampleFifo ) ) { return 0; } - enc->inited = 1; - - didSomething = 1; - enc->rawBufferPos = 0; - enc->position = enc->rawBuffer->position; - /* No resampling */ - audio->outSampleRate = audio->inSampleRate; + w->inited = 1; /* init */ - vorbis_info_init( &enc->vi ); - if( vorbis_encode_setup_managed( &enc->vi, 2, - audio->inSampleRate, -1, 1000 * audio->outBitrate, -1 ) || - vorbis_encode_ctl( &enc->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) || - vorbis_encode_setup_init( &enc->vi ) ) + vorbis_info_init( &w->vi ); + if( vorbis_encode_setup_managed( &w->vi, 2, + audio->outSampleRate, -1, 1000 * audio->outBitrate, -1 ) || + vorbis_encode_ctl( &w->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) || + vorbis_encode_setup_init( &w->vi ) ) { - HBLog( "VorbisEnc: vorbis_encode_setup_managed failed" ); + HBLog( "HBVorbisEnc: vorbis_encode_setup_managed failed" ); return 0; } /* add a comment */ - vorbis_comment_init( &enc->vc ); - vorbis_comment_add_tag( &enc->vc, "ENCODER", "HandBrake"); + vorbis_comment_init( &w->vc ); + vorbis_comment_add_tag( &w->vc, "ENCODER", "HandBrake"); /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init( &enc->vd, &enc->vi); - vorbis_block_init( &enc->vd, &enc->vb); + vorbis_analysis_init( &w->vd, &w->vi); + vorbis_block_init( &w->vd, &w->vb); /* get the 3 headers */ - vorbis_analysis_headerout( &enc->vd, &enc->vc, + vorbis_analysis_headerout( &w->vd, &w->vc, &header[0], &header[1], &header[2] ); - - enc->header[0] = PacketToBuffer( &header[0] ); - enc->header[1] = PacketToBuffer( &header[1] ); - enc->header[2] = PacketToBuffer( &header[2] ); - } - - if( enc->header[0] ) - { - HBLog( "VorbisEncWork: sending header 1" ); - if( !HBFifoPush( audio->outFifo, &enc->header[0] ) ) - { - return didSomething; - } - didSomething = 1; - } - if( enc->header[1] ) - { - HBLog( "VorbisEncWork: sending header 2" ); - if( !HBFifoPush( audio->outFifo, &enc->header[1] ) ) - { - return didSomething; - } - didSomething = 1; - } - if( enc->header[2] ) - { - HBLog( "VorbisEncWork: sending header 3" ); - if( !HBFifoPush( audio->outFifo, &enc->header[2] ) ) - { - return didSomething; - } - didSomething = 1; - } - - /* Push already encoded data */ - if( enc->vorbisBuffer ) - { - if( !HBFifoPush( audio->outFifo, &enc->vorbisBuffer ) ) + for( i = 0; i < 3; i++ ) { - return didSomething; + vorbisBuffer = PacketToBuffer( &header[i] ); + if( !HBFifoPush( audio->outFifo, &vorbisBuffer ) ) + { + HBLog( "HBVorbisEnc: HBFifoPush failed" ); + } } } /* Try to extract more data */ - if( vorbis_analysis_blockout( &enc->vd, &enc->vb ) == 1 ) + if( vorbis_analysis_blockout( &w->vd, &w->vb ) == 1 ) { ogg_packet op; - vorbis_analysis( &enc->vb, NULL ); - vorbis_bitrate_addblock( &enc->vb ); + vorbis_analysis( &w->vb, NULL ); + vorbis_bitrate_addblock( &w->vb ); - if( vorbis_bitrate_flushpacket( &enc->vd, &op ) ) + if( vorbis_bitrate_flushpacket( &w->vd, &op ) ) { - enc->vorbisBuffer = PacketToBuffer( &op ); - enc->vorbisBuffer->position = enc->position; + vorbisBuffer = PacketToBuffer( &op ); + vorbisBuffer->position = w->position; + if( !HBFifoPush( audio->outFifo, &vorbisBuffer ) ) + { + HBLog( "HBVorbisEnc: HBFifoPush failed" ); + } return 1; } } - /* FUCK -Werror ! */ - if( !GetSamples( enc ) ) + if( !HBFifoGetBytes( audio->resampleFifo, (uint8_t*) inputBuffer, + OGGVORBIS_FRAME_SIZE * 2 * sizeof( float ), + &w->position ) ) { - return didSomething; + return 0; } - didSomething = 1; - - buffer = vorbis_analysis_buffer( &enc->vd, OGGVORBIS_FRAME_SIZE ); + buffer = vorbis_analysis_buffer( &w->vd, OGGVORBIS_FRAME_SIZE ); for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ ) { - buffer[0][i] = (float)enc->inputBuffer[2 * i + 0]/32768.f; - buffer[1][i] = (float)enc->inputBuffer[2 * i + 1]/32768.f; + buffer[0][i] = inputBuffer[2*i] / 32768.f; + buffer[1][i] = inputBuffer[2*i+1] / 32768.f; } - vorbis_analysis_wrote( &enc->vd, OGGVORBIS_FRAME_SIZE ); - - enc->samplesGot = 0; + vorbis_analysis_wrote( &w->vd, OGGVORBIS_FRAME_SIZE ); return 1; } -static int GetSamples( HBVorbisEnc * f ) -{ - while( f->samplesGot < f->inputSamples ) - { - int i, copy; - - if( !f->rawBuffer ) - { - if( !( f->rawBuffer = HBFifoPop( f->audio->rawFifo ) ) ) - { - return 0; - } - - f->rawBufferPos = 0; - f->position = f->rawBuffer->position; - } - - copy = MIN( f->inputSamples - f->samplesGot, - ( f->rawBuffer->samples - f->rawBufferPos ) * 2 ); - - for( i = 0; i < copy; i += 2 ) - { - f->inputBuffer[f->samplesGot++] = - f->rawBuffer->left[f->rawBufferPos]; - f->inputBuffer[f->samplesGot++] = - f->rawBuffer->right[f->rawBufferPos]; - f->rawBufferPos++; - } - - if( f->rawBufferPos == f->rawBuffer->samples ) - { - HBBufferClose( &f->rawBuffer ); - } - } - - return 1; -} diff --git a/core/Work.c b/core/Work.c index f2f05030a..e23af2421 100644 --- a/core/Work.c +++ b/core/Work.c @@ -1,4 +1,4 @@ -/* $Id: Work.c,v 1.12 2004/01/05 16:50:25 titer Exp $ +/* $Id: Work.c,v 1.14 2004/04/27 19:30:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -53,6 +53,7 @@ HBWorkThread * HBWorkThreadInit( HBHandle * handle, HBTitle * title, { audio = HBListItemAt( title->ripAudioList, i ); HBListAdd( t->workList, audio->decoder ); + HBListAdd( t->workList, audio->resample ); HBListAdd( t->workList, audio->encoder ); } @@ -105,7 +106,7 @@ void HBWorkThreadClose( HBWorkThread ** _t ) for( i = 0; i < HBListCount( t->workList ); i++ ) { w = (HBWork*) HBListItemAt( t->workList, i ); - HBLog( "HBWorkThreadClose: %- 9s = %05.2f %%", w->name, + HBLog( "HBWorkThread: %- 9s = %05.2f %%", w->name, 100.0 * w->time / total ); } @@ -126,7 +127,7 @@ static void WorkThread( void * _t ) uint64_t date; didSomething = 0; - + for( i = 0; !t->die; i++ ) { HBCheckPaused( t->handle ); diff --git a/core/X264Enc.c b/core/X264Enc.c index 50b9ab8bf..be8d76709 100644 --- a/core/X264Enc.c +++ b/core/X264Enc.c @@ -1,4 +1,4 @@ -/* $Id: X264Enc.c,v 1.3 2003/12/26 20:03:27 titer Exp $ +/* $Id: X264Enc.c,v 1.8 2004/05/02 16:25:00 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -9,79 +9,69 @@ /* x264 */ #include "x264.h" -typedef struct HBX264Enc +struct HBWork { HB_WORK_COMMON_MEMBERS HBHandle *handle; HBTitle *title; - HBBuffer *buffer; - x264_t *h; x264_picture_t picture; -} HBX264Enc; +}; /* Local prototypes */ static int HBX264EncWork( HBWork * ); -HBWork *HBX264EncInit( HBHandle * handle, HBTitle * title ) +HBWork * HBX264EncInit( HBHandle * handle, HBTitle * title ) { - HBX264Enc *f = malloc( sizeof( HBX264Enc ) ); + HBWork * w = malloc( sizeof( HBWork ) ); - if( f ) + if( w ) { x264_param_t param; - f->name = strdup( "X264Enc" ); - f->work = HBX264EncWork; - - f->handle = handle; - f->title = title; + w->name = strdup( "X264Enc" ); + w->work = HBX264EncWork; - f->buffer = NULL; + w->handle = handle; + w->title = title; x264_param_default( ¶m ); param.i_width = title->outWidth; param.i_height= title->outHeight; - param.i_iframe = 5 * title->rate / title->rateBase; - /* FIXME */ - param.b_deblocking_filter = 0; - param.i_me = 1; - - if( ( f->h = x264_encoder_open( ¶m ) ) == NULL ) + param.i_iframe = 20 * title->rate / title->rateBase; + param.i_idrframe = 1; + param.b_cabac = 0; + param.analyse.inter = + X264_ANALYSE_I16x16|X264_ANALYSE_I4x4|X264_ANALYSE_P16x16| + X264_ANALYSE_P16x8|X264_ANALYSE_P8x16|X264_ANALYSE_P8x8| + X264_ANALYSE_SMART_PSUB; + + if( ( w->h = x264_encoder_open( ¶m ) ) == NULL ) { HBLog( "x264: x264_encoder_new failed" ); return NULL; } - memset( &f->picture, 0, sizeof( x264_picture_t ) ); - f->picture.i_width = param.i_width; - f->picture.i_height = param.i_height; - f->picture.i_plane = 3; + memset( &w->picture, 0, sizeof( x264_picture_t ) ); + w->picture.i_width = param.i_width; + w->picture.i_height = param.i_height; + w->picture.i_plane = 3; HBLog( "x264: opening with %dx%d iframes=%d", param.i_width, param.i_height, param.i_iframe ); } - return (HBWork*) f; + return w; } -void HBX264EncClose( HBWork **_f ) +void HBX264EncClose( HBWork ** _w ) { - HBX264Enc *f = (HBX264Enc*) *_f; - - x264_encoder_close( f->h ); - - if( f->buffer ) - { - HBBufferClose( &f->buffer ); - } - - free( f->name ); - - free( f ); - - *_f = NULL; + HBWork * w = *_w; + x264_encoder_close( w->h ); + free( w->name ); + free( w ); + *_w = NULL; } /* TODO trash buffer->pass == 1 @@ -90,29 +80,22 @@ void HBX264EncClose( HBWork **_f ) */ static int HBX264EncWork( HBWork * w ) { - HBX264Enc * f = (HBX264Enc*) w; - HBTitle * title = f->title; + HBTitle * title = w->title; - HBBuffer * frame; - int didSomething = 0; + HBBuffer * frame, * buffer; x264_nal_t *nal; int i_nal; int i; - if( f->buffer ) + if( HBFifoIsHalfFull( title->outFifo ) ) { - if( !HBFifoPush( title->outFifo, &f->buffer ) ) - { - /* nothing done */ - return 0; - } - didSomething = 1; + return 0; } - if( ( frame = HBFifoPop( title->scaledFifo ) ) == NULL ) + if( !( frame = HBFifoPop( title->scaledFifo ) ) ) { - return didSomething; + return 0; } if( frame->pass == 1 ) @@ -122,46 +105,51 @@ static int HBX264EncWork( HBWork * w ) return 1; } - f->picture.i_stride[0] = title->outWidth; - f->picture.i_stride[1] = title->outWidth/2; - f->picture.i_stride[2] = title->outWidth/2; + w->picture.i_stride[0] = title->outWidth; + w->picture.i_stride[1] = title->outWidth/2; + w->picture.i_stride[2] = title->outWidth/2; - f->picture.plane[0] = frame->data; - f->picture.plane[1] = &f->picture.plane[0][title->outWidth*title->outHeight]; - f->picture.plane[2] = &f->picture.plane[1][title->outWidth*title->outHeight/4]; + w->picture.plane[0] = frame->data; + w->picture.plane[1] = &w->picture.plane[0][title->outWidth*title->outHeight]; + w->picture.plane[2] = &w->picture.plane[1][title->outWidth*title->outHeight/4]; - x264_encoder_encode( f->h, &nal, &i_nal, &f->picture ); + x264_encoder_encode( w->h, &nal, &i_nal, &w->picture ); - f->buffer = HBBufferInit( 3 * title->outWidth * title->outHeight / 2 ); /* FIXME */ - f->buffer->keyFrame = 0; - f->buffer->position = frame->position; - f->buffer->size = 0; + buffer = HBBufferInit( 3 * title->outWidth * title->outHeight / 2 ); /* FIXME */ + buffer->keyFrame = 0; + buffer->position = frame->position; + buffer->size = 0; for( i = 0; i < i_nal; i++ ) { - int i_data = f->buffer->alloc - f->buffer->size; + int i_data = buffer->alloc - buffer->size; int i_size; - i_size = x264_nal_encode( &f->buffer->data[f->buffer->size], + i_size = x264_nal_encode( &buffer->data[buffer->size], &i_data, 1, &nal[i] ); if( i_size <= 0 ) { fprintf( stderr, "#################### error" ); } - f->buffer->size += i_size; + buffer->size += i_size; if( nal[i].i_ref_idc == NAL_PRIORITY_HIGH || nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) { - f->buffer->keyFrame = 1; + buffer->keyFrame = 1; } } /* Inform the GUI about the current position */ - HBPosition( f->handle, frame->position ); + HBPosition( w->handle, frame->position ); HBBufferClose( &frame ); + if( !HBFifoPush( title->outFifo, &buffer ) ) + { + HBLog( "HBX264Enc: HBFifoPush failed" ); + } + return 1; } diff --git a/core/XvidEnc.c b/core/XvidEnc.c index 8bf841f36..4c06da69e 100644 --- a/core/XvidEnc.c +++ b/core/XvidEnc.c @@ -1,4 +1,4 @@ -/* $Id: XvidEnc.c,v 1.20 2004/03/01 21:36:36 titer Exp $ +/* $Id: XvidEnc.c,v 1.26 2004/05/12 17:21:24 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -8,7 +8,7 @@ #include "xvid.h" -typedef struct HBXvidEnc +struct HBWork { HB_WORK_COMMON_MEMBERS @@ -18,120 +18,82 @@ typedef struct HBXvidEnc char file[1024]; void * xvid; xvid_enc_frame_t frame; - HBBuffer * mpeg4Buffer; int pass; - int frames; - int64_t bytes; -} HBXvidEnc; +}; /* Local prototypes */ static int XvidEncWork( HBWork * ); HBWork * HBXvidEncInit( HBHandle * handle, HBTitle * title ) { - HBXvidEnc * x; - if( !( x = malloc( sizeof( HBXvidEnc ) ) ) ) + HBWork * w; + if( !( w = malloc( sizeof( HBWork ) ) ) ) { HBLog( "HBXvidEncInit: malloc() failed, gonna crash" ); return NULL; } - x->name = strdup( "XvidEnc" ); - x->work = XvidEncWork; + w->name = strdup( "XvidEnc" ); + w->work = XvidEncWork; - x->handle = handle; - x->title = title; + w->handle = handle; + w->title = title; - memset( x->file, 0, 1024 ); - snprintf( x->file, 1023, "/tmp/HB.%d.xvid.log", - HBGetPid( x->handle ) ); + memset( w->file, 0, 1024 ); +#ifndef HB_CYGWIN + snprintf( w->file, 1023, "/tmp/HB.%d.xvid.log", + HBGetPid( w->handle ) ); +#else + snprintf( w->file, 1023, "C:\\HB.%d.xvid.log", + HBGetPid( w->handle ) ); +#endif - x->xvid = NULL; - x->mpeg4Buffer = NULL; - x->pass = 42; - x->frames = 0; - x->bytes = 0; + w->xvid = NULL; + w->pass = 42; - return (HBWork*) x; + return w; } -void HBXvidEncClose( HBWork ** _x ) +void HBXvidEncClose( HBWork ** _w ) { - HBXvidEnc * x = (HBXvidEnc*) *_x; + HBWork * w = *_w; - if( x->xvid ) + if( w->xvid ) { HBLog( "HBXvidEnc: closing libxvidcore (pass %d)", - x->pass ); - xvid_encore( x->xvid, XVID_ENC_DESTROY, NULL, NULL); - } - if( x->title->esConfig ) - { - free( x->title->esConfig ); - x->title->esConfig = NULL; - x->title->esConfigLength = 0; + w->pass ); + xvid_encore( w->xvid, XVID_ENC_DESTROY, NULL, NULL); } - if( x->frames ) + if( w->title->esConfig ) { - float bitrate = (float) x->bytes * x->title->rate / x->frames / - x->title->rateBase / 128; - int64_t bytes = (int64_t) x->frames * x->title->bitrate * 128 * - x->title->rateBase / x->title->rate; - - HBLog( "HBXvidEnc: %d frames encoded (%lld bytes), %.2f kbps", - x->frames, x->bytes, bitrate ); - - if( x->bytes > bytes ) - { - HBLog( "HBXvidEnc: %lld more bytes than expected " - "(error=%.2f %%)", x->bytes - bytes, - 100.0 * ( x->bytes - bytes ) / bytes ); - } - else if( x->bytes < bytes ) - { - HBLog( "HBXvidEnc: %lld less bytes than expected " - "(error=%.2f %%)", bytes - x->bytes, - 100.0 * ( bytes - x->bytes ) / bytes ); - } + free( w->title->esConfig ); + w->title->esConfig = NULL; + w->title->esConfigLength = 0; } - free( x->name ); - free( x ); - *_x = NULL; + free( w->name ); + free( w ); + *_w = NULL; } static int XvidEncWork( HBWork * w ) { - HBXvidEnc * x = (HBXvidEnc*) w; - HBTitle * title = x->title; + HBTitle * title = w->title; HBBuffer * scaledBuffer; HBBuffer * mpeg4Buffer; - int didSomething = 0; - - if( x->mpeg4Buffer ) + if( HBFifoIsHalfFull( title->outFifo ) ) { - if( HBFifoPush( title->outFifo, &x->mpeg4Buffer ) ) - { - didSomething = 1; - } - else - { - return didSomething; - } + return 0; } - if( ( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) - { - didSomething = 1; - } - else + if( !( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) { - return didSomething; + return 0; } /* Init or re-init if needed */ - if( scaledBuffer->pass != x->pass ) + if( scaledBuffer->pass != w->pass ) { xvid_gbl_init_t xvid_gbl_init; xvid_enc_create_t xvid_enc_create; @@ -140,15 +102,15 @@ static int XvidEncWork( HBWork * w ) xvid_plugin_2pass2_t rc2pass2; xvid_enc_plugin_t plugins[7]; - if( x->xvid ) + if( w->xvid ) { HBLog( "HBXvidEnc: closing libxvidcore (pass %d)", - x->pass ); - xvid_encore( x->xvid, XVID_ENC_DESTROY, NULL, NULL); + w->pass ); + xvid_encore( w->xvid, XVID_ENC_DESTROY, NULL, NULL); } - x->pass = scaledBuffer->pass; - HBLog( "HBXvidEnc: opening libxvidcore (pass %d)", x->pass ); + w->pass = scaledBuffer->pass; + HBLog( "HBXvidEnc: opening libxvidcore (pass %d)", w->pass ); memset( &xvid_gbl_init, 0, sizeof( xvid_gbl_init ) ); xvid_gbl_init.version = XVID_VERSION; @@ -163,7 +125,7 @@ static int XvidEncWork( HBWork * w ) xvid_enc_create.plugins = plugins; xvid_enc_create.num_plugins = 0; - if( !x->pass ) + if( !w->pass ) { memset( &single, 0, sizeof( single ) ); single.version = XVID_VERSION; @@ -172,20 +134,20 @@ static int XvidEncWork( HBWork * w ) plugins[xvid_enc_create.num_plugins].param = &single; xvid_enc_create.num_plugins++; } - else if( x->pass == 1 ) + else if( w->pass == 1 ) { memset( &rc2pass1, 0, sizeof( rc2pass1 ) ); rc2pass1.version = XVID_VERSION; - rc2pass1.filename = x->file; + rc2pass1.filename = w->file; plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass1; plugins[xvid_enc_create.num_plugins].param = &rc2pass1; xvid_enc_create.num_plugins++; } - else if( x->pass == 2 ) + else if( w->pass == 2 ) { memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t)); rc2pass2.version = XVID_VERSION; - rc2pass2.filename = x->file; + rc2pass2.filename = w->file; rc2pass2.bitrate = 1024 * title->bitrate; plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; plugins[xvid_enc_create.num_plugins].param = &rc2pass2; @@ -203,83 +165,83 @@ static int XvidEncWork( HBWork * w ) xvid_enc_create.global = 0; xvid_encore( NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL ); - x->xvid = xvid_enc_create.handle; + w->xvid = xvid_enc_create.handle; } mpeg4Buffer = HBBufferInit( title->outWidth * title->outHeight * 3 / 2 ); mpeg4Buffer->position = scaledBuffer->position; - memset( &x->frame, 0, sizeof( x->frame ) ); - x->frame.version = XVID_VERSION; - x->frame.bitstream = mpeg4Buffer->data; - x->frame.length = -1; - x->frame.input.plane[0] = scaledBuffer->data; - x->frame.input.csp = XVID_CSP_I420; - x->frame.input.stride[0] = title->outWidth; - x->frame.vol_flags = 0; - x->frame.vop_flags = XVID_VOP_HALFPEL | XVID_VOP_INTER4V | + memset( &w->frame, 0, sizeof( w->frame ) ); + w->frame.version = XVID_VERSION; + w->frame.bitstream = mpeg4Buffer->data; + w->frame.length = -1; + w->frame.input.plane[0] = scaledBuffer->data; + w->frame.input.csp = XVID_CSP_I420; + w->frame.input.stride[0] = title->outWidth; + w->frame.vol_flags = 0; + w->frame.vop_flags = XVID_VOP_HALFPEL | XVID_VOP_INTER4V | XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED; - x->frame.type = XVID_TYPE_AUTO; - x->frame.quant = 0; - x->frame.motion = XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | + w->frame.type = XVID_TYPE_AUTO; + w->frame.quant = 0; + w->frame.motion = XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 | XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 | XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP; - x->frame.quant_intra_matrix = NULL; - x->frame.quant_inter_matrix = NULL; + w->frame.quant_intra_matrix = NULL; + w->frame.quant_inter_matrix = NULL; - mpeg4Buffer->size = xvid_encore( x->xvid, XVID_ENC_ENCODE, - &x->frame, NULL ); - mpeg4Buffer->keyFrame = ( x->frame.out_flags & XVID_KEYFRAME ); + mpeg4Buffer->size = xvid_encore( w->xvid, XVID_ENC_ENCODE, + &w->frame, NULL ); + mpeg4Buffer->keyFrame = ( w->frame.out_flags & XVID_KEYFRAME ); /* Inform the GUI about the current position */ - HBPosition( x->handle, scaledBuffer->position ); + HBPosition( w->handle, scaledBuffer->position ); HBBufferClose( &scaledBuffer ); - if( x->pass == 1 ) + if( w->pass == 1 ) { HBBufferClose( &mpeg4Buffer ); - return didSomething; + return 1; } - else + + if( !title->esConfig ) { - if( !title->esConfig ) + int volStart, vopStart; + for( volStart = 0; ; volStart++ ) { - int volStart, vopStart; - for( volStart = 0; ; volStart++ ) + if( mpeg4Buffer->data[volStart] == 0x0 && + mpeg4Buffer->data[volStart+1] == 0x0 && + mpeg4Buffer->data[volStart+2] == 0x1 && + mpeg4Buffer->data[volStart+3] == 0x20 ) { - if( mpeg4Buffer->data[volStart] == 0x0 && - mpeg4Buffer->data[volStart+1] == 0x0 && - mpeg4Buffer->data[volStart+2] == 0x1 && - mpeg4Buffer->data[volStart+3] == 0x20 ) - { - break; - } + break; } - for( vopStart = volStart + 4; ; vopStart++ ) + } + for( vopStart = volStart + 4; ; vopStart++ ) + { + if( mpeg4Buffer->data[vopStart] == 0x0 && + mpeg4Buffer->data[vopStart+1] == 0x0 && + mpeg4Buffer->data[vopStart+2] == 0x1 && + mpeg4Buffer->data[vopStart+3] == 0xB6 ) { - if( mpeg4Buffer->data[vopStart] == 0x0 && - mpeg4Buffer->data[vopStart+1] == 0x0 && - mpeg4Buffer->data[vopStart+2] == 0x1 && - mpeg4Buffer->data[vopStart+3] == 0xB6 ) - { - break; - } + break; } - - HBLog( "XvidEnc: VOL size is %d bytes", vopStart - volStart ); - title->esConfig = malloc( vopStart - volStart ); - title->esConfigLength = vopStart - volStart; - memcpy( title->esConfig, mpeg4Buffer->data + volStart, - vopStart - volStart ); } - x->frames++; - x->bytes += mpeg4Buffer->size; - x->mpeg4Buffer = mpeg4Buffer; + + HBLog( "XvidEnc: VOL size is %d bytes", vopStart - volStart ); + title->esConfig = malloc( vopStart - volStart ); + title->esConfigLength = vopStart - volStart; + memcpy( title->esConfig, mpeg4Buffer->data + volStart, + vopStart - volStart ); + } + + if( !HBFifoPush( title->outFifo, &mpeg4Buffer ) ) + { + HBLog( "HBXvidEnc: HBFifoPush failed" ); } - return didSomething; + return 1; } |