X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fencavcodec.c;h=22eb286d524158c8e300c04d8f5143f623e7bfaa;hb=3e441ebb595c36a1f2f029e4ce907bb1bffaea50;hp=deff7c527cdbba2140633b6377d4f5a1be0b74ee;hpb=cdba71d1dca214142fdcca4c52f7672252752c2e;p=handbrake-jp%2Fhandbrake-jp-git.git
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index deff7c52..22eb286d 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -1,45 +1,42 @@
/* $Id: encavcodec.c,v 1.23 2005/10/13 23:47:06 titer Exp $
This file is part of the HandBrake source code.
- Homepage: .
+ Homepage: .
It may be used under the terms of the GNU General Public License. */
#include "hb.h"
+#include "hbffmpeg.h"
-#include "ffmpeg/avcodec.h"
-
-struct hb_work_object_s
+struct hb_work_private_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 );
+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_encavcodec_init
- ***********************************************************************
- *
- **********************************************************************/
-hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job )
+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_object_t * w = calloc( sizeof( hb_work_object_t ), 1 );
- w->name = strdup( "MPEG-4 encoder (libavcodec)" );
- w->work = Work;
- w->close = Close;
+ int rate_num, rate_den;
+
+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
- w->job = job;
+ pv->job = job;
codec = avcodec_find_encoder( CODEC_ID_MPEG4 );
if( !codec )
@@ -48,7 +45,7 @@ hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job )
"failed" );
}
context = avcodec_alloc_context();
- if( job->vquality < 0.0 || job->vquality > 1.0 )
+ if( job->vquality < 0.0 )
{
/* Rate control */
context->bit_rate = 1000 * job->vbitrate;
@@ -57,34 +54,88 @@ hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job )
else
{
/* Constant quantizer */
- context->qmin = 31 - job->vquality * 30;
- context->qmax = context->qmin;
+ // These settings produce better image quality than
+ // what was previously used
+ context->flags |= CODEC_FLAG_QSCALE;
+ if (job->vquality < 1.0)
+ {
+ float vquality;
+ vquality = 31 - job->vquality * 31;
+ // A value of 0 has undefined behavior
+ // and ffmpeg qp has integral increments
+ if (vquality < 1.0)
+ vquality = 1.0;
+ context->global_quality = FF_QP2LAMBDA * vquality + 0.5;
+ }
+ else
+ {
+ context->global_quality = FF_QP2LAMBDA * job->vquality + 0.5;
+ }
+ context->mb_decision = 1;
hb_log( "encavcodec: encoding at constant quantizer %d",
- context->qmin );
+ context->global_quality );
}
context->width = job->width;
context->height = job->height;
- context->time_base = (AVRational) { job->vrate_base, job->vrate };
+ rate_num = job->vrate_base;
+ rate_den = job->vrate;
+ if (rate_den == 27000000)
+ {
+ int ii;
+ for (ii = 0; ii < hb_video_rates_count; ii++)
+ {
+ if (abs(rate_num - hb_video_rates[ii].rate) < 10)
+ {
+ rate_num = hb_video_rates[ii].rate;
+ break;
+ }
+ }
+ }
+ hb_reduce(&rate_num, &rate_den, rate_num, rate_den);
+ if ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
+ {
+ hb_log( "encavcodec: truncating framerate %d / %d",
+ rate_num, rate_den );
+ }
+ while ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
+ {
+ rate_num >>= 1;
+ rate_den >>= 1;
+ }
+ context->time_base = (AVRational) { rate_num, rate_den };
context->gop_size = 10 * job->vrate / job->vrate_base;
context->pix_fmt = PIX_FMT_YUV420P;
- if( job->mux & HB_MUX_MP4 )
+ if( job->anamorphic.mode )
+ {
+ context->sample_aspect_ratio.num = job->anamorphic.par_width;
+ context->sample_aspect_ratio.den = job->anamorphic.par_height;
+
+ hb_log( "encavcodec: encoding with stored aspect %d/%d",
+ job->anamorphic.par_width, job->anamorphic.par_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 )
+ if( job->pass != 0 && job->pass != -1 )
{
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" );
+ pv->file = fopen( filename, "wb" );
context->flags |= CODEC_FLAG_PASS1;
}
else
@@ -92,38 +143,41 @@ hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job )
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 );
+ 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, w->file );
- fclose( w->file );
- w->file = NULL;
+ 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 ) )
+ if( hb_avcodec_open( context, codec ) )
{
hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
}
- w->context = context;
+ pv->context = context;
- if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 )
+ if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 )
{
-#define c job->config.mpeg4
+#if 0
/* Hem hem */
- c.config = malloc( 15 );
- c.config_length = 15;
- memcpy( c.config, context->extradata + 15, 15 );
-#undef c
+ 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 w;
+
+ return 0;
}
/***********************************************************************
@@ -131,30 +185,22 @@ hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job )
***********************************************************************
*
**********************************************************************/
-static void Close( hb_work_object_t ** _w )
+void encavcodecClose( hb_work_object_t * w )
{
- hb_work_object_t * w = *_w;
- hb_job_t * job = w->job;
+ hb_work_private_t * pv = w->private_data;
- if( w->context )
- {
- hb_log( "encavcodec: closing libavcodec" );
- avcodec_close( w->context );
- }
- if( w->file )
+ if( pv->context )
{
- fclose( w->file );
+ hb_deep_log( 2, "encavcodec: closing libavcodec" );
+ avcodec_flush_buffers( pv->context );
+ hb_avcodec_close( pv->context );
}
- if( job->es_config )
+ if( pv->file )
{
- free( job->es_config );
- job->es_config = NULL;
- job->es_config_length = 0;
+ fclose( pv->file );
}
-
- free( w->name );
- free( w );
- *_w = NULL;
+ free( pv );
+ w->private_data = NULL;
}
/***********************************************************************
@@ -162,13 +208,22 @@ 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 )
+int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
{
- hb_job_t * job = w->job;
+ hb_work_private_t * pv = w->private_data;
+ hb_job_t * job = pv->job;
AVFrame * frame;
hb_buffer_t * in = *buf_in, * buf;
+ if ( in->size <= 0 )
+ {
+ /* EOF on input - send it downstream & say we're done */
+ *buf_out = in;
+ *buf_in = NULL;
+ return HB_WORK_DONE;
+ }
+
frame = avcodec_alloc_frame();
frame->data[0] = in->data;
frame->data[1] = frame->data[0] + job->width * job->height;
@@ -176,21 +231,24 @@ static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
frame->linesize[0] = job->width;
frame->linesize[1] = job->width / 2;
frame->linesize[2] = job->width / 2;
+ // For constant quality, setting the quality in AVCodecContext
+ // doesn't do the trick. It must be set in the AVFrame.
+ frame->quality = pv->context->global_quality;
/* 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,
+ buf = hb_video_buffer_init( job->width, job->height );
+ buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
frame );
buf->start = in->start;
buf->stop = in->stop;
- buf->key = w->context->coded_frame->key_frame;
+ buf->frametype = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF;
av_free( frame );
if( job->pass == 1 )
{
/* Write stats */
- fprintf( w->file, "%s", w->context->stats_out );
+ fprintf( pv->file, "%s", pv->context->stats_out );
}
*buf_out = buf;