OSDN Git Service

Don't drop subtitles when crossing PTS discontinuities by using buffer sequence numbe...
[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_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 || job->vquality > 1.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         context->qmin = 31 - job->vquality * 30;
58         context->qmax = context->qmin;
59         hb_log( "encavcodec: encoding at constant quantizer %d",
60                 context->qmin );
61     }
62     context->width     = job->width;
63     context->height    = job->height;
64     context->time_base = (AVRational) { job->vrate_base, job->vrate };
65     context->gop_size  = 10 * job->vrate / job->vrate_base;
66     context->pix_fmt   = PIX_FMT_YUV420P;
67
68     if( job->pixel_ratio )
69     {
70         context->sample_aspect_ratio.num = job->pixel_aspect_width;
71         context->sample_aspect_ratio.den = job->pixel_aspect_height;
72
73         hb_log( "encavcodec: encoding with stored aspect %d/%d", 
74                 job->pixel_aspect_width, job->pixel_aspect_height );
75     }
76
77     if( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) )
78     {
79         context->flags |= CODEC_FLAG_GLOBAL_HEADER;
80     }
81     if( job->mux & HB_MUX_PSP )
82     {
83         context->flags |= CODEC_FLAG_BITEXACT;
84     }
85     if( job->grayscale )
86     {
87         context->flags |= CODEC_FLAG_GRAY;
88     }
89
90     if( job->pass != 0 && job->pass != -1 )
91     {
92         char filename[1024]; memset( filename, 0, 1024 );
93         hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
94
95         if( job->pass == 1 )
96         {
97             pv->file = fopen( filename, "wb" );
98             context->flags |= CODEC_FLAG_PASS1;
99         }
100         else
101         {
102             int    size;
103             char * log;
104
105             pv->file = fopen( filename, "rb" );
106             fseek( pv->file, 0, SEEK_END );
107             size = ftell( pv->file );
108             fseek( pv->file, 0, SEEK_SET );
109             log = malloc( size + 1 );
110             log[size] = '\0';
111             fread( log, size, 1, pv->file );
112             fclose( pv->file );
113             pv->file = NULL;
114
115             context->flags    |= CODEC_FLAG_PASS2;
116             context->stats_in  = log;
117         }
118     }
119
120     if( avcodec_open( context, codec ) )
121     {
122         hb_log( "hb_work_encavcodec_init: avcodec_open failed" );
123     }
124     pv->context = context;
125
126     if( ( job->mux & ( HB_MUX_MP4 | HB_MUX_PSP ) ) && job->pass != 1 )
127     {
128 #if 0
129         /* Hem hem */
130         w->config->mpeg4.length = 15;
131         memcpy( w->config->mpeg4.bytes, context->extradata + 15, 15 );
132 #else
133         w->config->mpeg4.length = context->extradata_size;
134         memcpy( w->config->mpeg4.bytes, context->extradata,
135                 context->extradata_size );
136 #endif
137     }
138     
139     return 0;
140 }
141
142 /***********************************************************************
143  * Close
144  ***********************************************************************
145  *
146  **********************************************************************/
147 void encavcodecClose( hb_work_object_t * w )
148 {
149     hb_work_private_t * pv = w->private_data;
150
151     if( pv->context )
152     {
153         hb_log( "encavcodec: closing libavcodec" );
154         avcodec_flush_buffers( pv->context );
155         avcodec_close( pv->context );
156     }
157     if( pv->file )
158     {
159         fclose( pv->file );
160     }
161     free( pv );
162     w->private_data = NULL;
163 }
164
165 /***********************************************************************
166  * Work
167  ***********************************************************************
168  *
169  **********************************************************************/
170 int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
171                     hb_buffer_t ** buf_out )
172 {
173     hb_work_private_t * pv = w->private_data;
174     hb_job_t * job = pv->job;
175     AVFrame  * frame;
176     hb_buffer_t * in = *buf_in, * buf;
177
178     if(!in->data)
179     {
180        *buf_out        = NULL;
181        return HB_WORK_DONE;
182     }
183
184     frame              = avcodec_alloc_frame();
185     frame->data[0]     = in->data;
186     frame->data[1]     = frame->data[0] + job->width * job->height;
187     frame->data[2]     = frame->data[1] + job->width * job->height / 4;
188     frame->linesize[0] = job->width;
189     frame->linesize[1] = job->width / 2;
190     frame->linesize[2] = job->width / 2;
191
192     /* Should be way too large */
193     buf = hb_buffer_init( 3 * job->width * job->height / 2 );
194     buf->size = avcodec_encode_video( pv->context, buf->data, buf->alloc,
195                                       frame );
196     buf->start = in->start;
197     buf->stop  = in->stop;
198     buf->frametype   = pv->context->coded_frame->key_frame ? HB_FRAME_KEY : HB_FRAME_REF;
199
200     av_free( frame );
201
202     if( job->pass == 1 )
203     {
204         /* Write stats */
205         fprintf( pv->file, "%s", pv->context->stats_out );
206     }
207
208     *buf_out = buf;
209
210     return HB_WORK_OK;
211 }
212
213