Minor MingW32 build fixes.
[xiph/unicode.git] / ffmpeg2theora / theorautils.c
blob6a6bf65dc959cb54191a61e8b850f3604bb1edc0
1 /* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
2 /*
3 * theorautils.c - Ogg Theora/Ogg Vorbis Abstraction and Muxing
4 * Copyright (C) 2003-2005 <j@v2v.cc>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <time.h>
28 #include "theora/theora.h"
29 #include "vorbis/codec.h"
30 #include "vorbis/vorbisenc.h"
32 #include "theorautils.h"
36 static double rint(double x)
38 if (x < 0.0)
39 return (double)(int)(x - 0.5);
40 else
41 return (double)(int)(x + 0.5);
44 void init_info(oggmux_info *info) {
45 info->with_skeleton = 0; /* skeleton is disabled by default */
46 info->frontend = 0; /*frontend mode*/
47 info->videotime = 0;
48 info->audiotime = 0;
49 info->audio_bytesout = 0;
50 info->video_bytesout = 0;
52 info->videopage_valid = 0;
53 info->audiopage_valid = 0;
54 info->audiopage_buffer_length = 0;
55 info->videopage_buffer_length = 0;
56 info->audiopage = NULL;
57 info->videopage = NULL;
58 info->start_time = time(NULL);
59 info->duration = -1;
60 info->speed_level = -1;
62 info->v_pkg=0;
63 info->a_pkg=0;
64 #ifdef OGGMUX_DEBUG
65 info->a_page=0;
66 info->v_page=0;
67 #endif
70 void add_fishead_packet (oggmux_info *info) {
71 ogg_packet op;
73 memset (&op, 0, sizeof (op));
75 op.packet = _ogg_calloc (64, sizeof(unsigned char));
76 memset (op.packet, 0, 64);
77 memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
78 *((ogg_uint16_t*)(op.packet+8)) = SKELETON_VERSION_MAJOR; /* version major */
79 *((ogg_uint16_t*)(op.packet+10)) = SKELETON_VERSION_MINOR; /* version minor */
80 *((ogg_int64_t*)(op.packet+12)) = (ogg_int64_t)0; /* presentationtime numerator */
81 *((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)1000; /* presentationtime denominator */
82 *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)0; /* basetime numerator */
83 *((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)1000; /* basetime denominator */
84 /* both the numerator are zero hence handled by the memset */
85 *((ogg_uint32_t*)(op.packet+44)) = 0; /* UTC time, set to zero for now */
87 op.b_o_s = 1; /* its the first packet of the stream */
88 op.e_o_s = 0; /* its not the last packet of the stream */
89 op.bytes = 64; /* length of the packet in bytes */
91 ogg_stream_packetin (&info->so, &op); /* adding the packet to the skeleton stream */
92 _ogg_free (op.packet);
96 * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
98 void add_fisbone_packet (oggmux_info *info) {
99 ogg_packet op;
101 if (!info->audio_only) {
102 memset (&op, 0, sizeof (op));
103 op.packet = _ogg_calloc (82, sizeof(unsigned char));
104 memset (op.packet, 0, 82);
105 /* it will be the fisbone packet for the theora video */
106 memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
107 *((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
108 *((ogg_uint32_t*)(op.packet+12)) = info->to.serialno; /* serialno of the theora stream */
109 *((ogg_uint32_t*)(op.packet+16)) = 3; /* number of header packets */
110 /* granulerate, temporal resolution of the bitstream in samples/microsecond */
111 *((ogg_int64_t*)(op.packet+20)) = info->ti.fps_numerator; /* granulrate numerator */
112 *((ogg_int64_t*)(op.packet+28)) = info->ti.fps_denominator; /* granulrate denominator */
113 *((ogg_int64_t*)(op.packet+36)) = 0; /* start granule */
114 *((ogg_uint32_t*)(op.packet+44)) = 0; /* preroll, for theora its 0 */
115 *(op.packet+48) = theora_granule_shift (&info->ti); /* granule shift */
116 memcpy(op.packet+FISBONE_SIZE, "Content-Type: video/x-theora\r\n", 30); /* message header field, Content-Type */
118 op.b_o_s = 0;
119 op.e_o_s = 0;
120 op.bytes = 82; /* size of the packet in bytes */
122 ogg_stream_packetin (&info->so, &op);
123 _ogg_free (op.packet);
126 if (!info->video_only) {
127 memset (&op, 0, sizeof (op));
128 op.packet = _ogg_calloc (82, sizeof(unsigned char));
129 memset (op.packet, 0, 82);
130 /* it will be the fisbone packet for the vorbis audio */
131 memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
132 *((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
133 *((ogg_uint32_t*)(op.packet+12)) = info->vo.serialno; /* serialno of the vorbis stream */
134 *((ogg_uint32_t*)(op.packet+16)) = 3; /* number of header packet */
135 /* granulerate, temporal resolution of the bitstream in Hz */
136 *((ogg_int64_t*)(op.packet+20)) = info->sample_rate; /* granulerate numerator */
137 *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)1; /* granulerate denominator */
138 *((ogg_int64_t*)(op.packet+36)) = 0; /* start granule */
139 *((ogg_uint32_t*)(op.packet+44)) = 2; /* preroll, for vorbis its 2 */
140 *(op.packet+48) = 0; /* granule shift, always 0 for vorbis */
141 memcpy (op.packet+FISBONE_SIZE, "Content-Type: audio/x-vorbis\r\n", 30);
142 /* Important: Check the case of Content-Type for correctness */
144 op.b_o_s = 0;
145 op.e_o_s = 0;
146 op.bytes = 82;
148 ogg_stream_packetin (&info->so, &op);
149 _ogg_free (op.packet);
153 void oggmux_init (oggmux_info *info){
154 ogg_page og;
155 ogg_packet op;
157 /* yayness. Set up Ogg output stream */
158 srand (time (NULL));
159 ogg_stream_init (&info->vo, rand ());
161 if(!info->audio_only){
162 ogg_stream_init (&info->to, rand ()); /* oops, add one ot the above */
163 theora_encode_init (&info->td, &info->ti);
165 if(info->speed_level >= 0) {
166 int max_speed_level;
167 theora_control(&info->td, TH_ENCCTL_GET_SPLEVEL_MAX, &max_speed_level, sizeof(int));
168 if(info->speed_level > max_speed_level)
169 info->speed_level = max_speed_level;
170 theora_control(&info->td, TH_ENCCTL_SET_SPLEVEL, &info->speed_level, sizeof(int));
173 /* init theora done */
175 /* initialize Vorbis too, if we have audio. */
176 if(!info->video_only){
177 int ret;
178 vorbis_info_init (&info->vi);
179 /* Encoding using a VBR quality mode. */
180 if(info->vorbis_quality>-99)
181 ret =vorbis_encode_init_vbr (&info->vi, info->channels,info->sample_rate,info->vorbis_quality);
182 else
183 ret=vorbis_encode_init(&info->vi,info->channels,info->sample_rate,-1,info->vorbis_bitrate,-1);
185 if (ret){
186 fprintf (stderr,
187 "The Vorbis encoder could not set up a mode according to\n"
188 "the requested quality or bitrate.\n\n");
189 exit (1);
192 vorbis_comment_init (&info->vc);
193 vorbis_comment_add_tag (&info->vc, "ENCODER",PACKAGE_STRING);
194 /* set up the analysis state and auxiliary encoding storage */
195 vorbis_analysis_init (&info->vd, &info->vi);
196 vorbis_block_init (&info->vd, &info->vb);
199 /* audio init done */
201 /* first packet should be skeleton fishead packet, if skeleton is used */
203 if (info->with_skeleton) {
204 ogg_stream_init (&info->so, rand());
205 add_fishead_packet (info);
206 if (ogg_stream_pageout (&info->so, &og) != 1){
207 fprintf (stderr, "Internal Ogg library error.\n");
208 exit (1);
210 fwrite (og.header, 1, og.header_len, info->outfile);
211 fwrite (og.body, 1, og.body_len, info->outfile);
214 /* write the bitstream header packets with proper page interleave */
216 /* first packet will get its own page automatically */
217 if(!info->audio_only){
218 theora_encode_header (&info->td, &op);
219 ogg_stream_packetin (&info->to, &op);
220 if (ogg_stream_pageout (&info->to, &og) != 1){
221 fprintf (stderr, "Internal Ogg library error.\n");
222 exit (1);
224 fwrite (og.header, 1, og.header_len, info->outfile);
225 fwrite (og.body, 1, og.body_len, info->outfile);
227 /* create the remaining theora headers */
228 /* theora_comment_init (&info->tc); is called in main() prior to parsing options */
229 theora_comment_add_tag (&info->tc, "ENCODER",PACKAGE_STRING);
230 theora_encode_comment (&info->tc, &op);
231 ogg_stream_packetin (&info->to, &op);
232 theora_encode_tables (&info->td, &op);
233 ogg_stream_packetin (&info->to, &op);
235 if(!info->video_only){
236 ogg_packet header;
237 ogg_packet header_comm;
238 ogg_packet header_code;
240 vorbis_analysis_headerout (&info->vd, &info->vc, &header,
241 &header_comm, &header_code);
242 ogg_stream_packetin (&info->vo, &header); /* automatically placed in its own
243 * page */
244 if (ogg_stream_pageout (&info->vo, &og) != 1){
245 fprintf (stderr, "Internal Ogg library error.\n");
246 exit (1);
248 fwrite (og.header, 1, og.header_len, info->outfile);
249 fwrite (og.body, 1, og.body_len, info->outfile);
251 /* remaining vorbis header packets */
252 ogg_stream_packetin (&info->vo, &header_comm);
253 ogg_stream_packetin (&info->vo, &header_code);
256 /* output the appropriate fisbone packets */
257 if (info->with_skeleton) {
258 add_fisbone_packet (info);
259 while (1) {
260 int result = ogg_stream_flush (&info->so, &og);
261 if (result < 0){
262 /* can't get here */
263 fprintf (stderr, "Internal Ogg library error.\n");
264 exit (1);
266 if (result == 0)
267 break;
268 fwrite (og.header, 1, og.header_len, info->outfile);
269 fwrite (og.body, 1, og.body_len, info->outfile);
273 if (!info->audio_only) {
274 theora_info_clear(&info->ti);
277 /* Flush the rest of our headers. This ensures
278 * the actual data in each stream will start
279 * on a new page, as per spec. */
280 while (1 && !info->audio_only){
281 int result = ogg_stream_flush (&info->to, &og);
282 if (result < 0){
283 /* can't get here */
284 fprintf (stderr, "Internal Ogg library error.\n");
285 exit (1);
287 if (result == 0)
288 break;
289 fwrite (og.header, 1, og.header_len, info->outfile);
290 fwrite (og.body, 1, og.body_len, info->outfile);
292 while (1 && !info->video_only){
293 int result = ogg_stream_flush (&info->vo, &og);
294 if (result < 0){
295 /* can't get here */
296 fprintf (stderr, "Internal Ogg library error.\n");
297 exit (1);
299 if (result == 0)
300 break;
301 fwrite (og.header, 1, og.header_len,info->outfile);
302 fwrite (og.body, 1, og.body_len, info->outfile);
305 if (info->with_skeleton) {
306 int result;
308 /* build and add the e_o_s packet */
309 memset (&op, 0, sizeof (op));
310 op.b_o_s = 0;
311 op.e_o_s = 1; /* its the e_o_s packet */
312 op.granulepos = 0;
313 op.bytes = 0; /* e_o_s packet is an empty packet */
314 ogg_stream_packetin (&info->so, &op);
316 result = ogg_stream_flush (&info->so, &og);
317 if (result < 0){
318 /* can't get here */
319 fprintf (stderr, "Internal Ogg library error.\n");
320 exit (1);
322 fwrite (og.header, 1, og.header_len,info->outfile);
323 fwrite (og.body, 1, og.body_len, info->outfile);
327 /**
328 * adds a video frame to the encoding sink
329 * if e_o_s is 1 the end of the logical bitstream will be marked.
330 * @param this ff2theora struct
331 * @param info oggmux_info
332 * @param yuv_buffer
333 * @param e_o_s 1 indicates ond of stream
335 void oggmux_add_video (oggmux_info *info, yuv_buffer *yuv, int e_o_s){
336 ogg_packet op;
337 theora_encode_YUVin (&info->td, yuv);
338 while(theora_encode_packetout (&info->td, e_o_s, &op)) {
339 ogg_stream_packetin (&info->to, &op);
340 info->v_pkg++;
344 /**
345 * adds audio samples to encoding sink
346 * @param buffer pointer to buffer
347 * @param bytes bytes in buffer
348 * @param samples samples in buffer
349 * @param e_o_s 1 indicates end of stream.
351 void oggmux_add_audio (oggmux_info *info, int16_t * buffer, int bytes, int samples, int e_o_s){
352 ogg_packet op;
354 int i,j, count = 0;
355 float **vorbis_buffer;
356 if (bytes <= 0 && samples <= 0){
357 /* end of audio stream */
358 if(e_o_s)
359 vorbis_analysis_wrote (&info->vd, 0);
361 else{
362 vorbis_buffer = vorbis_analysis_buffer (&info->vd, samples);
363 /* uninterleave samples */
364 for (i = 0; i < samples; i++){
365 for(j=0;j<info->channels;j++){
366 vorbis_buffer[j][i] = buffer[count++] / 32768.f;
369 vorbis_analysis_wrote (&info->vd, samples);
371 while(vorbis_analysis_blockout (&info->vd, &info->vb) == 1){
372 /* analysis, assume we want to use bitrate management */
373 vorbis_analysis (&info->vb, NULL);
374 vorbis_bitrate_addblock (&info->vb);
376 /* weld packets into the bitstream */
377 while (vorbis_bitrate_flushpacket (&info->vd, &op)){
378 ogg_stream_packetin (&info->vo, &op);
379 info->a_pkg++;
384 static double get_remaining(oggmux_info *info, double timebase) {
385 double remaining = 0;
386 double to_encode, time_so_far;
388 if(info->duration != -1 && timebase > 0) {
389 time_so_far = time(NULL) - info->start_time;
390 to_encode = info->duration - timebase;
391 if(to_encode > 0) {
392 remaining = (time_so_far / timebase) * to_encode;
395 return remaining;
398 static void print_stats(oggmux_info *info, double timebase){
399 int hundredths = timebase * 100 - (long) timebase * 100;
400 int seconds = (long) timebase % 60;
401 int minutes = ((long) timebase / 60) % 60;
402 int hours = (long) timebase / 3600;
403 double remaining = get_remaining(info, timebase);
404 int remaining_seconds = (long) remaining % 60;
405 int remaining_minutes = ((long) remaining / 60) % 60;
406 int remaining_hours = (long) remaining / 3600;
407 if(info->frontend) {
408 fprintf (stderr,"\nf2t ;position: %.02lf;audio_kbps: %d;video_kbps: %d;remaining: %.02lf\n",
409 timebase,
410 info->akbps, info->vkbps,
411 remaining
415 else {
416 fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time remaining: %02d:%02d:%02d ",
417 hours, minutes, seconds, hundredths,
418 info->akbps, info->vkbps,
419 remaining_hours, remaining_minutes, remaining_seconds
424 static int write_audio_page(oggmux_info *info)
426 int ret;
428 ret = fwrite(info->audiopage, 1, info->audiopage_len, info->outfile);
429 if(ret < info->audiopage_len) {
430 fprintf(stderr,"error writing audio page\n");
432 else {
433 info->audio_bytesout += ret;
435 info->audiopage_valid = 0;
436 info->a_pkg -=ogg_page_packets((ogg_page *)&info->audiopage);
437 #ifdef OGGMUX_DEBUG
438 info->a_page++;
439 info->v_page=0;
440 fprintf(stderr,"\naudio page %d (%d pkgs) | pkg remaining %d\n",info->a_page,ogg_page_packets((ogg_page *)&info->audiopage),info->a_pkg);
441 #endif
443 info->akbps = rint (info->audio_bytesout * 8. / info->audiotime * .001);
444 if(info->akbps<0)
445 info->akbps=0;
446 print_stats(info, info->audiotime);
449 static int write_video_page(oggmux_info *info)
451 int ret;
453 ret = fwrite(info->videopage, 1, info->videopage_len, info->outfile);
454 if(ret < info->videopage_len) {
455 fprintf(stderr,"error writing video page\n");
457 else {
458 info->video_bytesout += ret;
460 info->videopage_valid = 0;
461 info->v_pkg -= ogg_page_packets((ogg_page *)&info->videopage);
462 #ifdef OGGMUX_DEBUG
463 info->v_page++;
464 info->a_page=0;
465 fprintf(stderr,"\nvideo page %d (%d pkgs) | pkg remaining %d\n",info->v_page,ogg_page_packets((ogg_page *)&info->videopage),info->v_pkg);
466 #endif
469 info->vkbps = rint (info->video_bytesout * 8. / info->videotime * .001);
470 if(info->vkbps<0)
471 info->vkbps=0;
472 print_stats(info, info->videotime);
475 void oggmux_flush (oggmux_info *info, int e_o_s)
477 int len;
478 ogg_page og;
480 /* flush out the ogg pages to info->outfile */
481 while(1) {
482 /* Get pages for both streams, if not already present, and if available.*/
483 if(!info->audio_only && !info->videopage_valid) {
484 // this way seeking is much better,
485 // not sure if 23 packets is a good value. it works though
486 int v_next=0;
487 if(info->v_pkg>22 && ogg_stream_flush(&info->to, &og) > 0) {
488 v_next=1;
490 else if(ogg_stream_pageout(&info->to, &og) > 0) {
491 v_next=1;
493 if(v_next) {
494 len = og.header_len + og.body_len;
495 if(info->videopage_buffer_length < len) {
496 info->videopage = realloc(info->videopage, len);
497 info->videopage_buffer_length = len;
499 info->videopage_len = len;
500 memcpy(info->videopage, og.header, og.header_len);
501 memcpy(info->videopage+og.header_len , og.body, og.body_len);
503 info->videopage_valid = 1;
504 if(ogg_page_granulepos(&og)>0) {
505 info->videotime = theora_granule_time (&info->td,
506 ogg_page_granulepos(&og));
510 if(!info->video_only && !info->audiopage_valid) {
511 // this way seeking is much better,
512 // not sure if 23 packets is a good value. it works though
513 int a_next=0;
514 if(info->a_pkg>22 && ogg_stream_flush(&info->vo, &og) > 0) {
515 a_next=1;
517 else if(ogg_stream_pageout(&info->vo, &og) > 0) {
518 a_next=1;
520 if(a_next) {
521 len = og.header_len + og.body_len;
522 if(info->audiopage_buffer_length < len) {
523 info->audiopage = realloc(info->audiopage, len);
524 info->audiopage_buffer_length = len;
526 info->audiopage_len = len;
527 memcpy(info->audiopage, og.header, og.header_len);
528 memcpy(info->audiopage+og.header_len , og.body, og.body_len);
530 info->audiopage_valid = 1;
531 if(ogg_page_granulepos(&og)>0) {
532 info->audiotime= vorbis_granule_time (&info->vd,
533 ogg_page_granulepos(&og));
538 if(info->video_only && info->videopage_valid) {
539 write_video_page(info);
541 else if(info->audio_only && info->audiopage_valid) {
542 write_audio_page(info);
544 /* We're using both. We can output only:
545 * a) If we have valid pages for both
546 * b) At EOS, for the remaining stream.
548 else if(info->videopage_valid && info->audiopage_valid) {
549 /* Make sure they're in the right order. */
550 if(info->videotime <= info->audiotime)
551 write_video_page(info);
552 else
553 write_audio_page(info);
555 else if(e_o_s && info->videopage_valid) {
556 write_video_page(info);
558 else if(e_o_s && info->audiopage_valid) {
559 write_audio_page(info);
561 else {
562 break; /* Nothing more writable at the moment */
567 void oggmux_close (oggmux_info *info){
568 ogg_stream_clear (&info->vo);
569 vorbis_block_clear (&info->vb);
570 vorbis_dsp_clear (&info->vd);
571 vorbis_comment_clear (&info->vc);
572 vorbis_info_clear (&info->vi);
574 ogg_stream_clear (&info->to);
575 theora_clear (&info->td);
577 if (info->outfile && info->outfile != stdout)
578 fclose (info->outfile);
580 if(info->videopage)
581 free(info->videopage);
582 if(info->audiopage)
583 free(info->audiopage);