OSDN Git Service

Repeat after me, eddyg is a wally.
[handbrake-jp/handbrake-jp-git.git] / libhb / encvorbis.c
index 01c71e8..a90b285 100644 (file)
@@ -37,31 +37,58 @@ struct hb_work_private_s
     uint64_t        pts;
 
     hb_list_t     * list;
-    int           channelsused;
+    int           out_discrete_channels;
     int           channel_map[6];
+    int64_t       prev_blocksize;
 };
 
 int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
 {
     int i;
     ogg_packet header[3];
+    struct ovectl_ratemanage2_arg  ctl_rate_arg;
 
     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
     w->private_data = pv;
-    pv->channelsused = w->config->vorbis.channelsused;
+    pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown);
 
     pv->job   = job;
 
     hb_log( "encvorbis: opening libvorbis" );
 
+    /* 28kbps/channel seems to be the minimum for 6ch vorbis. */
+    int min_bitrate = 28 * pv->out_discrete_channels;
+    if (pv->out_discrete_channels > 2 && job->abitrate < min_bitrate)
+    {
+        hb_log( "encvorbis: Selected bitrate (%d kbps) too low for %d channel audio.", job->abitrate, pv->out_discrete_channels);
+        hb_log( "encvorbis: Resetting bitrate to %d kbps", min_bitrate);
+        job->abitrate = min_bitrate;
+    }
+
     /* init */
     vorbis_info_init( &pv->vi );
-    if( vorbis_encode_setup_managed( &pv->vi, pv->channelsused,
-          job->arate, -1, 1000 * job->abitrate, -1 ) ||
-        vorbis_encode_ctl( &pv->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) ||
+    if( vorbis_encode_setup_managed( &pv->vi, pv->out_discrete_channels,
+          job->arate, -1, 1000 * job->abitrate, -1 ) )
+    {
+        hb_error( "encvorbis: vorbis_encode_setup_managed failed.\n" );
+        *job->die = 1;
+        return 0;
+    }
+
+    if( vorbis_encode_ctl( &pv->vi, OV_ECTL_RATEMANAGE2_GET, &ctl_rate_arg) )
+    {
+        hb_log( "encvorbis: vorbis_encode_ctl( ratemanage2_get ) failed" );
+    }
+
+    ctl_rate_arg.bitrate_average_kbps = 1000 * job->abitrate;
+    ctl_rate_arg.management_active = 1;
+
+    if( vorbis_encode_ctl( &pv->vi, OV_ECTL_RATEMANAGE2_SET, &ctl_rate_arg ) ||
           vorbis_encode_setup_init( &pv->vi ) )
     {
-        hb_log( "encvorbis: vorbis_encode_setup_managed failed" );
+        hb_error( "encvorbis: vorbis_encode_ctl( ratemanage2_set ) OR vorbis_encode_setup_init failed.\n" );
+        *job->die = 1;
+        return 0;
     }
 
     /* add a comment */
@@ -84,12 +111,12 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
                 header[i].packet, header[i].bytes );
     }
 
-    pv->input_samples = pv->channelsused * OGGVORBIS_FRAME_SIZE;
+    pv->input_samples = pv->out_discrete_channels * OGGVORBIS_FRAME_SIZE;
     pv->buf = malloc( pv->input_samples * sizeof( float ) );
 
     pv->list = hb_list_init();
 
-    switch (pv->channelsused) {
+    switch (pv->out_discrete_channels) {
         case 1:
             pv->channel_map[0] = 0;
             break;
@@ -102,7 +129,7 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
             pv->channel_map[5] = 3;
             break;
         default:
-            hb_log("encvorbis.c: Unable to correctly proccess %d channels, assuming stereo.", pv->channelsused);
+            hb_log("encvorbis.c: Unable to correctly proccess %d channels, assuming stereo.", pv->out_discrete_channels);
         case 2:
             // Assume stereo
             pv->channel_map[0] = 0;
@@ -120,6 +147,19 @@ int encvorbisInit( hb_work_object_t * w, hb_job_t * job )
  **********************************************************************/
 void encvorbisClose( hb_work_object_t * w )
 {
+    hb_work_private_t * pv = w->private_data;
+    
+    vorbis_block_clear( &pv->vb );
+    vorbis_dsp_clear( &pv->vd );
+    vorbis_comment_clear( &pv->vc );
+    vorbis_info_clear( &pv->vi );
+
+    if (pv->list)
+        hb_list_empty( &pv->list );
+    
+    free( pv->buf );
+    free( pv );
+    w->private_data = NULL;
 }
 
 /***********************************************************************
@@ -131,6 +171,7 @@ static hb_buffer_t * Flush( hb_work_object_t * w )
 {
     hb_work_private_t * pv = w->private_data;
     hb_buffer_t * buf;
+    int64_t     blocksize = 0;
 
     if( vorbis_analysis_blockout( &pv->vd, &pv->vb ) == 1 )
     {
@@ -145,12 +186,12 @@ static hb_buffer_t * Flush( hb_work_object_t * w )
             memcpy( buf->data, &op, sizeof( ogg_packet ) );
             memcpy( buf->data + sizeof( ogg_packet ), op.packet,
                     op.bytes );
-            buf->key   = 1;
-            buf->start = pv->pts; /* No exact, but who cares - the OGM
-                                    muxer doesn't use it */
-            buf->stop  = buf->start +
-                90000 * OGGVORBIS_FRAME_SIZE + pv->job->arate;
-
+            blocksize = vorbis_packet_blocksize(&pv->vi, &op);
+            buf->frametype   = HB_FRAME_AUDIO;
+            buf->start = (int64_t)(vorbis_granule_time(&pv->vd, op.granulepos) * 90000);
+            buf->stop  = (int64_t)(vorbis_granule_time(&pv->vd, (pv->prev_blocksize + blocksize)/4 + op.granulepos) * 90000);
+            /* The stop time isn't accurate for the first ~3 packets, as the actual blocksize depends on the previous _and_ current packets. */
+            pv->prev_blocksize = blocksize;
             return buf;
         }
     }
@@ -187,9 +228,9 @@ static hb_buffer_t * Encode( hb_work_object_t * w )
     buffer = vorbis_analysis_buffer( &pv->vd, OGGVORBIS_FRAME_SIZE );
     for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ )
     {
-        for( j = 0; j < pv->channelsused; j++)
+        for( j = 0; j < pv->out_discrete_channels; j++)
         {
-            buffer[j][i] = ((float *) pv->buf)[(pv->channelsused * i + pv->channel_map[j])] / 32768.f;
+            buffer[j][i] = ((float *) pv->buf)[(pv->out_discrete_channels * i + pv->channel_map[j])] / 32768.f;
         }
     }
     vorbis_analysis_wrote( &pv->vd, OGGVORBIS_FRAME_SIZE );