OSDN Git Service

Fixed dvd_seek for titles which are not linear
[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.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8
9 #include "ffmpeg/avcodec.h"
10
11 struct hb_work_object_s
12 {
13     HB_WORK_COMMON;
14
15     hb_job_t * job;
16     AVCodecContext * context;
17     FILE * file;
18 };
19
20 /***********************************************************************
21  * Local prototypes
22  **********************************************************************/
23 static void Close( hb_work_object_t ** _w );
24 static int  Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
25                   hb_buffer_t ** buf_out );
26
27 /***********************************************************************
28  * hb_work_encavcodec_init
29  ***********************************************************************
30  *
31  **********************************************************************/
32 hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job )
33 {
34     AVCodec * codec;
35     AVCodecContext * context;
36     
37     hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 );
38     w->name  = strdup( "MPEG-4 encoder (libavcodec)" );
39     w->work  = Work;
40     w->close = Close;
41
42     w->job = job;
43
44     codec = avcodec_find_encoder( CODEC_ID_MPEG4 );
45     if( !codec )
46     {
47         hb_log( "hb_work_encavcodec_init: avcodec_find_encoder "
48                 "failed" );
49     }
50     context = avcodec_alloc_context();
51     if( job->vquality < 0.0 || job->vquality > 1.0 )
52     {
53         /* Rate control */
54         context->bit_rate = 1000 * job->vbitrate;
55         context->bit_rate_tolerance = 10 * context->bit_rate;
56     }
57     else
58     {
59         /* Constant quantizer */
60         context->qmin = 31 - job->vquality * 30;
61         context->qmax = context->qmin;
62         hb_log( "encavcodec: encoding at constant quantizer %d",
63                 context->qmin );
64     }
65     context->width     = job->width;
66     context->height    = job->height;
67     context->time_base = (AVRational) { job->vrate_base, job->vrate };
68     context->gop_size  = 10 * job->vrate / job->vrate_base;
69     context->pix_fmt   = PIX_FMT_YUV420P;
70
71     if( job->mux & HB_MUX_MP4 )
72     {
73         context->flags |= CODEC_FLAG_GLOBAL_HEADER;
74     }
75     if( job->grayscale )
76     {
77         context->flags |= CODEC_FLAG_GRAY;
78     }
79
80     if( job->pass )
81     {
82         char filename[1024]; memset( filename, 0, 1024 );
83         hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
84
85         if( job->pass == 1 )
86         {
87             w->file = fopen( filename, "wb" );
88             context->flags |= CODEC_FLAG_PASS1;
89         }
90         else
91         {
92             int    size;
93             char * log;
94
95             w->file = fopen( filename, "rb" );
96             fseek( w->file, 0, SEEK_END );
97             size = ftell( w->file );
98             fseek( w->file, 0, SEEK_SET );
99             log = malloc( size + 1 );
100             log[size] = '\0';
101             fread( log, size, 1, w->file );
102             fclose( w->file );
103             w->file = NULL;
104
105             context->flags    |= CODEC_FLAG_PASS2;
106             context->stats_in  = log;
107         }
108     }
109
110     if( avcodec_open( context, codec ) )
111     {
112         hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
113     }
114     w->context = context;
115
116     if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 )
117     {
118 #define c job->config.mpeg4
119         /* Hem hem */
120         c.config        = malloc( 15 );
121         c.config_length = 15;
122         memcpy( c.config, context->extradata + 15, 15 );
123 #undef c
124     }
125     
126     return w;
127 }
128
129 /***********************************************************************
130  * Close
131  ***********************************************************************
132  *
133  **********************************************************************/
134 static void Close( hb_work_object_t ** _w )
135 {
136     hb_work_object_t * w = *_w;
137     hb_job_t * job = w->job;
138
139     if( w->context )
140     {
141         hb_log( "encavcodec: closing libavcodec" );
142         avcodec_close( w->context );
143     }
144     if( w->file )
145     {
146         fclose( w->file );
147     }
148     if( job->es_config )
149     {
150         free( job->es_config );
151         job->es_config = NULL;
152         job->es_config_length = 0;
153     }
154
155     free( w->name );
156     free( w );
157     *_w = NULL;
158 }
159
160 /***********************************************************************
161  * Work
162  ***********************************************************************
163  *
164  **********************************************************************/
165 static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
166                  hb_buffer_t ** buf_out )
167 {
168     hb_job_t * job = w->job;
169     AVFrame  * frame;
170     hb_buffer_t * in = *buf_in, * buf;
171
172     frame              = avcodec_alloc_frame();
173     frame->data[0]     = in->data;
174     frame->data[1]     = frame->data[0] + job->width * job->height;
175     frame->data[2]     = frame->data[1] + job->width * job->height / 4;
176     frame->linesize[0] = job->width;
177     frame->linesize[1] = job->width / 2;
178     frame->linesize[2] = job->width / 2;
179
180     /* Should be way too large */
181     buf = hb_buffer_init( 3 * job->width * job->height / 2 );
182     buf->size = avcodec_encode_video( w->context, buf->data, buf->alloc,
183                                       frame );
184     buf->start = in->start;
185     buf->stop  = in->stop;
186     buf->key   = w->context->coded_frame->key_frame;
187
188     av_free( frame );
189
190     if( job->pass == 1 )
191     {
192         /* Write stats */
193         fprintf( w->file, "%s", w->context->stats_out );
194     }
195
196     *buf_out = buf;
197
198     return HB_WORK_OK;
199 }
200
201