OSDN Git Service

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