OSDN Git Service

f3837b3e74e86ab8bd93ec8dbf48ef617ba8e4e6
[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
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
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     context->time_base = (AVRational) { job->vrate_base, job->vrate };
81     context->gop_size  = 10 * job->vrate / job->vrate_base;
82     context->pix_fmt   = PIX_FMT_YUV420P;
83
84     if( job->pixel_ratio )
85     {
86         context->sample_aspect_ratio.num = job->pixel_aspect_width;
87         context->sample_aspect_ratio.den = job->pixel_aspect_height;
88
89         hb_log( "encavcodec: encoding with stored aspect %d/%d",
90                 job->pixel_aspect_width, job->pixel_aspect_height );
91     }
92
93     if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) )
94     {
95         context->flags |= CODEC_FLAG_GLOBAL_HEADER;
96     }
97     if( job->mux & HB_MUX_PSP )
98     {
99         context->flags |= CODEC_FLAG_BITEXACT;
100     }
101     if( job->grayscale )
102     {
103         context->flags |= CODEC_FLAG_GRAY;
104     }
105
106     if( job->pass != 0 && job->pass != -1 )
107     {
108         char filename[1024]; memset( filename, 0, 1024 );
109         hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
110
111         if( job->pass == 1 )
112         {
113             pv->file = fopen( filename, "wb" );
114             context->flags |= CODEC_FLAG_PASS1;
115         }
116         else
117         {
118             int    size;
119             char * log;
120
121             pv->file = fopen( filename, "rb" );
122             fseek( pv->file, 0, SEEK_END );
123             size = ftell( pv->file );
124             fseek( pv->file, 0, SEEK_SET );
125             log = malloc( size + 1 );
126             log[size] = '\0';
127             fread( log, size, 1, pv->file );
128             fclose( pv->file );
129             pv->file = NULL;
130
131             context->flags    |= CODEC_FLAG_PASS2;
132             context->stats_in  = log;
133         }
134     }
135
136     if( avcodec_open( context, codec ) )
137     {
138         hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
139     }
140     pv->context = context;
141
142     if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 )
143     {
144 #if 0
145         /* Hem hem */
146         w->config->mpeg4.length = 15;
147         memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 );
148 #else
149         w->config->mpeg4.length = context->extradata_size;
150         memcpy( w->config->mpeg4.bytes, context->extradata,
151                 context->extradata_size );
152 #endif
153     }
154
155     return 0;
156 }
157
158 /***********************************************************************
159  * Close
160  ***********************************************************************
161  *
162  **********************************************************************/
163 void encavcodecClose( hb_work_object_t * w )
164 {
165     hb_work_private_t * pv = w->private_data;
166
167     if( pv->context )
168     {
169         hb_log( "encavcodec: closing libavcodec" );
170         avcodec_flush_buffers( pv->context );
171         avcodec_close( pv->context );
172     }
173     if( pv->file )
174     {
175         fclose( pv->file );
176     }
177     free( pv );
178     w->private_data = NULL;
179 }
180
181 /***********************************************************************
182  * Work
183  ***********************************************************************
184  *
185  **********************************************************************/
186 int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
187                     hb_buffer_t ** buf_out )
188 {
189     hb_work_private_t * pv = w->private_data;
190     hb_job_t * job = pv->job;
191     AVFrame  * frame;
192     hb_buffer_t * in = *buf_in, * buf;
193
194     if ( in->size <= 0 )
195     {
196         /* EOF on input - send it downstream & say we're done */
197         *buf_out = in;
198         *buf_in = NULL;
199        return HB_WORK_DONE;
200     }
201
202     frame              = avcodec_alloc_frame();
203     frame->data[0]     = in->data;
204     frame->data[1]     = frame->data[0] + job->width * job->height;
205     frame->data[2]     = frame->data[1] + job->width * job->height / 4;
206     frame->linesize[0] = job->width;
207     frame->linesize[1] = job->width / 2;
208     frame->linesize[2] = job->width / 2;
209     // For constant quality, setting the quality in AVCodecContext 
210     // doesn't do the trick.  It must be set in the AVFrame.
211     frame->quality = pv->context->global_quality;
212
213     /* Should be way too large */
214     buf = hb_buffer_init( 3 * job->width * job->height / 2 );
215     buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
216                                       frame );
217     buf->start = in->start;
218     buf->stop  = in->stop;
219     buf->frametype   = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF;
220
221     av_free( frame );
222
223     if( job->pass == 1 )
224     {
225         /* Write stats */
226         fprintf( pv->file, "%s", pv->context->stats_out );
227     }
228
229     *buf_out = buf;
230
231     return HB_WORK_OK;
232 }
233
234