1 /* enctheora.c
2 
3    Copyright (c) 2003-2021 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  */
9 
10 #include "handbrake/handbrake.h"
11 #include "theora/codec.h"
12 #include "theora/theoraenc.h"
13 
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 * );
17 
18 hb_work_object_t hb_enctheora =
19 {
20     WORK_ENCTHEORA,
21     "Theora encoder (libtheora)",
22     enctheoraInit,
23     enctheoraWork,
24     enctheoraClose
25 };
26 
27 struct hb_work_private_s
28 {
29     hb_job_t    * job;
30 
31     th_enc_ctx    * ctx;
32 
33     FILE          * file;
34     unsigned char   stat_buf[80];
35     int             stat_read;
36     int             stat_fill;
37 };
38 
enctheoraInit(hb_work_object_t * w,hb_job_t * job)39 int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
40 {
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;
44 
45     pv->job = job;
46 
47     if( job->pass_id == HB_PASS_ENCODE_1ST ||
48         job->pass_id == HB_PASS_ENCODE_2ND )
49     {
50         char * filename;
51         filename = hb_get_temporary_filename("theora.log");
52         if ( job->pass_id == HB_PASS_ENCODE_1ST )
53         {
54             pv->file = hb_fopen(filename, "wb");
55         }
56         else
57         {
58             pv->file = hb_fopen(filename, "rb");
59         }
60         free(filename);
61     }
62 
63     th_info ti;
64     th_comment tc;
65     ogg_packet op;
66     th_info_init( &ti );
67 
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;
74     ti.fps_numerator = job->vrate.num;
75     ti.fps_denominator = job->vrate.den;
76     ti.aspect_numerator = job->par.num;
77     ti.aspect_denominator = job->par.den;
78     ti.colorspace = TH_CS_UNSPECIFIED;
79     ti.pixel_fmt = TH_PF_420;
80     if (job->vquality <= HB_INVALID_VIDEO_QUALITY)
81     {
82         ti.target_bitrate = job->vbitrate * 1000;
83         ti.quality = 0;
84     }
85     else
86     {
87         ti.target_bitrate = 0;
88         ti.quality = job->vquality;
89     }
90 
91     keyframe_frequency = ((double)job->orig_vrate.num / job->orig_vrate.den +
92                                   0.5) * 10;
93 
94     hb_log("theora: keyint: %i", keyframe_frequency);
95 
96     int tmp = keyframe_frequency - 1;
97     for (log_keyframe = 0; tmp; log_keyframe++)
98         tmp >>= 1;
99 
100     ti.keyframe_granule_shift = log_keyframe;
101 
102     pv->ctx = th_encode_alloc( &ti );
103     th_info_clear( &ti );
104 
105     ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
106                         &keyframe_frequency, sizeof(keyframe_frequency));
107     if( ret < 0 )
108     {
109         hb_log("theora: Could not set keyframe interval to %d", keyframe_frequency);
110     }
111 
112     /* Set "soft target" rate control which improves quality at the
113      * expense of solid bitrate caps */
114     int arg = TH_RATECTL_CAP_UNDERFLOW;
115     ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_RATE_FLAGS, &arg, sizeof(arg));
116     if( ret < 0 )
117     {
118         hb_log("theora: Could not set soft ratecontrol");
119     }
120     if( job->pass_id == HB_PASS_ENCODE_1ST ||
121         job->pass_id == HB_PASS_ENCODE_2ND )
122     {
123         arg = keyframe_frequency * 7 >> 1;
124         ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_RATE_BUFFER, &arg, sizeof(arg));
125         if( ret < 0 )
126         {
127             hb_log("theora: Could not set rate control buffer");
128         }
129     }
130 
131     if( job->pass_id == HB_PASS_ENCODE_1ST )
132     {
133         unsigned char *buffer;
134         int bytes;
135         bytes = th_encode_ctl(pv->ctx, TH_ENCCTL_2PASS_OUT, &buffer, sizeof(buffer));
136         if( bytes < 0 )
137         {
138             hb_error("Could not set up the first pass of two-pass mode.\n");
139             hb_error("Did you remember to specify an estimated bitrate?\n");
140             return 1;
141         }
142         if( fwrite( buffer, 1, bytes, pv->file ) < bytes )
143         {
144             hb_error("Unable to write to two-pass data file.\n");
145             return 1;
146         }
147         fflush( pv->file );
148     }
149     if( job->pass_id == HB_PASS_ENCODE_2ND )
150     {
151         /* Enable the second pass here.
152          * We make this call just to set the encoder into 2-pass mode, because
153          * by default enabling two-pass sets the buffer delay to the whole file
154          * (because there's no way to explicitly request that behavior).
155          * If we waited until we were actually encoding, it would overwrite our
156          * settings.*/
157         hb_log("enctheora: init 2nd pass");
158         if( th_encode_ctl( pv->ctx, TH_ENCCTL_2PASS_IN, NULL, 0) < 0)
159         {
160             hb_log("theora: Could not set up the second pass of two-pass mode.");
161             return 1;
162         }
163     }
164 
165     th_comment_init( &tc );
166 
167     ogg_packet *header;
168 
169     int ii;
170     for (ii = 0; ii < 3; ii++)
171     {
172         th_encode_flushheader( pv->ctx, &tc, &op );
173         header = (ogg_packet*)w->config->theora.headers[ii];
174         memcpy(header, &op, sizeof(op));
175         header->packet = w->config->theora.headers[ii] + sizeof(ogg_packet);
176         memcpy(header->packet, op.packet, op.bytes );
177     }
178 
179     th_comment_clear( &tc );
180 
181     return 0;
182 }
183 
184 /***********************************************************************
185  * Close
186  ***********************************************************************
187  *
188  **********************************************************************/
enctheoraClose(hb_work_object_t * w)189 void enctheoraClose( hb_work_object_t * w )
190 {
191     hb_work_private_t * pv = w->private_data;
192 
193     if (pv == NULL)
194     {
195         return;
196     }
197 
198     th_encode_free( pv->ctx );
199 
200     if( pv->file )
201     {
202         fclose( pv->file );
203     }
204     free( pv );
205     w->private_data = NULL;
206 }
207 
208 /***********************************************************************
209  * Work
210  ***********************************************************************
211  *
212  **********************************************************************/
enctheoraWork(hb_work_object_t * w,hb_buffer_t ** buf_in,hb_buffer_t ** buf_out)213 int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
214                  hb_buffer_t ** buf_out )
215 {
216     hb_work_private_t * pv = w->private_data;
217     hb_job_t * job = pv->job;
218     hb_buffer_t * in = *buf_in, * buf;
219     th_ycbcr_buffer ycbcr;
220     ogg_packet op;
221 
222     int frame_width, frame_height;
223 
224     if (in->s.flags & HB_BUF_FLAG_EOF)
225     {
226         // EOF on input - send it downstream & say we're done.
227         // XXX may need to flush packets via a call to
228         //  th_encode_packetout( pv->ctx, 1, &op );
229         // but we don't have a timestamp to put on those packets so we
230         // drop them for now.
231         *buf_out = in;
232         *buf_in = NULL;
233         th_encode_packetout( pv->ctx, 1, &op );
234         if( job->pass_id == HB_PASS_ENCODE_1ST )
235         {
236             unsigned char *buffer;
237             int bytes;
238 
239             bytes = th_encode_ctl(pv->ctx, TH_ENCCTL_2PASS_OUT,
240                                   &buffer, sizeof(buffer));
241             if( bytes < 0 )
242             {
243                 fprintf(stderr,"Could not read two-pass data from encoder.\n");
244                 return HB_WORK_DONE;
245             }
246             fseek( pv->file, 0, SEEK_SET );
247             if( fwrite( buffer, 1, bytes, pv->file ) < bytes)
248             {
249                 fprintf(stderr,"Unable to write to two-pass data file.\n");
250                 return HB_WORK_DONE;
251             }
252             fflush( pv->file );
253         }
254         return HB_WORK_DONE;
255     }
256 
257     if( job->pass_id == HB_PASS_ENCODE_2ND )
258     {
259         for(;;)
260         {
261             int bytes, size, ret;
262             /*Ask the encoder how many bytes it would like.*/
263             bytes = th_encode_ctl( pv->ctx, TH_ENCCTL_2PASS_IN, NULL, 0 );
264             if( bytes < 0 )
265             {
266                 hb_error("Error requesting stats size in second pass.");
267                 *job->done_error = HB_ERROR_UNKNOWN;
268                 *job->die = 1;
269                 return HB_WORK_DONE;
270             }
271 
272             /*If it's got enough, stop.*/
273             if( bytes == 0 ) break;
274 
275             /*Read in some more bytes, if necessary.*/
276             if( bytes > pv->stat_fill - pv->stat_read )
277                 size = bytes - (pv->stat_fill - pv->stat_read);
278             else
279                 size = 0;
280             if( size > 80 - pv->stat_fill )
281                 size = 80 - pv->stat_fill;
282             if( size > 0 &&
283                 fread( pv->stat_buf+pv->stat_fill, 1, size, pv->file ) < size )
284             {
285                 hb_error("Could not read frame data from two-pass data file!");
286                 *job->done_error = HB_ERROR_UNKNOWN;
287                 *job->die = 1;
288                 return HB_WORK_DONE;
289             }
290             pv->stat_fill += size;
291 
292             /*And pass them off.*/
293             if( bytes > pv->stat_fill - pv->stat_read )
294                 bytes = pv->stat_fill - pv->stat_read;
295             ret = th_encode_ctl( pv->ctx, TH_ENCCTL_2PASS_IN,
296                                  pv->stat_buf+pv->stat_read, bytes);
297             if( ret < 0 )
298             {
299                 hb_error("Error submitting pass data in second pass.");
300                 *job->done_error = HB_ERROR_UNKNOWN;
301                 *job->die = 1;
302                 return HB_WORK_DONE;
303             }
304             /*If the encoder consumed the whole buffer, reset it.*/
305             if( ret >= pv->stat_fill - pv->stat_read )
306                 pv->stat_read = pv->stat_fill = 0;
307             /*Otherwise remember how much it used.*/
308             else
309                 pv->stat_read += ret;
310         }
311     }
312     memset(&op, 0, sizeof(op));
313     memset(&ycbcr, 0, sizeof(ycbcr));
314 
315     frame_width = (job->width + 0xf) & ~0xf;
316     frame_height = (job->height + 0xf) & ~0xf;
317 
318     // Y
319     ycbcr[0].width = frame_width;
320     ycbcr[0].height = frame_height;
321 
322     // CbCr decimated by factor of 2 in both width and height
323     ycbcr[1].width  = ycbcr[2].width  = (frame_width + 1) / 2;
324     ycbcr[1].height = ycbcr[2].height = (frame_height + 1) / 2;
325 
326     ycbcr[0].stride = in->plane[0].stride;
327     ycbcr[1].stride = in->plane[1].stride;
328     ycbcr[2].stride = in->plane[2].stride;
329 
330     ycbcr[0].data = in->plane[0].data;
331     ycbcr[1].data = in->plane[1].data;
332     ycbcr[2].data = in->plane[2].data;
333 
334     th_encode_ycbcr_in( pv->ctx, ycbcr );
335 
336     if( job->pass_id == HB_PASS_ENCODE_1ST )
337     {
338         unsigned char *buffer;
339         int bytes;
340 
341         bytes = th_encode_ctl(pv->ctx, TH_ENCCTL_2PASS_OUT,
342                               &buffer, sizeof(buffer));
343         if( bytes < 0 )
344         {
345             fprintf(stderr,"Could not read two-pass data from encoder.\n");
346             *job->done_error = HB_ERROR_UNKNOWN;
347             *job->die = 1;
348             return HB_WORK_DONE;
349         }
350         if( fwrite( buffer, 1, bytes, pv->file ) < bytes)
351         {
352             fprintf(stderr,"Unable to write to two-pass data file.\n");
353             *job->done_error = HB_ERROR_UNKNOWN;
354             *job->die = 1;
355             return HB_WORK_DONE;
356         }
357         fflush( pv->file );
358     }
359     th_encode_packetout( pv->ctx, 0, &op );
360 
361     buf = hb_buffer_init(op.bytes);
362     memcpy(buf->data, op.packet, op.bytes);
363     buf->f.fmt = AV_PIX_FMT_YUV420P;
364     buf->f.width = frame_width;
365     buf->f.height = frame_height;
366     buf->s.flags = HB_FLAG_FRAMETYPE_REF;
367     buf->s.frametype = HB_FRAME_I;
368     if (th_packet_iskeyframe(&op))
369     {
370         buf->s.flags |= HB_FLAG_FRAMETYPE_KEY;
371     }
372     buf->s.start    = in->s.start;
373     buf->s.stop     = in->s.stop;
374     buf->s.duration = in->s.stop - in->s.start;
375 
376     *buf_out = buf;
377 
378     return HB_WORK_OK;
379 }
380 
381