summaryrefslogtreecommitdiffstats
path: root/libhb/encavcodec.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/encavcodec.c')
-rw-r--r--libhb/encavcodec.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
new file mode 100644
index 000000000..c71c8384e
--- /dev/null
+++ b/libhb/encavcodec.c
@@ -0,0 +1,204 @@
+/* $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_private_s
+{
+ hb_job_t * job;
+ AVCodecContext * context;
+ FILE * file;
+};
+
+int encavcodecInit( hb_work_object_t *, hb_job_t * );
+int encavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+void encavcodecClose( hb_work_object_t * );
+
+hb_work_object_t hb_encavcodec =
+{
+ WORK_ENCAVCODEC,
+ "MPEG-4 encoder (libavcodec)",
+ encavcodecInit,
+ encavcodecWork,
+ encavcodecClose
+};
+
+int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
+{
+ AVCodec * codec;
+ AVCodecContext * context;
+
+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
+
+ pv->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->pixel_ratio )
+ {
+ context->sample_aspect_ratio.num = job->pixel_aspect_width;
+ context->sample_aspect_ratio.den = job->pixel_aspect_height;
+
+ hb_log( "encavcodec: encoding with stored aspect %d/%d",
+ job->pixel_aspect_width, job->pixel_aspect_height );
+ }
+
+ if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) )
+ {
+ context->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ }
+ if( job->mux & HB_MUX_PSP )
+ {
+ context->flags |= CODEC_FLAG_BITEXACT;
+ }
+ 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 )
+ {
+ pv->file = fopen( filename, "wb" );
+ context->flags |= CODEC_FLAG_PASS1;
+ }
+ else
+ {
+ int size;
+ char * log;
+
+ pv->file = fopen( filename, "rb" );
+ fseek( pv->file, 0, SEEK_END );
+ size = ftell( pv->file );
+ fseek( pv->file, 0, SEEK_SET );
+ log = malloc( size + 1 );
+ log[size] = '\0';
+ fread( log, size, 1, pv->file );
+ fclose( pv->file );
+ pv->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" );
+ }
+ pv->context = context;
+
+ if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 )
+ {
+#if 0
+ /* Hem hem */
+ w->config->mpeg4.length = 15;
+ memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 );
+#else
+ w->config->mpeg4.length = context->extradata_size;
+ memcpy( w->config->mpeg4.bytes, context->extradata,
+ context->extradata_size );
+#endif
+ }
+
+ return 0;
+}
+
+/***********************************************************************
+ * Close
+ ***********************************************************************
+ *
+ **********************************************************************/
+void encavcodecClose( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+
+ if( pv->context )
+ {
+ hb_log( "encavcodec: closing libavcodec" );
+ avcodec_close( pv->context );
+ }
+ if( pv->file )
+ {
+ fclose( pv->file );
+ }
+}
+
+/***********************************************************************
+ * Work
+ ***********************************************************************
+ *
+ **********************************************************************/
+int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
+{
+ hb_work_private_t * pv = w->private_data;
+ hb_job_t * job = pv->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( pv->context, buf->data, buf->alloc,
+ frame );
+ buf->start = in->start;
+ buf->stop = in->stop;
+ buf->key = pv->context->coded_frame->key_frame;
+
+ av_free( frame );
+
+ if( job->pass == 1 )
+ {
+ /* Write stats */
+ fprintf( pv->file, "%s", pv->context->stats_out );
+ }
+
+ *buf_out = buf;
+
+ return HB_WORK_OK;
+}
+
+