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