no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / fileogg.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
4  * Copyright (C) 2003-2016 Cinelerra CV contributors
5  *
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.
10  *
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.
15  *
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
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21 #ifdef HAVE_OGG
22
23 #include "asset.h"
24 #include "bcsignals.h"
25 #include "byteorder.h"
26 #include "clip.h"
27 #include "edit.h"
28 #include "file.h"
29 #include "fileogg.h"
30 #include "guicast.h"
31 #include "interlacemodes.h"
32 #include "language.h"
33 #include "mainerror.h"
34 #include "mutex.h"
35 #include "mwindow.inc"
36 #include "preferences.h"
37 #include "render.h"
38 #include "vframe.h"
39 #include "versioninfo.h"
40 #include "videodevice.inc"
41
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <errno.h>
48
49 /* This code was aspired by ffmpeg2theora */
50 /* Special thanks for help on this code goes out to j@v2v.cc */
51
52
53 #define READ_SIZE 4*66000
54 #define SEEK_SIZE 2*66000
55
56 sync_window_t::sync_window_t(FILE *fp, Mutex *sync_lock, int64_t begin, int64_t end)
57 {
58         ogg_sync_init(this);
59         this->fp = fp;
60         this->sync_lock = sync_lock;
61         this->file_begin = begin;
62         this->file_end = end;
63         filepos = -1;
64         bufpos = -1;
65         pagpos = -1;
66 }
67
68 sync_window_t::~sync_window_t()
69 {
70         ogg_sync_clear(this);
71 }
72
73 int sync_window_t::ogg_read_locked(int buflen)
74 {
75         char *buffer = ogg_sync_buffer(this, buflen);
76         int len = fread(buffer, 1, buflen, fp);
77         ogg_sync_wrote(this, len);
78         filepos += len;
79         return len;
80 }
81
82 int sync_window_t::ogg_read_buffer(int buflen)
83 {
84         sync_lock->lock("sync_window_t::ogg_read_buffer_at");
85         fseeko(fp, filepos, SEEK_SET);
86         int len = ogg_read_locked(buflen);
87         sync_lock->unlock();
88         return len;
89 }
90
91 int sync_window_t::ogg_read_buffer_at(off_t filepos, int buflen)
92 {
93         if( bufpos == filepos && buflen == this->filepos - bufpos )
94                 return buflen;
95         sync_lock->lock("sync_window_t::ogg_read_buffer_at");
96         this->bufpos = filepos;
97         fseeko(fp, filepos, SEEK_SET);
98         this->filepos = filepos;
99         ogg_sync_reset(this);
100         int ret = ogg_read_locked(buflen);
101         sync_lock->unlock();
102         return ret;
103 }
104
105 // we never need to autoadvance when syncing, since our read chunks are larger than
106 // maximum page size
107 int sync_window_t::ogg_sync_and_take_page_out(ogg_page *og)
108 {
109         og->header_len = 0;
110         og->body_len = 0;
111         og->header = 0;
112         og->body = 0;
113         int ret = ogg_sync_pageseek(this, og);
114         bufpos += abs(ret); // can be zero
115         return ret;
116 }
117
118 int sync_window_t::ogg_sync_and_get_next_page(long serialno, ogg_page *og)
119 {
120         int ret = 0, retries = 1000;
121         while( --retries >= 0 && (ret = ogg_sync_and_take_page_out(og)) < 0 );
122         if( ret >= mn_pagesz && ogg_page_serialno(og) != serialno )
123                 ret = ogg_get_next_page(serialno, og);
124         if( ret ) {
125                 pagpos = bufpos - (og->header_len + og->body_len);
126                 return 1;
127         }
128         return 0;
129 }
130
131 int sync_window_t::ogg_get_next_page(long serialno, ogg_page *og)
132 {
133         int ret = 0, retries = 1000;
134         while( --retries >= 0 && (ret=ogg_take_page_out_autoadvance(og)) &&
135                 ogg_page_serialno(og) != serialno );
136         if( ret ) {
137                 pagpos = bufpos - (og->header_len + og->body_len);
138 }
139         else
140                 printf("ogg_get_next_page missed\n");
141         return ret;
142 }
143
144 int sync_window_t::ogg_prev_page_search(long serialno, ogg_page *og,
145                 off_t begin, off_t end)
146 {
147         ogg_page page;
148         int retries = 100, ret = 0;
149         int64_t ppos = -1;
150         while( ppos < 0 && --retries >= 0 ) {
151                 int64_t fpos = end;
152                 int read_len = SEEK_SIZE;
153                 fpos -= read_len;
154                 if( fpos < begin ) {
155                         read_len += fpos - begin;
156                         if( read_len <= 0 ) break;
157                         fpos = begin;
158                 }
159                 read_len = ogg_read_buffer_at(fpos, read_len);
160                 if( read_len <= 0 ) return 0;
161                 while( (ret=ogg_sync_and_take_page_out(&page)) < 0 );
162                 end = bufpos;
163                 while( ret > 0 ) {
164                         if( ogg_page_serialno(&page) == serialno ) {
165                                 memcpy(og, &page, sizeof(page));
166                                 ppos = bufpos - (page.header_len + page.body_len);
167                         }
168                         ret = ogg_sync_pageout(this, &page);
169                         bufpos += page.header_len + page.body_len;
170                 }
171         }
172         if( ppos >= 0 ) {
173                 pagpos = ppos;
174                 return 1;
175         }
176         printf("ogg_prev_page_search missed\n");
177         return 0;
178 }
179
180 int sync_window_t::ogg_get_prev_page(long serialno, ogg_page *og)
181 {
182         return ogg_prev_page_search(serialno, og, file_begin, pagpos);
183 }
184
185 int sync_window_t::ogg_get_first_page(long serialno, ogg_page *og)
186 {
187         ogg_read_buffer_at(file_begin, SEEK_SIZE);
188         return ogg_sync_and_get_next_page(serialno, og);
189 }
190
191 int sync_window_t::ogg_get_last_page(long serialno, ogg_page *og)
192 {
193
194         ogg_page page;
195         off_t filepos = file_end - READ_SIZE;
196         if( filepos < 0 ) filepos = 0;
197         int ret = 0, first_page_offset = 0;
198         while( !ret && filepos >= 0 ) {
199                 int readlen = ogg_read_buffer_at(filepos, READ_SIZE);
200                 int page_offset = 0, page_length = 0;
201                 int first_page = 1; // read all pages in the buffer
202                 while( first_page || page_length ) {
203                         // if negative, skip bytes
204                         while( (page_length = ogg_sync_and_take_page_out(&page)) < 0 )
205                                 page_offset -= page_length;
206                         if( page_length < mn_pagesz ) continue;
207                         if( first_page ) {
208                                 first_page = 0;
209                                 first_page_offset = page_offset;
210                         }
211                         if( ogg_page_serialno(&page) == serialno ) {
212                                 // return last match page
213                                 pagpos = bufpos - (page.header_len + page.body_len);
214                                 memcpy(og, &page, sizeof(page));
215                                 ret = 1;
216                         }
217                 }
218                 filepos -= readlen - first_page_offset;  // move backward
219         }
220         return ret;
221 }
222
223 OGG_PageBfr::OGG_PageBfr()
224 {
225         allocated = len = 0;
226         valid = packets = 0;
227         position = 0;
228         page = 0;
229 }
230
231 OGG_PageBfr::~OGG_PageBfr()
232 {
233         delete [] page;
234 }
235
236 void OGG_PageBfr::demand(int sz)
237 {
238         if( allocated >= sz ) return;
239         uint8_t *new_page = new uint8_t[sz];
240         memcpy(new_page, page, len);
241         delete [] page;  page = new_page;
242         allocated = sz;
243 }
244
245 int OGG_PageBfr::write_page(FILE *fp)
246 {
247         int sz = fwrite(page, 1, len, fp);
248         if( sz != len ) return -1;
249         ogg_page op;  // kludgy
250         op.header = page;    op.header_len = len;
251         op.body = page+len;  op.body_len = 0;
252         packets -= ogg_page_packets(&op);
253         valid = len = 0;
254         return packets;
255 }
256
257 int64_t OGG_PageBfr::load(ogg_page *og)
258 {
259         int sz = og->header_len + og->body_len;
260         demand(sz);
261         memcpy(page, og->header, og->header_len);
262         memcpy(page+og->header_len, og->body, og->body_len);
263         len = sz;  valid = 1;
264         position = ogg_page_granulepos(og);
265         return position;
266 }
267
268
269
270 FileOGG::FileOGG(Asset *asset, File *file)
271  : FileBase(asset, file)
272 {
273         if( asset->format == FILE_UNKNOWN )
274                 asset->format = FILE_OGG;
275         asset->byte_order = 0;
276         init();
277         file_lock = new Mutex("OGGFile::Flush lock");
278 }
279
280 FileOGG::~FileOGG()
281 {
282         close_file();
283         delete file_lock;
284 }
285
286
287 void FileOGG::init()
288 {
289         inp = 0;
290         out = 0;
291         audio = 0;
292         video = 0;
293         file_length = 0;
294         temp_frame = 0;
295         file_lock = 0;
296         ach = 0;
297         ahz = 0;
298         asz = 0;
299         amn = 0;
300         amx = 0;
301         abr = 0;
302         avbr = 0;
303         aqu = 0;
304         afrmsz = 0;
305         pcm_history = 0;
306         pcm_channels = 0;
307         frame_position = 0;
308         sample_position = 0;
309         audiosync = 0;
310         videosync = 0;
311         file_begin = 0;
312         file_end = 0;
313
314         memset(&to, 0, sizeof(to));
315         memset(&vo, 0, sizeof(vo));
316         ogg_sample_position = 0;
317         ogg_frame_position = 0;
318         next_sample_position = 0;
319         next_frame_position = 0;
320         start_sample = 0;
321         last_sample = 0;
322         start_frame = 0;
323         last_frame = 0;
324         audiotime = 0;
325         videotime = 0;
326         audio_pos = 0;  audio_eos = 0;
327         video_pos = 0;  video_eos = 0;
328
329         keyframe_granule_shift = 0;
330         iframe_granule_offset = 0;
331         theora_cmodel = BC_YUV420P;
332         enc = 0;
333         dec = 0;
334         memset(&ti, 0, sizeof(ti));
335         ts = 0;
336         memset(&tc, 0, sizeof(tc));
337         memset(&vi, 0, sizeof(vi));
338         memset(&vc, 0, sizeof(vc));
339         memset(&vd, 0, sizeof(vd));
340         memset(&vb, 0, sizeof(vb));
341         force_keyframes = 0;
342         vp3_compatible = 0;
343         soft_target = 0;
344
345         pic_x = pic_y = 0;
346         pic_w = pic_h = 0;
347         frame_w = frame_h = 0;
348         colorspace = OC_CS_UNSPECIFIED;
349         pixfmt = TH_PF_420;
350         bitrate = 0;  quality = 0;
351         keyframe_period = 0;
352         keyframe_force = 0;
353         fps_num = fps_den = 0;
354         aratio_num = aratio_den = 0;
355 }
356
357
358 static int ilog(unsigned v)
359 {
360         int ret = 0;
361         while( v ) { ++ret;  v >>= 1; }
362         return ret;
363 }
364
365 int FileOGG::encode_theora_init()
366 {
367         ogg_stream_init(&to, rand());
368         th_info_init(&ti);
369         pic_w = asset->width, pic_h = asset->height;
370         frame_w = (pic_w+0x0f) & ~0x0f;
371         frame_h = (pic_h+0x0f) & ~0x0f;
372         pic_x = ((frame_w-pic_w) >> 1) & ~1;
373         pic_y = ((frame_h-pic_h) >> 1) & ~1;
374         fps_num = asset->frame_rate * 1000000;
375         fps_den = 1000000;
376         if( asset->aspect_ratio > 0 ) {
377                 // Cinelerra uses frame aspect ratio, theora uses pixel aspect ratio
378                 float pixel_aspect = asset->aspect_ratio / asset->width * asset->height;
379                 aratio_num = pixel_aspect * 1000000;
380                 aratio_den = 1000000;
381         }
382         else {
383                 aratio_num = 1000000;
384                 aratio_den = 1000000;
385         }
386         if( EQUIV(asset->frame_rate, 25) || EQUIV(asset->frame_rate, 50) )
387                 colorspace = OC_CS_ITU_REC_470BG;
388         else if( (asset->frame_rate > 29 && asset->frame_rate < 31) ||
389                  (asset->frame_rate > 59 && asset->frame_rate < 61) )
390                 colorspace = OC_CS_ITU_REC_470M;
391         else
392                 colorspace = OC_CS_UNSPECIFIED;
393         pixfmt = TH_PF_420;
394         if( asset->theora_fix_bitrate ) {
395                 bitrate = asset->theora_bitrate;
396                 quality = -1;
397         }
398         else {
399                 bitrate = -1;
400                 quality = asset->theora_quality;     // 0-63
401         }
402         keyframe_period = asset->theora_keyframe_frequency;
403         keyframe_force = asset->theora_keyframe_force_frequency;
404         vp3_compatible = 1;
405         soft_target = 0;
406
407         ti.frame_width = frame_w;
408         ti.frame_height = frame_h;
409         ti.pic_width = pic_w;
410         ti.pic_height = pic_h;
411         ti.pic_x = pic_x;
412         ti.pic_y = pic_x;
413         ti.colorspace = (th_colorspace)colorspace;
414         ti.pixel_fmt = (th_pixel_fmt)pixfmt;
415         ti.target_bitrate = bitrate;
416         ti.quality = quality;
417         ti.fps_numerator = fps_num;
418         ti.fps_denominator = fps_den;
419         ti.aspect_numerator = aratio_num;
420         ti.aspect_denominator = aratio_den;
421         ti.keyframe_granule_shift = ilog(keyframe_period-1);
422
423         enc = th_encode_alloc(&ti);
424         int ret =  enc ? 0 : 1;
425         if( !ret && force_keyframes )
426                 ret = th_encode_ctl(enc,TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
427                         &keyframe_period, sizeof(keyframe_period));
428         if( !ret && vp3_compatible )
429                 ret = th_encode_ctl(enc,TH_ENCCTL_SET_VP3_COMPATIBLE,
430                         &vp3_compatible, sizeof(vp3_compatible));
431         if( !ret && soft_target ) {
432                 int arg = TH_RATECTL_CAP_UNDERFLOW;
433                 if( th_encode_ctl(enc, TH_ENCCTL_SET_RATE_FLAGS, &arg, sizeof(arg)) < 0 ) {
434                         eprintf(_("Could not set rate flags"));
435                         ret = 1;
436                 }
437                 int kr = keyframe_period*7>>1, fr = 5*fps_num/fps_den;
438                 arg = kr > fr ? kr : fr;
439                 if( th_encode_ctl(enc, TH_ENCCTL_SET_RATE_BUFFER, &arg, sizeof(arg)) ) {
440                         eprintf(_("Could not set rate buffer"));
441                         ret = 1;
442                 }
443         }
444         if( ret ) {
445                 eprintf(_("theora init context failed"));
446                 return 1;
447         }
448
449         th_comment_init(&tc);
450         th_comment_add_tag(&tc, (char*)"ENCODER",
451                 (char*)PROGRAM_NAME " " CINELERRA_VERSION);
452         ogg_page og;
453         ogg_packet op;
454         ret = th_encode_flushheader(enc, &tc, &op);
455         if( ret <= 0 ) return 1;
456         ogg_stream_packetin(&to, &op);
457         ret = ogg_stream_pageout(&to, &og) != 1 ? 1 : 0;
458         if( !ret ) {
459                 fwrite(og.header, 1, og.header_len, out);
460                 fwrite(og.body, 1, og.body_len, out);
461         }
462         if( ret ) {
463                 eprintf(_("write header out failed"));
464                 return 1;
465         }
466         while( (ret=th_encode_flushheader(enc, &tc, &op)) > 0 )
467                 ogg_stream_packetin(&to, &op);
468         if( ret ) {
469                 eprintf(_("ogg_encoder_init video failed"));
470                 return 1;
471         }
472         return 0;
473 }
474
475 int FileOGG::encode_vorbis_init()
476 {
477         ach = asset->channels;
478         ahz = asset->sample_rate;
479         amx = asset->vorbis_max_bitrate;
480         amn = asset->vorbis_min_bitrate;
481         abr = asset->vorbis_bitrate;
482         avbr = asset->vorbis_vbr;
483         asz = sizeof(short);
484         afrmsz = asz * ach;
485         aqu = -99;
486         ogg_stream_init(&vo, rand());
487         vorbis_info_init(&vi);
488         int ret = 0;
489         if( avbr ) {
490                 ret = vorbis_encode_setup_managed(&vi, ach, ahz, -1, abr, -1);
491                 if( !ret )
492                         ret = vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, 0);
493                 if( !ret )
494                         ret = vorbis_encode_setup_init(&vi);
495         }
496         else
497                 ret = vorbis_encode_init(&vi, ach, ahz, amx, abr, amn);
498         if( ret ) {
499                 eprintf(_("ogg_encoder_init audio init failed"));
500                 return 1;
501         }
502         vorbis_comment_init(&vc);
503         vorbis_comment_add_tag(&vc, (char*)"ENCODER",
504                 (char*)PROGRAM_NAME " " CINELERRA_VERSION);
505         vorbis_analysis_init(&vd, &vi);
506         vorbis_block_init(&vd, &vb);
507         ogg_packet header;
508         ogg_packet header_comm;
509         ogg_packet header_code;
510         vorbis_analysis_headerout(&vd, &vc,
511                 &header, &header_comm, &header_code);
512         ogg_stream_packetin(&vo, &header);
513         ogg_page og;
514         ret = ogg_stream_pageout(&vo, &og)==1 ? 0 : -1;
515         if( ret >= 0 ) {
516                 fwrite(og.header, 1, og.header_len, out);
517                 fwrite(og.body, 1, og.body_len, out);
518                 ogg_stream_packetin(&vo, &header_comm);
519                 ogg_stream_packetin(&vo, &header_code);
520         }
521         if( ret < 0 ) {
522                 eprintf(_("ogg_encoder_init audio failed"));
523                 return 1;
524         }
525         return 0;
526 }
527
528 int FileOGG::ogg_init_encode(FILE *out)
529 {
530         this->out = out;
531         srand(time(0));
532         video = asset->video_data;
533         if( video && encode_theora_init() )
534                 return 1;
535         audio = asset->audio_data;
536         if( audio && encode_vorbis_init() )
537                 return 1;
538         ogg_page og;
539         int ret = 0;
540         if( !ret && video ) {
541                 while( (ret=ogg_stream_flush(&to, &og)) > 0 ) {
542                         fwrite(og.header, 1, og.header_len, out);
543                         fwrite(og.body, 1, og.body_len, out);
544                 }
545         }
546         if( !ret && audio ) {
547                 while( (ret=ogg_stream_flush(&vo, &og)) > 0 ) {
548                         fwrite(og.header, 1, og.header_len, out);
549                         fwrite(og.body, 1, og.body_len, out);
550                 }
551         }
552         if( ret < 0 ) {
553                 eprintf(_("render init failed"));
554                 return 1;
555         }
556         return 0;
557 }
558
559 int FileOGG::decode_theora_init()
560 {
561         dec = th_decode_alloc(&ti, ts);
562         if( !dec ) {
563                 eprintf(_("Error in probe data"));
564                 return 1;
565         }
566         keyframe_granule_shift = ti.keyframe_granule_shift;
567         iframe_granule_offset = th_granule_frame(dec, 0);
568         double fps = (double)ti.fps_numerator/ti.fps_denominator;
569
570         videosync = new sync_window_t(inp, file_lock, file_begin, file_end);
571         ogg_page og;
572         int ret = videosync->ogg_get_first_page(to.serialno, &og);
573         if( ret <= 0 ) {
574                 eprintf(_("cannot read video page from file"));
575                 return 1;
576         }
577         videosync->file_begin = videosync->pagpos;
578         ret = videosync->ogg_get_first_page(to.serialno, &og);
579         // video data starts here
580         // get to the page of the finish of the first packet
581         while( ret > 0 && !ogg_page_packets(&og) ) {
582                 if( ogg_page_granulepos(&og) != -1 ) {
583                         printf(_("FileOGG: Broken ogg file - broken page:"
584                                 " ogg_page_packets == 0 and granulepos != -1\n"));
585                         return 1;
586                 }
587                 ret = videosync->ogg_get_next_page(to.serialno, &og);
588         }
589         // video frames start here
590         start_frame = ogg_frame_pos(&og);
591         ret = videosync->ogg_get_first_page(to.serialno, &og);
592         if( ret <= 0 ) {
593                 printf(_("FileOGG: Cannot read data past header\n"));
594                 return 1;
595         }
596 //printf("start frame = %jd, gpos %jd, begins %jd\n",
597 // start_frame, ogg_page_granulepos(&og), videosync->file_begin);
598
599         ret = videosync->ogg_get_last_page(to.serialno, &og);
600         while( ret > 0 && !ogg_page_packets(&og) )
601                 ret = videosync->ogg_get_prev_page(to.serialno, &og);
602         if( ret > 0 ) {
603                 last_frame = ogg_next_frame_pos(&og);
604                 if( start_frame >= last_frame ) {
605                         eprintf(_("no video frames in file"));
606                         last_frame = start_frame = 0;
607                 }
608                 asset->video_length = last_frame - start_frame;
609         }
610         else {
611                 printf("FileOGG: Cannot find the video length\n");
612                 return 1;
613         }
614         asset->layers = 1;
615         asset->width = ti.pic_width;
616         asset->height = ti.pic_height;
617 // Don't want a user configured frame rate to get destroyed
618         if( !asset->frame_rate )
619                 asset->frame_rate = fps;
620 // All theora material is noninterlaced by definition
621         if( !asset->interlace_mode )
622                 asset->interlace_mode = ILACE_MODE_NOTINTERLACED;
623
624         set_video_position(0); // make sure seeking is done to the first sample
625         ogg_frame_position = -10;
626         asset->video_data = 1;
627         strncpy(asset->vcodec, "theo", 4);
628 //      report_colorspace(&ti);
629 //      dump_comments(&tc);
630         return 0;
631 }
632
633 int FileOGG::decode_vorbis_init()
634 {
635         ogg_stream_reset(&vo);
636         vorbis_synthesis_init(&vd, &vi);
637         vorbis_block_init(&vd, &vb);
638         audiosync = new sync_window_t(inp, file_lock, file_begin, file_end);
639         ogg_page og;
640         int ret = audiosync->ogg_get_first_page(vo.serialno, &og);
641         if( ret <= 0 ) {
642                 eprintf(_("cannot read audio page from file"));
643                 return 1;
644         }
645         // audio data starts here
646         audiosync->file_begin = audiosync->pagpos;
647         // audio samples starts here
648         start_sample = ogg_sample_pos(&og);
649 //printf("start sample = %jd, gpos %jd, begins %jd\n",
650 // start_sample, ogg_page_granulepos(&og), audiosync->file_begin);
651         ret = audiosync->ogg_get_last_page(vo.serialno, &og);
652         last_sample = ret > 0 ? ogg_next_sample_pos(&og) : 0;
653         asset->audio_length = last_sample - start_sample;
654         if( asset->audio_length <= 0 ) {
655                 eprintf(_("no audio samples in file"));
656                 asset->audio_length = 0;
657                 last_sample = start_sample;
658         }
659
660         asset->channels = vi.channels;
661         if( !asset->sample_rate )
662                 asset->sample_rate = vi.rate;
663         asset->audio_data = 1;
664
665         ogg_sample_position = -10;
666         set_audio_position(0); // make sure seeking is done to the first sample
667         strncpy(asset->acodec, "vorb", 4);
668         return 0;
669 }
670
671 int FileOGG::ogg_init_decode(FILE *inp)
672 {
673         if( !inp ) return 1;
674         this->inp = inp;
675         struct stat file_stat; /* get file length */
676         file_end = stat(asset->path, &file_stat)>=0 ? file_stat.st_size : 0;
677         if( file_end < mn_pagesz ) return 1;
678         fseek(inp, 0, SEEK_SET);
679         vorbis_info_init(&vi);
680         vorbis_comment_init(&vc);
681         th_comment_init(&tc);
682         th_info_init(&ti);
683         ogg_page og;
684         ogg_packet op;
685         sync_window_t sy(inp, file_lock, 0, file_end);
686         int ret = sy.ogg_read_buffer_at(0, READ_SIZE);
687         if( ret < mn_pagesz ) return 1;
688         if( !sy.ogg_sync_and_take_page_out(&og) ) return 1;
689         ogg_stream_state tst;
690
691         while( ogg_page_bos(&og) ) {
692                 ogg_stream_init(&tst, ogg_page_serialno(&og));
693                 ogg_stream_pagein(&tst, &og);
694                 if( ogg_stream_packetout(&tst, &op) ) {
695                         if( !video && th_decode_headerin(&ti, &tc, &ts, &op) >=0 ) {
696                                 ogg_stream_init(&to, ogg_page_serialno(&og));
697                                 video = 1;
698                         }
699                         else if( !audio && vorbis_synthesis_headerin(&vi, &vc, &op) >=0 ) {
700                                 ogg_stream_init(&vo, ogg_page_serialno(&og));
701                                 audio = 1;
702                         }
703                 }
704                 ogg_stream_clear(&tst);
705                 ret = sy.ogg_take_page_out_autoadvance(&og);
706         }
707
708         if( !ret || !video && !audio )
709                 return 1;
710
711         // expecting more a/v header packets
712         int vpkts = video ? 2 : 0;
713         int apkts = audio ? 2 : 0;
714         int retries = 100;
715         ret = 0;
716         while( --retries >= 0 && !ret && (vpkts || apkts) ) {
717                 if( vpkts && ogg_page_serialno(&og) == to.serialno ) {
718                         ogg_stream_init(&tst, to.serialno);
719                         ogg_stream_pagein(&tst, &og);
720                         while( !ret && vpkts > 0 ) {
721                                 while( (ret=ogg_stream_packetout(&tst, &op)) < 0 );
722                                 if( !ret ) break;
723                                 --vpkts;
724                                 ret = !th_decode_headerin(&ti, &tc, &ts, &op) ? 1 : 0;
725                         }
726                         if( ret )
727                                 printf("theora header error\n");
728                         ogg_stream_clear(&tst);
729                 }
730                 else if( apkts && ogg_page_serialno(&og) == vo.serialno ) {
731                         ogg_stream_init(&tst, vo.serialno);
732                         ogg_stream_pagein(&tst, &og);
733                         while( !ret && apkts > 0 ) {
734                                 while( (ret=ogg_stream_packetout(&tst, &op)) < 0 );
735                                 if( !ret ) break;
736                                 --apkts;
737                                 ret = vorbis_synthesis_headerin(&vi, &vc, &op) ? 1 : 0;
738                         }
739                         if( ret )
740                                 printf("vorbis header error\n");
741                         ogg_stream_clear(&tst);
742                 }
743                 if( !ret && !sy.ogg_take_page_out_autoadvance(&og) )
744                         ret = 1;
745                 if( ret )
746                         printf("incomplete headers\n");
747
748         }
749 // find first start packet (not continued) with data
750         int64_t start_pos = sy.bufpos - (og.header_len + og.body_len);
751         if( !ret ) {
752                 while( --retries >= 0 && !ret && !ogg_page_packets(&og) ) {
753                         if( !ogg_page_continued(&og) )
754                                 start_pos = sy.bufpos - (og.header_len + og.body_len);
755                         if( !sy.ogg_take_page_out_autoadvance(&og) ) ret = 1;
756                 }
757                 if( ret )
758                         printf("no data past headers\n");
759                 if( audio && apkts )
760                         printf("missed %d audio headers\n",apkts);
761                 if( video && vpkts )
762                         printf("missed %d video headers\n",vpkts);
763         }
764         if( retries < 0 || ret || (audio && apkts) || (video && vpkts) ) {
765                 eprintf(_("Error in headers"));
766                 return 1;
767         }
768         // headers end here
769         file_begin = start_pos;
770
771         if( video && decode_theora_init() )
772                 return 1;
773         if( audio && decode_vorbis_init() )
774                 return 1;
775         return 0;
776 }
777
778 void FileOGG::close_encoder()
779 {
780 // flush streams
781         if( audio )
782                 write_samples_vorbis(0, 0, 1);
783         if( video )
784                 write_frames_theora(0, 1, 1);
785         flush_ogg(1);
786
787         if( audio ) {
788                 vorbis_block_clear(&vb);
789                 vorbis_dsp_clear(&vd);
790                 vorbis_comment_clear(&vc);
791                 vorbis_info_clear(&vi);
792                 ogg_stream_clear(&vo);
793                 audio = 0;
794         }
795         if( video ) {
796                 th_comment_clear(&tc);
797                 ogg_stream_clear(&to);
798                 video = 0;
799         }
800         if( enc ) {
801                 th_encode_free(enc);
802                 enc = 0;
803         }
804         if( out ) {
805                 fclose(out);
806                 out = 0;
807         }
808 }
809
810 void FileOGG::close_decoder()
811 {
812         if( audio ) {
813                 for( int i=0; i<pcm_channels; ++i )
814                         delete [] pcm_history[i];
815                 pcm_channels = 0;
816                 delete [] pcm_history;  pcm_history = 0;
817
818                 vorbis_dsp_clear(&vd);
819                 vorbis_info_clear(&vi);
820                 vorbis_block_clear(&vb);
821                 vorbis_comment_clear(&vc);
822                 ogg_stream_clear(&vo);
823                 delete audiosync;  audiosync = 0;
824                 audio = 0;
825         }
826         if( video ) {
827                 th_info_clear(&ti);
828                 th_setup_free(ts);  ts = 0;
829                 th_comment_clear(&tc);
830                 ogg_stream_clear(&to);
831                 delete videosync;  videosync = 0;
832                 video = 0;
833         }
834         if( dec ) {
835                 th_decode_free(dec);
836                 dec = 0;
837         }
838         if( inp ) {
839                 fclose(inp);
840                 inp = 0;
841         }
842 }
843
844
845
846 void FileOGG::get_parameters(BC_WindowBase *parent_window, Asset *asset,
847         BC_WindowBase* &format_window, int audio_options,
848         int video_options, EDL *edl)
849 {
850         if(audio_options)
851         {
852                 OGGConfigAudio *window = new OGGConfigAudio(parent_window, asset);
853                 format_window = window;
854                 window->create_objects();
855                 window->run_window();
856                 delete window;
857         }
858         else
859         if(video_options)
860         {
861                 OGGConfigVideo *window = new OGGConfigVideo(parent_window, asset);
862                 format_window = window;
863                 window->create_objects();
864                 window->run_window();
865                 delete window;
866         }
867 }
868
869
870
871 int sync_window_t::ogg_take_page_out_autoadvance(ogg_page *og)
872 {
873         for(;;) {
874                 int ret = ogg_sync_pageout(this, og);
875                 if( ret < 0 ) {
876                         printf("FileOGG: Lost sync reading input file\n");
877                         return 0;
878                 }
879                 if( ret > 0 ) {
880                         bufpos += og->header_len + og->body_len;
881                         return ret;
882                 }
883                 // need more data for page
884                 if( !ogg_read_buffer(READ_SIZE) ) {
885                         printf("FileOGG: Read past end of input file\n");
886                         return 0;  // No more data
887                 }
888         }
889         return 1;
890 }
891
892
893 int FileOGG::check_sig(Asset *asset)
894 {
895         FILE *fp = fopen(asset->path, "rb");
896         if( !fp ) return 0;
897 // Test for "OggS"
898         fseek(fp, 0, SEEK_SET);
899         char data[4];
900         int ret = fread(data, 4, 1, fp) == 1 &&
901                 data[0] == 'O' && data[1] == 'g' &&
902                 data[2] == 'g' && data[3] == 'S' ? 1 : 0;
903         fclose(fp);
904         return ret;
905
906 }
907
908 int FileOGG::open_file(int rd, int wr)
909 {
910         int ret = 1;
911         if( wr ) {
912                 if( !(out = fopen(asset->path, "wb")) ) {
913                         eprintf(_("Error while opening %s for writing. %m\n"), asset->path);
914                         return 1;
915                 }
916                 if( (ret = ogg_init_encode(out)) && out ) {
917                         fclose(out);  out = 0;
918                 }
919         }
920         else if( rd ) {
921                 if( !(inp = fopen(asset->path, "rb")) ) {
922                         eprintf(_("Error while opening %s for reading. %m\n"), asset->path);
923                         return 1;
924                 }
925                 if( (ret = ogg_init_decode(inp)) && inp ) {
926                         fclose(inp);  inp = 0;
927                 }
928         }
929         return ret;
930 }
931
932 int FileOGG::close_file()
933 {
934         if( file->wr )
935                 close_encoder();
936         else if( file->rd )
937                 close_decoder();
938         return 0;
939 }
940
941
942 int64_t FileOGG::ogg_sample_pos(ogg_page *og)
943 {
944         ogg_packet op;
945         ogg_stream_state ss;
946         ogg_stream_init(&ss, vo.serialno);
947         ogg_stream_pagein(&ss, og);
948         int64_t bsz = 0;
949         long prev = -1;
950         int ret = 0;
951         while( (ret=ogg_stream_packetout(&ss, &op)) ) {
952                 if( ret < 0 ) continue; // ignore holes
953                 long sz =  vorbis_packet_blocksize(&vi, &op);
954                 if( prev != -1 ) bsz += (prev + sz) >> 2;
955                 prev = sz;
956         }
957         ogg_stream_clear(&ss);
958         return ogg_next_sample_pos(og) - bsz;
959 }
960
961 int64_t FileOGG::ogg_next_sample_pos(ogg_page *og)
962 {
963         return ogg_page_granulepos(og);
964 }
965
966 int64_t FileOGG::ogg_frame_pos(ogg_page *og)
967 {
968         int64_t pos = th_granule_frame(dec, ogg_page_granulepos(og)) - ogg_page_packets(og);
969         if( ogg_page_continued(og) ) --pos;
970         return pos;
971 }
972
973 int64_t FileOGG::ogg_next_frame_pos(ogg_page *og)
974 {
975         return th_granule_frame(dec, ogg_page_granulepos(og)) + 1;
976 }
977
978
979 int FileOGG::ogg_get_page_of_sample(ogg_page *og, int64_t sample)
980 {
981         if( sample >= asset->audio_length + start_sample ) {
982                 printf(_("FileOGG: Illegal seek beyond end of samples\n"));
983                 return 0;
984         }
985 // guess about position
986         int64_t file_length =  audiosync->file_end - audiosync->file_begin;
987         off_t guess = file_length * (sample - start_sample) /
988                 asset->audio_length - SEEK_SIZE;
989         if( guess < 0 ) guess = 0;
990         guess += audiosync->file_begin;
991         audiosync->ogg_read_buffer_at(guess, READ_SIZE);
992         if( !audiosync->ogg_sync_and_get_next_page(vo.serialno, og) ) {
993                 printf(_("FileOGG: llegal seek no pages\n"));
994                 return 0;
995         }
996         int ret = 1;
997         while( ret && (ogg_page_granulepos(og) == -1 || !ogg_page_packets(og)) )
998                 ret = videosync->ogg_get_next_page(to.serialno, og);
999         if( !ret ) return 0;
1000         // linear seek to the sample
1001         int missp = 0, missm = 0;
1002         int64_t next_pos = ogg_next_sample_pos(og);
1003         if( sample >= next_pos ) { // scan forward
1004                 while( sample >= next_pos ) {
1005                         while( !(ret=audiosync->ogg_get_next_page(vo.serialno, og)) &&
1006                                 (ogg_page_granulepos(og) == -1 || !ogg_page_packets(og)) );
1007                         if( !ret ) break;
1008                         next_pos = ogg_next_sample_pos(og);
1009                         ++missp;
1010 //printf("audio %jd next %jd %jd\n", sample, ogg_sample_pos(og), next_pos);
1011                 }
1012         }
1013         else { // scan backward
1014                 int64_t pos = ogg_sample_pos(og);
1015                 while( sample < pos ) {
1016                         while( (ret=audiosync->ogg_get_prev_page(vo.serialno, og)) &&
1017                                 (ogg_page_continued(og) && ogg_page_packets(og) == 1) );
1018                         if( !ret ) break;
1019                         ++missm;
1020                         pos = ogg_sample_pos(og);
1021 //printf("audio %jd prev %jd %jd\n", sample, pos, ogg_next_sample_pos(og));
1022                 }
1023         }
1024 //printf("audio %d seek %jd, missp %d, missm %d  from %jd to %jd\n", ret,
1025 // sample, missp, missm, ogg_sample_pos(og), ogg_next_sample_pos(og));
1026         return ret;
1027 }
1028
1029 int FileOGG::ogg_seek_to_sample(int64_t ogg_sample)
1030 {
1031         ogg_page og;
1032         ogg_packet op;
1033         if( !ogg_get_page_of_sample(&og, ogg_sample) ) {
1034                 eprintf(_("Seeking to sample's page failed\n"));
1035                 return 0;
1036         }
1037         int ret = 1;
1038         int64_t pos = ogg_sample_pos(&og);
1039         int64_t next_pos = pos;
1040         if( ogg_page_continued(&og) ) {
1041                 while( (ret=audiosync->ogg_get_prev_page(to.serialno, &og)) &&
1042                         (ogg_page_packets(&og) == 0 && ogg_page_continued(&og)) );
1043         }
1044         if( ret ) {
1045                 audio_eos = 0;
1046                 ogg_stream_reset(&vo);
1047                 ogg_stream_pagein(&vo, &og);
1048                 vorbis_synthesis_restart(&vd);
1049                 ret = ogg_get_audio_packet(&op);
1050         }
1051         if( ret && !vorbis_synthesis(&vb, &op) ) {
1052                 vorbis_synthesis_blockin(&vd, &vb);
1053                 if( vorbis_synthesis_pcmout(&vd, 0) )
1054                         ret = 0;
1055         }
1056         if( !ret ) {
1057                 eprintf(_("Something wrong while trying to seek\n"));
1058                 return 0;
1059         }
1060
1061         while( ogg_sample > next_pos ) {
1062                 if( !(ret=ogg_get_audio_packet(&op)) ) break;
1063                 if( vorbis_synthesis(&vb, &op) ) continue;
1064                 vorbis_synthesis_blockin(&vd, &vb);
1065                 pos = next_pos;
1066                 next_pos += vorbis_synthesis_pcmout(&vd, NULL);
1067                 if( next_pos > ogg_sample ) break;
1068                 // discard decoded data before current sample
1069                 vorbis_synthesis_read(&vd, (next_pos - pos));
1070         }
1071         if( ret ) {
1072                 audio_pos = next_pos;
1073                 vorbis_synthesis_read(&vd, (ogg_sample - pos));
1074         }
1075         return ret;
1076 }
1077
1078
1079 int FileOGG::ogg_get_page_of_frame(ogg_page *og, int64_t frame)
1080 {
1081         if( frame >= asset->video_length + start_frame ) {
1082                 eprintf(_("Illegal seek beyond end of frames\n"));
1083                 return 0;
1084         }
1085         if( frame < start_frame ) {
1086                 eprintf(_("Illegal seek before start of frames\n"));
1087                 return 0;
1088         }
1089         int64_t file_length = videosync->file_end - videosync->file_begin;
1090         off_t guess = file_length * (frame - start_frame) /
1091                  asset->video_length - SEEK_SIZE;
1092         if( guess < 0 ) guess = 0;
1093         guess += videosync->file_begin;
1094         videosync->ogg_read_buffer_at(guess, SEEK_SIZE);
1095         videosync->ogg_sync_and_get_next_page(to.serialno, og);
1096         // find the page with "real" ending
1097         int ret = 1;
1098         while( ret && (ogg_page_granulepos(og) == -1 || !ogg_page_packets(og)) )
1099                ret = videosync->ogg_get_next_page(to.serialno, og);
1100         int64_t pos = ogg_next_frame_pos(og);
1101         // linear search
1102         int missp = 0, missm = 0;
1103 // move back if continued
1104         if( frame >= pos ) {
1105                 do { // scan forward
1106                         while( (ret=videosync->ogg_get_next_page(to.serialno, og)) &&
1107                                 ogg_page_packets(og) == 0 );
1108                         if( !ret ) break;
1109                         missp++;
1110                         pos = ogg_next_frame_pos(og);
1111 //printf("video %jd next %jd %jd\n", frame, ogg_frame_pos(og), pos);
1112                 } while( frame >= pos );
1113         }
1114         else if( (pos=ogg_frame_pos(og)) > frame ) {
1115                 while( pos > start_frame && frame < pos ) { // scan backward
1116                         while( (ret=videosync->ogg_get_prev_page(to.serialno, og)) &&
1117                                 ogg_page_packets(og) == 0 && ogg_page_continued(og) );
1118                         if( !ret ) break;
1119                         missm++;
1120                         pos = ogg_frame_pos(og);
1121 //printf("video %jd next %jd %jd\n", frame, pos, ogg_next_frame_pos(og));
1122                 }
1123         }
1124 //printf("video %d seek %jd, missp %d, missm %d first %jd, next %jd\n", ret,
1125 // frame, missp, missm, ogg_frame_pos(og), ogg_next_frame_pos(og));
1126         return ret;
1127 }
1128
1129 int FileOGG::ogg_seek_to_keyframe(int64_t frame, int64_t *keyframe_number)
1130 {
1131 //printf("ogg_seek_to_keyframe of === %jd\n", frame);
1132         ogg_page og;
1133         ogg_packet op;
1134         int64_t ipagpos = -1;
1135         int64_t istart = -1;
1136         int64_t iframe = -1;
1137         int ipkts = -1;
1138         int retries = 1000, ret = 1;
1139         while( --retries>=0 && frame>=start_frame ) {
1140                 if( !ogg_get_page_of_frame(&og, frame) ) break;
1141                 int64_t pos = ogg_frame_pos(&og);
1142                 istart = pos;
1143                 if( ogg_page_continued(&og) ) {
1144                         while( (ret=videosync->ogg_get_prev_page(to.serialno, &og)) &&
1145                                 (ogg_page_packets(&og) == 0 && ogg_page_continued(&og)) );
1146                 }
1147                 int64_t pagpos = videosync->pagpos;
1148                 video_eos = 0;
1149                 ogg_stream_reset(&to);
1150                 ogg_stream_pagein(&to, &og);
1151                 int pkts = 0;
1152                 while( frame >= pos && (ret=ogg_get_video_packet(&op)) ) {
1153                         if( th_packet_iskeyframe(&op) == 1 ) {
1154                                 ipagpos = pagpos;
1155                                 iframe = pos;
1156                                 ipkts = pkts;
1157 //printf("keyframe %jd pkts %d\n", pos, pkts);
1158                         }
1159 //printf("packet %jd pkts %d is a %d\n", pos, pkts,  th_packet_iskeyframe(&op));
1160                         ++pkts;  ++pos;
1161                 }
1162                 if( ipagpos >= 0 ) break;
1163                 frame = istart - 1;
1164         }
1165         if( ipagpos < 0 ) {
1166                 printf(_("Seeking to keyframe %jd search failed\n"), frame);
1167                 return 0;
1168         }
1169         videosync->ogg_read_buffer_at(ipagpos, READ_SIZE);
1170         videosync->ogg_sync_and_get_next_page(to.serialno, &og);
1171         video_eos = 0;
1172         ogg_stream_reset(&to);
1173         ogg_stream_pagein(&to, &og);
1174         video_pos = ogg_next_frame_pos(&og);
1175 // skip prev packets
1176 //      int ipkts = iframe - ogg_frame_pos(&og);
1177 //printf("iframe %jd, page %jd, ipkts %d\n", iframe, ogg_page_pageno(&og), ipkts);
1178         while( --ipkts >= 0 )
1179                 ogg_get_video_packet(&op);
1180         *keyframe_number = iframe;
1181         return 1;
1182 }
1183
1184
1185 int64_t FileOGG::get_video_position()
1186 {
1187 //      printf("GVP\n");
1188         return next_frame_position - start_frame;
1189 }
1190
1191 int64_t FileOGG::get_audio_position()
1192 {
1193         return next_sample_position - start_sample;
1194 }
1195
1196 int FileOGG::set_video_position(int64_t x)
1197 {
1198 //      x=0;
1199 //      printf("SVP: %lli\n", x);
1200
1201         next_frame_position = x + start_frame;
1202         return 1;
1203 }
1204
1205
1206 int FileOGG::colormodel_supported(int colormodel)
1207 {
1208 //      printf("CMS\n");
1209
1210         if (colormodel == BC_YUV420P)
1211                 return BC_YUV420P;
1212         else
1213                 return colormodel;
1214 }
1215 int FileOGG::get_best_colormodel(Asset *asset, int driver)
1216 {
1217
1218         return BC_YUV420P;
1219 }
1220
1221 int FileOGG::set_audio_position(int64_t x)
1222 {
1223         next_sample_position = x + start_sample;
1224         return 0;
1225 }
1226
1227
1228 int FileOGG::ogg_get_video_packet(ogg_packet *op)
1229 {
1230         int ret = 1;
1231         while( (ret=ogg_stream_packetout(&to, op)) <= 0 ) {
1232                 if( video_eos ) return 0;
1233                 ogg_page og;
1234                 if( !videosync->ogg_get_next_page(to.serialno, &og) ) break;
1235                 if( ogg_page_granulepos(&og) >= 0 )
1236                         video_pos = ogg_next_frame_pos(&og);
1237                 ogg_stream_pagein(&to, &og);
1238                 video_eos = ogg_page_eos(&og);
1239         }
1240         if( ret <= 0 ) {
1241                 printf("FileOGG: Cannot read video packet\n");
1242                 return 0;
1243         }
1244         return 1;
1245 }
1246
1247 int FileOGG::read_frame(VFrame *frame)
1248 {
1249         if( !inp || !video ) return 1;
1250         // skip is cheaper than seek, do it...
1251         int decode_frames = 0;
1252         int expect_keyframe = 0;
1253         if( ogg_frame_position >= 0 &&
1254             next_frame_position >= ogg_frame_position &&
1255             next_frame_position - ogg_frame_position < 32) {
1256                 decode_frames = next_frame_position - ogg_frame_position;
1257         }
1258         else if( next_frame_position != ogg_frame_position ) {
1259                 if( !ogg_seek_to_keyframe(next_frame_position, &ogg_frame_position) ) {
1260                         eprintf(_("Error while seeking to frame's keyframe"
1261                                 " (frame: %jd, keyframe: %jd)\n"),
1262                                 next_frame_position, ogg_frame_position);
1263                         return 1;
1264                 }
1265                 decode_frames = next_frame_position - ogg_frame_position + 1;
1266                 --ogg_frame_position;
1267                 if( decode_frames <= 0 ) {
1268                         eprintf(_("Error while seeking to keyframe,"
1269                                 " wrong keyframe number (frame: %jd, keyframe: %jd)\n"),
1270                                 next_frame_position, ogg_frame_position);
1271                         return 1;
1272
1273                 }
1274                 expect_keyframe = 1;
1275         }
1276         int ret = 0;
1277         ogg_packet op;
1278         while( decode_frames > 0 ) {
1279                 if( !ogg_get_video_packet(&op) ) break;
1280                 if( expect_keyframe ) {
1281                         expect_keyframe = 0;
1282                         if( th_packet_iskeyframe(&op) <= 0 )
1283                                 eprintf(_("FileOGG: Expecting keyframe, but didn't get it\n"));
1284                 }
1285                 ogg_int64_t granpos = 0;
1286                 if( th_decode_packetin(dec, &op, &granpos) >= 0 )
1287                         ret = 1;
1288                 ++ogg_frame_position;
1289                 --decode_frames;
1290         }
1291 //if(ret < 0 )printf("ret = %d\n", ret);
1292         if( ret > 0 ) {
1293                 th_ycbcr_buffer ycbcr;
1294                 ret = th_decode_ycbcr_out(dec, ycbcr);
1295                 if( ret ) {
1296                         eprintf(_("th_decode_ycbcr_out failed with code %i\n"), ret);
1297                         ret = 0; // not always fatal
1298                 }
1299                 uint8_t *yp = ycbcr[0].data;
1300                 uint8_t *up = ycbcr[1].data;
1301                 uint8_t *vp = ycbcr[2].data;
1302                 int yst = ycbcr[0].stride;
1303                 int yw = ycbcr[0].width;
1304                 int yh = ycbcr[0].height;
1305                 VFrame temp_frame(yp, -1, 0, up-yp, vp-yp, yw,yh, BC_YUV420P, yst);
1306                 int px = ti.pic_x, py = ti.pic_y;
1307                 int pw = ti.pic_width, ph = ti.pic_height;
1308                 frame->transfer_from(&temp_frame, -1, px, py, pw, ph);
1309         }
1310
1311         next_frame_position++;
1312         return ret;
1313 }
1314
1315
1316 int FileOGG::ogg_get_audio_packet(ogg_packet *op)
1317 {
1318         int ret = 1;
1319         while( (ret=ogg_stream_packetout(&vo, op)) <= 0 ) {
1320                 if( audio_eos ) return 0;
1321                 ogg_page og;
1322                 if( !audiosync->ogg_get_next_page(vo.serialno, &og) ) break;
1323                 if( ogg_page_granulepos(&og) >= 0 )
1324                         audio_pos = ogg_next_sample_pos(&og);
1325                 ogg_stream_pagein(&vo, &og);
1326                 audio_eos = ogg_page_eos(&og);
1327         }
1328         if( ret <= 0 ) {
1329                 printf("FileOGG: Cannot read audio packet\n");
1330                 return 0;
1331         }
1332         return 1;
1333 }
1334
1335 int FileOGG::ogg_decode_more_samples()
1336 {
1337         ogg_packet op;
1338         while( ogg_get_audio_packet(&op) ) {
1339                 if( !vorbis_synthesis(&vb, &op) ) {
1340                         vorbis_synthesis_blockin(&vd, &vb);
1341                         return 1;
1342                 }
1343         }
1344         ogg_sample_position = -11;
1345         eprintf(_("Cannot find next page while trying to decode more samples\n"));
1346         return 0;
1347 }
1348
1349 int FileOGG::move_history(int from, int to, int len)
1350 {
1351         if( len > 0 ) {
1352                 for( int i=0; i<asset->channels; ++i )
1353                         memmove(pcm_history[i] + to,
1354                                 pcm_history[i] + from,
1355                                 sizeof(float) * len);
1356         }
1357         history_start = history_start + from - to;
1358         if( history_start < 0 ) history_start = 0;
1359         return 0;
1360 }
1361
1362 int FileOGG::read_samples(double *buffer, int64_t len)
1363 {
1364         float **vorbis_buffer;
1365         if( len <= 0 )
1366                 return 0;
1367         if( len > HISTORY_MAX ) {
1368                 eprintf(_("max samples=%d\n"), HISTORY_MAX);
1369                 return 1;
1370         }
1371
1372         if( !pcm_history ) {
1373                 pcm_history = new float*[asset->channels];
1374                 for(int i = 0; i < asset->channels; i++)
1375                         pcm_history[i] = new float[HISTORY_MAX];
1376                 history_start = -100000000;
1377                 history_size = 0;
1378         }
1379
1380         int64_t hole_start = -1;
1381         int64_t hole_len = -1;
1382         int64_t hole_absstart = -1;
1383         int64_t hole_fill = 0;
1384
1385         if( history_start < next_sample_position &&
1386             history_start + history_size > next_sample_position &&
1387             history_start + history_size < next_sample_position + len ) {
1388                 hole_fill = 1;
1389                 hole_start = history_start + history_size - next_sample_position;
1390                 hole_len = history_size - hole_start;
1391                 hole_absstart = next_sample_position + hole_start;
1392                 move_history(next_sample_position - history_start, 0, hole_start);
1393         }
1394         else if( next_sample_position < history_start &&
1395                  history_start < next_sample_position + len ) {
1396                 hole_fill = 1;
1397                 hole_start = 0;
1398                 hole_len = history_start - next_sample_position;
1399                 hole_absstart = next_sample_position;
1400                 move_history(0,
1401                         history_start - next_sample_position,
1402                         history_size - history_start + next_sample_position);
1403
1404         }
1405         else if( next_sample_position >= history_start + history_size ||
1406                  next_sample_position + len <= history_start ) {
1407                 hole_fill = 1;
1408                 hole_start = 0;
1409                 hole_len = HISTORY_MAX;
1410                 hole_absstart = next_sample_position;
1411                 history_start = hole_absstart;
1412                 history_size = hole_len;
1413         }
1414
1415         if( hole_fill ) {
1416                 if( hole_start < 0 || hole_len <= 0 || hole_absstart < 0 ) {
1417                         eprintf(_("Error in finding read file position\n"));
1418                         return 1;
1419                 }
1420
1421                 if( hole_absstart + hole_len > asset->audio_length + start_sample ) {
1422                         hole_len = asset->audio_length + start_sample - hole_absstart;
1423                         history_size = asset->audio_length + start_sample - history_start;
1424                 }
1425                 else {
1426                         history_size = HISTORY_MAX;
1427                 }
1428
1429                 int64_t samples_read = 0;
1430                 if( ogg_sample_position != hole_absstart ) {
1431                         ogg_sample_position = hole_absstart;
1432                         if( !ogg_seek_to_sample(ogg_sample_position) ) {
1433                                 eprintf(_("Error while seeking to sample\n"));
1434                                 return 1;
1435                         }
1436                 }
1437                 // now we have ogg_sample_positon aligned
1438                 int64_t samples_to_read = hole_len;
1439                 while( samples_read < hole_len ) {
1440                         int64_t samples_waiting = vorbis_synthesis_pcmout(&vd, &vorbis_buffer);
1441                         int64_t samples_avail = !samples_waiting && audio_eos ?
1442                                 hole_len - samples_read : // silence after eos
1443                                 samples_waiting ;
1444                         int64_t sample_demand = samples_to_read - samples_read;
1445                         int64_t sample_count = MIN(samples_avail, sample_demand);
1446                         if( sample_count > 0 ) {
1447                                 int sz = sample_count*sizeof(float);
1448                                 if( samples_waiting ) {
1449                                         for( int i=0; i<asset->channels; ++i ) {
1450                                                 float *input = vorbis_buffer[i];
1451                                                 float *output = pcm_history[i] + hole_start;
1452                                                 memcpy(output, input, sz);
1453                                         }
1454                                         vorbis_synthesis_read(&vd, sample_count);
1455                                 }
1456                                 else {
1457                                         for( int i=0; i<asset->channels; ++i ) {
1458                                                 float *output = pcm_history[i] + hole_start;
1459                                                 memset(output, 0, sz);
1460                                         }
1461                                 }
1462                                 ogg_sample_position += sample_count;
1463                                 hole_start += sample_count;
1464                                 samples_read += sample_count;
1465                                 if( samples_read >= hole_len ) break;
1466                         }
1467                         if( samples_read < hole_len && !ogg_decode_more_samples() )
1468                                 break;
1469                 }
1470         }
1471
1472         if( next_sample_position < history_start ||
1473             next_sample_position + len > history_start + history_size ) {
1474                 printf(_("FileOGG:: History not aligned properly \n"));
1475                 printf(_("\tnext_sample_position: %jd, length: %jd\n"), next_sample_position, len);
1476                 printf(_("\thistory_start: %jd, length: %jd\n"), history_start, history_size);
1477                 return 1;
1478         }
1479         float *input = pcm_history[file->current_channel] + next_sample_position - history_start;
1480         for (int i = 0; i < len; i++)
1481                 buffer[i] = input[i];
1482
1483         next_sample_position += len;
1484         return 0;
1485 }
1486
1487
1488 int FileOGG::write_audio_page()
1489 {
1490         int ret = apage.write_page(out);
1491         if( ret < 0 )
1492                 eprintf(_("error writing audio page\n"));
1493         return ret;
1494 }
1495
1496 int FileOGG::write_video_page()
1497 {
1498         int ret = vpage.write_page(out);
1499         if( ret < 0 )
1500                 eprintf(_("error writing video page\n"));
1501         return ret;
1502 }
1503
1504 // flush out the ogg pages
1505 void FileOGG::flush_ogg(int last)
1506 {
1507         ogg_page og;
1508         file_lock->lock("FileOGG::flush_ogg");
1509         for(;;) {
1510 // this way seeking is much better, (per original fileogg)
1511 // not sure if 32 packets is a good value.
1512                 int mx_pkts = 32;
1513                 if( video && !vpage.valid ) {
1514                         if( (vpage.packets > mx_pkts && ogg_stream_flush(&to, &og) > 0) ||
1515                             ogg_stream_pageout(&to, &og) > 0 ) {
1516                                 videotime = th_granule_time(enc, vpage.load(&og));
1517                         }
1518                 }
1519                 if( audio && !apage.valid ) {
1520                         if( (apage.packets > mx_pkts && ogg_stream_flush(&vo, &og) > 0) ||
1521                             ogg_stream_pageout(&vo, &og) > 0 ) {
1522                                 audiotime = vorbis_granule_time(&vd, apage.load(&og));
1523                         }
1524                 }
1525                 if( !audio && vpage.valid )
1526                         write_video_page();
1527                 else if( !video && apage.valid )
1528                         write_audio_page();
1529                 else if( !vpage.valid || !apage.valid )
1530                         break;
1531 // output earliest page
1532                 else if( videotime > audiotime ) // output earliest
1533                         write_audio_page();
1534                 else
1535                         write_video_page();
1536         }
1537         if( last ) {  // at last
1538                 if( vpage.valid )
1539                         write_video_page();
1540                 if( apage.valid )
1541                         write_audio_page();
1542         }
1543         file_lock->unlock();
1544 }
1545
1546
1547 int FileOGG::write_samples_vorbis(double **buffer, int64_t len, int last)
1548 {
1549         if( !audio || !out ) return 1;
1550         flush_ogg(0);
1551         if( !last ) {
1552                 float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
1553                 for( int i=0; i<asset->channels; ++i ) // double to float
1554                         for( int j=0; j < len; ++j )
1555                                 vorbis_buffer[i][j] = buffer[i][j];
1556         }
1557         else
1558                 len = 0;
1559         vorbis_analysis_wrote(&vd, len);
1560
1561         while( vorbis_analysis_blockout(&vd, &vb) == 1 ) {
1562                 vorbis_analysis(&vb, 0);
1563                 vorbis_bitrate_addblock(&vb);
1564                 ogg_packet op;
1565                 while( vorbis_bitrate_flushpacket(&vd, &op) ) {
1566                         file_lock->lock("FileOGG::write_vorbis_audio");
1567                         ogg_stream_packetin(&vo, &op);
1568                         ++apage.packets;
1569                         file_lock->unlock();
1570                 }
1571         }
1572         return 0;
1573 }
1574
1575 int FileOGG::write_samples(double **buffer, int64_t len)
1576 {
1577         if (len > 0)
1578                 return write_samples_vorbis(buffer, len, 0);
1579         return 0;
1580 }
1581
1582
1583 int FileOGG::write_frames_theora(VFrame ***frames, int len, int last)
1584 {
1585         if( !video || !out ) return 1;
1586         for( int j=0; j<len; ++j ) {
1587                 flush_ogg(0);
1588                 if( temp_frame ) {
1589                         th_ycbcr_buffer ycbcr;
1590                         ycbcr[0].width = frame_w;
1591                         ycbcr[0].height = frame_h;
1592                         ycbcr[0].stride = temp_frame->get_bytes_per_line();
1593                         ycbcr[0].data = temp_frame->get_y();
1594                         ycbcr[1].width = frame_w/2;
1595                         ycbcr[1].height = frame_h/2;
1596                         ycbcr[1].stride = (temp_frame->get_bytes_per_line()+1)/2;
1597                         ycbcr[1].data = temp_frame->get_u();
1598                         ycbcr[2].width = frame_w/2;
1599                         ycbcr[2].height = frame_h/2;
1600                         ycbcr[2].stride = (temp_frame->get_bytes_per_line()+1)/2;
1601                         ycbcr[2].data = temp_frame->get_v();
1602                         if( th_encode_ycbcr_in(enc, ycbcr) ) {
1603                                 eprintf(_("th_encode_ycbcr_in failed"));
1604                                 return 1;
1605                         }
1606                         ogg_packet op;
1607                         while( th_encode_packetout(enc, last, &op) > 0 ) {
1608                                 file_lock->lock();
1609                                 ogg_stream_packetin (&to, &op);
1610                                 ++vpage.packets;
1611                                 file_lock->unlock();
1612                         }
1613                 }
1614                 if( last ) return 0;
1615                 if( !temp_frame )
1616                         temp_frame = new VFrame (0, -1, frame_w, frame_h, theora_cmodel, -1);
1617                 VFrame *frame = frames[0][j];
1618                 temp_frame->transfer_from(frame);
1619         }
1620         return 0;
1621 }
1622
1623 int FileOGG::write_frames(VFrame ***frames, int len)
1624 {
1625         return write_frames_theora(frames, len, 0);
1626 }
1627
1628
1629
1630 OGGConfigAudio::OGGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
1631  : BC_Window(PROGRAM_NAME ": Audio Compression",
1632         parent_window->get_abs_cursor_x(1),
1633         parent_window->get_abs_cursor_y(1),
1634         xS(350), yS(250))
1635 {
1636         this->parent_window = parent_window;
1637         this->asset = asset;
1638 // *** CONTEXT_HELP ***
1639         context_help_set_keyword("Single File Rendering");
1640 }
1641
1642 OGGConfigAudio::~OGGConfigAudio()
1643 {
1644
1645 }
1646
1647 void OGGConfigAudio::create_objects()
1648 {
1649 //      add_tool(new BC_Title(10, 10, _("There are no audio options for this format")));
1650
1651         int x = xS(10), y = yS(10);
1652         int x1 = xS(150);
1653         char string[BCTEXTLEN];
1654
1655         lock_window("OGGConfigAudio::create_objects");
1656         add_tool(fixed_bitrate = new OGGVorbisFixedBitrate(x, y, this));
1657         add_tool(variable_bitrate = new OGGVorbisVariableBitrate(x + fixed_bitrate->get_w() + xS(5),
1658                 y,
1659                 this));
1660
1661         y += yS(30);
1662         sprintf(string, "%d", asset->vorbis_min_bitrate);
1663         add_tool(new BC_Title(x, y, _("Min bitrate:")));
1664         add_tool(new OGGVorbisMinBitrate(x1, y, this, string));
1665
1666         y += yS(30);
1667         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
1668         sprintf(string, "%d", asset->vorbis_bitrate);
1669         add_tool(new OGGVorbisAvgBitrate(x1, y, this, string));
1670
1671         y += yS(30);
1672         add_tool(new BC_Title(x, y, _("Max bitrate:")));
1673         sprintf(string, "%d", asset->vorbis_max_bitrate);
1674         add_tool(new OGGVorbisMaxBitrate(x1, y, this, string));
1675
1676
1677         add_subwindow(new BC_OKButton(this));
1678         show_window(1);
1679         unlock_window();
1680 }
1681
1682 int OGGConfigAudio::close_event()
1683 {
1684         set_done(0);
1685         return 1;
1686 }
1687
1688 OGGVorbisFixedBitrate::OGGVorbisFixedBitrate(int x, int y, OGGConfigAudio *gui)
1689  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Average bitrate"))
1690 {
1691         this->gui = gui;
1692 }
1693 int OGGVorbisFixedBitrate::handle_event()
1694 {
1695         gui->asset->vorbis_vbr = 0;
1696         gui->variable_bitrate->update(0);
1697         return 1;
1698 }
1699
1700 OGGVorbisVariableBitrate::OGGVorbisVariableBitrate(int x, int y, OGGConfigAudio *gui)
1701  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
1702 {
1703         this->gui = gui;
1704 }
1705 int OGGVorbisVariableBitrate::handle_event()
1706 {
1707         gui->asset->vorbis_vbr = 1;
1708         gui->fixed_bitrate->update(0);
1709         return 1;
1710 }
1711
1712
1713 OGGVorbisMinBitrate::OGGVorbisMinBitrate(int x,
1714         int y,
1715         OGGConfigAudio *gui,
1716         char *text)
1717  : BC_TextBox(x, y, xS(180), 1, text)
1718 {
1719         this->gui = gui;
1720 }
1721 int OGGVorbisMinBitrate::handle_event()
1722 {
1723         gui->asset->vorbis_min_bitrate = atol(get_text());
1724         return 1;
1725 }
1726
1727
1728
1729 OGGVorbisMaxBitrate::OGGVorbisMaxBitrate(int x,
1730         int y,
1731         OGGConfigAudio *gui,
1732         char *text)
1733  : BC_TextBox(x, y, xS(180), 1, text)
1734 {
1735         this->gui = gui;
1736 }
1737 int OGGVorbisMaxBitrate::handle_event()
1738 {
1739         gui->asset->vorbis_max_bitrate = atol(get_text());
1740         return 1;
1741 }
1742
1743
1744
1745 OGGVorbisAvgBitrate::OGGVorbisAvgBitrate(int x, int y, OGGConfigAudio *gui, char *text)
1746  : BC_TextBox(x, y, xS(180), 1, text)
1747 {
1748         this->gui = gui;
1749 }
1750 int OGGVorbisAvgBitrate::handle_event()
1751 {
1752         gui->asset->vorbis_bitrate = atol(get_text());
1753         return 1;
1754 }
1755
1756
1757
1758
1759
1760 OGGConfigVideo::OGGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
1761  : BC_Window(PROGRAM_NAME ": Video Compression",
1762         parent_window->get_abs_cursor_x(1),
1763         parent_window->get_abs_cursor_y(1),
1764         xS(450), yS(220))
1765 {
1766         this->parent_window = parent_window;
1767         this->asset = asset;
1768 // *** CONTEXT_HELP ***
1769         context_help_set_keyword("Single File Rendering");
1770 }
1771
1772 OGGConfigVideo::~OGGConfigVideo()
1773 {
1774
1775 }
1776
1777 void OGGConfigVideo::create_objects()
1778 {
1779 //      add_tool(new BC_Title(10, 10, _("There are no video options for this format")));
1780         int x = xS(10), y = yS(10);
1781         int x1 = x + xS(150);
1782         int x2 = x + xS(300);
1783
1784         lock_window("OGGConfigVideo::create_objects");
1785         BC_Title *title;
1786         add_subwindow(title = new BC_Title(x, y, _("Bitrate:")));
1787         add_subwindow(new OGGTheoraBitrate(x + title->get_w() + xS(5), y, this));
1788         add_subwindow(fixed_bitrate = new OGGTheoraFixedBitrate(x2, y, this));
1789         y += yS(30);
1790
1791         add_subwindow(new BC_Title(x, y, _("Quality:")));
1792         add_subwindow(new BC_ISlider(x + xS(80), y, 0, xS(200), xS(200),
1793                 0, 63, asset->theora_quality,
1794                 0, 0, &asset->theora_quality));
1795
1796
1797         add_subwindow(fixed_quality = new OGGTheoraFixedQuality(x2, y, this));
1798         y += yS(30);
1799
1800         add_subwindow(new BC_Title(x, y, _("Keyframe frequency:")));
1801         OGGTheoraKeyframeFrequency *keyframe_frequency =
1802                 new OGGTheoraKeyframeFrequency(x1 + xS(60), y, this);
1803         keyframe_frequency->create_objects();
1804         y += yS(30);
1805
1806         add_subwindow(new BC_Title(x, y, _("Keyframe force frequency:")));
1807         OGGTheoraKeyframeForceFrequency *keyframe_force_frequency =
1808                 new OGGTheoraKeyframeForceFrequency(x1 + xS(60), y, this);
1809         keyframe_force_frequency->create_objects();
1810         y += yS(30);
1811
1812         add_subwindow(new BC_Title(x, y, _("Sharpness:")));
1813         OGGTheoraSharpness *sharpness =
1814                 new OGGTheoraSharpness(x1 + xS(60), y, this);
1815         sharpness->create_objects();
1816         y += yS(30);
1817
1818
1819         add_subwindow(new BC_OKButton(this));
1820         show_window(1);
1821         unlock_window();
1822 }
1823
1824
1825
1826
1827 int OGGConfigVideo::close_event()
1828 {
1829         set_done(0);
1830         return 1;
1831 }
1832
1833 OGGTheoraBitrate::OGGTheoraBitrate(int x, int y, OGGConfigVideo *gui)
1834  : BC_TextBox(x, y, xS(100), 1, gui->asset->theora_bitrate)
1835 {
1836         this->gui = gui;
1837 }
1838
1839
1840 int OGGTheoraBitrate::handle_event()
1841 {
1842         // TODO: MIN / MAX check
1843         gui->asset->theora_bitrate = atol(get_text());
1844         return 1;
1845 };
1846
1847
1848
1849
1850 OGGTheoraFixedBitrate::OGGTheoraFixedBitrate(int x, int y, OGGConfigVideo *gui)
1851  : BC_Radial(x, y, gui->asset->theora_fix_bitrate, _("Fixed bitrate"))
1852 {
1853         this->gui = gui;
1854 }
1855
1856 int OGGTheoraFixedBitrate::handle_event()
1857 {
1858         update(1);
1859         gui->asset->theora_fix_bitrate = 1;
1860         gui->fixed_quality->update(0);
1861         return 1;
1862 };
1863
1864 OGGTheoraFixedQuality::OGGTheoraFixedQuality(int x, int y, OGGConfigVideo *gui)
1865  : BC_Radial(x, y, !gui->asset->theora_fix_bitrate, _("Fixed quality"))
1866 {
1867         this->gui = gui;
1868 }
1869
1870 int OGGTheoraFixedQuality::handle_event()
1871 {
1872         update(1);
1873         gui->asset->theora_fix_bitrate = 0;
1874         gui->fixed_bitrate->update(0);
1875         return 1;
1876 };
1877
1878 OGGTheoraKeyframeFrequency::OGGTheoraKeyframeFrequency(int x, int y, OGGConfigVideo *gui)
1879  : BC_TumbleTextBox(gui, (int64_t)gui->asset->theora_keyframe_frequency,
1880         (int64_t)1, (int64_t)500, x, y, xS(40))
1881 {
1882         this->gui = gui;
1883 }
1884
1885 int OGGTheoraKeyframeFrequency::handle_event()
1886 {
1887         gui->asset->theora_keyframe_frequency = atol(get_text());
1888         return 1;
1889 }
1890
1891 OGGTheoraKeyframeForceFrequency::OGGTheoraKeyframeForceFrequency(int x, int y, OGGConfigVideo *gui)
1892  : BC_TumbleTextBox(gui, (int64_t)gui->asset->theora_keyframe_frequency,
1893         (int64_t)1, (int64_t)500, x, y, xS(40))
1894 {
1895         this->gui = gui;
1896 }
1897
1898 int OGGTheoraKeyframeForceFrequency::handle_event()
1899 {
1900         gui->asset->theora_keyframe_frequency = atol(get_text());
1901         return 1;
1902 }
1903
1904
1905 OGGTheoraSharpness::OGGTheoraSharpness(int x, int y, OGGConfigVideo *gui)
1906  : BC_TumbleTextBox(gui, (int64_t)gui->asset->theora_sharpness,
1907         (int64_t)0, (int64_t)2, x, y, xS(40))
1908 {
1909         this->gui = gui;
1910 }
1911
1912 int OGGTheoraSharpness::handle_event()
1913 {
1914         gui->asset->theora_sharpness = atol(get_text());
1915         return 1;
1916 }
1917
1918
1919 #endif