vorbis bld msgs, ffmpeg one frame/frame flush bug, ffmpeg audio history fixes
[goodguy/history.git] / cinelerra-5.0 / cinelerra / fileogg.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "byteorder.h"
25 #include "clip.h"
26 #include "cmodel_permutation.h"
27 #include "edit.h"
28 #include "file.h"
29 #include "fileogg.h"
30 #include "format.inc"
31 #include "guicast.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 "quicktime.h"
39 #include "vframe.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 #define READ_SIZE 66000
50
51 /* This code was aspired by ffmpeg2theora */
52 /* Special thanks for help on this code goes out to j@v2v.cc */
53
54 int ogg_ret0, ogg_ret1, ogg_ret2;
55
56 FileOGG::FileOGG(Asset *asset, File *file)
57  : FileBase(asset, file)
58 {
59         if(asset->format == FILE_UNKNOWN)
60                 asset->format = FILE_OGG;
61         asset->byte_order = 0;
62         reset_parameters();
63 }
64
65 FileOGG::~FileOGG()
66 {
67         if (tf) 
68         {
69
70                 if (tf->videosync) 
71                 {
72                         ogg_sync_clear(&tf->videosync->sync);
73                         delete tf->videosync;
74                         theora_info_clear(&tf->ti);
75                         theora_comment_clear(&tf->tc);
76                 }
77                 if (tf->audiosync) 
78                 {
79                         ogg_sync_clear(&tf->audiosync->sync);
80                         delete tf->audiosync;
81                         vorbis_info_clear(&tf->vi);
82                         vorbis_comment_clear(&tf->vc);
83                 }
84                 delete tf;
85         }
86         if (temp_frame) delete temp_frame;
87         if (stream) close_file();
88         if(pcm_history)
89         {
90                 for(int i = 0; i < asset->channels; i++)
91                         delete [] pcm_history[i];
92                 delete [] pcm_history;
93         }
94
95         if (flush_lock) delete flush_lock;
96 }
97
98 void FileOGG::get_parameters(BC_WindowBase *parent_window,
99         Asset *asset,
100         BC_WindowBase* &format_window,
101         int audio_options,
102         int video_options)
103 {
104         if(audio_options)
105         {
106                 OGGConfigAudio *window = new OGGConfigAudio(parent_window, asset);
107                 format_window = window;
108                 window->create_objects();
109                 window->run_window();
110                 delete window;
111         }
112         else
113         if(video_options)
114         {
115                 OGGConfigVideo *window = new OGGConfigVideo(parent_window, asset);
116                 format_window = window;
117                 window->create_objects();
118                 window->run_window();
119                 delete window;
120         }
121 }
122
123 int FileOGG::reset_parameters_derived()
124 {
125         tf = 0;
126         temp_frame = 0;
127         stream = 0;
128         flush_lock = 0;
129         pcm_history = 0;
130         start_frame = 0;
131         return 0;
132 }
133
134 static int read_buffer(FILE *in, sync_window_t *sw, int buflen)
135 {
136         char *buffer = ogg_sync_buffer(&sw->sync, buflen);
137 //      printf("reading range: %lli - %lli\n", sw->file_bufpos, sw->file_bufpos + buflen);
138         sw->wlen = fread(buffer, 1, buflen, in);
139         ogg_sync_wrote(&sw->sync, sw->wlen);
140 //      printf("XX data: %c %c %c %c\n", sw->sync.data[0], sw->sync.data[1], sw->sync.data[2], sw->sync.data[3]);
141         sw->file_bufpos += sw->wlen;
142 //      printf("sb: %i\n",buffer);
143         return (sw->wlen);
144 }
145
146 static int read_buffer_at(FILE *in, sync_window_t *sw, int buflen, off_t filepos)
147 {
148 //      printf("seeking to %lli %lli\n", filepos, sw->file_bufpos);
149         fseeko(in, filepos, SEEK_SET);
150 //      if (sw->file_bufpos != filepos)
151 //      {
152                 sw->file_bufpos = filepos;
153                 sw->file_pagepos = filepos; // this one is not valid until sync_pageseek!
154                 ogg_sync_reset(&sw->sync);
155                         
156 //      }
157         return read_buffer(in, sw, buflen);
158 }
159
160 static int take_page_out_autoadvance(FILE *in, sync_window_t *sw, ogg_page *og)
161 {
162         while (1)
163         {
164                 int ret = ogg_sync_pageout(&sw->sync, og);
165                 if (ret > 0)
166                 {
167 //              printf("fpa: %lli\n", sw->file_pagepos);
168 // advance 'virtual' position
169                         sw->file_pagepos += og->header_len + og->body_len; 
170 //              printf("ret2: %i %i\n",ret, og->header_len + og->body_len); 
171                         return ret;
172                 }
173                 else if (ret < 0)
174                 {
175                         printf("FileOGG: Taking page out on nonsynced stream!\n");
176                         return ret;
177                         
178                 } else
179                 {
180                         // need more data for page
181                         if ((ret = read_buffer(in, sw, READ_SIZE)) == 0) 
182                         {
183                                 printf("FileOGG: There is no more data in the file we are reading from\n");
184                                 return 0;  // No more data
185                         }
186                 }
187         }
188         return 1;
189 }
190
191
192 // we never need to autoadvance when syncing, since our read chunks are larger than 
193 // maximum page size
194 static int sync_and_take_page_out(sync_window_t *sw, ogg_page *page)
195 {
196         page->header_len = 0;
197         page->body_len = 0;
198         page->header = 0;
199         page->body = 0;
200         int ret = ogg_sync_pageseek(&sw->sync, page);
201         if (ret < 0)
202         {
203                 sw->file_pagepos -= ret;
204         }
205         else if (ret > 0)
206         {
207                 sw->file_pagepos += ret;
208 //              printf("ret: %i %i\n",ret, page->header_len + page->body_len); 
209         }
210         return ret;
211 }
212
213 int FileOGG::open_file(int rd, int wr)
214 {
215         if (!tf)
216         {
217                 tf = new theoraframes_info_t;
218                 tf->audiosync = 0;
219                 tf->videosync = 0;
220         }
221
222
223         if(wr)
224         {
225
226
227                 if((stream = fopen(asset->path, "w+b")) == 0)
228                 {
229                         perror(_("FileOGG::open_file rdwr"));
230                         return 1;
231                 }
232
233                 tf->audio_bytesout = 0;
234                 tf->video_bytesout = 0;
235                 tf->videotime = 0;
236                 tf->audiotime = 0;
237
238                 tf->vpage_valid = 0;
239                 tf->apage_valid = 0;
240                 tf->apage_buffer_length = 0;
241                 tf->vpage_buffer_length = 0;
242                 tf->apage = NULL;
243                 tf->vpage = NULL;
244             tf->v_pkg=0;
245         tf->a_pkg=0;
246
247
248                 /* yayness.  Set up Ogg output stream */
249                 srand (time (NULL));
250
251                 if(asset->video_data)
252                 {
253                         ogg_stream_init (&tf->to, rand ());    /* oops, add one ot the above */
254                 
255                         theora_info_init (&tf->ti);
256                         
257                         tf->ti.frame_width = asset->width; 
258                         tf->ti.frame_height = asset->height;
259                         
260                         tf->ti.width = ((asset->width + 15) >>4)<<4; // round up to the nearest multiple of 16 
261                         tf->ti.height = ((asset->height + 15) >>4)<<4; // round up to the nearest multiple of 16
262                         if (tf->ti.width != tf->ti.frame_width || tf->ti.height != tf->ti.frame_height)
263                                 printf("FileOGG: WARNING: Encoding theora when width or height are not dividable by 16 is suboptimal\n");
264                         
265                         tf->ti.offset_x = 0;
266                         tf->ti.offset_y = tf->ti.height - tf->ti.frame_height;
267                         tf->ti.fps_numerator = (unsigned int)(asset->frame_rate * 1000000);
268                         tf->ti.fps_denominator = 1000000;
269                         
270                         if (asset->aspect_ratio > 0)
271                         {
272                                 // Cinelerra uses frame aspect ratio, theora uses pixel aspect ratio
273                                 float pixel_aspect = asset->aspect_ratio / asset->width * asset->height;
274                                 tf->ti.aspect_numerator = (unsigned int)(pixel_aspect * 1000000);
275                                 tf->ti.aspect_denominator = 1000000;
276                         } else
277                         {
278                                 tf->ti.aspect_numerator = 1000000;
279                                 tf->ti.aspect_denominator = 1000000;
280                         }
281                         if(EQUIV(asset->frame_rate, 25) || EQUIV(asset->frame_rate, 50))
282                                 tf->ti.colorspace = OC_CS_ITU_REC_470BG;
283                         else if((asset->frame_rate > 29 && asset->frame_rate < 31) || (asset->frame_rate > 59 && asset->frame_rate < 61) )
284                                 tf->ti.colorspace = OC_CS_ITU_REC_470M;
285                         else
286                                 tf->ti.colorspace = OC_CS_UNSPECIFIED;
287
288                         if (asset->theora_fix_bitrate)
289                         {
290                                 tf->ti.target_bitrate = asset->theora_bitrate; 
291                                 tf->ti.quality = 0;
292                         } else
293                         {
294                                 tf->ti.target_bitrate = 0;
295                                 tf->ti.quality = asset->theora_quality;     // video quality 0-63
296                         }
297                         tf->ti.dropframes_p = 0;
298                         tf->ti.quick_p = 1;
299                         tf->ti.keyframe_auto_p = 1;
300                         tf->ti.keyframe_frequency = asset->theora_keyframe_frequency;
301                         tf->ti.keyframe_frequency_force = asset->theora_keyframe_force_frequency;
302                         tf->ti.keyframe_data_target_bitrate = (unsigned int) (tf->ti.target_bitrate * 1.5) ;
303                         tf->ti.keyframe_auto_threshold = 80;
304                         tf->ti.keyframe_mindistance = 8;
305                         tf->ti.noise_sensitivity = 1;           
306                         tf->ti.sharpness = 2;
307                         
308                                         
309                         if (theora_encode_init (&tf->td, &tf->ti))
310                         {
311                                 printf("FileOGG: initialization of theora codec failed\n");
312                         }
313                 }
314                 /* init theora done */
315
316                 /* initialize Vorbis too, if we have audio. */
317                 if(asset->audio_data)
318                 {
319                         ogg_stream_init (&tf->vo, rand ());    
320                         vorbis_info_init (&tf->vi);
321                         /* Encoding using a VBR quality mode.  */
322                         int ret;
323                         if(!asset->vorbis_vbr) 
324                         {
325                                 ret = vorbis_encode_init(&tf->vi, 
326                                                         asset->channels, 
327                                                         asset->sample_rate, 
328                                                         asset->vorbis_max_bitrate, 
329                                                         asset->vorbis_bitrate,
330                                                         asset->vorbis_min_bitrate); 
331                         } else
332                         {
333                                 // Set true VBR as demonstrated by http://svn.xiph.org/trunk/vorbis/doc/vorbisenc/examples.html
334                                 ret = vorbis_encode_setup_managed(&tf->vi,
335                                         asset->channels, 
336                                         asset->sample_rate, 
337                                         -1, 
338                                         asset->vorbis_bitrate, 
339                                         -1);
340                                 ret |= vorbis_encode_ctl(&tf->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
341                                 ret |= vorbis_encode_setup_init(&tf->vi);
342                         }
343
344                         if (ret)
345                         {
346                                 eprintf("The Vorbis encoder could not set up a mode according to\n"
347                                         "the requested quality or bitrate.\n\n");
348                                 return 1;
349                         }
350
351                         vorbis_comment_init (&tf->vc); // comment is cleared lateron 
352                         vorbis_comment_add_tag (&tf->vc, (char*)"ENCODER", (char*)PACKAGE_STRING);
353                         /* set up the analysis state and auxiliary encoding storage */
354                         vorbis_analysis_init (&tf->vd, &tf->vi);
355                         vorbis_block_init (&tf->vd, &tf->vb);
356
357                 }
358                 /* audio init done */
359
360                 /* write the bitstream header packets with proper page interleave */
361
362                 /* first packet will get its own page automatically */
363                 if(asset->video_data)
364                 {
365                         theora_encode_header (&tf->td, &tf->op);
366                         ogg_stream_packetin (&tf->to, &tf->op);
367                         if (ogg_stream_pageout (&tf->to, &tf->og) != 1)
368                         {
369                                 eprintf("Internal Ogg library error.\n");
370                                 return 1;
371                         }
372                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
373                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
374
375                         /* create the remaining theora headers */
376                         theora_comment_init (&tf->tc);
377                         theora_comment_add_tag (&tf->tc, (char*)"ENCODER", (char*)PACKAGE_STRING);
378                         theora_encode_comment (&tf->tc, &tf->op);
379                         ogg_stream_packetin (&tf->to, &tf->op);
380                         theora_comment_clear(&tf->tc);
381                         theora_encode_tables (&tf->td, &tf->op);
382                         ogg_stream_packetin (&tf->to, &tf->op);
383                 }
384                 if(asset->audio_data)
385                 {
386                         ogg_packet header;
387                         ogg_packet header_comm;
388                         ogg_packet header_code;
389
390                         vorbis_analysis_headerout (&tf->vd, &tf->vc, &header,
391                                        &header_comm, &header_code);
392                         ogg_stream_packetin (&tf->vo, &header);    /* automatically placed in its own page */
393                         vorbis_comment_clear(&tf->vc);
394                         if (ogg_stream_pageout (&tf->vo, &tf->og) != 1)
395                         {
396                                 eprintf("Internal Ogg library error.\n");
397                                 return 1;
398                         }
399                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
400                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
401
402                         /* remaining vorbis header packets */
403                         ogg_stream_packetin (&tf->vo, &header_comm);
404                         ogg_stream_packetin (&tf->vo, &header_code);
405                 }
406
407                 /* Flush the rest of our headers. This ensures
408                  * the actual data in each stream will start
409                  * on a new page, as per spec. */
410                 while (1 && asset->video_data)
411                 {
412                         int result = ogg_stream_flush (&tf->to, &tf->og);
413                         if (result < 0)
414                         {
415                                 /* can't get here */
416                                 eprintf("Internal Ogg library error.\n");
417                                 return 1;
418                         }
419                         if (result == 0)
420                                 break;
421                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
422                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
423                 }
424                 while (1 && asset->audio_data)
425                 {
426                         int result = ogg_stream_flush (&tf->vo, &tf->og);
427                         if (result < 0)
428                         {
429                                 /* can't get here */
430                                 eprintf("Internal Ogg library error.\n");
431                                 return 1;
432                         }
433                         if (result == 0)
434                                 break;
435                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
436                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
437                 }
438                 flush_lock = new Mutex("OGGFile::Flush lock");
439 //              printf("End of headers at position: %lli\n", ftello(stream));
440         } else
441         if (rd)
442         {
443
444                 if((stream = fopen(asset->path, "rb")) == 0)
445                 {
446                         perror(_("FileOGG::open_file rdwr"));
447                         return 1;
448                 }
449
450                 /* get file length */
451                 struct stat file_stat;
452                 stat(asset->path, &file_stat);
453                 file_length = file_stat.st_size;
454
455                 /* start up Ogg stream synchronization layer */
456                 /* oy is used just here to parse header, we use separate syncs for video and audio*/
457                 sync_window_t oy;
458                 ogg_sync_init(&oy.sync);
459                 // make sure we init the position structures to zero
460                 read_buffer_at(stream, &oy, READ_SIZE, 0);
461
462
463                 /* init supporting Vorbis structures needed in header parsing */
464                 vorbis_info_init(&tf->vi);
465                 vorbis_comment_init(&tf->vc);
466
467
468                 /* init supporting Theora structures needed in header parsing */
469                 theora_comment_init(&tf->tc);
470                 theora_info_init(&tf->ti);
471
472
473
474                 /* Ogg file open; parse the headers */
475                 /* Only interested in Vorbis/Theora streams */
476                 int stateflag = 0;
477                 int theora_p = 0;
478                 int vorbis_p = 0;
479                 while(!stateflag)
480                 {
481
482
483 //                      int ret = read_buffer(stream, &oy, 4096);
484                         TRACE("FileOGG::open_file 60")
485 //                      if(ret == 0)
486 //                              break;
487                         
488                         while(take_page_out_autoadvance(stream, &oy, &tf->og) > 0)
489                         {
490                                 ogg_stream_state test;
491
492                                 /* is this a mandated initial header? If not, stop parsing */
493                                 if(!ogg_page_bos(&tf->og))
494                                 {
495                                         /* don't leak the page; get it into the appropriate stream */
496                                 //      queue_page(&tf->og);
497                                         if(theora_p)ogg_stream_pagein(&tf->to, &tf->og);
498                                         if(vorbis_p)ogg_stream_pagein(&tf->vo, &tf->og);
499                                 
500                                         stateflag = 1;
501                                         break;
502                                 }
503
504                                 ogg_stream_init(&test, ogg_page_serialno(&tf->og));
505                                 ogg_stream_pagein(&test, &tf->og);
506                                 ogg_stream_packetout(&test, &tf->op);
507
508                                 /* identify the codec: try theora */
509                                 if(!theora_p && theora_decode_header(&tf->ti, &tf->tc, &tf->op)>=0)
510                                 {
511                                         /* it is theora */
512                                         memcpy(&tf->to, &test, sizeof(test));
513                                         theora_p = 1;
514         // find out granule shift - from liboggz's oggz_auto.c
515                                         unsigned char * header = tf->op.packet;
516                                         theora_keyframe_granule_shift = (char) ((header[40] & 0x03) << 3);
517                                         theora_keyframe_granule_shift |= (header[41] & 0xe0) >> 5;
518
519                                 } else if(!vorbis_p && vorbis_synthesis_headerin(&tf->vi, &tf->vc, &tf->op)>=0)
520                                 {
521                                         /* it is vorbis */
522                                         memcpy(&tf->vo, &test, sizeof(test));
523                                         vorbis_p = 1;
524                                 } else 
525                                 {
526                                         /* whatever it is, we don't care about it */
527                                         ogg_stream_clear(&test);
528                                 }
529                         }
530                 /* fall through to non-bos page parsing */
531                 }
532
533
534                 /* we're expecting more header packets. */
535                 while((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3))
536                 {
537                         int ret;
538
539                         /* look for further theora headers */
540                         while(theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&tf->to, &tf->op)))
541                         {
542                                 if(ret < 0)
543                                 {
544                                         eprintf("FileOGG: Error parsing Theora stream headers; corrupt stream?\n");
545                                         return 1;
546                                 }
547                                 if(theora_decode_header(&tf->ti, &tf->tc, &tf->op))
548                                 {
549                                         printf("FileOGG: Error parsing Theora stream headers; corrupt stream?\n");
550                                         return 1;
551                                 }
552                                 theora_p++;
553                                 if(theora_p == 3) 
554                                         break;
555                         }
556
557                         /* look for more vorbis header packets */
558                         while(vorbis_p && (vorbis_p < 3) && (ret = ogg_stream_packetout(&tf->vo, &tf->op)))
559                         {
560                                 if(ret<0)
561                                 {
562                                         eprintf("FileOGG: Error parsing Vorbis stream headers; corrupt stream?\n");
563                                         return 1;
564                                 }
565                                 if (vorbis_synthesis_headerin(&tf->vi, &tf->vc, &tf->op))
566                                 {
567                                         eprintf("FileOGG: Error parsing Vorbis stream headers; corrupt stream?\n");
568                                         return 1;
569                                 }
570                                 vorbis_p++;
571                                 if (vorbis_p == 3)
572                                         break;
573                         }
574
575                         if (vorbis_p == 3 && theora_p == 3) 
576                                 break;
577                         /* The header pages/packets will arrive before anything else we
578                             care about, or the stream is not obeying spec */
579
580                         if(take_page_out_autoadvance(stream, &oy, &tf->og) > 0)
581                         {
582 //                              queue_page(&tf->og); /* demux into the appropriate stream */
583                                 if(theora_p) ogg_stream_pagein(&tf->to, &tf->og);
584                                 if(vorbis_p) ogg_stream_pagein(&tf->vo, &tf->og);
585
586                         } else
587                         {
588                                 eprintf("FileOGG: End of file while searching for codec headers.\n");
589                                 return 1;
590                         }
591                 }
592                 // Remember where the real data begins for later seeking purposes
593                 filedata_begin = oy.file_pagepos; 
594
595
596
597                 /* and now we have it all.  initialize decoders */
598                 if(theora_p)
599                 {
600                         int ret;
601
602 // WORKAROUND for bug in alpha4 version of theora:
603                         tf->td.internal_encode = 0;
604
605                         ret = theora_decode_init(&tf->td, &tf->ti);
606                         if( ret ) printf("theora_decode_init ret=%d\n", ret);
607                         double fps = (double)tf->ti.fps_numerator/tf->ti.fps_denominator;
608 /*                      printf("FileOGG: Ogg logical stream %x is Theora %dx%d %.02f fps\n",
609                                 (unsigned int)tf->to.serialno, tf->ti.width, tf->ti.height, 
610                                 fps);
611 */
612 /*
613 Not yet available in alpha4, we assume 420 for now
614
615                         switch(tf->ti.pixelformat)
616                         {
617                                 case OC_PF_420: printf(" 4:2:0 video\n"); break;
618                                 case OC_PF_422: printf(" 4:2:2 video\n"); break;
619                                 case OC_PF_444: printf(" 4:4:4 video\n"); break;
620                                 case OC_PF_RSVD:
621                                 default:
622                                         printf(" video\n  (UNKNOWN Chroma sampling!)\n");
623                                 break;
624                         }
625 */
626
627                         theora_cmodel = BC_YUV420P;
628                         
629                         if(tf->ti.width!=tf->ti.frame_width || tf->ti.height!=tf->ti.frame_height)
630                                 printf("FileOGG::  Frame content is %dx%d with offset (%d,%d), We do not support this yet.\n",
631                                 tf->ti.frame_width, tf->ti.frame_height, tf->ti.offset_x, tf->ti.offset_y);
632
633                         tf->videosync = new sync_window_t;
634                         ogg_sync_init(&tf->videosync->sync);
635                         tf->videosync->wlen = 0;
636
637                         ret = ogg_get_first_page(tf->videosync, tf->to.serialno, &tf->videopage);
638                         if( !ret ) printf("ogg_get_first_page ret=%d\n", ret);
639                         ogg_packet op;
640
641                         // we have headers already decoded, so just skip them
642                         ogg_stream_reset(&tf->to);
643                         ogg_stream_pagein(&tf->to, &tf->videopage);
644                         while (1)
645                         {
646                                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
647                                 {
648                                         if (!ogg_get_next_page(tf->videosync, tf->to.serialno, &tf->videopage))
649                                         {
650                                                 printf("FileOGG: Cannot find next page while looking for first non-header packet\n");
651                                                 return 1;
652                                         }
653                                         ogg_stream_pagein(&tf->to, &tf->videopage);
654                                 }
655                                 ogg_stream_packetout(&tf->to, &op);
656                                 if (!theora_packet_isheader(&op))
657                                         break;
658                         }
659                         // now get to the page of the finish of the first packet
660                         while (ogg_page_packets(&tf->videopage) == 0) 
661                         {
662                                 if (ogg_page_granulepos(&tf->videopage) != -1)
663                                 {
664                                         printf("FileOGG: Broken ogg file - broken page: ogg_page_packets == 0 and granulepos != -1\n");
665                                         return 1;
666                                 }
667                                 ogg_get_next_page(tf->videosync, tf->to.serialno, &tf->videopage);
668                         }
669                         // FIXME - LOW PRIORITY - start counting at first decodable keyframe!
670                         // but then we have to fix a/v sync somehow
671                         start_frame = (int64_t) (theora_granule_frame (&tf->td, ogg_page_granulepos(&tf->videopage)) - ogg_page_packets(&tf->videopage)) + 1;
672
673                         ret = ogg_get_last_page(tf->videosync, tf->to.serialno, &tf->videopage);
674                         last_frame = (int64_t) (theora_granule_frame (&tf->td, ogg_page_granulepos(&tf->videopage)));
675                         asset->video_length = last_frame - start_frame + 1;
676 //                      printf("FileOGG:: first frame: %lli, last frame: %lli, video length: %lli\n", start_frame, last_frame, asset->video_length);
677                         
678                         asset->layers = 1;
679                         // FIXME - LOW PRIORITY Cinelerra does not honor the frame_width and frame_height
680                         asset->width = tf->ti.width;
681                         asset->height = tf->ti.height;
682 // Don't want a user configured frame rate to get destroyed
683                         if(!asset->frame_rate)
684                                 asset->frame_rate = fps;
685
686         /*              ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 0 +start_frame);
687                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 1 +start_frame);
688                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 5 +start_frame);
689                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 206 +start_frame);
690                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 207 +start_frame);
691                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 208 +start_frame);
692
693                         int64_t kf;
694                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 0 + start_frame, &kf);
695                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 1 + start_frame, &kf);
696                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 5 + start_frame, &kf);
697                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 66 + start_frame, &kf);
698                         //printf("Keyframe: %lli\n", kf);
699                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 1274 + start_frame, &kf);
700 */
701         
702                         set_video_position(0); // make sure seeking is done to the first sample
703                         ogg_frame_position = -10;
704                         asset->video_data = 1;
705                         strncpy(asset->vcodec, "theo", 4);
706
707
708 //                  report_colorspace(&ti);
709 //                  dump_comments(&tc);
710                 } else 
711                 {
712                         /* tear down the partial theora setup */
713                         theora_info_clear(&tf->ti);
714                         theora_comment_clear(&tf->tc);
715                 }
716
717
718                 if(vorbis_p)
719                 {
720                         vorbis_synthesis_init(&tf->vd, &tf->vi);
721                         vorbis_block_init(&tf->vd, &tf->vb);
722 /*                      eprintf("FileOGG: Ogg logical stream %x is Vorbis %d channel %d Hz audio.\n",
723                                 (unsigned int)tf->vo.serialno, tf->vi.channels, (int)tf->vi.rate);
724 */                      
725                         /* init audio_sync structure */
726                         tf->audiosync = new sync_window_t;
727                         ogg_sync_init(&tf->audiosync->sync);
728                         tf->audiosync->wlen = 0;
729
730                         ogg_get_first_page(tf->audiosync, tf->vo.serialno, &tf->audiopage);
731                         ogg_packet op;
732                         ogg_stream_reset(&tf->vo);
733                         // FIXME - LOW PRIORITY should be getting pages until one has granulepos,
734                         //   probably never happens in pracitce
735                         ogg_ret2 = ogg_stream_pagein(&tf->vo, &tf->audiopage);
736                         ogg_int64_t accumulated = 0;
737                         long lastblock = -1;
738                         int result;
739                         while((result = ogg_stream_packetout(&tf->vo, &op)))
740                         {
741                                 if(result > 0)
742                                 { // ignore holes 
743                                         long thisblock =  vorbis_packet_blocksize(&tf->vi, &op);
744                                         if(lastblock != -1)
745                                                 accumulated += (lastblock + thisblock) >> 2;
746                                         lastblock = thisblock;
747                                 }
748                         }
749                         start_sample = ogg_page_granulepos(&tf->audiopage) - accumulated;
750 /*
751                         printf("Begin: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
752                                         tf->audiosync->file_pagepos_found,
753                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
754                                         ogg_page_granulepos(&tf->audiopage), 
755                                         ogg_page_serialno(&tf->audiopage));
756                         while (ogg_get_next_page(tf->audiosync, tf->vo.serialno, &tf->audiopage))
757                                 printf("At byte: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
758                                         tf->audiosync->file_pagepos_found,
759                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
760                                         ogg_page_granulepos(&tf->audiopage), 
761                                         ogg_page_serialno(&tf->audiopage));
762 */
763
764                         ogg_ret1 = ogg_get_last_page(tf->audiosync, tf->vo.serialno, &tf->audiopage);
765                         last_sample = ogg_page_granulepos(&tf->audiopage);
766                         asset->audio_length = last_sample - start_sample;
767                                                 
768 /*                      printf("FileOGG:: First sample: %lli, last_sample: %lli\n", start_sample, last_sample);
769                         printf("FileOGG:: audio length: samples: %lli, playing time: %f\n", asset->audio_length, 1.0 * asset->audio_length / tf->vi.rate);
770 */                      
771 /*                      printf("End: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
772                                         tf->audiosync->file_pagepos_found,
773                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
774                                         ogg_page_granulepos(&tf->audiopage), 
775                                         ogg_page_serialno(&tf->audiopage));
776                         while (ogg_get_prev_page(tf->audiosync, tf->vo.serialno, &tf->audiopage))
777                                 printf("At byte: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
778                                         tf->audiosync->file_pagepos_found,
779                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
780                                         ogg_page_granulepos(&tf->audiopage), 
781                                         ogg_page_serialno(&tf->audiopage));
782 */
783                         
784 /*                      ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 0);
785                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 1);
786                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 50);
787                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 5000);
788                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 30000);
789                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 50000);
790                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 90000);
791                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 95999);
792                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 96000);
793                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 0);
794                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 1);
795                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 5000);
796                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 30000);
797                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 50000);
798                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 90000);
799                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 95999);
800                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 96000);
801 */                      
802                         asset->channels = tf->vi.channels;
803                         if(!asset->sample_rate)
804                                 asset->sample_rate = tf->vi.rate;
805                         asset->audio_data = 1;
806                         
807
808                         ogg_sample_position = -10;
809                         set_audio_position(0); // make sure seeking is done to the first sample
810                         strncpy(asset->acodec, "vorb", 4);
811
812
813                 } else 
814                 {
815                         /* tear down the partial vorbis setup */
816                         vorbis_info_clear(&tf->vi);
817                         vorbis_comment_clear(&tf->vc);
818                 }
819
820                 ogg_sync_clear(&oy.sync);
821
822         }
823         return 0;
824 }
825
826 int FileOGG::ogg_get_prev_page(sync_window_t *sw, long serialno, ogg_page *og)
827 {
828         ogg_page page;
829         off_t filepos = sw->file_pagepos_found - READ_SIZE;
830         int first_page_offset = 0;
831         int done = 0;   
832         int read_len = READ_SIZE;
833
834 //      printf("fp: %lli pagepos found: %lli\n", filepos, sw->file_pagepos_found);
835         while (!done)
836         {
837                 if (filepos < 0)
838                 {
839 //                      read_len = read_len - (filedata_begin - filepos);
840                         read_len = read_len + filepos;
841                         filepos = 0;
842                 }
843                 if (read_len <= 0) 
844                         return 0;
845                 int have_read = read_buffer_at(stream, sw, read_len, filepos);
846                 
847 //              printf("reading at %lli, len: %i, read: %i, pagepos: %lli, pageposfound: %lli\n", filepos, read_len, have_read, sw->file_pagepos, sw->file_pagepos_found);
848 //              printf("Buffer position: %lli\n", sw->file_bufpos);
849 //              printf("SS: storage: %i, fill: %i, returned: %i\n", sw->sync.storage, sw->sync.fill, sw->sync.returned);
850 //              printf("US: unsynced%i, headrebytes: %i, bodybyes: %i\n", sw->sync.unsynced, sw->sync.headerbytes, sw->sync.bodybytes);
851 //              printf("data: %c %c %c %c\n", sw->sync.data[0], sw->sync.data[1], sw->sync.data[2], sw->sync.data[3]);
852                 if (!have_read) 
853                         return 0;
854                 
855 // read all pages in the buffer
856                 int page_offset = 0;
857                 int page_length = 0;
858                 int first_page = 1;
859                 while (first_page || page_length) 
860                 {
861                         // if negative, skip bytes
862                         while ((page_length = sync_and_take_page_out(sw, &page)) < 0)
863                         {
864                                 page_offset -= page_length;
865                                                 
866 //                              if (filepos == 0)
867 //                                      printf("BBBb page_len: %i\n", page_length);
868                         }
869 //                      if (filepos == 0 && page_length)
870 //                      {
871 //                              printf("AAAAAAAAAAAAAAAAAAAAAAAAAaaa\n");
872 //                              printf("pp: %lli %x\n", sw->file_pagepos, ogg_page_serialno(&page));
873 //                      }
874                         if (first_page)
875                                 first_page_offset = page_offset;
876                         first_page = 0;
877 //                      printf("pl: %i, serial: %x iscem: %x\n", page_length, ogg_page_serialno(&page), serialno);
878                         if (page_length && ogg_page_serialno(&page) == serialno)
879                         {
880                                 // we will copy every page until last page in this buffer
881                                 done = 1;
882                                 
883                                 sw->file_pagepos_found = sw->file_pagepos - page.header_len - page.body_len;
884 //                              printf("got it : %lli %i %i\n", sw->file_pagepos, page.header_len, page.body_len);
885                                 memcpy(og, &page, sizeof(page));
886                         }
887                 }
888 //              printf("fpo: %i\n", first_page_offset);
889                 filepos += first_page_offset - READ_SIZE;
890         }
891         
892 //      printf("finished\n");
893         if (done) 
894                 return 1;
895         else 
896                 return 0;
897 }
898
899 int FileOGG::ogg_get_last_page(sync_window_t *sw, long serialno, ogg_page *og)
900 {
901         ogg_page page;
902         off_t filepos = file_length - READ_SIZE;
903         if (filepos < 0) 
904                 filepos = 0;
905
906         int first_page_offset = 0;
907         int done = 0;   
908         while (!done && filepos >= 0)
909         {
910                 //int readlen =
911                   read_buffer_at(stream, sw, READ_SIZE, filepos);
912
913 // read all pages in the buffer
914                 int page_offset = 0;
915                 int page_length = 0;
916                 int first_page = 1;
917                 while (first_page || page_length) 
918                 {
919                         // if negative, skip bytes
920                         while ((page_length = sync_and_take_page_out(sw, &page)) < 0)
921                                         page_offset -= page_length;
922                         if (first_page)
923                                 first_page_offset = page_offset;
924                         first_page = 0;
925                         if (page_length && ogg_page_serialno(&page) == serialno)
926                         {
927                                 // we will copy every page until last page in this buffer
928                                 done = 1;
929                                 sw->file_pagepos_found = sw->file_pagepos - page.header_len - page.body_len;
930                                 memcpy(og, &page, sizeof(page));
931                         }
932                 }
933                 filepos = filepos + first_page_offset - READ_SIZE;              
934         }
935         
936         if (done) 
937                 return 1;
938         else 
939                 return 0;
940 }
941
942 int FileOGG::ogg_get_first_page(sync_window_t *sw, long serialno, ogg_page *og)
943 {
944 //      printf("FileOGG:: Seeking to first page at %lli\n", filedata_begin);
945         read_buffer_at(stream, sw, READ_SIZE, 0);
946 // we don't even need to sync since we _know_ it is right
947         return (ogg_get_next_page(sw, serialno, og));
948 }
949
950 int FileOGG::ogg_seek_to_databegin(sync_window_t *sw, long serialno)
951 {
952         
953 //      printf("FileOGG:: Seeking to first page at %lli\n", filedata_begin);
954         read_buffer_at(stream, sw, READ_SIZE, filedata_begin);
955 // we don't even need to sync since we _know_ it is right
956         return (0);
957 }
958
959 int FileOGG::ogg_get_next_page(sync_window_t *sw, long serialno, ogg_page *og)
960 {
961         while (take_page_out_autoadvance(stream, sw, og) > 0)
962         { 
963                 if (ogg_page_serialno(og) == serialno)
964                 {
965                         sw->file_pagepos_found = sw->file_pagepos - og->header_len - og->body_len;
966                         return 1;
967                 }
968         }
969         return 0;
970 }
971
972 int FileOGG::ogg_sync_and_get_next_page(sync_window_t *sw, long serialno, ogg_page *og)
973 {
974 // TODO: Put better error reporting inhere
975         int ret;
976         while ((ret = sync_and_take_page_out(sw, og)) < 0)
977         {
978                 // do nothing;
979         }
980         if (ret == 0) 
981                 return 0;
982         if (ogg_page_serialno(og) == serialno)
983         {
984                 sw->file_pagepos_found = sw->file_pagepos - og->header_len - og->body_len;
985                 return 1;
986         }
987         while (ogg_get_next_page(sw, serialno, og))
988                 if (ogg_page_serialno(og) == serialno)
989                 {
990                         sw->file_pagepos_found = sw->file_pagepos - og->header_len - og->body_len;
991                         return 1;
992                 }
993         
994         return 0;
995 }
996 // Returns:
997 // >= 0, number of sample within a page
998 // <  0 error
999 int FileOGG::ogg_get_page_of_sample(sync_window_t *sw, long serialno, ogg_page *og, int64_t sample)
1000 {
1001 // First make an educated guess about position
1002         if (sample >= asset->audio_length + start_sample)
1003         {
1004                 printf("FileOGG: Illegal seek beyond end of samples\n");
1005                 return 0;
1006         }
1007         off_t educated_guess = filedata_begin + (file_length - filedata_begin) * (sample - start_sample) / asset->audio_length - READ_SIZE;
1008         if (educated_guess < 0) 
1009                 educated_guess = 0;
1010 //      printf("My educated guess: %lli\n", educated_guess); 
1011 // now see if we won
1012         read_buffer_at(stream, sw, READ_SIZE, educated_guess);
1013         ogg_sync_and_get_next_page(sw, serialno, og);
1014         int64_t end_sample = ogg_page_granulepos(og);
1015         // linear seek to the sample
1016         int64_t start_sample = 0;
1017 // TODO: Use bisection also
1018 //      printf("Next page granulepos: %lli, pagepos: %lli\n", end_sample, sw->file_pagepos_found);
1019         if (end_sample <= sample)
1020         {
1021         // scan forward
1022                 while (end_sample <= sample)
1023                 {
1024                         ogg_get_next_page(sw, serialno, og); 
1025                         start_sample = end_sample;
1026                         end_sample = ogg_page_granulepos(og);
1027                 }
1028                 ogg_get_prev_page(sw, serialno, og);
1029                 while (ogg_page_continued(og) && ogg_page_packets(og) == 1)
1030                         ogg_get_prev_page(sw, serialno, og);
1031         } else
1032         {
1033         // scan backward
1034                 start_sample = end_sample;
1035                 while (start_sample > sample || (ogg_page_continued(og) && 
1036                         ogg_page_packets(og) == 1))
1037                 {
1038 //                      printf("get prev page: %lli pagepos:%lli\n", ogg_page_granulepos(og), sw->file_pagepos_found);
1039                         ogg_get_prev_page(sw, serialno, og);
1040                         end_sample = start_sample;
1041                         start_sample = ogg_page_granulepos(og);
1042                 }
1043         // go forward one page at the end
1044
1045         }
1046         
1047 //      printf("For sample %lli we need to start decoding on page with granulepos: %lli\n", sample, ogg_page_granulepos(og));
1048         return 1;
1049 }
1050
1051 // seeks, so next sample returned will be the correct one
1052 // sample here is still the vorbis sample number (= cinelerra sample number + start_sample)
1053 // reinits the decoding engine
1054
1055 int FileOGG::ogg_seek_to_sample(sync_window_t *sw, long serialno, int64_t sample)
1056 {
1057         // MAYBE FIXME - find out if we really are decoding previous two packets or not
1058         // get to the sample
1059         ogg_page og;
1060         ogg_packet op;
1061 //      printf("Calling get page of sample\n");
1062         if (!ogg_get_page_of_sample(sw, serialno, &og, sample))
1063         {
1064                 printf("FileOGG: Seeking to sample's page failed\n");
1065                 return 0;
1066         }
1067 //      printf("Pagepos: %lli\n", sw->file_pagepos);
1068         vorbis_synthesis_restart(&tf->vd);
1069         ogg_stream_reset(&tf->vo);
1070         ogg_stream_pagein(&tf->vo, &og);
1071         int sync = 0;
1072 //      printf("seeking to sample : %lli , starting at page with gpos: %lli\n", sample, ogg_page_granulepos(&og));
1073         
1074         int64_t current_comming_sample = -1;
1075         while (1) 
1076         {
1077         
1078                 // make sure we have a packet ready
1079                 while (ogg_stream_packetpeek(&tf->vo, NULL) != 1)
1080                 {
1081                         if (!ogg_get_next_page(sw, serialno, &og))
1082                         {
1083                                 printf("FileOGG: Cannot find next page while seeking\n");
1084                                 return 0;
1085                         }
1086                         ogg_stream_pagein(&tf->vo, &og);
1087                 }
1088                 ogg_stream_packetout(&tf->vo, &op);
1089                 if (sync)
1090                 {
1091                         
1092                         if(!vorbis_synthesis(&tf->vb, &op))
1093                         {
1094                                 ogg_ret0 = vorbis_synthesis_blockin(&tf->vd, &tf->vb);
1095                                 int64_t previous_comming_sample = current_comming_sample;
1096                                 current_comming_sample += vorbis_synthesis_pcmout(&tf->vd, NULL);
1097                                 if (current_comming_sample > sample)
1098                                 {
1099                                         vorbis_synthesis_read(&tf->vd, (sample - previous_comming_sample));
1100 //                                      printf("WE GOT IT, samples already decoded: " _LD "\n", vorbis_synthesis_pcmout(&tf->vd,NULL));
1101                                         return 1; // YAY next sample read is going to be ours, sexy!
1102                                 } else
1103                                 {
1104                                         // discard decoded data before current sample
1105                                         vorbis_synthesis_read(&tf->vd, (current_comming_sample - previous_comming_sample));
1106                                         
1107                                 }
1108                         }
1109                 }
1110                 if (!sync && op.granulepos >= 0)
1111                 {
1112                         sync = 1;
1113                         current_comming_sample = op.granulepos;
1114                         if(!vorbis_synthesis(&tf->vb, &op))
1115                         {
1116                                 vorbis_synthesis_blockin(&tf->vd, &tf->vb);
1117                                 if (vorbis_synthesis_pcmout(&tf->vd, NULL) != 0)
1118                                 {
1119                                         printf("FileOGG: Something wrong while trying to seek\n");
1120                                         return 0;
1121                                 }
1122                         
1123                         }
1124                         
1125                 }
1126         }
1127         
1128         
1129         return 0;
1130 }
1131
1132 int FileOGG::ogg_get_page_of_frame(sync_window_t *sw, long serialno, ogg_page *og, int64_t frame)
1133 {
1134         if (frame >= asset->video_length + start_frame)
1135         {
1136                 printf("FileOGG: Illegal seek beyond end of frames\n");
1137                 return 0;
1138         }
1139 //      printf("frame: %lli start frame: %lli\n", frame, start_frame);
1140 //      printf("file_length: %lli filedata_begin: %lli\n", file_length, filedata_begin);
1141         off_t educated_guess = filedata_begin + (file_length - filedata_begin) * (frame - start_frame) / asset->video_length - READ_SIZE/2;
1142 //      educated_guess += 100000;
1143         if (educated_guess > file_length - READ_SIZE)
1144                 educated_guess = file_length - READ_SIZE;
1145         if (educated_guess < filedata_begin) 
1146                 educated_guess = filedata_begin;
1147 //      printf("My educated guess: %lli\n", educated_guess); 
1148 // now see if we won
1149         read_buffer_at(stream, sw, READ_SIZE, educated_guess);
1150         ogg_sync_and_get_next_page(sw, serialno, og);
1151         int64_t pageend_frame;
1152         //int read_back = 0;
1153         // find the page with "real" ending
1154         while ((pageend_frame = ogg_page_granulepos(og)) == -1)
1155         {
1156                 if (ogg_get_next_page(sw, serialno, og) == 0) 
1157                 {
1158                         //read_back = 1;
1159                         break;
1160                 } 
1161         }
1162         pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1163
1164         // FIXME - MEDIUM PRIORITY: read back if we've gone too far and no page of our serialno at all can be found
1165
1166         
1167         // linear seek to the sample
1168 // TODO: Use bisection also
1169 //      printf("Next page granulepos: %lli, pagepos: %lli\n", end_sample, sw->file_pagepos_found);
1170         //int discard_packets = 0;
1171         int missp = 0;
1172         int missm = 0;
1173         if (pageend_frame <= frame)
1174         {
1175         // scan forward
1176                 while (pageend_frame < frame)
1177                 {
1178                         do {
1179                                 ogg_get_next_page(sw, serialno, og); 
1180                         } while (ogg_page_packets(og) == 0);
1181                         pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1182                         missp++;
1183                 }
1184                 // go back if this frame starts on previous page
1185                 if (ogg_page_continued(og) && pageend_frame - ogg_page_packets(og) == frame - 1)
1186                 {
1187                         do {
1188                                 ogg_get_prev_page(sw, serialno, og); 
1189                         } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));          
1190                 }
1191                 pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1192         } else
1193         {
1194         // scan backward
1195                 int64_t first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(og)) - ogg_page_packets(og) + 2;
1196                 if (!ogg_page_continued(og))
1197                         first_frame_on_page--;
1198                 while (first_frame_on_page > frame)
1199                 {
1200 //                      printf("get prev page: %lli pagepos:%lli\n", ogg_page_granulepos(og), sw->file_pagepos_found);
1201                         do {
1202                                 ogg_get_prev_page(sw, serialno, og); 
1203                         } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));          
1204                         missm++;
1205 //                      pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1206                         first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(og)) - ogg_page_packets(og) + 2;
1207                         if (!ogg_page_continued(og))
1208                                 first_frame_on_page--;
1209                 }
1210         }
1211 //      printf("Miss plus: %i, miss minus: %i\n", missp, missm);
1212 //      printf("last frame of page with frame : %lli\n", pageend_frame);
1213         return 1;                       
1214 }
1215
1216
1217 int FileOGG::ogg_seek_to_keyframe(sync_window_t *sw, long serialno, int64_t frame, int64_t *keyframe_number)
1218 {
1219         ogg_page og;
1220         ogg_packet op;
1221 //      printf("Searching for the proper position to start decoding frame %lli\n", frame);
1222         if (!ogg_get_page_of_frame(sw, serialno, &og, frame))
1223         {
1224                 printf("FileOGG: Seeking to frame failed\n");
1225                 return 0;
1226         }
1227         // TODO: if the frame we are looking for continoues on the next page, we don't need to do this
1228         // Now go to previous page in order to find out the granulepos
1229         // Don't do it in case this is the first page.
1230 //      printf("GP: %lli\n", ogg_page_granulepos(&og));
1231         int64_t granulepos = ogg_page_granulepos(&og);
1232         int64_t iframe = granulepos >> theora_keyframe_granule_shift;
1233         //int64_t pframe = granulepos - (iframe << theora_keyframe_granule_shift);
1234         // check if maybe iframe is known from this page already
1235         if (granulepos != -1 && iframe <= frame)
1236         {
1237                 // optimisation, iframe is already known from this page
1238         } else
1239         {
1240                 // get previous page so we will get the iframe number 
1241                 do {
1242                         ogg_get_prev_page(sw, serialno, &og); 
1243                 } while (ogg_page_packets(&og) == 0);           
1244
1245                 granulepos = ogg_page_granulepos(&og);
1246                 iframe = granulepos >> theora_keyframe_granule_shift;
1247                 //pframe = granulepos - (iframe << theora_keyframe_granule_shift);
1248         }
1249         int64_t first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) - ogg_page_packets(&og) + 2;
1250         if (!ogg_page_continued(&og))
1251                 first_frame_on_page--;
1252         if (first_frame_on_page <= iframe)
1253         {
1254                 // optimisation, happens mainly in low-bitrate streams, it spares us one seek
1255         } else
1256         {
1257                 // get the page where keyframe starts
1258                 if (!ogg_get_page_of_frame(sw, serialno, &og, iframe))
1259                 {
1260                         printf("FileOGG: Seeking to keyframe failed\n");
1261                         return 0;
1262                 }
1263         }               
1264 //      printf("looking for frame: %lli, last frame of the page: %lli, last keyframe: %lli\n", frame, pframe+iframe, iframe);
1265         ogg_stream_reset(&tf->to);
1266         ogg_stream_pagein(&tf->to, &og);
1267         // Read until one frame before keyframe
1268 //      printf("c: %i\n", ogg_page_continued(&og));
1269         int numread = iframe - (theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) - ogg_page_packets(&og)) - 1;
1270         if (ogg_page_continued(&og))
1271                 numread--;
1272 //      printf("numread: %i\n", numread);
1273 //      printf("FileOGG:: Proper position: %lli\n", theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) + numread - ogg_page_packets(&og));
1274         while (numread > 0)
1275         {
1276                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
1277                 {
1278                         if (!ogg_get_next_page(sw, serialno, &og))
1279                         {
1280                                 printf("FileOGG: Cannot find next page while seeking\n");
1281                                 return 0;
1282                         }
1283                         ogg_stream_pagein(&tf->to, &og);
1284                 }
1285                 ogg_stream_packetout(&tf->to, &op);
1286                 numread --;
1287         }
1288         *keyframe_number = iframe;
1289         return 1;
1290 }
1291
1292
1293 int FileOGG::check_sig(Asset *asset)
1294 {
1295
1296         FILE *fd = fopen(asset->path, "rb");
1297
1298 // Test for "OggS"
1299         fseek(fd, 0, SEEK_SET);
1300         char data[4];
1301
1302         (void)fread(data, 4, 1, fd);
1303
1304         if(data[0] == 'O' &&
1305                 data[1] == 'g' &&
1306                 data[2] == 'g' &&
1307                 data[3] == 'S')
1308         {
1309
1310                 fclose(fd);
1311                 printf("Yay, we have an ogg file\n");
1312
1313                 return 1;
1314         }
1315
1316         fclose(fd);
1317
1318         return 0;
1319         
1320 }
1321
1322 int FileOGG::close_file()
1323 {
1324
1325         if (file->wr)
1326         {
1327                 if (asset->audio_data)
1328                         write_samples_vorbis(0, 0, 1); // set eos
1329                 if (asset->video_data)
1330                         write_frames_theora(0, 1, 1); // set eos
1331
1332                 flush_ogg(1); // flush all
1333         
1334                 if (asset->audio_data)
1335                 {
1336                         vorbis_block_clear (&tf->vb);
1337                         vorbis_dsp_clear (&tf->vd);
1338                         vorbis_info_clear (&tf->vi);
1339                         ogg_stream_clear (&tf->vo);
1340                 }
1341                 if (asset->video_data)
1342                 {
1343                         theora_info_clear (&tf->ti);
1344                         ogg_stream_clear (&tf->to);
1345                         theora_clear (&tf->td);
1346                 }
1347                 
1348                 if (stream) fclose(stream);
1349                 stream = 0;
1350         } 
1351         else 
1352         if (file->rd) 
1353         {       
1354                 if (asset->audio_data)
1355                 {
1356                         vorbis_block_clear (&tf->vb);
1357                         vorbis_dsp_clear (&tf->vd);
1358                         vorbis_comment_clear (&tf->vc);
1359                         vorbis_info_clear (&tf->vi);
1360                         ogg_stream_clear (&tf->vo);
1361                 }
1362                 theora_comment_clear(&tf->tc);
1363                 if (asset->video_data)
1364                 {
1365                         theora_info_clear (&tf->ti);
1366                         theora_comment_clear (&tf->tc);
1367                         theora_clear (&tf->td);
1368                         ogg_stream_clear (&tf->to);
1369                 }
1370                 
1371                         
1372                 if (stream) fclose(stream);
1373                 stream = 0;
1374
1375         }
1376         return 0;
1377 }
1378
1379 int FileOGG::close_file_derived()
1380 {
1381 //printf("FileOGG::close_file_derived(): 1\n");
1382         if (stream) fclose(stream);
1383         stream = 0;
1384         return 0;
1385 }
1386
1387 int64_t FileOGG::get_video_position()
1388 {
1389 //      printf("GVP\n");
1390         return next_frame_position - start_frame;
1391 }
1392
1393 int64_t FileOGG::get_audio_position()
1394 {
1395         return next_sample_position - start_sample;
1396 }
1397
1398 int FileOGG::set_video_position(int64_t x)
1399 {
1400 //      x=0;
1401 //      printf("SVP: %lli\n", x);
1402         
1403         next_frame_position = x + start_frame;
1404         return 1;
1405 }
1406
1407
1408 int FileOGG::colormodel_supported(int colormodel)
1409 {
1410 //      printf("CMS\n");
1411
1412         if (colormodel == BC_YUV420P)
1413                 return BC_YUV420P;
1414         else
1415                 return colormodel;
1416 }
1417 int FileOGG::get_best_colormodel(Asset *asset, int driver)
1418 {
1419
1420         return BC_YUV420P;
1421 }
1422
1423
1424 int FileOGG::read_frame(VFrame *frame)
1425 {
1426
1427         if(!stream) return 1;
1428
1429         
1430         // skip is cheaper than seek, do it...
1431         int decode_frames = 0;
1432         int expect_keyframe = 0;
1433         if (ogg_frame_position >= 0 && 
1434             next_frame_position >= ogg_frame_position && 
1435             next_frame_position - ogg_frame_position < 32)
1436         {
1437                 decode_frames = next_frame_position - ogg_frame_position;
1438         } else
1439         if (next_frame_position != ogg_frame_position)
1440         {
1441                 if (!ogg_seek_to_keyframe(tf->videosync, tf->to.serialno,
1442                         next_frame_position, &ogg_frame_position)) {
1443                         printf("FileOGG:: Error while seeking to frame's keyframe"
1444                                 " (frame: " _LD ", keyframe: " _LD ")\n",
1445                                 next_frame_position, ogg_frame_position);
1446                         return 1;
1447                 }
1448 //              printf("For frame: %lli, keyframe is: %lli\n", next_frame_position,ogg_frame_position);
1449                 // skip frames must be > 0 here
1450                 decode_frames = next_frame_position - ogg_frame_position + 1; 
1451                 ogg_frame_position --; // ogg_frame_position is at last decoded frame, so it will point right 
1452                 if (decode_frames <= 0) 
1453                 {
1454                         printf("FileOGG:: Error while seeking to keyframe,"
1455                                 " wrong keyframe number (frame: " _LD ", keyframe: " _LD ")\n",
1456                                 next_frame_position, ogg_frame_position);
1457                         return 1;
1458                         
1459                 }
1460                 expect_keyframe = 1;
1461         }
1462
1463 //      printf("Frames to decode: %i\n", decode_frames);
1464
1465 // THIS IS WHAT CAUSES SLOWNESS OF SEEKING, but we can do nothing about it.
1466         while (decode_frames > 0)
1467         {
1468                 ogg_page og;
1469                 ogg_packet op;
1470                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
1471                 {
1472                         if (!ogg_get_next_page(tf->videosync, tf->to.serialno, &og))
1473                         {
1474                                 printf("FileOGG: Cannot find next page while seeking\n");
1475                                 return 1;
1476                         }
1477                         ogg_stream_pagein(&tf->to, &og);
1478                 }
1479                 ogg_stream_packetout(&tf->to, &op);
1480                 if (expect_keyframe && !theora_packet_iskeyframe(&op))
1481                 {
1482                                 printf("FileOGG: Expecting keyframe, but didn't get it\n");
1483                         //      return 1; this is generally not a fatal error
1484                 }
1485                 expect_keyframe = 0;
1486                 
1487                 // decode
1488                 theora_decode_packetin(&tf->td, &op);
1489
1490                 decode_frames --;
1491                 ogg_frame_position ++;
1492         }
1493         {
1494                 yuv_buffer yuv;
1495                 int ret = theora_decode_YUVout (&tf->td, &yuv);
1496                 if (ret)
1497                 {
1498                         printf("FileOGG: theora_decode_YUVout failed with code %i\n", ret);
1499                 }
1500
1501 // Dirty magic 
1502 /*              yuv.y += yuv.y_stride * (yuv.y_height - 1);
1503                 yuv.u += yuv.uv_stride * (yuv.uv_height - 1);
1504                 yuv.v += yuv.uv_stride * (yuv.uv_height - 1);
1505                 yuv.y_stride = - yuv.y_stride;
1506                 yuv.uv_stride = - yuv.uv_stride;*/
1507                 VFrame *temp_frame = new VFrame(yuv.y, 
1508                                                 -1,
1509                                                 0,
1510                                                 yuv.u - yuv.y,
1511                                                 yuv.v - yuv.y,
1512                                                 - yuv.y_stride,
1513                                                 yuv.y_height,
1514                                                 BC_YUV420P,
1515                                                 - yuv.y_stride);
1516                 // copy into temp frame...
1517                 
1518                 BC_CModels::transfer(frame->get_rows(),
1519                         temp_frame->get_rows(),
1520                         frame->get_y(),
1521                         frame->get_u(),
1522                         frame->get_v(),
1523                         temp_frame->get_y(),
1524                         temp_frame->get_u(),
1525                         temp_frame->get_v(),
1526                         0,
1527                         0,
1528                         yuv.y_width,
1529                         yuv.y_height,
1530                         0,
1531                         0,
1532                         yuv.y_width,  // temp_frame can be larger than frame if width not dividable by 16
1533                         yuv.y_height,   
1534                         BC_YUV420P,
1535                         frame->get_color_model(),
1536                         0,
1537                         -temp_frame->get_w(),
1538                         frame->get_w());
1539                 delete temp_frame;
1540         }
1541
1542         next_frame_position ++;
1543         
1544         return 0;               
1545 }
1546
1547
1548
1549 int FileOGG::ogg_decode_more_samples(sync_window_t *sw, long serialno)
1550 {
1551         ogg_page og;
1552         ogg_packet op;
1553         int done = 0;
1554         while (!done)
1555         {
1556                 while (ogg_stream_packetpeek(&tf->vo, NULL) != 1)
1557                 {
1558                         if (!ogg_get_next_page(sw, serialno, &og))
1559                         {
1560                                 printf("FileOGG: Cannot find next page while trying to decode more samples\n");
1561                                 return 0;
1562                         }
1563                         ogg_stream_pagein(&tf->vo, &og);
1564                 }
1565                 ogg_stream_packetout(&tf->vo, &op);
1566                 if(!vorbis_synthesis(&tf->vb, &op))
1567                 {
1568                         done = 1;       
1569                         vorbis_synthesis_blockin(&tf->vd, &tf->vb);
1570                 }
1571         }
1572         return 1;
1573 }
1574
1575 int FileOGG::set_audio_position(int64_t x)
1576 {
1577         next_sample_position = x + start_sample;
1578         return 0;
1579 }
1580
1581 int FileOGG::move_history(int from, int to, int len)
1582 {
1583         for(int i = 0; i < asset->channels; i++)
1584                 memmove(pcm_history[i] + to, pcm_history[i] + from, sizeof(float) * len);
1585         history_start = history_start + from - to;
1586         return 0;
1587
1588
1589 int FileOGG::read_samples(double *buffer, int64_t len)
1590 {
1591         float **vorbis_buffer;
1592         if (len <= 0) 
1593                 return 0;
1594 //      printf("Reading samples: Channel: %i, number of samples: %lli, reading at :%lli\n", file->current_channel, len, next_sample_position);
1595 //              printf("\tnext_sample_position: %lli, length: %i\n", next_sample_position, len);
1596 //              printf("\thistory_start: %lli, length: %i\n", history_start, history_size);
1597
1598         if(len > HISTORY_MAX)
1599         {
1600                 printf("FileOGG::read_samples max samples=%d\n", HISTORY_MAX);
1601                 return 1;
1602         }
1603
1604         if(!pcm_history)
1605         {
1606                 pcm_history = new float*[asset->channels];
1607                 for(int i = 0; i < asset->channels; i++)
1608                         pcm_history[i] = new float[HISTORY_MAX];
1609                 history_start = -100000000; // insane value to trigger reload
1610                 history_size = 0;
1611         }
1612
1613         int64_t hole_start = -1;
1614         int64_t hole_len = -1;
1615         int64_t hole_absstart = -1;
1616         int64_t hole_fill = 0;
1617
1618         if (history_start < next_sample_position && history_start + history_size > next_sample_position && history_start + history_size < next_sample_position + len) 
1619         {
1620 //              printf("a\n");
1621                 hole_fill = 1;
1622                 hole_start = history_start + history_size - next_sample_position;
1623                 hole_len = history_size - hole_start;
1624                 hole_absstart = next_sample_position + hole_start;
1625                 move_history(next_sample_position - history_start,
1626                                 0,
1627                                 hole_start); // 
1628                 
1629         } else
1630         if (next_sample_position < history_start && history_start < next_sample_position + len)
1631         {
1632 //              printf("b\n");
1633                 hole_fill = 1;
1634                 hole_start = 0;
1635                 hole_len = history_start - next_sample_position;
1636                 hole_absstart = next_sample_position;
1637 //              printf("hs: %lli, histstart: %lli, next_sample_position: %lli\n", history_size, history_start, next_sample_position);
1638 //              printf("to: 0, from: %lli, size: %lli\n", 
1639  //                             history_start - next_sample_position,
1640 //                              history_size - history_start + next_sample_position);
1641                 move_history(0, 
1642                                 history_start - next_sample_position,
1643                                 history_size - history_start + next_sample_position);
1644                         
1645         } else 
1646         if (next_sample_position >= history_start + history_size || next_sample_position + len <= history_start)
1647         {
1648 //              printf("c\n");
1649                 hole_fill = 1;
1650                 hole_start = 0;
1651                 hole_len = HISTORY_MAX;
1652                 hole_absstart = next_sample_position;
1653                 history_start = hole_absstart;
1654                 history_size = hole_len;
1655         }
1656         
1657         if (hole_fill)
1658         {
1659                 if (hole_start < 0 || hole_len <= 0 || hole_absstart < 0)
1660                 {
1661                         printf("FileOGG: Error at finding out what to read from file\n");
1662                         return 1;
1663                 }
1664                 
1665                 if (hole_absstart + hole_len > asset->audio_length + start_sample)
1666                 {
1667                         hole_len = asset->audio_length + start_sample - hole_absstart;
1668                         history_size = asset->audio_length + start_sample - history_start;
1669                 } else
1670                 {
1671                         history_size = HISTORY_MAX;
1672                 }
1673                 
1674                 
1675 //              printf("Decode samples at position: %lli, samples to read: %lli\n", hole_absstart, hole_len);
1676         
1677                 int64_t samples_read = 0;        
1678                 if (ogg_sample_position != hole_absstart)
1679                 {
1680                         ogg_sample_position = hole_absstart;
1681                         if (!ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, ogg_sample_position))
1682                         {
1683                                 printf("FileOGG:: Error while seeking to sample\n");
1684                                 return 1;
1685                         }
1686                 }
1687                 // now we have ogg_sample_positon aligned
1688                 int64_t samples_to_read = hole_len;
1689                 while (samples_read < hole_len)
1690                 {
1691                         int64_t waiting_samples = vorbis_synthesis_pcmout(&tf->vd, &vorbis_buffer);
1692                         int64_t takeout_samples;
1693                         if (waiting_samples > samples_to_read - samples_read)
1694                                 takeout_samples = samples_to_read - samples_read;
1695                         else 
1696                                 takeout_samples = waiting_samples;
1697
1698 //                      printf("takeout samples: %lli, samples_read: %lli\n", takeout_samples, samples_read);
1699
1700                         if(waiting_samples)
1701                         {
1702                                 for(int i = 0; i < asset->channels; i++)
1703                                 {
1704                                         float *input = vorbis_buffer[i];
1705                                         float *output = pcm_history[i] + hole_start;
1706                                         // TODO: use memcpy
1707                                         for(int j = 0; j < takeout_samples ; j++)
1708                                         {
1709                                                 output[j] = input[j];
1710                                         }
1711                                 }                                                                   
1712                         }
1713
1714                         vorbis_synthesis_read(&tf->vd, takeout_samples);
1715                         samples_read += takeout_samples;
1716                         ogg_sample_position += takeout_samples;
1717                         hole_start += takeout_samples;
1718                         
1719                         if (samples_read < hole_len)
1720                                 if (!ogg_decode_more_samples(tf->audiosync, tf->vo.serialno))
1721                                 {
1722                                         ogg_sample_position = -1;
1723                                         return 1;
1724                                 }
1725
1726
1727                 }
1728         }       
1729         
1730         // now we can be sure our history is correct, just copy it out
1731         if (next_sample_position < history_start || next_sample_position + len > history_start + history_size)
1732         {
1733                 printf("FileOGG:: History not aligned properly \n");
1734                 printf("\tnext_sample_position: " _LD ", length: " _LD "\n", next_sample_position, len);
1735                 printf("\thistory_start: " _LD ", length: " _LD "\n", history_start, history_size);
1736                 
1737                 return 1;
1738         }
1739         float *input = pcm_history[file->current_channel] + next_sample_position - history_start;
1740         for (int i = 0; i < len; i++)
1741                 buffer[i] = input[i];
1742          
1743         next_sample_position += len;
1744         return 0;
1745 }
1746
1747
1748 int FileOGG::write_audio_page()
1749 {
1750   int ret;
1751
1752   ret = fwrite(tf->apage, 1, tf->apage_len, stream);
1753   if(ret < tf->apage_len) {
1754     eprintf("error writing audio page\n"); 
1755   }
1756   tf->apage_valid = 0;
1757   tf->a_pkg -= ogg_page_packets((ogg_page *)&tf->apage);
1758   return ret;
1759 }
1760
1761 int FileOGG::write_video_page()
1762 {
1763   int ret;
1764
1765   ret = fwrite(tf->vpage, 1, tf->vpage_len, stream);
1766   if(ret < tf->vpage_len) {
1767     eprintf("error writing video page\n");
1768   }
1769   tf->vpage_valid = 0;
1770   tf->v_pkg -= ogg_page_packets((ogg_page *)&tf->vpage);
1771   return ret;
1772 }
1773
1774 void FileOGG::flush_ogg (int e_o_s)
1775 {
1776     int len;
1777     ogg_page og;
1778
1779         flush_lock->lock();
1780     /* flush out the ogg pages  */
1781     while(1) {
1782       /* Get pages for both streams, if not already present, and if available.*/
1783       if(asset->video_data && !tf->vpage_valid) {
1784         // this way seeking is much better,
1785         // not sure if 23 packets  is a good value. it works though
1786         int v_next=0;
1787         if(tf->v_pkg>22 && ogg_stream_flush(&tf->to, &og) > 0) {
1788           v_next=1;
1789         }
1790         else if(ogg_stream_pageout(&tf->to, &og) > 0) {
1791           v_next=1;
1792         }
1793         if(v_next) {
1794           len = og.header_len + og.body_len;
1795           if(tf->vpage_buffer_length < len) {
1796             tf->vpage = (unsigned char *)realloc(tf->vpage, len);
1797             tf->vpage_buffer_length = len;
1798           }
1799           tf->vpage_len = len;
1800           memcpy(tf->vpage, og.header, og.header_len);
1801           memcpy(tf->vpage+og.header_len , og.body, og.body_len);
1802
1803           tf->vpage_valid = 1;
1804           tf->videotime = theora_granule_time (&tf->td,
1805                   ogg_page_granulepos(&og));
1806         }
1807       }
1808       if(asset->audio_data && !tf->apage_valid) {
1809         // this way seeking is much better,
1810         // not sure if 23 packets  is a good value. it works though
1811         int a_next=0;
1812         if(tf->a_pkg>22 && ogg_stream_flush(&tf->vo, &og) > 0) {
1813           a_next=1;
1814         }
1815         else if(ogg_stream_pageout(&tf->vo, &og) > 0) {
1816           a_next=1;
1817         }
1818         if(a_next) {
1819           len = og.header_len + og.body_len;
1820           if(tf->apage_buffer_length < len) {
1821             tf->apage = (unsigned char *)realloc(tf->apage, len);
1822             tf->apage_buffer_length = len;
1823           }
1824           tf->apage_len = len;
1825           memcpy(tf->apage, og.header, og.header_len);
1826           memcpy(tf->apage+og.header_len , og.body, og.body_len);
1827
1828           tf->apage_valid = 1;
1829           tf->audiotime= vorbis_granule_time (&tf->vd, 
1830                   ogg_page_granulepos(&og));
1831         }
1832       }
1833
1834       if(!asset->audio_data && tf->vpage_valid) {
1835         write_video_page();
1836       }
1837       else if(!asset->video_data && tf->apage_valid) {
1838         write_audio_page();
1839       }
1840       /* We're using both. We can output only:
1841        *  a) If we have valid pages for both
1842        *  b) At EOS, for the remaining stream.
1843        */
1844       else if(tf->vpage_valid && tf->apage_valid) {
1845         /* Make sure they're in the right order. */
1846         if(tf->videotime <= tf->audiotime)
1847           write_video_page();
1848         else
1849           write_audio_page();
1850       } 
1851       else if(e_o_s && tf->vpage_valid) {
1852           write_video_page();
1853       }
1854       else if(e_o_s && tf->apage_valid) {
1855           write_audio_page();
1856       }
1857       else {
1858         break; /* Nothing more writable at the moment */
1859       }
1860     }
1861         flush_lock->unlock();
1862 }
1863
1864
1865 int FileOGG::write_samples_vorbis(double **buffer, int64_t len, int e_o_s)
1866 {
1867         float **vorbis_buffer;
1868         static int samples = 0;
1869         samples += len;
1870         if(e_o_s)
1871         {
1872                 vorbis_analysis_wrote (&tf->vd, 0);
1873         } else
1874         {
1875                 vorbis_buffer = vorbis_analysis_buffer (&tf->vd, len);
1876                 /* double to float conversion */
1877                 for(int i = 0; i<asset->channels; i++)
1878                 {
1879                         for (int j = 0; j < len; j++)
1880                         {
1881                                 vorbis_buffer[i][j] = buffer[i][j];
1882                         }
1883                 }
1884                 vorbis_analysis_wrote (&tf->vd, len);
1885         }
1886         while(vorbis_analysis_blockout (&tf->vd, &tf->vb) == 1)
1887         {
1888             /* analysis, assume we want to use bitrate management */
1889             vorbis_analysis (&tf->vb, NULL);
1890             vorbis_bitrate_addblock (&tf->vb);
1891             
1892             /* weld packets into the bitstream */
1893             while (vorbis_bitrate_flushpacket (&tf->vd, &tf->op))
1894             {
1895                 flush_lock->lock();
1896                 ogg_stream_packetin (&tf->vo, &tf->op);
1897                 tf->a_pkg++;
1898                 flush_lock->unlock();
1899             }
1900
1901         }
1902         flush_ogg(0);
1903         return 0;
1904
1905
1906 }
1907
1908 int FileOGG::write_samples(double **buffer, int64_t len)
1909 {
1910         if (len > 0)
1911                 return write_samples_vorbis(buffer, len, 0);
1912         return 0;
1913 }
1914
1915 int FileOGG::write_frames_theora(VFrame ***frames, int len, int e_o_s)
1916 {
1917         // due to clumsy theora's design we need to delay writing out by one frame
1918         // always stay one frame behind, so we can correctly encode e_o_s
1919         int result = 0;
1920         if(!stream) return 0;
1921         
1922         for(int j = 0; j < len && !result; j++)
1923         {
1924                 if (temp_frame) // encode previous frame if available
1925                 {
1926                         yuv_buffer yuv;
1927                         yuv.y_width = tf->ti.width;
1928                         yuv.y_height = tf->ti.height;
1929                         yuv.y_stride = temp_frame->get_bytes_per_line();
1930
1931                         yuv.uv_width = tf->ti.width / 2;
1932                         yuv.uv_height = tf->ti.height / 2;
1933                         yuv.uv_stride = temp_frame->get_bytes_per_line() /2;
1934
1935                         yuv.y = temp_frame->get_y();
1936                         yuv.u = temp_frame->get_u();
1937                         yuv.v = temp_frame->get_v();
1938                         int ret = theora_encode_YUVin (&tf->td, &yuv);
1939                         if (ret)
1940                         {
1941                                 printf("FileOGG: theora_encode_YUVin failed with code %i\n", ret);
1942                                 printf("yuv_buffer: y_width: %i, y_height: %i, y_stride: %i,"
1943                                         " uv_width: %i, uv_height: %i, uv_stride: %i\n",
1944                                         yuv.y_width, yuv.y_height, yuv.y_stride,
1945                                         yuv.uv_width, yuv.uv_height, yuv.uv_stride);
1946                         }
1947                         while(theora_encode_packetout (&tf->td, e_o_s, &tf->op)) {
1948                                 flush_lock->lock();
1949                                 ogg_stream_packetin (&tf->to, &tf->op);
1950                                 tf->v_pkg++;
1951                                 flush_lock->unlock();
1952             }
1953                         flush_ogg(0);  // eos flush is done later at close_file
1954                 }
1955 // If we have e_o_s, don't encode any new frames
1956                 if (e_o_s) 
1957                         break;
1958
1959                 if (!temp_frame)
1960                 {
1961                         temp_frame = new VFrame (0, 
1962                                                 -1,
1963                                                 tf->ti.width, 
1964                                                 tf->ti.height,
1965                                                 BC_YUV420P,
1966                                                 -1);
1967                 } 
1968                 VFrame *frame = frames[0][j];
1969                 int in_color_model = frame->get_color_model();
1970                 if (in_color_model == BC_YUV422P &&
1971                     temp_frame->get_w() == frame->get_w() &&
1972                     temp_frame->get_h() == frame->get_h() &&
1973                     temp_frame->get_bytes_per_line() == frame->get_bytes_per_line())
1974                 {
1975                         temp_frame->copy_from(frame);
1976                 } else
1977                 {
1978
1979                         BC_CModels::transfer(temp_frame->get_rows(),
1980                                 frame->get_rows(),
1981                                 temp_frame->get_y(),
1982                                 temp_frame->get_u(),
1983                                 temp_frame->get_v(),
1984                                 frame->get_y(),
1985                                 frame->get_u(),
1986                                 frame->get_v(),
1987                                 0,
1988                                 0,
1989                                 frame->get_w(),
1990                                 frame->get_h(),
1991                                 0,
1992                                 0,
1993                                 frame->get_w(),  // temp_frame can be larger than frame if width not dividable by 16
1994                                 frame->get_h(), 
1995                                 frame->get_color_model(),
1996                                 BC_YUV420P,
1997                                 0,
1998                                 frame->get_w(),
1999                                 temp_frame->get_w());
2000
2001                 }
2002         }                                               
2003                                 
2004         return 0;
2005 }
2006
2007
2008 int FileOGG::write_frames(VFrame ***frames, int len)
2009 {
2010         
2011         return write_frames_theora(frames, len, 0);
2012 }
2013
2014 OGGConfigAudio::OGGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
2015  : BC_Window(PROGRAM_NAME ": Audio Compression",
2016         parent_window->get_abs_cursor_x(1),
2017         parent_window->get_abs_cursor_y(1),
2018         350,
2019         250)
2020 {
2021         this->parent_window = parent_window;
2022         this->asset = asset;
2023 }
2024
2025 OGGConfigAudio::~OGGConfigAudio()
2026 {
2027
2028 }
2029
2030 void OGGConfigAudio::create_objects()
2031 {
2032 //      add_tool(new BC_Title(10, 10, _("There are no audio options for this format")));
2033
2034         int x = 10, y = 10;
2035         int x1 = 150;
2036         char string[BCTEXTLEN];
2037
2038         lock_window("OGGConfigAudio::create_objects");
2039         add_tool(fixed_bitrate = new OGGVorbisFixedBitrate(x, y, this));
2040         add_tool(variable_bitrate = new OGGVorbisVariableBitrate(x1, y, this));
2041
2042         y += 30;
2043         sprintf(string, "%d", asset->vorbis_min_bitrate);
2044         add_tool(new BC_Title(x, y, _("Min bitrate:")));
2045         add_tool(new OGGVorbisMinBitrate(x1, y, this, string));
2046
2047         y += 30;
2048         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
2049         sprintf(string, "%d", asset->vorbis_bitrate);
2050         add_tool(new OGGVorbisAvgBitrate(x1, y, this, string));
2051
2052         y += 30;
2053         add_tool(new BC_Title(x, y, _("Max bitrate:")));
2054         sprintf(string, "%d", asset->vorbis_max_bitrate);
2055         add_tool(new OGGVorbisMaxBitrate(x1, y, this, string));
2056
2057
2058         add_subwindow(new BC_OKButton(this));
2059         show_window(1);
2060         unlock_window();
2061 }
2062
2063 int OGGConfigAudio::close_event()
2064 {
2065         set_done(0);
2066         return 1;
2067 }
2068
2069 OGGVorbisFixedBitrate::OGGVorbisFixedBitrate(int x, int y, OGGConfigAudio *gui)
2070  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Average bitrate"))
2071 {
2072         this->gui = gui;
2073 }
2074 int OGGVorbisFixedBitrate::handle_event()
2075 {
2076         gui->asset->vorbis_vbr = 0;
2077         gui->variable_bitrate->update(0);
2078         return 1;
2079 }
2080
2081 OGGVorbisVariableBitrate::OGGVorbisVariableBitrate(int x, int y, OGGConfigAudio *gui)
2082  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
2083 {
2084         this->gui = gui;
2085 }
2086 int OGGVorbisVariableBitrate::handle_event()
2087 {
2088         gui->asset->vorbis_vbr = 1;
2089         gui->fixed_bitrate->update(0);
2090         return 1;
2091 }
2092
2093
2094 OGGVorbisMinBitrate::OGGVorbisMinBitrate(int x, 
2095         int y, 
2096         OGGConfigAudio *gui, 
2097         char *text)
2098  : BC_TextBox(x, y, 180, 1, text)
2099 {
2100         this->gui = gui;
2101 }
2102 int OGGVorbisMinBitrate::handle_event()
2103 {
2104         gui->asset->vorbis_min_bitrate = atol(get_text());
2105         return 1;
2106 }
2107
2108
2109
2110 OGGVorbisMaxBitrate::OGGVorbisMaxBitrate(int x, 
2111         int y, 
2112         OGGConfigAudio *gui,
2113         char *text)
2114  : BC_TextBox(x, y, 180, 1, text)
2115 {
2116         this->gui = gui;
2117 }
2118 int OGGVorbisMaxBitrate::handle_event()
2119 {
2120         gui->asset->vorbis_max_bitrate = atol(get_text());
2121         return 1;
2122 }
2123
2124
2125
2126 OGGVorbisAvgBitrate::OGGVorbisAvgBitrate(int x, int y, OGGConfigAudio *gui, char *text)
2127  : BC_TextBox(x, y, 180, 1, text)
2128 {
2129         this->gui = gui;
2130 }
2131 int OGGVorbisAvgBitrate::handle_event()
2132 {
2133         gui->asset->vorbis_bitrate = atol(get_text());
2134         return 1;
2135 }
2136
2137
2138
2139
2140
2141 OGGConfigVideo::OGGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
2142  : BC_Window(PROGRAM_NAME ": Video Compression",
2143         parent_window->get_abs_cursor_x(1),
2144         parent_window->get_abs_cursor_y(1),
2145         450,
2146         220)
2147 {
2148         this->parent_window = parent_window;
2149         this->asset = asset;
2150 }
2151
2152 OGGConfigVideo::~OGGConfigVideo()
2153 {
2154
2155 }
2156
2157 void OGGConfigVideo::create_objects()
2158 {
2159 //      add_tool(new BC_Title(10, 10, _("There are no video options for this format")));
2160         int x = 10, y = 10;
2161         int x1 = x + 150;
2162         int x2 = x + 300;
2163
2164         lock_window("OGGConfigVideo::create_objects");
2165         add_subwindow(new BC_Title(x, y + 5, _("Bitrate:")));
2166         add_subwindow(new OGGTheoraBitrate(x1, y, this));
2167         add_subwindow(fixed_bitrate = new OGGTheoraFixedBitrate(x2, y, this));
2168         y += 30;
2169
2170         add_subwindow(new BC_Title(x, y, _("Quality:")));
2171         add_subwindow(new BC_ISlider(x + 80, 
2172                 y,
2173                 0,
2174                 200,
2175                 200,
2176                 0,
2177                 63,
2178                 asset->theora_quality,
2179                 0,
2180                 0,
2181                 &asset->theora_quality));
2182
2183         
2184         add_subwindow(fixed_quality = new OGGTheoraFixedQuality(x2, y, this));
2185         y += 30;
2186
2187         add_subwindow(new BC_Title(x, y, _("Keyframe frequency:")));
2188         OGGTheoraKeyframeFrequency *keyframe_frequency = 
2189                 new OGGTheoraKeyframeFrequency(x1 + 60, y, this);
2190         keyframe_frequency->create_objects();
2191         y += 30;
2192         
2193         add_subwindow(new BC_Title(x, y, _("Keyframe force frequency:")));
2194         OGGTheoraKeyframeForceFrequency *keyframe_force_frequency = 
2195                 new OGGTheoraKeyframeForceFrequency(x1 + 60, y, this);
2196         keyframe_force_frequency->create_objects();
2197         y += 30;
2198
2199         add_subwindow(new BC_Title(x, y, _("Sharpness:")));
2200         OGGTheoraSharpness *sharpness = 
2201                 new OGGTheoraSharpness(x1 + 60, y, this);
2202         sharpness->create_objects();
2203         y += 30;
2204         
2205
2206         add_subwindow(new BC_OKButton(this));
2207         show_window(1);
2208         unlock_window();
2209 }
2210
2211
2212
2213
2214 int OGGConfigVideo::close_event()
2215 {
2216         set_done(0);
2217         return 1;
2218 }
2219
2220 OGGTheoraBitrate::OGGTheoraBitrate(int x, int y, OGGConfigVideo *gui)
2221  : BC_TextBox(x, y, 100, 1, gui->asset->theora_bitrate)
2222 {
2223         this->gui = gui;
2224 }
2225
2226
2227 int OGGTheoraBitrate::handle_event()
2228 {
2229         // TODO: MIN / MAX check
2230         gui->asset->theora_bitrate = atol(get_text());
2231         return 1;
2232 };
2233
2234
2235
2236
2237 OGGTheoraFixedBitrate::OGGTheoraFixedBitrate(int x, int y, OGGConfigVideo *gui)
2238  : BC_Radial(x, y, gui->asset->theora_fix_bitrate, _("Fixed bitrate"))
2239 {
2240         this->gui = gui;
2241 }
2242
2243 int OGGTheoraFixedBitrate::handle_event()
2244 {
2245         update(1);
2246         gui->asset->theora_fix_bitrate = 1;
2247         gui->fixed_quality->update(0);
2248         return 1;
2249 };
2250
2251 OGGTheoraFixedQuality::OGGTheoraFixedQuality(int x, int y, OGGConfigVideo *gui)
2252  : BC_Radial(x, y, !gui->asset->theora_fix_bitrate, _("Fixed quality"))
2253 {
2254         this->gui = gui;
2255 }
2256
2257 int OGGTheoraFixedQuality::handle_event()
2258 {
2259         update(1);
2260         gui->asset->theora_fix_bitrate = 0;
2261         gui->fixed_bitrate->update(0);
2262         return 1;
2263 };
2264
2265 OGGTheoraKeyframeFrequency::OGGTheoraKeyframeFrequency(int x, int y, OGGConfigVideo *gui)
2266  : BC_TumbleTextBox(gui, 
2267         (int64_t)gui->asset->theora_keyframe_frequency, 
2268         (int64_t)1,
2269         (int64_t)500,
2270         x, 
2271         y,
2272         40)
2273 {
2274         this->gui = gui;
2275 }
2276
2277 int OGGTheoraKeyframeFrequency::handle_event()
2278 {
2279         gui->asset->theora_keyframe_frequency = atol(get_text());
2280         return 1;
2281 }
2282
2283 OGGTheoraKeyframeForceFrequency::OGGTheoraKeyframeForceFrequency(int x, int y, OGGConfigVideo *gui)
2284  : BC_TumbleTextBox(gui, 
2285         (int64_t)gui->asset->theora_keyframe_frequency, 
2286         (int64_t)1,
2287         (int64_t)500,
2288         x, 
2289         y,
2290         40)
2291 {
2292         this->gui = gui;
2293 }
2294
2295 int OGGTheoraKeyframeForceFrequency::handle_event()
2296 {
2297         gui->asset->theora_keyframe_frequency = atol(get_text());
2298         return 1;
2299 }
2300
2301
2302 OGGTheoraSharpness::OGGTheoraSharpness(int x, int y, OGGConfigVideo *gui)
2303  : BC_TumbleTextBox(gui, 
2304         (int64_t)gui->asset->theora_sharpness, 
2305         (int64_t)0,
2306         (int64_t)2,
2307         x, 
2308         y,
2309         40)
2310 {
2311         this->gui = gui;
2312 }
2313
2314 int OGGTheoraSharpness::handle_event()
2315 {
2316         gui->asset->theora_sharpness = atol(get_text());
2317         return 1;
2318 }
2319
2320
2321 PackagingEngineOGG::PackagingEngineOGG()
2322 {
2323         packages = 0;
2324         default_asset = 0;
2325 }
2326
2327 PackagingEngineOGG::~PackagingEngineOGG()
2328 {
2329         if(packages)
2330         {
2331                 for(int i = 0; i < total_packages; i++)
2332                         delete packages[i];
2333                 delete [] packages;
2334         }
2335         if (default_asset)
2336                 delete default_asset;
2337 }
2338
2339
2340
2341 int PackagingEngineOGG::create_packages_single_farm(
2342                 EDL *edl,
2343                 Preferences *preferences,
2344                 Asset *default_asset, 
2345                 double total_start, 
2346                 double total_end)
2347 {
2348         this->total_start = total_start;
2349         this->total_end = total_end;
2350         this->edl = edl;
2351
2352         this->preferences = preferences;
2353
2354 // We make A COPY of the asset, because we set audio_data = 0 on local asset which is the same copy as default_asset... 
2355 // Should be taken care of somewhere else actually
2356         this->default_asset = new Asset(*default_asset);
2357
2358         audio_start = Units::to_int64(total_start * default_asset->sample_rate);
2359         video_start = Units::to_int64(total_start * default_asset->frame_rate);
2360         audio_position = audio_start;
2361         video_position = video_start;
2362         audio_end = Units::to_int64(total_end * default_asset->sample_rate);
2363         video_end = Units::to_int64(total_end * default_asset->frame_rate);
2364         current_package = 0;
2365
2366         double total_len = total_end - total_start;
2367 //printf("PackageDispatcher::create_packages: %f / %d = %f\n", total_len, total_packages, package_len);
2368
2369         total_packages = 0;
2370         if (default_asset->audio_data)
2371                 total_packages++;
2372         if (default_asset->video_data)
2373                 total_packages += preferences->renderfarm_job_count;
2374
2375         packages = new RenderPackage*[total_packages];
2376
2377         int local_current_package = 0;
2378         if (default_asset->audio_data)
2379         {
2380                 packages[local_current_package] = new RenderPackage;
2381                 sprintf(packages[current_package]->path, "%s.audio", default_asset->path);
2382                 local_current_package++;
2383         }
2384         
2385         if (default_asset->video_data)
2386         {
2387                 video_package_len = (total_len) / preferences->renderfarm_job_count;
2388                 int current_number;    // The number being injected into the filename.
2389                 int number_start;      // Character in the filename path at which the number begins
2390                 int total_digits;      // Total number of digits including padding the user specified.
2391
2392                 Render::get_starting_number(default_asset->path, 
2393                         current_number,
2394                         number_start, 
2395                         total_digits,
2396                         3);
2397
2398                 for(int i = 0; i < preferences->renderfarm_job_count; i++)
2399                 {
2400                         RenderPackage *package = packages[local_current_package] = new RenderPackage;
2401                         Render::create_filename(package->path, 
2402                                 default_asset->path, 
2403                                 current_number,
2404                                 total_digits,
2405                                 number_start);
2406                         current_number++;
2407                         local_current_package++;
2408                 }
2409         }
2410         return 0;
2411 }
2412
2413 RenderPackage* PackagingEngineOGG::get_package_single_farm(double frames_per_second, 
2414                 int client_number,
2415                 int use_local_rate)
2416 {
2417
2418 //printf("PackageDispatcher::get_package %ld %ld %ld %ld\n", audio_position, video_position, audio_end, video_end);
2419         if (current_package == total_packages)
2420                 return 0;
2421
2422         RenderPackage *result = 0;
2423         if (current_package == 0 && default_asset->audio_data)
2424         {
2425                 result = packages[0];
2426                 result->audio_start = audio_start;
2427                 result->video_start = video_start;
2428                 result->audio_end = audio_end;
2429                 result->video_end = video_end;
2430                 result->audio_do = 1;
2431                 result->video_do = 0;
2432         } else if (default_asset->video_data)
2433         {
2434                 // Do not do any scaling according to node speed, so we know we can get evenly distributed 'forced' keyframes
2435                 result = packages[current_package];
2436                 result->audio_do = 0;
2437                 result->video_do = 1;
2438
2439                 result->audio_start = audio_position;
2440                 result->video_start = video_position;
2441                 result->audio_end = audio_position + 
2442                         Units::round(video_package_len * default_asset->sample_rate);
2443                 result->video_end = video_position + 
2444                         Units::round(video_package_len * default_asset->frame_rate);
2445
2446 // Last package... take it all!
2447                 if (current_package == total_packages -1 ) 
2448                 {
2449                         result->audio_end = audio_end;
2450                         result->video_end = video_end;
2451                 }
2452
2453                 audio_position = result->audio_end;
2454                 video_position = result->video_end;
2455
2456         }
2457         
2458         current_package ++;
2459         return result;
2460
2461 }
2462
2463 void PackagingEngineOGG::get_package_paths(ArrayList<char*> *path_list)
2464 {
2465         for(int i = 0; i < total_packages; i++)
2466         {
2467                 path_list->append(strdup(packages[i]->path));
2468         }
2469 // We will mux to the the final file at the end!
2470         path_list->append(strdup(default_asset->path));
2471         path_list->set_free();
2472 }
2473
2474 int64_t PackagingEngineOGG::get_progress_max()
2475 {
2476         return Units::to_int64(default_asset->sample_rate * 
2477                         (total_end - total_start)) * 2+
2478                 Units::to_int64(preferences->render_preroll * 
2479                         total_packages *
2480                         default_asset->sample_rate);
2481 }
2482
2483 int PackagingEngineOGG::packages_are_done()
2484 {
2485
2486
2487 // Mux audio and video into one file    
2488
2489 // First fix our asset... have to workaround the bug of corruption of local asset
2490 //      Render::check_asset(edl, *default_asset);
2491
2492         Asset *video_asset = 0, *audio_asset = 0;
2493         File *audio_file_gen = 0, *video_file_gen = 0;
2494         FileOGG *video_file = 0, *audio_file = 0;
2495         ogg_stream_state audio_in_stream, video_in_stream;
2496         
2497         int local_current_package = 0;
2498         if (default_asset->audio_data)
2499         {
2500                 audio_asset = new Asset(packages[local_current_package]->path);
2501                 local_current_package++;
2502
2503                 audio_file_gen = new File();
2504                 audio_file_gen->open_file(preferences, audio_asset, 1, 0);
2505                 audio_file = (FileOGG*) audio_file_gen->file;
2506                 ogg_stream_init(&audio_in_stream, audio_file->tf->vo.serialno);
2507                 audio_file->ogg_seek_to_databegin(audio_file->tf->audiosync, audio_file->tf->vo.serialno);
2508         }
2509
2510         if (default_asset->video_data)
2511         {
2512                 video_asset = new Asset(packages[local_current_package]->path);
2513                 local_current_package++;
2514
2515                 video_file_gen = new File();
2516                 video_file_gen->open_file(preferences, video_asset, 1, 0);
2517                 video_file = (FileOGG*) video_file_gen->file;
2518                 ogg_stream_init(&video_in_stream, video_file->tf->to.serialno);
2519                 video_file->ogg_seek_to_databegin(video_file->tf->videosync, video_file->tf->to.serialno);
2520         }
2521
2522 // Output file
2523         File *output_file_gen = new File();
2524         output_file_gen->open_file(preferences, default_asset, 0, 1);
2525         FileOGG *output_file = (FileOGG*) output_file_gen->file;
2526
2527         //ogg_page og;    /* one Ogg bitstream page.  Vorbis packets are inside */
2528         ogg_packet op;  /* one raw packet of data for decode */
2529
2530
2531         int audio_ready = default_asset->audio_data;
2532         int video_ready = default_asset->video_data;
2533         int64_t video_packetno = 1;
2534         int64_t audio_packetno = 1;
2535         int64_t frame_offset = 0;
2536         int64_t current_frame = 0;
2537         while ((default_asset->audio_data && audio_ready) || (default_asset->video_data && video_ready))
2538         {
2539                 if (video_ready)
2540                 {
2541                         while (ogg_stream_packetpeek(&video_in_stream, NULL) != 1) // get as many pages as needed for one package
2542                         {
2543                                 if (!video_file->ogg_get_next_page(video_file->tf->videosync, video_file->tf->to.serialno, &video_file->tf->videopage))
2544                                 {
2545                                         // We are at the end of our file, see if it is more and open more if there is
2546                                         if (local_current_package < total_packages)
2547                                         {
2548                                                 frame_offset = current_frame +1;
2549                                                 ogg_stream_clear(&video_in_stream);
2550                                                 video_file_gen->close_file();
2551                                                 delete video_file_gen;
2552                                                 delete video_asset;
2553                                                 video_asset = new Asset(packages[local_current_package]->path);
2554                                                 local_current_package++;
2555
2556                                                 video_file_gen = new File();
2557                                                 video_file_gen->open_file(preferences, video_asset, 1, 0);
2558                                                 video_file = (FileOGG*) video_file_gen->file;
2559                                                 ogg_stream_init(&video_in_stream, video_file->tf->to.serialno);
2560                                                 video_file->ogg_seek_to_databegin(video_file->tf->videosync, video_file->tf->to.serialno);
2561
2562                                         } else
2563                                                 video_ready = 0;
2564                                         break;
2565                                 }
2566                                 ogg_stream_pagein(&video_in_stream, &video_file->tf->videopage);
2567                         }
2568                         while (ogg_stream_packetpeek(&video_in_stream, NULL) == 1) // get all packets out of the page
2569                         {
2570                                 ogg_stream_packetout(&video_in_stream, &op);
2571                                 if (local_current_package != total_packages) // keep it from closing the stream
2572                                         op.e_o_s = 0;
2573                                 if (video_packetno != 1)                     // if this is not the first video package do not start with b_o_s
2574                                         op.b_o_s = 0;
2575                                 else
2576                                         op.b_o_s = 1;
2577                                 op.packetno = video_packetno;
2578                                 video_packetno ++;
2579                                 int64_t granulepos = op.granulepos;
2580                                 if (granulepos != -1)
2581                                 {
2582                                 // Fix granulepos!      
2583                                         int64_t rel_iframe = granulepos >> video_file->theora_keyframe_granule_shift;
2584                                         int64_t rel_pframe = granulepos - (rel_iframe << video_file->theora_keyframe_granule_shift);
2585                                         int64_t rel_current_frame = rel_iframe + rel_pframe;
2586                                         current_frame = frame_offset + rel_current_frame;
2587                                         int64_t abs_iframe = current_frame - rel_pframe;
2588                                         
2589                                         op.granulepos = (abs_iframe << video_file->theora_keyframe_granule_shift) + rel_pframe;
2590                                         
2591 //                                      printf("iframe: %i, pframe: %i, granulepos: %i, op.packetno %lli, abs_iframe: %i\n", rel_iframe, rel_pframe, granulepos, op.packetno, abs_iframe);                              
2592                                 
2593                                 }
2594                                 ogg_stream_packetin (&output_file->tf->to, &op);
2595                                 output_file->tf->v_pkg++; 
2596                         }
2597                 }
2598                 if (audio_ready)
2599                 {
2600                         while (ogg_stream_packetpeek(&audio_in_stream, NULL) != 1) // get as many pages as needed for one package
2601                         {
2602                                 if (!audio_file->ogg_get_next_page(audio_file->tf->audiosync, audio_file->tf->vo.serialno, &audio_file->tf->audiopage))
2603                                 {
2604                                         audio_ready = 0;
2605                                         break;
2606                                 }
2607                                 ogg_stream_pagein(&audio_in_stream, &audio_file->tf->audiopage);
2608                         }
2609                         while (ogg_stream_packetpeek(&audio_in_stream, NULL) == 1) // get all packets out of the page
2610                         {
2611                                 ogg_stream_packetout(&audio_in_stream, &op);
2612                                 ogg_stream_packetin (&output_file->tf->vo, &op);
2613                                 audio_packetno++;
2614                                 output_file->tf->a_pkg++; 
2615                         }
2616                 }
2617                 
2618                 output_file->flush_ogg(0);
2619                 
2620         
2621         }
2622         
2623 // flush_ogg(1) is called on file closing time...       
2624 //      output_file->flush_ogg(1);
2625
2626 // Just prevent thet write_samples and write_frames are called
2627         output_file->final_write = 0;
2628                 
2629         if (default_asset->audio_data)
2630         {
2631                 ogg_stream_clear(&audio_in_stream);
2632                 audio_file_gen->close_file();
2633                 delete audio_file_gen;
2634                 delete audio_asset;
2635         }
2636         if (default_asset->video_data)
2637         {
2638                 ogg_stream_clear(&video_in_stream);
2639                 video_file_gen->close_file();
2640                 delete video_file_gen;
2641                 delete video_asset;
2642         }
2643
2644         output_file_gen->close_file();
2645         delete output_file_gen;
2646
2647 // Now delete the temp files
2648         for(int i = 0; i < total_packages; i++)
2649                 unlink(packages[i]->path);
2650
2651         return 0;
2652 }
2653
2654
2655