diff options
author | handbrake <[email protected]> | 2006-01-14 13:05:49 +0000 |
---|---|---|
committer | handbrake <[email protected]> | 2006-01-14 13:05:49 +0000 |
commit | 5824c4979fbc54ae3d3015c07cbf6fa4aea7516d (patch) | |
tree | 49ba3bbe1f8d8166fa4f7f964055d4011d2deca0 /core/HandBrake.c | |
parent | f013e3544c0bdf17348d617a467af0e4fde0f545 (diff) |
HandBrake 0.5
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@7 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'core/HandBrake.c')
-rw-r--r-- | core/HandBrake.c | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/core/HandBrake.c b/core/HandBrake.c new file mode 100644 index 000000000..3f84a5757 --- /dev/null +++ b/core/HandBrake.c @@ -0,0 +1,767 @@ +/* $Id: HandBrake.c,v 1.15 2003/11/07 21:52:57 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "HandBrakeInternal.h" + +#include <ffmpeg/avcodec.h> + +#include "Ac3Dec.h" +#include "AviMux.h" +#include "DVDRead.h" +#include "FfmpegEnc.h" +#include "Fifo.h" +#include "Mp3Enc.h" +#include "Mpeg2Dec.h" +#include "Scale.h" +#include "Scan.h" +#include "Thread.h" +#include "Work.h" +#include "XvidEnc.h" + +/* Local prototypes */ +static void HandBrakeThread( void * ); +static void _StopRip( HBHandle * ); +static void FixPictureSettings( HBTitle * ); +static int GetCPUCount(); + +struct HBHandle +{ + HBThread * thread; + int die; + int pid; + + int cpuCount; + + int stopScan; + int stopRip; + int ripDone; + int error; + + HBScan * scan; + + HBLock * lock; + HBStatus status; + int modeChanged; + HBTitle * curTitle; + HBAudio * curAudio; + HBAudio * curOptAudio; + + int frames; + uint64_t beginDate; + int framesSinceFpsUpdate; + uint64_t lastFpsUpdate; + uint64_t pauseDate; + + HBLock * pauseLock; +}; + +HBHandle * HBInit( int debug, int cpuCount ) +{ + HBHandle * h; + if( !( h = malloc( sizeof( HBHandle ) ) ) ) + { + HBLog( "HBInit: malloc() failed, gonna crash" ); + return NULL; + } + + /* See HBLog() in Utils.cpp */ + if( debug ) + { + putenv( "HB_DEBUG=1" ); + } + + /* Init libavcodec */ + avcodec_init(); + register_avcodec( &mpeg4_encoder ); + + /* Check CPU count */ + if( !cpuCount ) + { + h->cpuCount = GetCPUCount(); + HBLog( "HBInit: %d CPU%s detected", h->cpuCount, + ( h->cpuCount > 1 ) ? "s" : "" ); + } + else + { + if( cpuCount < 1 ) + { + HBLog( "HBInit: invalid CPU count (%d), using 1", + cpuCount ); + h->cpuCount = 1; + } + else if( cpuCount > 8 ) + { + HBLog( "HBInit: invalid CPU count (%d), using 8", + cpuCount ); + h->cpuCount = 8; + } + else + { + HBLog( "HBInit: user specified %d CPU%s", + cpuCount, ( cpuCount > 1 ) ? "s" : "" ); + h->cpuCount = cpuCount; + } + } + + /* Initializations */ + h->stopScan = 0; + h->stopRip = 0; + h->ripDone = 0; + h->error = 0; + + h->scan = NULL; + + h->lock = HBLockInit(); + h->modeChanged = 1; + h->status.mode = HB_MODE_NEED_DEVICE; + h->curTitle = NULL; + h->curAudio = NULL; + h->curOptAudio = NULL; + + h->pauseLock = HBLockInit(); + + h->die = 0; + h->thread = HBThreadInit( "libhb", HandBrakeThread, h, + HB_NORMAL_PRIORITY ); + + return h; +} + +int HBGetStatus( HBHandle * h, HBStatus * status ) +{ + HBLockLock( h->lock ); + memcpy( status, &h->status, sizeof( HBStatus ) ); + + if( !h->modeChanged ) + { + HBLockUnlock( h->lock ); + return 0; + } + + h->modeChanged = 0; + HBLockUnlock( h->lock ); + return 1; +} + +void HBScanDevice( HBHandle * h, char * device, int title ) +{ + if( !( h->status.mode & ( HB_MODE_NEED_DEVICE | + HB_MODE_INVALID_DEVICE ) ) ) + { + HBLog( "HBScanDevice: current mode is %d, aborting", + h->status.mode ); + return; + } + + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_SCANNING; + h->status.scannedTitle = 0; + HBLockUnlock( h->lock ); + + h->scan = HBScanInit( h, device, title ); +} + +void HBStartRip( HBHandle * h, HBTitle * t, + HBAudio * a1, HBAudio * a2 ) +{ + int i; + + if( !( h->status.mode & ( HB_MODE_READY_TO_RIP | HB_MODE_DONE | + HB_MODE_CANCELED | HB_MODE_ERROR ) ) ) + { + HBLog( "HBStartRip: current mode is %d, aborting", + h->status.mode ); + return; + } + + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_ENCODING; + h->status.position = 0.0; + h->status.pass = 1; + h->status.passCount = t->twoPass ? 2 : 1; + h->frames = 0; + h->framesSinceFpsUpdate = 0; + HBLockUnlock( h->lock ); + + FixPictureSettings( t ); + + /* Create fifos */ + t->mpeg2Fifo = HBFifoInit( 512 ); + t->rawFifo = HBFifoInit( 1 ); + t->scaledFifo = HBFifoInit( 1 ); + t->mpeg4Fifo = HBFifoInit( 1 ); + a1->ac3Fifo = HBFifoInit( 512 ); + a1->rawFifo = HBFifoInit( 1 ); + a1->mp3Fifo = HBFifoInit( 1 ); + if( a2 ) + { + a2->ac3Fifo = HBFifoInit( 512 ); + a2->rawFifo = HBFifoInit( 1 ); + a2->mp3Fifo = HBFifoInit( 1 ); + } + + /* Create work objects */ + t->mpeg2Dec = HBMpeg2DecInit( h, t ); + t->scale = HBScaleInit( h, t ); + + if( t->codec == HB_CODEC_FFMPEG ) + t->ffmpegEnc = HBFfmpegEncInit( h, t ); + else if( t->codec == HB_CODEC_XVID ) + t->xvidEnc = HBXvidEncInit( h, t ); + + a1->ac3Dec = HBAc3DecInit( h, a1 ); + a1->mp3Enc = HBMp3EncInit( h, a1 ); + if( a2 ) + { + a2->ac3Dec = HBAc3DecInit( h, a2 ); + a2->mp3Enc = HBMp3EncInit( h, a2 ); + } + + /* Create threads */ + t->dvdRead = HBDVDReadInit( h, t, a1, a2 ); + t->aviMux = HBAviMuxInit( h, t, a1, a2 ); + for( i = 0; i < h->cpuCount; i++ ) + { + t->workThreads[i] = HBWorkThreadInit( h, t, a1, a2, i ? 0 : 1 ); + } + + h->curTitle = t; + h->curAudio = a1; + h->curOptAudio = a2; +} + +void HBPauseRip( HBHandle * h ) +{ + if( h->status.mode != HB_MODE_ENCODING ) + { + HBLog( "HBPauseRip: current mode is %d, aborting", + h->status.mode ); + return; + } + + h->pauseDate = HBGetDate(); + HBLockLock( h->pauseLock ); + HBLockLock( h->lock ); + h->status.mode = HB_MODE_PAUSED; + h->modeChanged = 1; + HBLockUnlock( h->lock ); +} + +void HBResumeRip( HBHandle * h ) +{ + if( h->status.mode != HB_MODE_PAUSED ) + { + HBLog( "HBResumeRip: current mode is %d, aborting", + h->status.mode ); + return; + } + + h->beginDate += HBGetDate() - h->pauseDate; + h->lastFpsUpdate += HBGetDate() - h->pauseDate; + HBLockUnlock( h->pauseLock ); + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_ENCODING; + HBLockUnlock( h->lock ); +} + +void HBStopRip( HBHandle * h ) +{ + if( !( h->status.mode & ( HB_MODE_ENCODING | HB_MODE_PAUSED ) ) ) + { + HBLog( "HBStopRip: current mode is %d, aborting", + h->status.mode ); + return; + } + + if( h->status.mode & HB_MODE_PAUSED ) + { + HBLockUnlock( h->pauseLock ); + } + + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_STOPPING; + HBLockUnlock( h->lock ); + h->stopRip = 1; +} + +uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) +{ + AVPicture pic1, pic2, pic3, pic4; + uint8_t * buf1, * buf2, * buf3, * buf4; + char fileName[1024]; + FILE * file; + ImgReSampleContext * resampleContext; + int8_t * preview, * pen; + int i; + + FixPictureSettings( t ); + + buf1 = malloc( 3 * t->inWidth * t->inHeight / 2 ); + buf2 = malloc( 3 * t->inWidth * t->inHeight / 2 ); + buf3 = malloc( 3 * t->outWidth * t->outHeight / 2 ); + buf4 = malloc( 4 * t->outWidth * t->outHeight ); + + if( !buf1 || !buf2 || !buf3 || !buf4 ) + { + HBLog( "HBGetPreview: malloc() failed, gonna crash" ); + return NULL; + } + + /* Original YUV picture */ + avpicture_fill( &pic1, buf1, PIX_FMT_YUV420P, t->inWidth, + t->inHeight ); + + /* Deinterlaced YUV picture */ + avpicture_fill( &pic2, buf2, PIX_FMT_YUV420P, + t->inWidth, t->inHeight ); + + /* Scaled YUV picture */ + avpicture_fill( &pic3, buf3, PIX_FMT_YUV420P, t->outWidth, + t->outHeight ); + + /* Scaled RGB picture ) */ + avpicture_fill( &pic4, buf4, PIX_FMT_RGBA32, t->outWidth, + t->outHeight ); + + /* Get the original image from the temp file */ + memset( fileName, 0, 1024 ); + sprintf( fileName, "/tmp/HB.%d.%d.%d", h->pid, t->index, + picture ); + file = fopen( fileName, "r" ); + if( file ) + { + fread( buf1, 3 * t->inWidth * t->inHeight / 2, 1, file ); + fclose( file ); + } + else + { + HBLog( "HBGetPreview: could not open %s", fileName ); + memset( buf1, 0, 3 * t->inWidth * t->inHeight / 2 ); + } + + /* Deinterlace if needed, and scale */ + resampleContext = + img_resample_full_init( t->outWidth, t->outHeight, + t->inWidth, t->inHeight, + t->topCrop, t->bottomCrop, + t->leftCrop, t->rightCrop ); + if( t->deinterlace ) + { + avpicture_deinterlace( &pic2, &pic1, PIX_FMT_YUV420P, + t->inWidth, t->inHeight ); + img_resample( resampleContext, &pic3, &pic2 ); + } + else + { + img_resample( resampleContext, &pic3, &pic1 ); + } + + /* Convert to RGB */ + img_convert( &pic4, PIX_FMT_RGBA32, &pic3, PIX_FMT_YUV420P, + t->outWidth, t->outHeight ); + + /* Create the final preview */ + preview = malloc( 4 * ( t->outWidthMax + 2 ) * + ( t->outHeightMax + 2 ) ); + + if( !preview ) + { + HBLog( "HBGetPreview: malloc() failed, gonna crash" ); + return NULL; + } + + /* Blank it */ + memset( preview, 0x80, + 4 * ( t->outWidthMax + 2 ) * ( t->outHeightMax + 2 ) ); + + /* Draw the picture (centered) and draw the cropping zone */ + pen = preview + ( t->outHeightMax - t->outHeight ) * + ( t->outWidthMax + 2 ) * 2 + + ( t->outWidthMax - t->outWidth ) * 2; + + memset( pen, 0xFF, 4 * ( t->outWidth + 2 ) ); + pen += 4 * ( t->outWidthMax + 2 ); + + for( i = 0; i < t->outHeight; i++ ) + { + uint8_t * nextLine = pen + 4 * ( t->outWidthMax + 2 ); + + memset( pen, 0xFF, 4 ); + pen += 4; + memcpy( pen, buf4 + 4 * t->outWidth * i, 4 * t->outWidth ); + pen += 4 * t->outWidth; + memset( pen, 0xFF, 4 ); + + pen = nextLine; + } + + memset( pen, 0xFF, 4 * ( t->outWidth + 2 ) ); + + /* Free memory */ + free( buf1 ); + free( buf2 ); + free( buf3 ); + free( buf4 ); + + return preview; + return NULL; +} + +void HBClose( HBHandle ** _h ) +{ + char command[1024]; + + HBHandle * h = *_h; + + h->die = 1; + HBThreadClose( &h->thread ); + + if( h->status.mode == HB_MODE_SCANNING ) + { + HBScanClose( &h->scan ); + } + else if( h->status.mode == HB_MODE_PAUSED ) + { + HBLockUnlock( h->pauseLock ); + _StopRip( h ); + } + else if( h->status.mode == HB_MODE_ENCODING ) + { + _StopRip( h ); + } + + memset( command, 0, 1024 ); + sprintf( command, "rm -f /tmp/HB.%d.*", h->pid ); + system( command ); + + if( h->status.titleList ) + { + HBTitle * title; + while( ( title = HBListItemAt( h->status.titleList, 0 ) ) ) + { + HBListRemove( h->status.titleList, title ); + HBTitleClose( &title ); + } + HBListClose( &h->status.titleList ); + } + + HBLockClose( &h->lock ); + HBLockClose( &h->pauseLock ); + free( h ); + + *_h = NULL; +} + +/* Following functions are called by libhb's internal threads */ +void HBCheckPaused( HBHandle * h ) +{ + HBLockLock( h->pauseLock ); + HBLockUnlock( h->pauseLock ); +} + +void HBScanning( HBHandle * h, int title ) +{ + HBLockLock( h->lock ); + h->status.scannedTitle = title; + HBLockUnlock( h->lock ); +} + +void HBScanDone( HBHandle * h, HBList * titleList ) +{ + h->status.titleList = titleList; + h->stopScan = 1; +} + +int HBGetPid( HBHandle * h ) +{ + return h->pid; +} + +void HBDone( HBHandle * h ) +{ + h->ripDone = 1; +} + +void HBPosition( HBHandle * h, float position ) +{ + if( !h->frames ) + { + h->beginDate = HBGetDate(); + h->lastFpsUpdate = h->beginDate; + } + + h->frames++; + h->framesSinceFpsUpdate++; + + HBLockLock( h->lock ); + if( position - h->status.position > 0.0001 || h->frames == 2 ) + { + HBLog( "Progress: %.2f %%", 100.0 * position ); + h->status.position = position; + + if( h->curTitle->twoPass ) + h->status.pass = ( position < 0.5 ) ? 1 : 2; + else + h->status.pass = 1; + } + if( HBGetDate() - h->lastFpsUpdate > 1000000 ) + { + h->status.frameRate = 1000000.0 * h->framesSinceFpsUpdate / + ( HBGetDate() - h->lastFpsUpdate ); + h->status.avFrameRate = 1000000.0 * h->frames / + ( HBGetDate() - h->beginDate ); + h->status.remainingTime = ( 1.0 - h->status.position ) * + ( HBGetDate() - h->beginDate ) / + h->status.position / 1000000; + + HBLog( "Speed: %.2f fps (average: %.2f fps, " + "remaining: %02d:%02d:%02d)", + h->status.frameRate, h->status.avFrameRate, + h->status.remainingTime / 3600, + ( h->status.remainingTime / 60 ) % 60, + h->status.remainingTime % 60 ); + + h->lastFpsUpdate = HBGetDate(); + h->framesSinceFpsUpdate = 0; + } + HBLockUnlock( h->lock ); +} + +void HBErrorOccured( HBHandle * h, HBError error ) +{ + if( !( h->status.mode & ( HB_MODE_ENCODING | HB_MODE_PAUSED ) ) ) + { + return; + } + + h->status.error = error; + h->error = 1; +} + +/* Local functions */ +static void HandBrakeThread( void * _h ) +{ + HBHandle * h = (HBHandle*) _h; + + h->pid = getpid(); + + while( !h->die ) + { + if( h->stopScan ) + { + HBScanClose( &h->scan ); + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HBListCountItems( h->status.titleList ) ? + HB_MODE_READY_TO_RIP : HB_MODE_INVALID_DEVICE; + HBLockUnlock( h->lock ); + h->stopScan = 0; + } + + if( h->stopRip ) + { + _StopRip( h ); + + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_CANCELED; + HBLockUnlock( h->lock ); + + h->stopRip = 0; + } + + if( h->ripDone ) + { + /* Wait a bit */ + HBSnooze( 500000 ); + + _StopRip( h ); + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_DONE; + HBLockUnlock( h->lock ); + + h->ripDone = 0; + } + + if( h->error ) + { + _StopRip( h ); + + HBLockLock( h->lock ); + h->modeChanged = 1; + h->status.mode = HB_MODE_ERROR; + HBLockUnlock( h->lock ); + + h->error = 0; + } + + HBSnooze( 10000 ); + } +} + +static void _StopRip( HBHandle * h ) +{ + int i; + + /* Stop threads */ + HBDVDReadClose( &h->curTitle->dvdRead ); + HBAviMuxClose( &h->curTitle->aviMux ); + for( i = 0; i < h->cpuCount; i++ ) + { + HBWorkThreadClose( &h->curTitle->workThreads[h->cpuCount-i-1] ); + } + + /* Clean up */ + HBMpeg2DecClose( &h->curTitle->mpeg2Dec ); + HBScaleClose( &h->curTitle->scale ); + + if( h->curTitle->codec == HB_CODEC_FFMPEG ) + HBFfmpegEncClose( &h->curTitle->ffmpegEnc ); + else if( h->curTitle->codec == HB_CODEC_XVID ) + HBXvidEncClose( &h->curTitle->xvidEnc ); + + HBAc3DecClose( &h->curAudio->ac3Dec ); + HBMp3EncClose( &h->curAudio->mp3Enc ); + if( h->curOptAudio ) + { + HBAc3DecClose( &h->curOptAudio->ac3Dec ); + HBMp3EncClose( &h->curOptAudio->mp3Enc ); + } + + /* Destroy fifos */ + HBFifoClose( &h->curTitle->mpeg2Fifo ); + HBFifoClose( &h->curTitle->rawFifo ); + HBFifoClose( &h->curTitle->scaledFifo ); + HBFifoClose( &h->curTitle->mpeg4Fifo ); + HBFifoClose( &h->curAudio->ac3Fifo ); + HBFifoClose( &h->curAudio->rawFifo ); + HBFifoClose( &h->curAudio->mp3Fifo ); + if( h->curOptAudio ) + { + HBFifoClose( &h->curOptAudio->ac3Fifo ); + HBFifoClose( &h->curOptAudio->rawFifo ); + HBFifoClose( &h->curOptAudio->mp3Fifo ); + } +} + +static void FixPictureSettings( HBTitle * t ) +{ + /* Sanity checks */ + t->topCrop = EVEN( t->topCrop ); + t->bottomCrop = EVEN( t->bottomCrop ); + t->leftCrop = EVEN( t->leftCrop ); + t->rightCrop = EVEN( t->rightCrop ); + + t->outWidth = MIN( t->outWidth, t->outWidthMax ); + t->outWidth = MAX( 16, t->outWidth ); + + t->outHeight = + MULTIPLE_16( (uint64_t) t->outWidth * t->inWidth * + ( t->inHeight - t->topCrop - t->bottomCrop ) * + VOUT_ASPECT_FACTOR / + ( (uint64_t) t->inHeight * + ( t->inWidth - t->leftCrop - t->rightCrop ) * + t->aspect ) ); + t->outHeight = MAX( 16, t->outHeight ); + + if( t->outHeight > t->outHeightMax ) + { + t->outHeight = t->outHeightMax; + t->outWidth = + MULTIPLE_16( (uint64_t) t->outHeight * t->inHeight * + ( t->inWidth - t->leftCrop - t->rightCrop ) * + t->aspect / + ( (uint64_t) t->inWidth * + ( t->inHeight - t->topCrop - t->bottomCrop ) * + VOUT_ASPECT_FACTOR ) ); + t->outWidth = MIN( t->outWidth, t->outWidthMax ); + t->outWidth = MAX( 16, t->outWidth ); + } +} + +static int GetCPUCount() +{ + int CPUCount = 1; + +#if defined( SYS_BEOS ) + system_info info; + get_system_info( &info ); + CPUCount = info.cpu_count; + +#elif defined( SYS_MACOSX ) + FILE * info; + char buffer[256]; + + if( ( info = popen( "/usr/sbin/sysctl hw.ncpu", "r" ) ) ) + { + if( fgets( buffer, 256, info ) ) + { + int count; + if( sscanf( buffer, "hw.ncpu: %d", &count ) == 1 ) + { + CPUCount = count; + } + else + { + HBLog( "GetCPUCount: sscanf() failed" ); + } + } + else + { + HBLog( "GetCPUCount: fgets() failed" ); + } + fclose( info ); + } + else + { + HBLog( "GetCPUCount: popen() failed" ); + } + +#elif defined( SYS_LINUX ) + FILE * info; + char buffer[256]; + + if( ( info = popen( "grep -c '^processor' /proc/cpuinfo", "r" ) ) ) + { + if( fgets( buffer, 256, info ) ) + { + int count; + if( sscanf( buffer, "%d", &count ) == 1 ) + { + CPUCount = count; + } + else + { + HBLog( "GetCPUCount: sscanf() failed" ); + } + } + else + { + HBLog( "GetCPUCount: fgets() failed" ); + } + fclose( info ); + } + else + { + HBLog( "GetCPUCount: fopen() failed" ); + } + +#elif defined( SYS_CYGWIN ) + /* TODO */ + CPUCount = 1; + +#endif + CPUCount = MAX( 1, CPUCount ); + CPUCount = MIN( CPUCount, 8 ); + + return CPUCount; +} + |