WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / enctheora.c
bloba49d7ff6beb8a008bc88894d7edb2149c491810b
1 /* enctheora.c
3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
10 #include "hb.h"
11 #include "theora/codec.h"
12 #include "theora/theoraenc.h"
14 int enctheoraInit( hb_work_object_t *, hb_job_t * );
15 int enctheoraWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
16 void enctheoraClose( hb_work_object_t * );
18 hb_work_object_t hb_enctheora =
20 WORK_ENCTHEORA,
21 "Theora encoder (libtheora)",
22 enctheoraInit,
23 enctheoraWork,
24 enctheoraClose
27 struct hb_work_private_s
29 hb_job_t * job;
31 th_enc_ctx * ctx;
33 FILE * file;
34 unsigned char stat_buf[80];
35 int stat_read;
36 int stat_fill;
39 int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
41 int keyframe_frequency, log_keyframe, ret;
42 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
43 w->private_data = pv;
45 pv->job = job;
47 if( job->pass_id == HB_PASS_ENCODE_1ST ||
48 job->pass_id == HB_PASS_ENCODE_2ND )
50 char filename[1024];
51 memset( filename, 0, 1024 );
52 hb_get_tempory_filename( job->h, filename, "theroa.log" );
53 if ( job->pass_id == HB_PASS_ENCODE_1ST )
55 pv->file = hb_fopen(filename, "wb");
57 else
59 pv->file = hb_fopen(filename, "rb");
63 th_info ti;
64 th_comment tc;
65 ogg_packet op;
66 th_info_init( &ti );
68 /* Frame width and height need to be multiples of 16 */
69 ti.pic_width = job->width;
70 ti.pic_height = job->height;
71 ti.frame_width = (job->width + 0xf) & ~0xf;
72 ti.frame_height = (job->height + 0xf) & ~0xf;
73 ti.pic_x = ti.pic_y = 0;
75 if( job->pass_id == HB_PASS_ENCODE_2ND )
77 hb_interjob_t * interjob = hb_interjob_get( job->h );
78 ti.fps_numerator = interjob->vrate.num;
79 ti.fps_denominator = interjob->vrate.den;
81 else
83 ti.fps_numerator = job->vrate.num;
84 ti.fps_denominator = job->vrate.den;
86 ti.aspect_numerator = job->par.num;
87 ti.aspect_denominator = job->par.den;
88 ti.colorspace = TH_CS_UNSPECIFIED;
89 ti.pixel_fmt = TH_PF_420;
90 if (job->vquality < 0.0)
92 ti.target_bitrate = job->vbitrate * 1000;
93 ti.quality = 0;
95 else
97 ti.target_bitrate = 0;
98 ti.quality = job->vquality;
101 keyframe_frequency = 10 * ((double)job->vrate.num / job->vrate.den + 0.5);
103 hb_log("theora: keyint: %i", keyframe_frequency);
105 int tmp = keyframe_frequency - 1;
106 for (log_keyframe = 0; tmp; log_keyframe++)
107 tmp >>= 1;
109 ti.keyframe_granule_shift = log_keyframe;
111 pv->ctx = th_encode_alloc( &ti );
112 th_info_clear( &ti );
114 ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
115 &keyframe_frequency, sizeof(keyframe_frequency));
116 if( ret < 0 )
118 hb_log("theora: Could not set keyframe interval to %d", keyframe_frequency);
121 /* Set "soft target" rate control which improves quality at the
122 * expense of solid bitrate caps */
123 int arg = TH_RATECTL_CAP_UNDERFLOW;
124 ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_RATE_FLAGS, &arg, sizeof(arg));
125 if( ret < 0 )
127 hb_log("theora: Could not set soft ratecontrol");
129 if( job->pass_id == HB_PASS_ENCODE_1ST ||
130 job->pass_id == HB_PASS_ENCODE_2ND )
132 arg = keyframe_frequency * 7 >> 1;
133 ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_RATE_BUFFER, &arg, sizeof(arg));
134 if( ret < 0 )
136 hb_log("theora: Could not set rate control buffer");
140 if( job->pass_id == HB_PASS_ENCODE_1ST )
142 unsigned char *buffer;
143 int bytes;
144 bytes = th_encode_ctl(pv->ctx, TH_ENCCTL_2PASS_OUT, &buffer, sizeof(buffer));
145 if( bytes < 0 )
147 hb_error("Could not set up the first pass of two-pass mode.\n");
148 hb_error("Did you remember to specify an estimated bitrate?\n");
149 return 1;
151 if( fwrite( buffer, 1, bytes, pv->file ) < bytes )
153 hb_error("Unable to write to two-pass data file.\n");
154 return 1;
156 fflush( pv->file );
158 if( job->pass_id == HB_PASS_ENCODE_2ND )
160 /* Enable the second pass here.
161 * We make this call just to set the encoder into 2-pass mode, because
162 * by default enabling two-pass sets the buffer delay to the whole file
163 * (because there's no way to explicitly request that behavior).
164 * If we waited until we were actually encoding, it would overwite our
165 * settings.*/
166 hb_log("enctheora: init 2nd pass");
167 if( th_encode_ctl( pv->ctx, TH_ENCCTL_2PASS_IN, NULL, 0) < 0)
169 hb_log("theora: Could not set up the second pass of two-pass mode.");
170 return 1;
174 th_comment_init( &tc );
176 ogg_packet *header;
178 int ii;
179 for (ii = 0; ii < 3; ii++)
181 th_encode_flushheader( pv->ctx, &tc, &op );
182 header = (ogg_packet*)w->config->theora.headers[ii];
183 memcpy(header, &op, sizeof(op));
184 header->packet = w->config->theora.headers[ii] + sizeof(ogg_packet);
185 memcpy(header->packet, op.packet, op.bytes );
188 th_comment_clear( &tc );
190 return 0;
193 /***********************************************************************
194 * Close
195 ***********************************************************************
197 **********************************************************************/
198 void enctheoraClose( hb_work_object_t * w )
200 hb_work_private_t * pv = w->private_data;
202 th_encode_free( pv->ctx );
204 if( pv->file )
206 fclose( pv->file );
208 free( pv );
209 w->private_data = NULL;
212 /***********************************************************************
213 * Work
214 ***********************************************************************
216 **********************************************************************/
217 int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
218 hb_buffer_t ** buf_out )
220 hb_work_private_t * pv = w->private_data;
221 hb_job_t * job = pv->job;
222 hb_buffer_t * in = *buf_in, * buf;
223 th_ycbcr_buffer ycbcr;
224 ogg_packet op;
226 int frame_width, frame_height;
228 if (in->s.flags & HB_BUF_FLAG_EOF)
230 // EOF on input - send it downstream & say we're done.
231 // XXX may need to flush packets via a call to
232 // th_encode_packetout( pv->ctx, 1, &op );
233 // but we don't have a timestamp to put on those packets so we
234 // drop them for now.
235 *buf_out = in;
236 *buf_in = NULL;
237 th_encode_packetout( pv->ctx, 1, &op );
238 if( job->pass_id == HB_PASS_ENCODE_1ST )
240 unsigned char *buffer;
241 int bytes;
243 bytes = th_encode_ctl(pv->ctx, TH_ENCCTL_2PASS_OUT,
244 &buffer, sizeof(buffer));
245 if( bytes < 0 )
247 fprintf(stderr,"Could not read two-pass data from encoder.\n");
248 return HB_WORK_DONE;
250 fseek( pv->file, 0, SEEK_SET );
251 if( fwrite( buffer, 1, bytes, pv->file ) < bytes)
253 fprintf(stderr,"Unable to write to two-pass data file.\n");
254 return HB_WORK_DONE;
256 fflush( pv->file );
258 return HB_WORK_DONE;
261 if( job->pass_id == HB_PASS_ENCODE_2ND )
263 for(;;)
265 int bytes, size, ret;
266 /*Ask the encoder how many bytes it would like.*/
267 bytes = th_encode_ctl( pv->ctx, TH_ENCCTL_2PASS_IN, NULL, 0 );
268 if( bytes < 0 )
270 hb_error("Error requesting stats size in second pass.");
271 *job->done_error = HB_ERROR_UNKNOWN;
272 *job->die = 1;
273 return HB_WORK_DONE;
276 /*If it's got enough, stop.*/
277 if( bytes == 0 ) break;
279 /*Read in some more bytes, if necessary.*/
280 if( bytes > pv->stat_fill - pv->stat_read )
281 size = bytes - (pv->stat_fill - pv->stat_read);
282 else
283 size = 0;
284 if( size > 80 - pv->stat_fill )
285 size = 80 - pv->stat_fill;
286 if( size > 0 &&
287 fread( pv->stat_buf+pv->stat_fill, 1, size, pv->file ) < size )
289 hb_error("Could not read frame data from two-pass data file!");
290 *job->done_error = HB_ERROR_UNKNOWN;
291 *job->die = 1;
292 return HB_WORK_DONE;
294 pv->stat_fill += size;
296 /*And pass them off.*/
297 if( bytes > pv->stat_fill - pv->stat_read )
298 bytes = pv->stat_fill - pv->stat_read;
299 ret = th_encode_ctl( pv->ctx, TH_ENCCTL_2PASS_IN,
300 pv->stat_buf+pv->stat_read, bytes);
301 if( ret < 0 )
303 hb_error("Error submitting pass data in second pass.");
304 *job->done_error = HB_ERROR_UNKNOWN;
305 *job->die = 1;
306 return HB_WORK_DONE;
308 /*If the encoder consumed the whole buffer, reset it.*/
309 if( ret >= pv->stat_fill - pv->stat_read )
310 pv->stat_read = pv->stat_fill = 0;
311 /*Otherwise remember how much it used.*/
312 else
313 pv->stat_read += ret;
316 memset(&op, 0, sizeof(op));
317 memset(&ycbcr, 0, sizeof(ycbcr));
319 frame_width = (job->width + 0xf) & ~0xf;
320 frame_height = (job->height + 0xf) & ~0xf;
322 // Y
323 ycbcr[0].width = frame_width;
324 ycbcr[0].height = frame_height;
326 // CbCr decimated by factor of 2 in both width and height
327 ycbcr[1].width = ycbcr[2].width = (frame_width + 1) / 2;
328 ycbcr[1].height = ycbcr[2].height = (frame_height + 1) / 2;
330 ycbcr[0].stride = in->plane[0].stride;
331 ycbcr[1].stride = in->plane[1].stride;
332 ycbcr[2].stride = in->plane[2].stride;
334 ycbcr[0].data = in->plane[0].data;
335 ycbcr[1].data = in->plane[1].data;
336 ycbcr[2].data = in->plane[2].data;
338 th_encode_ycbcr_in( pv->ctx, ycbcr );
340 if( job->pass_id == HB_PASS_ENCODE_1ST )
342 unsigned char *buffer;
343 int bytes;
345 bytes = th_encode_ctl(pv->ctx, TH_ENCCTL_2PASS_OUT,
346 &buffer, sizeof(buffer));
347 if( bytes < 0 )
349 fprintf(stderr,"Could not read two-pass data from encoder.\n");
350 *job->done_error = HB_ERROR_UNKNOWN;
351 *job->die = 1;
352 return HB_WORK_DONE;
354 if( fwrite( buffer, 1, bytes, pv->file ) < bytes)
356 fprintf(stderr,"Unable to write to two-pass data file.\n");
357 *job->done_error = HB_ERROR_UNKNOWN;
358 *job->die = 1;
359 return HB_WORK_DONE;
361 fflush( pv->file );
363 th_encode_packetout( pv->ctx, 0, &op );
365 buf = hb_buffer_init(op.bytes);
366 memcpy(buf->data, op.packet, op.bytes);
367 buf->f.fmt = AV_PIX_FMT_YUV420P;
368 buf->f.width = frame_width;
369 buf->f.height = frame_height;
370 buf->s.frametype = ( th_packet_iskeyframe(&op) ) ? HB_FRAME_KEY : HB_FRAME_REF;
371 buf->s.start = in->s.start;
372 buf->s.stop = in->s.stop;
373 buf->s.duration = in->s.stop - in->s.start;
375 *buf_out = buf;
377 return HB_WORK_OK;