diff options
Diffstat (limited to 'libhb/encavcodec.c')
-rw-r--r-- | libhb/encavcodec.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c new file mode 100644 index 000000000..deff7c527 --- /dev/null +++ b/libhb/encavcodec.c @@ -0,0 +1,201 @@ +/* $Id: encavcodec.c,v 1.23 2005/10/13 23:47:06 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 "hb.h" + +#include "ffmpeg/avcodec.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + AVCodecContext * context; + FILE * file; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +/*********************************************************************** + * hb_work_encavcodec_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job ) +{ + AVCodec * codec; + AVCodecContext * context; + + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "MPEG-4 encoder (libavcodec)" ); + w->work = Work; + w->close = Close; + + w->job = job; + + codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); + if( !codec ) + { + hb_log( "hb_work_encavcodec_init: avcodec_find_encoder " + "failed" ); + } + context = avcodec_alloc_context(); + if( job->vquality < 0.0 || job->vquality > 1.0 ) + { + /* Rate control */ + context->bit_rate = 1000 * job->vbitrate; + context->bit_rate_tolerance = 10 * context->bit_rate; + } + else + { + /* Constant quantizer */ + context->qmin = 31 - job->vquality * 30; + context->qmax = context->qmin; + hb_log( "encavcodec: encoding at constant quantizer %d", + context->qmin ); + } + context->width = job->width; + context->height = job->height; + context->time_base = (AVRational) { job->vrate_base, job->vrate }; + context->gop_size = 10 * job->vrate / job->vrate_base; + context->pix_fmt = PIX_FMT_YUV420P; + + if( job->mux & HB_MUX_MP4 ) + { + context->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + if( job->grayscale ) + { + context->flags |= CODEC_FLAG_GRAY; + } + + if( job->pass ) + { + char filename[1024]; memset( filename, 0, 1024 ); + hb_get_tempory_filename( job->h, filename, "ffmpeg.log" ); + + if( job->pass == 1 ) + { + w->file = fopen( filename, "wb" ); + context->flags |= CODEC_FLAG_PASS1; + } + else + { + int size; + char * log; + + w->file = fopen( filename, "rb" ); + fseek( w->file, 0, SEEK_END ); + size = ftell( w->file ); + fseek( w->file, 0, SEEK_SET ); + log = malloc( size + 1 ); + log[size] = '\0'; + fread( log, size, 1, w->file ); + fclose( w->file ); + w->file = NULL; + + context->flags |= CODEC_FLAG_PASS2; + context->stats_in = log; + } + } + + if( avcodec_open( context, codec ) ) + { + hb_log( "hb_work_encavcodec_init: avcodec_open failed" ); + } + w->context = context; + + if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 ) + { +#define c job->config.mpeg4 + /* Hem hem */ + c.config = malloc( 15 ); + c.config_length = 15; + memcpy( c.config, context->extradata + 15, 15 ); +#undef c + } + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + hb_job_t * job = w->job; + + if( w->context ) + { + hb_log( "encavcodec: closing libavcodec" ); + avcodec_close( w->context ); + } + if( w->file ) + { + fclose( w->file ); + } + if( job->es_config ) + { + free( job->es_config ); + job->es_config = NULL; + job->es_config_length = 0; + } + + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_job_t * job = w->job; + AVFrame * frame; + hb_buffer_t * in = *buf_in, * buf; + + frame = avcodec_alloc_frame(); + frame->data[0] = in->data; + frame->data[1] = frame->data[0] + job->width * job->height; + frame->data[2] = frame->data[1] + job->width * job->height / 4; + frame->linesize[0] = job->width; + frame->linesize[1] = job->width / 2; + frame->linesize[2] = job->width / 2; + + /* Should be way too large */ + buf = hb_buffer_init( 3 * job->width * job->height / 2 ); + buf->size = avcodec_encode_video( w->context, buf->data, buf->alloc, + frame ); + buf->start = in->start; + buf->stop = in->stop; + buf->key = w->context->coded_frame->key_frame; + + av_free( frame ); + + if( job->pass == 1 ) + { + /* Write stats */ + fprintf( w->file, "%s", w->context->stats_out ); + } + + *buf_out = buf; + + return HB_WORK_OK; +} + + |