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/FfmpegEnc.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/FfmpegEnc.c')
-rw-r--r-- | core/FfmpegEnc.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/core/FfmpegEnc.c b/core/FfmpegEnc.c new file mode 100644 index 000000000..2118c29d6 --- /dev/null +++ b/core/FfmpegEnc.c @@ -0,0 +1,230 @@ +/* $Id: FfmpegEnc.c,v 1.5 2003/11/06 13:03:19 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "FfmpegEnc.h" +#include "Fifo.h" +#include "Work.h" + +#include <ffmpeg/avcodec.h> + +/* Extern functions */ +void HBSetPosition( HBHandle *, float ); + +/* Local prototypes */ +static int FfmpegEncWork( HBWork * ); + +struct HBFfmpegEnc +{ + HB_WORK_COMMON_MEMBERS + + HBHandle * handle; + HBTitle * title; + + HBBuffer * mpeg4Buffer; + int pass; + AVCodecContext * context; + FILE * file; +}; + +HBFfmpegEnc * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) +{ + HBFfmpegEnc * f; + if( !( f = malloc( sizeof( HBFfmpegEnc ) ) ) ) + { + HBLog( "HBFfmpegEncInit: malloc() failed, gonna crash" ); + return NULL; + } + + f->name = strdup( "FfmpegEnc" ); + f->work = FfmpegEncWork; + + f->handle = handle; + f->title = title; + + f->mpeg4Buffer = NULL; + f->pass = 42; + f->context = NULL; + f->file = NULL; + + return f; +} + +void HBFfmpegEncClose( HBFfmpegEnc ** _f ) +{ + HBFfmpegEnc * f = *_f; + + if( f->context ) + { + HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", + f->pass ); + + avcodec_close( f->context ); + if( f->file ) + { + fclose( f->file ); + f->file = NULL; + } + } + free( f->name ); + free( f ); + + *_f = NULL; +} + +static int FfmpegEncWork( HBWork * w ) +{ + HBFfmpegEnc * f = (HBFfmpegEnc*) w; + HBTitle * title = f->title; + + HBBuffer * scaledBuffer; + HBBuffer * mpeg4Buffer; + AVFrame * frame; + + int didSomething = 0; + + if( f->mpeg4Buffer ) + { + if( HBFifoPush( title->mpeg4Fifo, &f->mpeg4Buffer ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + } + + if( ( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) + { + didSomething = 1; + } + else + { + return didSomething; + } + + /* Init or re-init if needed */ + if( scaledBuffer->pass != f->pass ) + { + AVCodec * codec; + AVCodecContext * context; + + if( f->context ) + { + HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", + f->pass ); + + avcodec_close( f->context ); + if( f->file ) + { + fclose( f->file ); + f->file = NULL; + } + } + + f->pass = scaledBuffer->pass; + + HBLog( "HBFfmpegEnc: opening libavcodec (pass %d)", f->pass ); + codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); + if( !codec ) + { + HBLog( "HBFfmpegEnc: avcodec_find_encoder() failed" ); + HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); + return didSomething; + } + + context = avcodec_alloc_context(); + context->bit_rate = 1024 * title->bitrate; + context->bit_rate_tolerance = 10240 * title->bitrate; + context->width = title->outWidth; + context->height = title->outHeight; + context->frame_rate = title->rate; + context->frame_rate_base = title->rateBase; + context->gop_size = 10 * title->rate / + title->rateBase; + + if( f->pass ) + { + char fileName[1024]; memset( fileName, 0, 1024 ); + sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", + HBGetPid( f->handle ) ); + + if( f->pass == 1 ) + { + f->file = fopen( fileName, "w" ); + + context->flags |= CODEC_FLAG_PASS1; + } + else + { + FILE * file; + int size; + char * log; + + file = fopen( fileName, "r" ); + fseek( file, 0, SEEK_END ); + size = ftell( file ); + fseek( file, 0, SEEK_SET ); + if( !( log = malloc( size + 1 ) ) ) + { + HBLog( "HBFfmpegEnc: malloc() failed, gonna crash" ); + } + log[size] = '\0'; + fread( log, size, 1, file ); + fclose( file ); + + context->flags |= CODEC_FLAG_PASS2; + context->stats_in = log; + } + } + + if( avcodec_open( context, codec ) < 0 ) + { + HBLog( "HBFfmpegEnc: avcodec_open() failed" ); + HBErrorOccured( f->handle, HB_ERROR_MPEG4_INIT ); + return didSomething; + } + + f->context = context; + } + + frame = avcodec_alloc_frame(); + frame->data[0] = scaledBuffer->data; + frame->data[1] = frame->data[0] + title->outWidth * + title->outHeight; + frame->data[2] = frame->data[1] + title->outWidth * + title->outHeight / 4; + frame->linesize[0] = title->outWidth; + frame->linesize[1] = title->outWidth / 2; + frame->linesize[2] = title->outWidth / 2; + + mpeg4Buffer = HBBufferInit( 3 * title->outWidth * + title->outHeight / 2 ); + mpeg4Buffer->position = scaledBuffer->position; + mpeg4Buffer->size = + avcodec_encode_video( f->context, mpeg4Buffer->data, + mpeg4Buffer->alloc, frame ); + mpeg4Buffer->keyFrame = f->context->coded_frame->key_frame; + + /* Inform the GUI about the current position */ + HBPosition( f->handle, scaledBuffer->position ); + + if( f->pass == 1 ) + { + if( f->context->stats_out ) + { + fprintf( f->file, "%s", f->context->stats_out ); + } + HBBufferClose( &mpeg4Buffer ); + } + + HBBufferClose( &scaledBuffer ); + free( frame ); + + f->mpeg4Buffer = mpeg4Buffer; + + return didSomething; +} |