OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / libhb / encavcodec.c
1 /* $Id: encavcodec.c,v 1.23 2005/10/13 23:47:06 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8 #include "hbffmpeg.h"
9
10 struct hb_work_private_s
11 {
12     hb_job_t * job;
13     AVCodecContext * context;
14     FILE * file;
15 };
16
17 int  encavcodecInit( hb_work_object_t *, hb_job_t * );
18 int  encavcodecWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
19 void encavcodecClose( hb_work_object_t * );
20
21 hb_work_object_t hb_encavcodec =
22 {
23     WORK_ENCAVCODEC,
24     "MPEG-4 encoder (libavcodec)",
25     encavcodecInit,
26     encavcodecWork,
27     encavcodecClose
28 };
29
30 int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
31 {
32     AVCodec * codec;
33     AVCodecContext * context;
34     int rate_num, rate_den;
35
36     hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
37     w->private_data = pv;
38
39     pv->job = job;
40
41     codec = avcodec_find_encoder( CODEC_ID_MPEG4 );
42     if( !codec )
43     {
44         hb_log( "hb_work_encavcodec_init: avcodec_find_encoder "
45                 "failed" );
46     }
47     context = avcodec_alloc_context();
48     if( job->vquality < 0.0 )
49     {
50         /* Rate control */
51         context->bit_rate = 1000 * job->vbitrate;
52         context->bit_rate_tolerance = 10 * context->bit_rate;
53     }
54     else
55     {
56         /* Constant quantizer */
57         // These settings produce better image quality than
58         // what was previously used
59         context->flags |= CODEC_FLAG_QSCALE;
60         if (job->vquality < 1.0)
61         {
62             float vquality;
63             vquality = 31 - job->vquality * 31;
64             // A value of 0 has undefined behavior
65             // and ffmpeg qp has integral increments
66             if (vquality < 1.0)
67                 vquality = 1.0;
68             context->global_quality = FF_QP2LAMBDA * vquality + 0.5;
69         }
70         else
71         {
72             context->global_quality = FF_QP2LAMBDA * job->vquality + 0.5;
73         }
74         context->mb_decision = 1;
75         hb_log( "encavcodec: encoding at constant quantizer %d",
76                 context->global_quality );
77     }
78     context->width     = job->width;
79     context->height    = job->height;
80     rate_num = job->vrate_base;
81     rate_den = job->vrate;
82     if (rate_den == 27000000)
83     {
84         int ii;
85         for (ii = 0; ii < hb_video_rates_count; ii++)
86         {
87             if (abs(rate_num - hb_video_rates[ii].rate) < 10)
88             {
89                 rate_num = hb_video_rates[ii].rate;
90                 break;
91             }
92         }
93     }
94     hb_reduce(&rate_num, &rate_den, rate_num, rate_den);
95     if ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
96     {
97         hb_log( "encavcodec: truncating framerate %d / %d", 
98                 rate_num, rate_den );
99     }
100     while ((rate_num & ~0xFFFF) || (rate_den & ~0xFFFF))
101     {
102         rate_num >>= 1;
103         rate_den >>= 1;
104     }
105     context->time_base = (AVRational) { rate_num, rate_den };
106     context->gop_size  = 10 * job->vrate / job->vrate_base;
107     context->pix_fmt   = PIX_FMT_YUV420P;
108
109     if( job->anamorphic.mode )
110     {
111         context->sample_aspect_ratio.num = job->anamorphic.par_width;
112         context->sample_aspect_ratio.den = job->anamorphic.par_height;
113
114         hb_log( "encavcodec: encoding with stored aspect %d/%d",
115                 job->anamorphic.par_width, job->anamorphic.par_height );
116     }
117
118     if( job->mux & HB_MUX_MP4 )
119     {
120         context->flags |= CODEC_FLAG_GLOBAL_HEADER;
121     }
122     if( job->grayscale )
123     {
124         context->flags |= CODEC_FLAG_GRAY;
125     }
126
127     if( job->pass != 0 && job->pass != -1 )
128     {
129         char filename[1024]; memset( filename, 0, 1024 );
130         hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
131
132         if( job->pass == 1 )
133         {
134             pv->file = fopen( filename, "wb" );
135             context->flags |= CODEC_FLAG_PASS1;
136         }
137         else
138         {
139             int    size;
140             char * log;
141
142             pv->file = fopen( filename, "rb" );
143             fseek( pv->file, 0, SEEK_END );
144             size = ftell( pv->file );
145             fseek( pv->file, 0, SEEK_SET );
146             log = malloc( size + 1 );
147             log[size] = '\0';
148             fread( log, size, 1, pv->file );
149             fclose( pv->file );
150             pv->file = NULL;
151
152             context->flags    |= CODEC_FLAG_PASS2;
153             context->stats_in  = log;
154         }
155     }
156
157     if( hb_avcodec_open( context, codec ) )
158     {
159         hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
160     }
161     pv->context = context;
162
163     if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 )
164     {
165 #if 0
166         /* Hem hem */
167         w->config->mpeg4.length = 15;
168         memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 );
169 #else
170         w->config->mpeg4.length = context->extradata_size;
171         memcpy( w->config->mpeg4.bytes, context->extradata,
172                 context->extradata_size );
173 #endif
174     }
175
176     return 0;
177 }
178
179 /***********************************************************************
180  * Close
181  ***********************************************************************
182  *
183  **********************************************************************/
184 void encavcodecClose( hb_work_object_t * w )
185 {
186     hb_work_private_t * pv = w->private_data;
187
188     if( pv->context )
189     {
190         hb_deep_log( 2, "encavcodec: closing libavcodec" );
191         avcodec_flush_buffers( pv->context );
192         hb_avcodec_close( pv->context );
193     }
194     if( pv->file )
195     {
196         fclose( pv->file );
197     }
198     free( pv );
199     w->private_data = NULL;
200 }
201
202 /***********************************************************************
203  * Work
204  ***********************************************************************
205  *
206  **********************************************************************/
207 int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
208                     hb_buffer_t ** buf_out )
209 {
210     hb_work_private_t * pv = w->private_data;
211     hb_job_t * job = pv->job;
212     AVFrame  * frame;
213     hb_buffer_t * in = *buf_in, * buf;
214
215     if ( in->size <= 0 )
216     {
217         /* EOF on input - send it downstream & say we're done */
218         *buf_out = in;
219         *buf_in = NULL;
220        return HB_WORK_DONE;
221     }
222
223     frame              = avcodec_alloc_frame();
224     frame->data[0]     = in->data;
225     frame->data[1]     = frame->data[0] + job->width * job->height;
226     frame->data[2]     = frame->data[1] + job->width * job->height / 4;
227     frame->linesize[0] = job->width;
228     frame->linesize[1] = job->width / 2;
229     frame->linesize[2] = job->width / 2;
230     // For constant quality, setting the quality in AVCodecContext 
231     // doesn't do the trick.  It must be set in the AVFrame.
232     frame->quality = pv->context->global_quality;
233
234     if ( pv->context->codec )
235     {
236         /* Should be way too large */
237         buf = hb_video_buffer_init( job->width, job->height );
238         buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
239                                           frame );
240         buf->start = in->start;
241         buf->stop  = in->stop;
242         buf->frametype   = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF;
243     }
244     else
245     {
246         buf = NULL;
247         
248         hb_error( "encavcodec: codec context has uninitialized codec; skipping frame" );
249     }
250
251     av_free( frame );
252
253     if( job->pass == 1 )
254     {
255         /* Write stats */
256         fprintf( pv->file, "%s", pv->context->stats_out );
257     }
258
259     *buf_out = buf;
260
261     return HB_WORK_OK;
262 }
263
264