3 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "bcsignals.h"
24 #include "byteorder.h"
30 #include "interlacemodes.h"
32 #include "mainerror.h"
34 #include "mwindow.inc"
35 #include "preferences.h"
38 #include "versioninfo.h"
39 #include "videodevice.inc"
41 #include <sys/types.h>
48 /* This code was aspired by ffmpeg2theora */
49 /* Special thanks for help on this code goes out to j@v2v.cc */
52 #define READ_SIZE 4*66000
53 #define SEEK_SIZE 2*66000
55 sync_window_t::sync_window_t(FILE *fp, Mutex *sync_lock, int64_t begin, int64_t end)
59 this->sync_lock = sync_lock;
60 this->file_begin = begin;
67 sync_window_t::~sync_window_t()
72 int sync_window_t::ogg_read_locked(int buflen)
74 char *buffer = ogg_sync_buffer(this, buflen);
75 int len = fread(buffer, 1, buflen, fp);
76 ogg_sync_wrote(this, len);
81 int sync_window_t::ogg_read_buffer(int buflen)
83 sync_lock->lock("sync_window_t::ogg_read_buffer_at");
84 fseeko(fp, filepos, SEEK_SET);
85 int len = ogg_read_locked(buflen);
90 int sync_window_t::ogg_read_buffer_at(off_t filepos, int buflen)
92 if( bufpos == filepos && buflen == this->filepos - bufpos )
94 sync_lock->lock("sync_window_t::ogg_read_buffer_at");
95 this->bufpos = filepos;
96 fseeko(fp, filepos, SEEK_SET);
97 this->filepos = filepos;
99 int ret = ogg_read_locked(buflen);
104 // we never need to autoadvance when syncing, since our read chunks are larger than
106 int sync_window_t::ogg_sync_and_take_page_out(ogg_page *og)
112 int ret = ogg_sync_pageseek(this, og);
113 bufpos += abs(ret); // can be zero
117 int sync_window_t::ogg_sync_and_get_next_page(long serialno, ogg_page *og)
119 int ret = 0, retries = 1000;
120 while( --retries >= 0 && (ret = ogg_sync_and_take_page_out(og)) < 0 );
121 if( ret >= mn_pagesz && ogg_page_serialno(og) != serialno )
122 ret = ogg_get_next_page(serialno, og);
124 pagpos = bufpos - (og->header_len + og->body_len);
130 int sync_window_t::ogg_get_next_page(long serialno, ogg_page *og)
132 int ret = 0, retries = 1000;
133 while( --retries >= 0 && (ret=ogg_take_page_out_autoadvance(og)) &&
134 ogg_page_serialno(og) != serialno );
136 pagpos = bufpos - (og->header_len + og->body_len);
139 printf("ogg_get_next_page missed\n");
143 int sync_window_t::ogg_prev_page_search(long serialno, ogg_page *og,
144 off_t begin, off_t end)
147 int retries = 100, ret = 0;
149 while( ppos < 0 && --retries >= 0 ) {
151 int read_len = SEEK_SIZE;
154 read_len += fpos - begin;
155 if( read_len <= 0 ) break;
158 read_len = ogg_read_buffer_at(fpos, read_len);
159 if( read_len <= 0 ) return 0;
160 while( (ret=ogg_sync_and_take_page_out(&page)) < 0 );
163 if( ogg_page_serialno(&page) == serialno ) {
164 memcpy(og, &page, sizeof(page));
165 ppos = bufpos - (page.header_len + page.body_len);
167 ret = ogg_sync_pageout(this, &page);
168 bufpos += page.header_len + page.body_len;
175 printf("ogg_prev_page_search missed\n");
179 int sync_window_t::ogg_get_prev_page(long serialno, ogg_page *og)
181 return ogg_prev_page_search(serialno, og, file_begin, pagpos);
184 int sync_window_t::ogg_get_first_page(long serialno, ogg_page *og)
186 ogg_read_buffer_at(file_begin, SEEK_SIZE);
187 return ogg_sync_and_get_next_page(serialno, og);
190 int sync_window_t::ogg_get_last_page(long serialno, ogg_page *og)
194 off_t filepos = file_end - READ_SIZE;
195 if( filepos < 0 ) filepos = 0;
196 int ret = 0, first_page_offset = 0;
197 while( !ret && filepos >= 0 ) {
198 int readlen = ogg_read_buffer_at(filepos, READ_SIZE);
199 int page_offset = 0, page_length = 0;
200 int first_page = 1; // read all pages in the buffer
201 while( first_page || page_length ) {
202 // if negative, skip bytes
203 while( (page_length = ogg_sync_and_take_page_out(&page)) < 0 )
204 page_offset -= page_length;
205 if( page_length < mn_pagesz ) continue;
208 first_page_offset = page_offset;
210 if( ogg_page_serialno(&page) == serialno ) {
211 // return last match page
212 pagpos = bufpos - (page.header_len + page.body_len);
213 memcpy(og, &page, sizeof(page));
217 filepos -= readlen - first_page_offset; // move backward
222 OGG_PageBfr::OGG_PageBfr()
230 OGG_PageBfr::~OGG_PageBfr()
235 void OGG_PageBfr::demand(int sz)
237 if( allocated >= sz ) return;
238 uint8_t *new_page = new uint8_t[sz];
239 memcpy(new_page, page, len);
240 delete [] page; page = new_page;
244 int OGG_PageBfr::write_page(FILE *fp)
246 int sz = fwrite(page, 1, len, fp);
247 if( sz != len ) return -1;
248 ogg_page op; // kludgy
249 op.header = page; op.header_len = len;
250 op.body = page+len; op.body_len = 0;
251 packets -= ogg_page_packets(&op);
256 int64_t OGG_PageBfr::load(ogg_page *og)
258 int sz = og->header_len + og->body_len;
260 memcpy(page, og->header, og->header_len);
261 memcpy(page+og->header_len, og->body, og->body_len);
263 position = ogg_page_granulepos(og);
269 FileOGG::FileOGG(Asset *asset, File *file)
270 : FileBase(asset, file)
272 if( asset->format == FILE_UNKNOWN )
273 asset->format = FILE_OGG;
274 asset->byte_order = 0;
276 file_lock = new Mutex("OGGFile::Flush lock");
313 memset(&to, 0, sizeof(to));
314 memset(&vo, 0, sizeof(vo));
315 ogg_sample_position = 0;
316 ogg_frame_position = 0;
317 next_sample_position = 0;
318 next_frame_position = 0;
325 audio_pos = 0; audio_eos = 0;
326 video_pos = 0; video_eos = 0;
328 keyframe_granule_shift = 0;
329 iframe_granule_offset = 0;
330 theora_cmodel = BC_YUV420P;
333 memset(&ti, 0, sizeof(ti));
335 memset(&tc, 0, sizeof(tc));
336 memset(&vi, 0, sizeof(vi));
337 memset(&vc, 0, sizeof(vc));
338 memset(&vd, 0, sizeof(vd));
339 memset(&vb, 0, sizeof(vb));
346 frame_w = frame_h = 0;
347 colorspace = OC_CS_UNSPECIFIED;
349 bitrate = 0; quality = 0;
352 fps_num = fps_den = 0;
353 aratio_num = aratio_den = 0;
357 static int ilog(unsigned v)
360 while( v ) { ++ret; v >>= 1; }
364 int FileOGG::encode_theora_init()
366 ogg_stream_init(&to, rand());
368 pic_w = asset->width, pic_h = asset->height;
369 frame_w = (pic_w+0x0f) & ~0x0f;
370 frame_h = (pic_h+0x0f) & ~0x0f;
371 pic_x = ((frame_w-pic_w) >> 1) & ~1;
372 pic_y = ((frame_h-pic_h) >> 1) & ~1;
373 fps_num = asset->frame_rate * 1000000;
375 if( asset->aspect_ratio > 0 ) {
376 // Cinelerra uses frame aspect ratio, theora uses pixel aspect ratio
377 float pixel_aspect = asset->aspect_ratio / asset->width * asset->height;
378 aratio_num = pixel_aspect * 1000000;
379 aratio_den = 1000000;
382 aratio_num = 1000000;
383 aratio_den = 1000000;
385 if( EQUIV(asset->frame_rate, 25) || EQUIV(asset->frame_rate, 50) )
386 colorspace = OC_CS_ITU_REC_470BG;
387 else if( (asset->frame_rate > 29 && asset->frame_rate < 31) ||
388 (asset->frame_rate > 59 && asset->frame_rate < 61) )
389 colorspace = OC_CS_ITU_REC_470M;
391 colorspace = OC_CS_UNSPECIFIED;
393 if( asset->theora_fix_bitrate ) {
394 bitrate = asset->theora_bitrate;
399 quality = asset->theora_quality; // 0-63
401 keyframe_period = asset->theora_keyframe_frequency;
402 keyframe_force = asset->theora_keyframe_force_frequency;
406 ti.frame_width = frame_w;
407 ti.frame_height = frame_h;
408 ti.pic_width = pic_w;
409 ti.pic_height = pic_h;
412 ti.colorspace = (th_colorspace)colorspace;
413 ti.pixel_fmt = (th_pixel_fmt)pixfmt;
414 ti.target_bitrate = bitrate;
415 ti.quality = quality;
416 ti.fps_numerator = fps_num;
417 ti.fps_denominator = fps_den;
418 ti.aspect_numerator = aratio_num;
419 ti.aspect_denominator = aratio_den;
420 ti.keyframe_granule_shift = ilog(keyframe_period-1);
422 enc = th_encode_alloc(&ti);
423 int ret = enc ? 0 : 1;
424 if( !ret && force_keyframes )
425 ret = th_encode_ctl(enc,TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
426 &keyframe_period, sizeof(keyframe_period));
427 if( !ret && vp3_compatible )
428 ret = th_encode_ctl(enc,TH_ENCCTL_SET_VP3_COMPATIBLE,
429 &vp3_compatible, sizeof(vp3_compatible));
430 if( !ret && soft_target ) {
431 int arg = TH_RATECTL_CAP_UNDERFLOW;
432 if( th_encode_ctl(enc, TH_ENCCTL_SET_RATE_FLAGS, &arg, sizeof(arg)) < 0 ) {
433 eprintf(_("Could not set rate flags"));
436 int kr = keyframe_period*7>>1, fr = 5*fps_num/fps_den;
437 arg = kr > fr ? kr : fr;
438 if( th_encode_ctl(enc, TH_ENCCTL_SET_RATE_BUFFER, &arg, sizeof(arg)) ) {
439 eprintf(_("Could not set rate buffer"));
444 eprintf(_("theora init context failed"));
448 th_comment_init(&tc);
449 th_comment_add_tag(&tc, (char*)"ENCODER",
450 (char*)PROGRAM_NAME " " CINELERRA_VERSION);
453 ret = th_encode_flushheader(enc, &tc, &op);
454 if( ret <= 0 ) return 1;
455 ogg_stream_packetin(&to, &op);
456 ret = ogg_stream_pageout(&to, &og) != 1 ? 1 : 0;
458 fwrite(og.header, 1, og.header_len, out);
459 fwrite(og.body, 1, og.body_len, out);
462 eprintf(_("write header out failed"));
465 while( (ret=th_encode_flushheader(enc, &tc, &op)) > 0 )
466 ogg_stream_packetin(&to, &op);
468 eprintf(_("ogg_encoder_init video failed"));
474 int FileOGG::encode_vorbis_init()
476 ach = asset->channels;
477 ahz = asset->sample_rate;
478 amx = asset->vorbis_max_bitrate;
479 amn = asset->vorbis_min_bitrate;
480 abr = asset->vorbis_bitrate;
481 avbr = asset->vorbis_vbr;
485 ogg_stream_init(&vo, rand());
486 vorbis_info_init(&vi);
489 ret = vorbis_encode_setup_managed(&vi, ach, ahz, -1, abr, -1);
491 ret = vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, 0);
493 ret = vorbis_encode_setup_init(&vi);
496 ret = vorbis_encode_init(&vi, ach, ahz, amx, abr, amn);
498 eprintf(_("ogg_encoder_init audio init failed"));
501 vorbis_comment_init(&vc);
502 vorbis_comment_add_tag(&vc, (char*)"ENCODER",
503 (char*)PROGRAM_NAME " " CINELERRA_VERSION);
504 vorbis_analysis_init(&vd, &vi);
505 vorbis_block_init(&vd, &vb);
507 ogg_packet header_comm;
508 ogg_packet header_code;
509 vorbis_analysis_headerout(&vd, &vc,
510 &header, &header_comm, &header_code);
511 ogg_stream_packetin(&vo, &header);
513 ret = ogg_stream_pageout(&vo, &og)==1 ? 0 : -1;
515 fwrite(og.header, 1, og.header_len, out);
516 fwrite(og.body, 1, og.body_len, out);
517 ogg_stream_packetin(&vo, &header_comm);
518 ogg_stream_packetin(&vo, &header_code);
521 eprintf(_("ogg_encoder_init audio failed"));
527 int FileOGG::ogg_init_encode(FILE *out)
531 video = asset->video_data;
532 if( video && encode_theora_init() )
534 audio = asset->audio_data;
535 if( audio && encode_vorbis_init() )
539 if( !ret && video ) {
540 while( (ret=ogg_stream_flush(&to, &og)) > 0 ) {
541 fwrite(og.header, 1, og.header_len, out);
542 fwrite(og.body, 1, og.body_len, out);
545 if( !ret && audio ) {
546 while( (ret=ogg_stream_flush(&vo, &og)) > 0 ) {
547 fwrite(og.header, 1, og.header_len, out);
548 fwrite(og.body, 1, og.body_len, out);
552 eprintf(_("render init failed"));
558 int FileOGG::decode_theora_init()
560 dec = th_decode_alloc(&ti, ts);
562 eprintf(_("Error in probe data"));
565 keyframe_granule_shift = ti.keyframe_granule_shift;
566 iframe_granule_offset = th_granule_frame(dec, 0);
567 double fps = (double)ti.fps_numerator/ti.fps_denominator;
569 videosync = new sync_window_t(inp, file_lock, file_begin, file_end);
571 int ret = videosync->ogg_get_first_page(to.serialno, &og);
573 eprintf(_("cannot read video page from file"));
576 videosync->file_begin = videosync->pagpos;
577 ret = videosync->ogg_get_first_page(to.serialno, &og);
578 // video data starts here
579 // get to the page of the finish of the first packet
580 while( ret > 0 && !ogg_page_packets(&og) ) {
581 if( ogg_page_granulepos(&og) != -1 ) {
582 printf(_("FileOGG: Broken ogg file - broken page:"
583 " ogg_page_packets == 0 and granulepos != -1\n"));
586 ret = videosync->ogg_get_next_page(to.serialno, &og);
588 // video frames start here
589 start_frame = ogg_frame_pos(&og);
590 ret = videosync->ogg_get_first_page(to.serialno, &og);
592 printf(_("FileOGG: Cannot read data past header\n"));
595 //printf("start frame = %jd, gpos %jd, begins %jd\n",
596 // start_frame, ogg_page_granulepos(&og), videosync->file_begin);
598 ret = videosync->ogg_get_last_page(to.serialno, &og);
599 while( ret > 0 && !ogg_page_packets(&og) )
600 ret = videosync->ogg_get_prev_page(to.serialno, &og);
602 last_frame = ogg_next_frame_pos(&og);
603 if( start_frame >= last_frame ) {
604 eprintf(_("no video frames in file"));
605 last_frame = start_frame = 0;
607 asset->video_length = last_frame - start_frame;
610 printf("FileOGG: Cannot find the video length\n");
614 asset->width = ti.pic_width;
615 asset->height = ti.pic_height;
616 // Don't want a user configured frame rate to get destroyed
617 if( !asset->frame_rate )
618 asset->frame_rate = fps;
619 // All theora material is noninterlaced by definition
620 if( !asset->interlace_mode )
621 asset->interlace_mode = ILACE_MODE_NOTINTERLACED;
623 set_video_position(0); // make sure seeking is done to the first sample
624 ogg_frame_position = -10;
625 asset->video_data = 1;
626 strncpy(asset->vcodec, "theo", 4);
627 // report_colorspace(&ti);
628 // dump_comments(&tc);
632 int FileOGG::decode_vorbis_init()
634 ogg_stream_reset(&vo);
635 vorbis_synthesis_init(&vd, &vi);
636 vorbis_block_init(&vd, &vb);
637 audiosync = new sync_window_t(inp, file_lock, file_begin, file_end);
639 int ret = audiosync->ogg_get_first_page(vo.serialno, &og);
641 eprintf(_("cannot read audio page from file"));
644 // audio data starts here
645 audiosync->file_begin = audiosync->pagpos;
646 // audio samples starts here
647 start_sample = ogg_sample_pos(&og);
648 //printf("start sample = %jd, gpos %jd, begins %jd\n",
649 // start_sample, ogg_page_granulepos(&og), audiosync->file_begin);
650 ret = audiosync->ogg_get_last_page(vo.serialno, &og);
651 last_sample = ret > 0 ? ogg_next_sample_pos(&og) : 0;
652 asset->audio_length = last_sample - start_sample;
653 if( asset->audio_length <= 0 ) {
654 eprintf(_("no audio samples in file"));
655 asset->audio_length = 0;
656 last_sample = start_sample;
659 asset->channels = vi.channels;
660 if( !asset->sample_rate )
661 asset->sample_rate = vi.rate;
662 asset->audio_data = 1;
664 ogg_sample_position = -10;
665 set_audio_position(0); // make sure seeking is done to the first sample
666 strncpy(asset->acodec, "vorb", 4);
670 int FileOGG::ogg_init_decode(FILE *inp)
674 struct stat file_stat; /* get file length */
675 file_end = stat(asset->path, &file_stat)>=0 ? file_stat.st_size : 0;
676 if( file_end < mn_pagesz ) return 1;
677 fseek(inp, 0, SEEK_SET);
678 vorbis_info_init(&vi);
679 vorbis_comment_init(&vc);
680 th_comment_init(&tc);
684 sync_window_t sy(inp, file_lock, 0, file_end);
685 int ret = sy.ogg_read_buffer_at(0, READ_SIZE);
686 if( ret < mn_pagesz ) return 1;
687 if( !sy.ogg_sync_and_take_page_out(&og) ) return 1;
688 ogg_stream_state tst;
690 while( ogg_page_bos(&og) ) {
691 ogg_stream_init(&tst, ogg_page_serialno(&og));
692 ogg_stream_pagein(&tst, &og);
693 if( ogg_stream_packetout(&tst, &op) ) {
694 if( !video && th_decode_headerin(&ti, &tc, &ts, &op) >=0 ) {
695 ogg_stream_init(&to, ogg_page_serialno(&og));
698 else if( !audio && vorbis_synthesis_headerin(&vi, &vc, &op) >=0 ) {
699 ogg_stream_init(&vo, ogg_page_serialno(&og));
703 ogg_stream_clear(&tst);
704 ret = sy.ogg_take_page_out_autoadvance(&og);
707 if( !ret || !video && !audio )
710 // expecting more a/v header packets
711 int vpkts = video ? 2 : 0;
712 int apkts = audio ? 2 : 0;
715 while( --retries >= 0 && !ret && (vpkts || apkts) ) {
716 if( vpkts && ogg_page_serialno(&og) == to.serialno ) {
717 ogg_stream_init(&tst, to.serialno);
718 ogg_stream_pagein(&tst, &og);
719 while( !ret && vpkts > 0 ) {
720 while( (ret=ogg_stream_packetout(&tst, &op)) < 0 );
723 ret = !th_decode_headerin(&ti, &tc, &ts, &op) ? 1 : 0;
726 printf("theora header error\n");
727 ogg_stream_clear(&tst);
729 else if( apkts && ogg_page_serialno(&og) == vo.serialno ) {
730 ogg_stream_init(&tst, vo.serialno);
731 ogg_stream_pagein(&tst, &og);
732 while( !ret && apkts > 0 ) {
733 while( (ret=ogg_stream_packetout(&tst, &op)) < 0 );
736 ret = vorbis_synthesis_headerin(&vi, &vc, &op) ? 1 : 0;
739 printf("vorbis header error\n");
740 ogg_stream_clear(&tst);
742 if( !ret && !sy.ogg_take_page_out_autoadvance(&og) )
745 printf("incomplete headers\n");
748 // find first start packet (not continued) with data
749 int64_t start_pos = sy.bufpos - (og.header_len + og.body_len);
751 while( --retries >= 0 && !ret && !ogg_page_packets(&og) ) {
752 if( !ogg_page_continued(&og) )
753 start_pos = sy.bufpos - (og.header_len + og.body_len);
754 if( !sy.ogg_take_page_out_autoadvance(&og) ) ret = 1;
757 printf("no data past headers\n");
759 printf("missed %d audio headers\n",apkts);
761 printf("missed %d video headers\n",vpkts);
763 if( retries < 0 || ret || (audio && apkts) || (video && vpkts) ) {
764 eprintf(_("Error in headers"));
768 file_begin = start_pos;
770 if( video && decode_theora_init() )
772 if( audio && decode_vorbis_init() )
777 void FileOGG::close_encoder()
781 write_samples_vorbis(0, 0, 1);
783 write_frames_theora(0, 1, 1);
787 vorbis_block_clear(&vb);
788 vorbis_dsp_clear(&vd);
789 vorbis_comment_clear(&vc);
790 vorbis_info_clear(&vi);
791 ogg_stream_clear(&vo);
795 th_comment_clear(&tc);
796 ogg_stream_clear(&to);
809 void FileOGG::close_decoder()
812 for( int i=0; i<pcm_channels; ++i )
813 delete [] pcm_history[i];
815 delete [] pcm_history; pcm_history = 0;
817 vorbis_dsp_clear(&vd);
818 vorbis_info_clear(&vi);
819 vorbis_block_clear(&vb);
820 vorbis_comment_clear(&vc);
821 ogg_stream_clear(&vo);
822 delete audiosync; audiosync = 0;
827 th_setup_free(ts); ts = 0;
828 th_comment_clear(&tc);
829 ogg_stream_clear(&to);
830 delete videosync; videosync = 0;
845 void FileOGG::get_parameters(BC_WindowBase *parent_window, Asset *asset,
846 BC_WindowBase* &format_window, int audio_options,
847 int video_options, EDL *edl)
851 OGGConfigAudio *window = new OGGConfigAudio(parent_window, asset);
852 format_window = window;
853 window->create_objects();
854 window->run_window();
860 OGGConfigVideo *window = new OGGConfigVideo(parent_window, asset);
861 format_window = window;
862 window->create_objects();
863 window->run_window();
870 int sync_window_t::ogg_take_page_out_autoadvance(ogg_page *og)
873 int ret = ogg_sync_pageout(this, og);
875 printf("FileOGG: Lost sync reading input file\n");
879 bufpos += og->header_len + og->body_len;
882 // need more data for page
883 if( !ogg_read_buffer(READ_SIZE) ) {
884 printf("FileOGG: Read past end of input file\n");
885 return 0; // No more data
892 int FileOGG::check_sig(Asset *asset)
894 FILE *fp = fopen(asset->path, "rb");
897 fseek(fp, 0, SEEK_SET);
899 int ret = fread(data, 4, 1, fp) == 1 &&
900 data[0] == 'O' && data[1] == 'g' &&
901 data[2] == 'g' && data[3] == 'S' ? 1 : 0;
907 int FileOGG::open_file(int rd, int wr)
911 if( !(out = fopen(asset->path, "wb")) ) {
912 eprintf(_("Error while opening %s for writing. %m\n"), asset->path);
915 if( (ret = ogg_init_encode(out)) && out ) {
916 fclose(out); out = 0;
920 if( !(inp = fopen(asset->path, "rb")) ) {
921 eprintf(_("Error while opening %s for reading. %m\n"), asset->path);
924 if( (ret = ogg_init_decode(inp)) && inp ) {
925 fclose(inp); inp = 0;
931 int FileOGG::close_file()
941 int64_t FileOGG::ogg_sample_pos(ogg_page *og)
945 ogg_stream_init(&ss, vo.serialno);
946 ogg_stream_pagein(&ss, og);
950 while( (ret=ogg_stream_packetout(&ss, &op)) ) {
951 if( ret < 0 ) continue; // ignore holes
952 long sz = vorbis_packet_blocksize(&vi, &op);
953 if( prev != -1 ) bsz += (prev + sz) >> 2;
956 ogg_stream_clear(&ss);
957 return ogg_next_sample_pos(og) - bsz;
960 int64_t FileOGG::ogg_next_sample_pos(ogg_page *og)
962 return ogg_page_granulepos(og);
965 int64_t FileOGG::ogg_frame_pos(ogg_page *og)
967 int64_t pos = th_granule_frame(dec, ogg_page_granulepos(og)) - ogg_page_packets(og);
968 if( ogg_page_continued(og) ) --pos;
972 int64_t FileOGG::ogg_next_frame_pos(ogg_page *og)
974 return th_granule_frame(dec, ogg_page_granulepos(og)) + 1;
978 int FileOGG::ogg_get_page_of_sample(ogg_page *og, int64_t sample)
980 if( sample >= asset->audio_length + start_sample ) {
981 printf(_("FileOGG: Illegal seek beyond end of samples\n"));
984 // guess about position
985 int64_t file_length = audiosync->file_end - audiosync->file_begin;
986 off_t guess = file_length * (sample - start_sample) /
987 asset->audio_length - SEEK_SIZE;
988 if( guess < 0 ) guess = 0;
989 guess += audiosync->file_begin;
990 audiosync->ogg_read_buffer_at(guess, READ_SIZE);
991 if( !audiosync->ogg_sync_and_get_next_page(vo.serialno, og) ) {
992 printf(_("FileOGG: llegal seek no pages\n"));
996 while( ret && (ogg_page_granulepos(og) == -1 || !ogg_page_packets(og)) )
997 ret = videosync->ogg_get_next_page(to.serialno, og);
999 // linear seek to the sample
1000 int missp = 0, missm = 0;
1001 int64_t next_pos = ogg_next_sample_pos(og);
1002 if( sample >= next_pos ) { // scan forward
1003 while( sample >= next_pos ) {
1004 while( !(ret=audiosync->ogg_get_next_page(vo.serialno, og)) &&
1005 (ogg_page_granulepos(og) == -1 || !ogg_page_packets(og)) );
1007 next_pos = ogg_next_sample_pos(og);
1009 //printf("audio %jd next %jd %jd\n", sample, ogg_sample_pos(og), next_pos);
1012 else { // scan backward
1013 int64_t pos = ogg_sample_pos(og);
1014 while( sample < pos ) {
1015 while( (ret=audiosync->ogg_get_prev_page(vo.serialno, og)) &&
1016 (ogg_page_continued(og) && ogg_page_packets(og) == 1) );
1019 pos = ogg_sample_pos(og);
1020 //printf("audio %jd prev %jd %jd\n", sample, pos, ogg_next_sample_pos(og));
1023 //printf("audio %d seek %jd, missp %d, missm %d from %jd to %jd\n", ret,
1024 // sample, missp, missm, ogg_sample_pos(og), ogg_next_sample_pos(og));
1028 int FileOGG::ogg_seek_to_sample(int64_t ogg_sample)
1032 if( !ogg_get_page_of_sample(&og, ogg_sample) ) {
1033 eprintf(_("Seeking to sample's page failed\n"));
1037 int64_t pos = ogg_sample_pos(&og);
1038 int64_t next_pos = pos;
1039 if( ogg_page_continued(&og) ) {
1040 while( (ret=audiosync->ogg_get_prev_page(to.serialno, &og)) &&
1041 (ogg_page_packets(&og) == 0 && ogg_page_continued(&og)) );
1045 ogg_stream_reset(&vo);
1046 ogg_stream_pagein(&vo, &og);
1047 vorbis_synthesis_restart(&vd);
1048 ret = ogg_get_audio_packet(&op);
1050 if( ret && !vorbis_synthesis(&vb, &op) ) {
1051 vorbis_synthesis_blockin(&vd, &vb);
1052 if( vorbis_synthesis_pcmout(&vd, 0) )
1056 eprintf(_("Something wrong while trying to seek\n"));
1060 while( ogg_sample > next_pos ) {
1061 if( !(ret=ogg_get_audio_packet(&op)) ) break;
1062 if( vorbis_synthesis(&vb, &op) ) continue;
1063 vorbis_synthesis_blockin(&vd, &vb);
1065 next_pos += vorbis_synthesis_pcmout(&vd, NULL);
1066 if( next_pos > ogg_sample ) break;
1067 // discard decoded data before current sample
1068 vorbis_synthesis_read(&vd, (next_pos - pos));
1071 audio_pos = next_pos;
1072 vorbis_synthesis_read(&vd, (ogg_sample - pos));
1078 int FileOGG::ogg_get_page_of_frame(ogg_page *og, int64_t frame)
1080 if( frame >= asset->video_length + start_frame ) {
1081 eprintf(_("Illegal seek beyond end of frames\n"));
1084 if( frame < start_frame ) {
1085 eprintf(_("Illegal seek before start of frames\n"));
1088 int64_t file_length = videosync->file_end - videosync->file_begin;
1089 off_t guess = file_length * (frame - start_frame) /
1090 asset->video_length - SEEK_SIZE;
1091 if( guess < 0 ) guess = 0;
1092 guess += videosync->file_begin;
1093 videosync->ogg_read_buffer_at(guess, SEEK_SIZE);
1094 videosync->ogg_sync_and_get_next_page(to.serialno, og);
1095 // find the page with "real" ending
1097 while( ret && (ogg_page_granulepos(og) == -1 || !ogg_page_packets(og)) )
1098 ret = videosync->ogg_get_next_page(to.serialno, og);
1099 int64_t pos = ogg_next_frame_pos(og);
1101 int missp = 0, missm = 0;
1102 // move back if continued
1103 if( frame >= pos ) {
1104 do { // scan forward
1105 while( (ret=videosync->ogg_get_next_page(to.serialno, og)) &&
1106 ogg_page_packets(og) == 0 );
1109 pos = ogg_next_frame_pos(og);
1110 //printf("video %jd next %jd %jd\n", frame, ogg_frame_pos(og), pos);
1111 } while( frame >= pos );
1113 else if( (pos=ogg_frame_pos(og)) > frame ) {
1114 while( pos > start_frame && frame < pos ) { // scan backward
1115 while( (ret=videosync->ogg_get_prev_page(to.serialno, og)) &&
1116 ogg_page_packets(og) == 0 && ogg_page_continued(og) );
1119 pos = ogg_frame_pos(og);
1120 //printf("video %jd next %jd %jd\n", frame, pos, ogg_next_frame_pos(og));
1123 //printf("video %d seek %jd, missp %d, missm %d first %jd, next %jd\n", ret,
1124 // frame, missp, missm, ogg_frame_pos(og), ogg_next_frame_pos(og));
1128 int FileOGG::ogg_seek_to_keyframe(int64_t frame, int64_t *keyframe_number)
1130 //printf("ogg_seek_to_keyframe of === %jd\n", frame);
1133 int64_t ipagpos = -1;
1134 int64_t istart = -1;
1135 int64_t iframe = -1;
1137 int retries = 1000, ret = 1;
1138 while( --retries>=0 && frame>=start_frame ) {
1139 if( !ogg_get_page_of_frame(&og, frame) ) break;
1140 int64_t pos = ogg_frame_pos(&og);
1142 if( ogg_page_continued(&og) ) {
1143 while( (ret=videosync->ogg_get_prev_page(to.serialno, &og)) &&
1144 (ogg_page_packets(&og) == 0 && ogg_page_continued(&og)) );
1146 int64_t pagpos = videosync->pagpos;
1148 ogg_stream_reset(&to);
1149 ogg_stream_pagein(&to, &og);
1151 while( frame >= pos && (ret=ogg_get_video_packet(&op)) ) {
1152 if( th_packet_iskeyframe(&op) == 1 ) {
1156 //printf("keyframe %jd pkts %d\n", pos, pkts);
1158 //printf("packet %jd pkts %d is a %d\n", pos, pkts, th_packet_iskeyframe(&op));
1161 if( ipagpos >= 0 ) break;
1165 printf(_("Seeking to keyframe %jd search failed\n"), frame);
1168 videosync->ogg_read_buffer_at(ipagpos, READ_SIZE);
1169 videosync->ogg_sync_and_get_next_page(to.serialno, &og);
1171 ogg_stream_reset(&to);
1172 ogg_stream_pagein(&to, &og);
1173 video_pos = ogg_next_frame_pos(&og);
1174 // skip prev packets
1175 // int ipkts = iframe - ogg_frame_pos(&og);
1176 //printf("iframe %jd, page %jd, ipkts %d\n", iframe, ogg_page_pageno(&og), ipkts);
1177 while( --ipkts >= 0 )
1178 ogg_get_video_packet(&op);
1179 *keyframe_number = iframe;
1184 int64_t FileOGG::get_video_position()
1187 return next_frame_position - start_frame;
1190 int64_t FileOGG::get_audio_position()
1192 return next_sample_position - start_sample;
1195 int FileOGG::set_video_position(int64_t x)
1198 // printf("SVP: %lli\n", x);
1200 next_frame_position = x + start_frame;
1205 int FileOGG::colormodel_supported(int colormodel)
1209 if (colormodel == BC_YUV420P)
1214 int FileOGG::get_best_colormodel(Asset *asset, int driver)
1220 int FileOGG::set_audio_position(int64_t x)
1222 next_sample_position = x + start_sample;
1227 int FileOGG::ogg_get_video_packet(ogg_packet *op)
1230 while( (ret=ogg_stream_packetout(&to, op)) <= 0 ) {
1231 if( video_eos ) return 0;
1233 if( !videosync->ogg_get_next_page(to.serialno, &og) ) break;
1234 if( ogg_page_granulepos(&og) >= 0 )
1235 video_pos = ogg_next_frame_pos(&og);
1236 ogg_stream_pagein(&to, &og);
1237 video_eos = ogg_page_eos(&og);
1240 printf("FileOGG: Cannot read video packet\n");
1246 int FileOGG::read_frame(VFrame *frame)
1248 if( !inp || !video ) return 1;
1249 // skip is cheaper than seek, do it...
1250 int decode_frames = 0;
1251 int expect_keyframe = 0;
1252 if( ogg_frame_position >= 0 &&
1253 next_frame_position >= ogg_frame_position &&
1254 next_frame_position - ogg_frame_position < 32) {
1255 decode_frames = next_frame_position - ogg_frame_position;
1257 else if( next_frame_position != ogg_frame_position ) {
1258 if( !ogg_seek_to_keyframe(next_frame_position, &ogg_frame_position) ) {
1259 eprintf(_("Error while seeking to frame's keyframe"
1260 " (frame: %jd, keyframe: %jd)\n"),
1261 next_frame_position, ogg_frame_position);
1264 decode_frames = next_frame_position - ogg_frame_position + 1;
1265 --ogg_frame_position;
1266 if( decode_frames <= 0 ) {
1267 eprintf(_("Error while seeking to keyframe,"
1268 " wrong keyframe number (frame: %jd, keyframe: %jd)\n"),
1269 next_frame_position, ogg_frame_position);
1273 expect_keyframe = 1;
1277 while( decode_frames > 0 ) {
1278 if( !ogg_get_video_packet(&op) ) break;
1279 if( expect_keyframe ) {
1280 expect_keyframe = 0;
1281 if( th_packet_iskeyframe(&op) <= 0 )
1282 eprintf(_("FileOGG: Expecting keyframe, but didn't get it\n"));
1284 ogg_int64_t granpos = 0;
1285 if( th_decode_packetin(dec, &op, &granpos) >= 0 )
1287 ++ogg_frame_position;
1290 //if(ret < 0 )printf("ret = %d\n", ret);
1292 th_ycbcr_buffer ycbcr;
1293 ret = th_decode_ycbcr_out(dec, ycbcr);
1295 eprintf(_("th_decode_ycbcr_out failed with code %i\n"), ret);
1296 ret = 0; // not always fatal
1298 uint8_t *yp = ycbcr[0].data;
1299 uint8_t *up = ycbcr[1].data;
1300 uint8_t *vp = ycbcr[2].data;
1301 int yst = ycbcr[0].stride;
1302 int yw = ycbcr[0].width;
1303 int yh = ycbcr[0].height;
1304 VFrame temp_frame(yp, -1, 0, up-yp, vp-yp, yw,yh, BC_YUV420P, yst);
1305 int px = ti.pic_x, py = ti.pic_y;
1306 int pw = ti.pic_width, ph = ti.pic_height;
1307 frame->transfer_from(&temp_frame, -1, px, py, pw, ph);
1310 next_frame_position++;
1315 int FileOGG::ogg_get_audio_packet(ogg_packet *op)
1318 while( (ret=ogg_stream_packetout(&vo, op)) <= 0 ) {
1319 if( audio_eos ) return 0;
1321 if( !audiosync->ogg_get_next_page(vo.serialno, &og) ) break;
1322 if( ogg_page_granulepos(&og) >= 0 )
1323 audio_pos = ogg_next_sample_pos(&og);
1324 ogg_stream_pagein(&vo, &og);
1325 audio_eos = ogg_page_eos(&og);
1328 printf("FileOGG: Cannot read audio packet\n");
1334 int FileOGG::ogg_decode_more_samples()
1337 while( ogg_get_audio_packet(&op) ) {
1338 if( !vorbis_synthesis(&vb, &op) ) {
1339 vorbis_synthesis_blockin(&vd, &vb);
1343 ogg_sample_position = -11;
1344 eprintf(_("Cannot find next page while trying to decode more samples\n"));
1348 int FileOGG::move_history(int from, int to, int len)
1351 for( int i=0; i<asset->channels; ++i )
1352 memmove(pcm_history[i] + to,
1353 pcm_history[i] + from,
1354 sizeof(float) * len);
1356 history_start = history_start + from - to;
1357 if( history_start < 0 ) history_start = 0;
1361 int FileOGG::read_samples(double *buffer, int64_t len)
1363 float **vorbis_buffer;
1366 if( len > HISTORY_MAX ) {
1367 eprintf(_("max samples=%d\n"), HISTORY_MAX);
1371 if( !pcm_history ) {
1372 pcm_history = new float*[asset->channels];
1373 for(int i = 0; i < asset->channels; i++)
1374 pcm_history[i] = new float[HISTORY_MAX];
1375 history_start = -100000000;
1379 int64_t hole_start = -1;
1380 int64_t hole_len = -1;
1381 int64_t hole_absstart = -1;
1382 int64_t hole_fill = 0;
1384 if( history_start < next_sample_position &&
1385 history_start + history_size > next_sample_position &&
1386 history_start + history_size < next_sample_position + len ) {
1388 hole_start = history_start + history_size - next_sample_position;
1389 hole_len = history_size - hole_start;
1390 hole_absstart = next_sample_position + hole_start;
1391 move_history(next_sample_position - history_start, 0, hole_start);
1393 else if( next_sample_position < history_start &&
1394 history_start < next_sample_position + len ) {
1397 hole_len = history_start - next_sample_position;
1398 hole_absstart = next_sample_position;
1400 history_start - next_sample_position,
1401 history_size - history_start + next_sample_position);
1404 else if( next_sample_position >= history_start + history_size ||
1405 next_sample_position + len <= history_start ) {
1408 hole_len = HISTORY_MAX;
1409 hole_absstart = next_sample_position;
1410 history_start = hole_absstart;
1411 history_size = hole_len;
1415 if( hole_start < 0 || hole_len <= 0 || hole_absstart < 0 ) {
1416 eprintf(_("Error in finding read file position\n"));
1420 if( hole_absstart + hole_len > asset->audio_length + start_sample ) {
1421 hole_len = asset->audio_length + start_sample - hole_absstart;
1422 history_size = asset->audio_length + start_sample - history_start;
1425 history_size = HISTORY_MAX;
1428 int64_t samples_read = 0;
1429 if( ogg_sample_position != hole_absstart ) {
1430 ogg_sample_position = hole_absstart;
1431 if( !ogg_seek_to_sample(ogg_sample_position) ) {
1432 eprintf(_("Error while seeking to sample\n"));
1436 // now we have ogg_sample_positon aligned
1437 int64_t samples_to_read = hole_len;
1438 while( samples_read < hole_len ) {
1439 int64_t samples_waiting = vorbis_synthesis_pcmout(&vd, &vorbis_buffer);
1440 int64_t samples_avail = !samples_waiting && audio_eos ?
1441 hole_len - samples_read : // silence after eos
1443 int64_t sample_demand = samples_to_read - samples_read;
1444 int64_t sample_count = MIN(samples_avail, sample_demand);
1445 if( sample_count > 0 ) {
1446 int sz = sample_count*sizeof(float);
1447 if( samples_waiting ) {
1448 for( int i=0; i<asset->channels; ++i ) {
1449 float *input = vorbis_buffer[i];
1450 float *output = pcm_history[i] + hole_start;
1451 memcpy(output, input, sz);
1453 vorbis_synthesis_read(&vd, sample_count);
1456 for( int i=0; i<asset->channels; ++i ) {
1457 float *output = pcm_history[i] + hole_start;
1458 memset(output, 0, sz);
1461 ogg_sample_position += sample_count;
1462 hole_start += sample_count;
1463 samples_read += sample_count;
1464 if( samples_read >= hole_len ) break;
1466 if( samples_read < hole_len && !ogg_decode_more_samples() )
1471 if( next_sample_position < history_start ||
1472 next_sample_position + len > history_start + history_size ) {
1473 printf(_("FileOGG:: History not aligned properly \n"));
1474 printf(_("\tnext_sample_position: %jd, length: %jd\n"), next_sample_position, len);
1475 printf(_("\thistory_start: %jd, length: %jd\n"), history_start, history_size);
1478 float *input = pcm_history[file->current_channel] + next_sample_position - history_start;
1479 for (int i = 0; i < len; i++)
1480 buffer[i] = input[i];
1482 next_sample_position += len;
1487 int FileOGG::write_audio_page()
1489 int ret = apage.write_page(out);
1491 eprintf(_("error writing audio page\n"));
1495 int FileOGG::write_video_page()
1497 int ret = vpage.write_page(out);
1499 eprintf(_("error writing video page\n"));
1503 // flush out the ogg pages
1504 void FileOGG::flush_ogg(int last)
1507 file_lock->lock("FileOGG::flush_ogg");
1509 // this way seeking is much better, (per original fileogg)
1510 // not sure if 32 packets is a good value.
1512 if( video && !vpage.valid ) {
1513 if( (vpage.packets > mx_pkts && ogg_stream_flush(&to, &og) > 0) ||
1514 ogg_stream_pageout(&to, &og) > 0 ) {
1515 videotime = th_granule_time(enc, vpage.load(&og));
1518 if( audio && !apage.valid ) {
1519 if( (apage.packets > mx_pkts && ogg_stream_flush(&vo, &og) > 0) ||
1520 ogg_stream_pageout(&vo, &og) > 0 ) {
1521 audiotime = vorbis_granule_time(&vd, apage.load(&og));
1524 if( !audio && vpage.valid )
1526 else if( !video && apage.valid )
1528 else if( !vpage.valid || !apage.valid )
1530 // output earliest page
1531 else if( videotime > audiotime ) // output earliest
1536 if( last ) { // at last
1542 file_lock->unlock();
1546 int FileOGG::write_samples_vorbis(double **buffer, int64_t len, int last)
1548 if( !audio || !out ) return 1;
1551 float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
1552 for( int i=0; i<asset->channels; ++i ) // double to float
1553 for( int j=0; j < len; ++j )
1554 vorbis_buffer[i][j] = buffer[i][j];
1558 vorbis_analysis_wrote(&vd, len);
1560 while( vorbis_analysis_blockout(&vd, &vb) == 1 ) {
1561 vorbis_analysis(&vb, 0);
1562 vorbis_bitrate_addblock(&vb);
1564 while( vorbis_bitrate_flushpacket(&vd, &op) ) {
1565 file_lock->lock("FileOGG::write_vorbis_audio");
1566 ogg_stream_packetin(&vo, &op);
1568 file_lock->unlock();
1574 int FileOGG::write_samples(double **buffer, int64_t len)
1577 return write_samples_vorbis(buffer, len, 0);
1582 int FileOGG::write_frames_theora(VFrame ***frames, int len, int last)
1584 if( !video || !out ) return 1;
1585 for( int j=0; j<len; ++j ) {
1588 th_ycbcr_buffer ycbcr;
1589 ycbcr[0].width = frame_w;
1590 ycbcr[0].height = frame_h;
1591 ycbcr[0].stride = temp_frame->get_bytes_per_line();
1592 ycbcr[0].data = temp_frame->get_y();
1593 ycbcr[1].width = frame_w/2;
1594 ycbcr[1].height = frame_h/2;
1595 ycbcr[1].stride = (temp_frame->get_bytes_per_line()+1)/2;
1596 ycbcr[1].data = temp_frame->get_u();
1597 ycbcr[2].width = frame_w/2;
1598 ycbcr[2].height = frame_h/2;
1599 ycbcr[2].stride = (temp_frame->get_bytes_per_line()+1)/2;
1600 ycbcr[2].data = temp_frame->get_v();
1601 if( th_encode_ycbcr_in(enc, ycbcr) ) {
1602 eprintf(_("th_encode_ycbcr_in failed"));
1606 while( th_encode_packetout(enc, last, &op) > 0 ) {
1608 ogg_stream_packetin (&to, &op);
1610 file_lock->unlock();
1613 if( last ) return 0;
1615 temp_frame = new VFrame (0, -1, frame_w, frame_h, theora_cmodel, -1);
1616 VFrame *frame = frames[0][j];
1617 temp_frame->transfer_from(frame);
1622 int FileOGG::write_frames(VFrame ***frames, int len)
1624 return write_frames_theora(frames, len, 0);
1629 OGGConfigAudio::OGGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
1630 : BC_Window(PROGRAM_NAME ": Audio Compression",
1631 parent_window->get_abs_cursor_x(1),
1632 parent_window->get_abs_cursor_y(1),
1635 this->parent_window = parent_window;
1636 this->asset = asset;
1637 // *** CONTEXT_HELP ***
1638 context_help_set_keyword("Single File Rendering");
1641 OGGConfigAudio::~OGGConfigAudio()
1646 void OGGConfigAudio::create_objects()
1648 // add_tool(new BC_Title(10, 10, _("There are no audio options for this format")));
1650 int x = xS(10), y = yS(10);
1652 char string[BCTEXTLEN];
1654 lock_window("OGGConfigAudio::create_objects");
1655 add_tool(fixed_bitrate = new OGGVorbisFixedBitrate(x, y, this));
1656 add_tool(variable_bitrate = new OGGVorbisVariableBitrate(x + fixed_bitrate->get_w() + xS(5),
1661 sprintf(string, "%d", asset->vorbis_min_bitrate);
1662 add_tool(new BC_Title(x, y, _("Min bitrate:")));
1663 add_tool(new OGGVorbisMinBitrate(x1, y, this, string));
1666 add_tool(new BC_Title(x, y, _("Avg bitrate:")));
1667 sprintf(string, "%d", asset->vorbis_bitrate);
1668 add_tool(new OGGVorbisAvgBitrate(x1, y, this, string));
1671 add_tool(new BC_Title(x, y, _("Max bitrate:")));
1672 sprintf(string, "%d", asset->vorbis_max_bitrate);
1673 add_tool(new OGGVorbisMaxBitrate(x1, y, this, string));
1676 add_subwindow(new BC_OKButton(this));
1681 int OGGConfigAudio::close_event()
1687 OGGVorbisFixedBitrate::OGGVorbisFixedBitrate(int x, int y, OGGConfigAudio *gui)
1688 : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Average bitrate"))
1692 int OGGVorbisFixedBitrate::handle_event()
1694 gui->asset->vorbis_vbr = 0;
1695 gui->variable_bitrate->update(0);
1699 OGGVorbisVariableBitrate::OGGVorbisVariableBitrate(int x, int y, OGGConfigAudio *gui)
1700 : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
1704 int OGGVorbisVariableBitrate::handle_event()
1706 gui->asset->vorbis_vbr = 1;
1707 gui->fixed_bitrate->update(0);
1712 OGGVorbisMinBitrate::OGGVorbisMinBitrate(int x,
1714 OGGConfigAudio *gui,
1716 : BC_TextBox(x, y, xS(180), 1, text)
1720 int OGGVorbisMinBitrate::handle_event()
1722 gui->asset->vorbis_min_bitrate = atol(get_text());
1728 OGGVorbisMaxBitrate::OGGVorbisMaxBitrate(int x,
1730 OGGConfigAudio *gui,
1732 : BC_TextBox(x, y, xS(180), 1, text)
1736 int OGGVorbisMaxBitrate::handle_event()
1738 gui->asset->vorbis_max_bitrate = atol(get_text());
1744 OGGVorbisAvgBitrate::OGGVorbisAvgBitrate(int x, int y, OGGConfigAudio *gui, char *text)
1745 : BC_TextBox(x, y, xS(180), 1, text)
1749 int OGGVorbisAvgBitrate::handle_event()
1751 gui->asset->vorbis_bitrate = atol(get_text());
1759 OGGConfigVideo::OGGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
1760 : BC_Window(PROGRAM_NAME ": Video Compression",
1761 parent_window->get_abs_cursor_x(1),
1762 parent_window->get_abs_cursor_y(1),
1765 this->parent_window = parent_window;
1766 this->asset = asset;
1767 // *** CONTEXT_HELP ***
1768 context_help_set_keyword("Single File Rendering");
1771 OGGConfigVideo::~OGGConfigVideo()
1776 void OGGConfigVideo::create_objects()
1778 // add_tool(new BC_Title(10, 10, _("There are no video options for this format")));
1779 int x = xS(10), y = yS(10);
1780 int x1 = x + xS(150);
1781 int x2 = x + xS(300);
1783 lock_window("OGGConfigVideo::create_objects");
1785 add_subwindow(title = new BC_Title(x, y, _("Bitrate:")));
1786 add_subwindow(new OGGTheoraBitrate(x + title->get_w() + xS(5), y, this));
1787 add_subwindow(fixed_bitrate = new OGGTheoraFixedBitrate(x2, y, this));
1790 add_subwindow(new BC_Title(x, y, _("Quality:")));
1791 add_subwindow(new BC_ISlider(x + xS(80), y, 0, xS(200), xS(200),
1792 0, 63, asset->theora_quality,
1793 0, 0, &asset->theora_quality));
1796 add_subwindow(fixed_quality = new OGGTheoraFixedQuality(x2, y, this));
1799 add_subwindow(new BC_Title(x, y, _("Keyframe frequency:")));
1800 OGGTheoraKeyframeFrequency *keyframe_frequency =
1801 new OGGTheoraKeyframeFrequency(x1 + xS(60), y, this);
1802 keyframe_frequency->create_objects();
1805 add_subwindow(new BC_Title(x, y, _("Keyframe force frequency:")));
1806 OGGTheoraKeyframeForceFrequency *keyframe_force_frequency =
1807 new OGGTheoraKeyframeForceFrequency(x1 + xS(60), y, this);
1808 keyframe_force_frequency->create_objects();
1811 add_subwindow(new BC_Title(x, y, _("Sharpness:")));
1812 OGGTheoraSharpness *sharpness =
1813 new OGGTheoraSharpness(x1 + xS(60), y, this);
1814 sharpness->create_objects();
1818 add_subwindow(new BC_OKButton(this));
1826 int OGGConfigVideo::close_event()
1832 OGGTheoraBitrate::OGGTheoraBitrate(int x, int y, OGGConfigVideo *gui)
1833 : BC_TextBox(x, y, xS(100), 1, gui->asset->theora_bitrate)
1839 int OGGTheoraBitrate::handle_event()
1841 // TODO: MIN / MAX check
1842 gui->asset->theora_bitrate = atol(get_text());
1849 OGGTheoraFixedBitrate::OGGTheoraFixedBitrate(int x, int y, OGGConfigVideo *gui)
1850 : BC_Radial(x, y, gui->asset->theora_fix_bitrate, _("Fixed bitrate"))
1855 int OGGTheoraFixedBitrate::handle_event()
1858 gui->asset->theora_fix_bitrate = 1;
1859 gui->fixed_quality->update(0);
1863 OGGTheoraFixedQuality::OGGTheoraFixedQuality(int x, int y, OGGConfigVideo *gui)
1864 : BC_Radial(x, y, !gui->asset->theora_fix_bitrate, _("Fixed quality"))
1869 int OGGTheoraFixedQuality::handle_event()
1872 gui->asset->theora_fix_bitrate = 0;
1873 gui->fixed_bitrate->update(0);
1877 OGGTheoraKeyframeFrequency::OGGTheoraKeyframeFrequency(int x, int y, OGGConfigVideo *gui)
1878 : BC_TumbleTextBox(gui, (int64_t)gui->asset->theora_keyframe_frequency,
1879 (int64_t)1, (int64_t)500, x, y, xS(40))
1884 int OGGTheoraKeyframeFrequency::handle_event()
1886 gui->asset->theora_keyframe_frequency = atol(get_text());
1890 OGGTheoraKeyframeForceFrequency::OGGTheoraKeyframeForceFrequency(int x, int y, OGGConfigVideo *gui)
1891 : BC_TumbleTextBox(gui, (int64_t)gui->asset->theora_keyframe_frequency,
1892 (int64_t)1, (int64_t)500, x, y, xS(40))
1897 int OGGTheoraKeyframeForceFrequency::handle_event()
1899 gui->asset->theora_keyframe_frequency = atol(get_text());
1904 OGGTheoraSharpness::OGGTheoraSharpness(int x, int y, OGGConfigVideo *gui)
1905 : BC_TumbleTextBox(gui, (int64_t)gui->asset->theora_sharpness,
1906 (int64_t)0, (int64_t)2, x, y, xS(40))
1911 int OGGTheoraSharpness::handle_event()
1913 gui->asset->theora_sharpness = atol(get_text());