OSDN Git Service

x264 bump to r1339-82b80ef
[handbrake-jp/handbrake-jp-git.git] / libhb / encavcodec.c
index 5e55b00..22eb286 100644 (file)
@@ -5,8 +5,7 @@
    It may be used under the terms of the GNU General Public License. */
 
 #include "hb.h"
-
-#include "libavcodec/avcodec.h"
+#include "hbffmpeg.h"
 
 struct hb_work_private_s
 {
@@ -32,6 +31,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
 {
     AVCodec * codec;
     AVCodecContext * context;
+    int rate_num, rate_den;
 
     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
     w->private_data = pv;
@@ -45,7 +45,7 @@ int encavcodecInit( hb_work_object_t * w, 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;
@@ -54,24 +54,65 @@ int encavcodecInit( hb_work_object_t * w, 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->pixel_ratio )
+    if( job->anamorphic.mode )
     {
-        context->sample_aspect_ratio.num = job->pixel_aspect_width;
-        context->sample_aspect_ratio.den = job->pixel_aspect_height;
+        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->pixel_aspect_width, job->pixel_aspect_height );
+                job->anamorphic.par_width, job->anamorphic.par_height );
     }
 
     if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) )
@@ -117,7 +158,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
         }
     }
 
-    if( avcodec_open( context, codec ) )
+    if( hb_avcodec_open( context, codec ) )
     {
         hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
     }
@@ -150,9 +191,9 @@ void encavcodecClose( hb_work_object_t * w )
 
     if( pv->context )
     {
-        hb_log( "encavcodec: closing libavcodec" );
+        hb_deep_log( 2, "encavcodec: closing libavcodec" );
         avcodec_flush_buffers( pv->context );
-        avcodec_close( pv->context );
+        hb_avcodec_close( pv->context );
     }
     if( pv->file )
     {
@@ -175,9 +216,11 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
     AVFrame  * frame;
     hb_buffer_t * in = *buf_in, * buf;
 
-    if(!in->data)
+    if ( in->size <= 0 )
     {
-       *buf_out        = NULL;
+        /* EOF on input - send it downstream & say we're done */
+        *buf_out = in;
+        *buf_in = NULL;
        return HB_WORK_DONE;
     }
 
@@ -188,9 +231,12 @@ int encavcodecWork( 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 = hb_video_buffer_init( job->width, job->height );
     buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
                                       frame );
     buf->start = in->start;