569853ae3cd19322350becd2aa1af2b4188e64e6
[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 3*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*)PROGRAM_NAME " " CINELERRA_VERSION);
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*)PROGRAM_NAME " " CINELERRA_VERSION);
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         if( !ogg_sync_and_get_next_page(sw, serialno, og) ) {
1151                 printf("FileOGG: ogg_sync_and_get_next_page failed\n");
1152                 return 0;
1153         }
1154         int64_t pageend_frame;
1155         //int read_back = 0;
1156         // find the page with "real" ending
1157         while ((pageend_frame = ogg_page_granulepos(og)) == -1)
1158         {
1159                 if (ogg_get_next_page(sw, serialno, og) == 0) 
1160                 {
1161                         //read_back = 1;
1162                         break;
1163                 } 
1164         }
1165         pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1166
1167         // FIXME - MEDIUM PRIORITY: read back if we've gone too far and no page of our serialno at all can be found
1168
1169         
1170         // linear seek to the sample
1171 // TODO: Use bisection also
1172 //      printf("Next page granulepos: %lli, pagepos: %lli\n", end_sample, sw->file_pagepos_found);
1173         //int discard_packets = 0;
1174         int missp = 0;
1175         int missm = 0;
1176         if (pageend_frame <= frame)
1177         {
1178         // scan forward
1179                 while (pageend_frame < frame)
1180                 {
1181                         do {
1182                                 ogg_get_next_page(sw, serialno, og); 
1183                         } while (ogg_page_packets(og) == 0);
1184                         pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1185                         missp++;
1186                 }
1187                 // go back if this frame starts on previous page
1188                 if (ogg_page_continued(og) && pageend_frame - ogg_page_packets(og) == frame - 1)
1189                 {
1190                         do {
1191                                 ogg_get_prev_page(sw, serialno, og); 
1192                         } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));          
1193                 }
1194                 pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1195         } else
1196         {
1197         // scan backward
1198                 int64_t first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(og)) - ogg_page_packets(og) + 2;
1199                 if (!ogg_page_continued(og))
1200                         first_frame_on_page--;
1201                 while (first_frame_on_page > frame)
1202                 {
1203 //                      printf("get prev page: %lli pagepos:%lli\n", ogg_page_granulepos(og), sw->file_pagepos_found);
1204                         do {
1205                                 ogg_get_prev_page(sw, serialno, og); 
1206                         } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));          
1207                         missm++;
1208 //                      pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
1209                         first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(og)) - ogg_page_packets(og) + 2;
1210                         if (!ogg_page_continued(og))
1211                                 first_frame_on_page--;
1212                 }
1213         }
1214 //      printf("Miss plus: %i, miss minus: %i\n", missp, missm);
1215 //      printf("last frame of page with frame : %lli\n", pageend_frame);
1216         return 1;                       
1217 }
1218
1219
1220 int FileOGG::ogg_seek_to_keyframe(sync_window_t *sw, long serialno, int64_t frame, int64_t *keyframe_number)
1221 {
1222         ogg_page og;
1223         ogg_packet op;
1224 //      printf("Searching for the proper position to start decoding frame %lli\n", frame);
1225         if (!ogg_get_page_of_frame(sw, serialno, &og, frame))
1226         {
1227                 printf("FileOGG: Seeking to frame failed\n");
1228                 return 0;
1229         }
1230         // TODO: if the frame we are looking for continoues on the next page, we don't need to do this
1231         // Now go to previous page in order to find out the granulepos
1232         // Don't do it in case this is the first page.
1233 //      printf("GP: %lli\n", ogg_page_granulepos(&og));
1234         int64_t granulepos = ogg_page_granulepos(&og);
1235         int64_t iframe = granulepos >> theora_keyframe_granule_shift;
1236         //int64_t pframe = granulepos - (iframe << theora_keyframe_granule_shift);
1237         // check if maybe iframe is known from this page already
1238         if (granulepos != -1 && iframe <= frame)
1239         {
1240                 // optimisation, iframe is already known from this page
1241         } else
1242         {
1243                 // get previous page so we will get the iframe number 
1244                 do {
1245                         ogg_get_prev_page(sw, serialno, &og); 
1246                 } while (ogg_page_packets(&og) == 0);           
1247
1248                 granulepos = ogg_page_granulepos(&og);
1249                 iframe = granulepos >> theora_keyframe_granule_shift;
1250                 //pframe = granulepos - (iframe << theora_keyframe_granule_shift);
1251         }
1252         int64_t first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) - ogg_page_packets(&og) + 2;
1253         if (!ogg_page_continued(&og))
1254                 first_frame_on_page--;
1255         if (first_frame_on_page <= iframe)
1256         {
1257                 // optimisation, happens mainly in low-bitrate streams, it spares us one seek
1258         } else
1259         {
1260                 // get the page where keyframe starts
1261                 if (!ogg_get_page_of_frame(sw, serialno, &og, iframe))
1262                 {
1263                         printf("FileOGG: Seeking to keyframe failed\n");
1264                         return 0;
1265                 }
1266         }               
1267 //      printf("looking for frame: %lli, last frame of the page: %lli, last keyframe: %lli\n", frame, pframe+iframe, iframe);
1268         ogg_stream_reset(&tf->to);
1269         ogg_stream_pagein(&tf->to, &og);
1270         // Read until one frame before keyframe
1271 //      printf("c: %i\n", ogg_page_continued(&og));
1272         int numread = iframe - (theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) - ogg_page_packets(&og)) - 1;
1273         if (ogg_page_continued(&og))
1274                 numread--;
1275 //      printf("numread: %i\n", numread);
1276 //      printf("FileOGG:: Proper position: %lli\n", theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) + numread - ogg_page_packets(&og));
1277         while (numread > 0)
1278         {
1279                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
1280                 {
1281                         if (!ogg_get_next_page(sw, serialno, &og))
1282                         {
1283                                 printf("FileOGG: Cannot find next page while seeking\n");
1284                                 return 0;
1285                         }
1286                         ogg_stream_pagein(&tf->to, &og);
1287                 }
1288                 ogg_stream_packetout(&tf->to, &op);
1289                 numread --;
1290         }
1291         *keyframe_number = iframe;
1292         return 1;
1293 }
1294
1295
1296 int FileOGG::check_sig(Asset *asset)
1297 {
1298
1299         FILE *fd = fopen(asset->path, "rb");
1300
1301 // Test for "OggS"
1302         fseek(fd, 0, SEEK_SET);
1303         char data[4];
1304
1305         (void)fread(data, 4, 1, fd);
1306
1307         if(data[0] == 'O' &&
1308                 data[1] == 'g' &&
1309                 data[2] == 'g' &&
1310                 data[3] == 'S')
1311         {
1312
1313                 fclose(fd);
1314                 printf("Yay, we have an ogg file\n");
1315
1316                 return 1;
1317         }
1318
1319         fclose(fd);
1320
1321         return 0;
1322         
1323 }
1324
1325 int FileOGG::close_file()
1326 {
1327
1328         if (file->wr)
1329         {
1330                 if (asset->audio_data)
1331                         write_samples_vorbis(0, 0, 1); // set eos
1332                 if (asset->video_data)
1333                         write_frames_theora(0, 1, 1); // set eos
1334
1335                 flush_ogg(1); // flush all
1336         
1337                 if (asset->audio_data)
1338                 {
1339                         vorbis_block_clear (&tf->vb);
1340                         vorbis_dsp_clear (&tf->vd);
1341                         vorbis_info_clear (&tf->vi);
1342                         ogg_stream_clear (&tf->vo);
1343                 }
1344                 if (asset->video_data)
1345                 {
1346                         theora_info_clear (&tf->ti);
1347                         ogg_stream_clear (&tf->to);
1348                         theora_clear (&tf->td);
1349                 }
1350                 
1351                 if (stream) fclose(stream);
1352                 stream = 0;
1353         } 
1354         else 
1355         if (file->rd) 
1356         {       
1357                 if (asset->audio_data)
1358                 {
1359                         vorbis_block_clear (&tf->vb);
1360                         vorbis_dsp_clear (&tf->vd);
1361                         vorbis_comment_clear (&tf->vc);
1362                         vorbis_info_clear (&tf->vi);
1363                         ogg_stream_clear (&tf->vo);
1364                 }
1365                 theora_comment_clear(&tf->tc);
1366                 if (asset->video_data)
1367                 {
1368                         theora_info_clear (&tf->ti);
1369                         theora_comment_clear (&tf->tc);
1370                         theora_clear (&tf->td);
1371                         ogg_stream_clear (&tf->to);
1372                 }
1373                 
1374                         
1375                 if (stream) fclose(stream);
1376                 stream = 0;
1377
1378         }
1379         return 0;
1380 }
1381
1382 int FileOGG::close_file_derived()
1383 {
1384 //printf("FileOGG::close_file_derived(): 1\n");
1385         if (stream) fclose(stream);
1386         stream = 0;
1387         return 0;
1388 }
1389
1390 int64_t FileOGG::get_video_position()
1391 {
1392 //      printf("GVP\n");
1393         return next_frame_position - start_frame;
1394 }
1395
1396 int64_t FileOGG::get_audio_position()
1397 {
1398         return next_sample_position - start_sample;
1399 }
1400
1401 int FileOGG::set_video_position(int64_t x)
1402 {
1403 //      x=0;
1404 //      printf("SVP: %lli\n", x);
1405         
1406         next_frame_position = x + start_frame;
1407         return 1;
1408 }
1409
1410
1411 int FileOGG::colormodel_supported(int colormodel)
1412 {
1413 //      printf("CMS\n");
1414
1415         if (colormodel == BC_YUV420P)
1416                 return BC_YUV420P;
1417         else
1418                 return colormodel;
1419 }
1420 int FileOGG::get_best_colormodel(Asset *asset, int driver)
1421 {
1422
1423         return BC_YUV420P;
1424 }
1425
1426
1427 int FileOGG::read_frame(VFrame *frame)
1428 {
1429
1430         if(!stream) return 1;
1431
1432         
1433         // skip is cheaper than seek, do it...
1434         int decode_frames = 0;
1435         int expect_keyframe = 0;
1436         if (ogg_frame_position >= 0 && 
1437             next_frame_position >= ogg_frame_position && 
1438             next_frame_position - ogg_frame_position < 32)
1439         {
1440                 decode_frames = next_frame_position - ogg_frame_position;
1441         } else
1442         if (next_frame_position != ogg_frame_position)
1443         {
1444                 if (!ogg_seek_to_keyframe(tf->videosync, tf->to.serialno,
1445                         next_frame_position, &ogg_frame_position)) {
1446                         printf("FileOGG:: Error while seeking to frame's keyframe"
1447                                 " (frame: " _LD ", keyframe: " _LD ")\n",
1448                                 next_frame_position, ogg_frame_position);
1449                         return 1;
1450                 }
1451 //              printf("For frame: %lli, keyframe is: %lli\n", next_frame_position,ogg_frame_position);
1452                 // skip frames must be > 0 here
1453                 decode_frames = next_frame_position - ogg_frame_position + 1; 
1454                 ogg_frame_position --; // ogg_frame_position is at last decoded frame, so it will point right 
1455                 if (decode_frames <= 0) 
1456                 {
1457                         printf("FileOGG:: Error while seeking to keyframe,"
1458                                 " wrong keyframe number (frame: " _LD ", keyframe: " _LD ")\n",
1459                                 next_frame_position, ogg_frame_position);
1460                         return 1;
1461                         
1462                 }
1463                 expect_keyframe = 1;
1464         }
1465
1466 //      printf("Frames to decode: %i\n", decode_frames);
1467
1468 // THIS IS WHAT CAUSES SLOWNESS OF SEEKING, but we can do nothing about it.
1469         while (decode_frames > 0)
1470         {
1471                 ogg_page og;
1472                 ogg_packet op;
1473                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
1474                 {
1475                         if (!ogg_get_next_page(tf->videosync, tf->to.serialno, &og))
1476                         {
1477                                 printf("FileOGG: Cannot find next page while seeking\n");
1478                                 return 1;
1479                         }
1480                         ogg_stream_pagein(&tf->to, &og);
1481                 }
1482                 ogg_stream_packetout(&tf->to, &op);
1483                 if (expect_keyframe && !theora_packet_iskeyframe(&op))
1484                 {
1485                                 printf("FileOGG: Expecting keyframe, but didn't get it\n");
1486                         //      return 1; this is generally not a fatal error
1487                 }
1488                 expect_keyframe = 0;
1489                 
1490                 // decode
1491                 theora_decode_packetin(&tf->td, &op);
1492
1493                 decode_frames --;
1494                 ogg_frame_position ++;
1495         }
1496         {
1497                 yuv_buffer yuv;
1498                 int ret = theora_decode_YUVout (&tf->td, &yuv);
1499                 if (ret)
1500                 {
1501                         printf("FileOGG: theora_decode_YUVout failed with code %i\n", ret);
1502                 }
1503
1504 // Dirty magic 
1505 /*              yuv.y += yuv.y_stride * (yuv.y_height - 1);
1506                 yuv.u += yuv.uv_stride * (yuv.uv_height - 1);
1507                 yuv.v += yuv.uv_stride * (yuv.uv_height - 1);
1508                 yuv.y_stride = - yuv.y_stride;
1509                 yuv.uv_stride = - yuv.uv_stride;*/
1510                 VFrame *temp_frame = new VFrame(yuv.y, 
1511                                                 -1,
1512                                                 0,
1513                                                 yuv.u - yuv.y,
1514                                                 yuv.v - yuv.y,
1515                                                 - yuv.y_stride,
1516                                                 yuv.y_height,
1517                                                 BC_YUV420P,
1518                                                 - yuv.y_stride);
1519                 // copy into temp frame...
1520                 
1521                 BC_CModels::transfer(frame->get_rows(),
1522                         temp_frame->get_rows(),
1523                         frame->get_y(),
1524                         frame->get_u(),
1525                         frame->get_v(),
1526                         temp_frame->get_y(),
1527                         temp_frame->get_u(),
1528                         temp_frame->get_v(),
1529                         0,
1530                         0,
1531                         yuv.y_width,
1532                         yuv.y_height,
1533                         0,
1534                         0,
1535                         yuv.y_width,  // temp_frame can be larger than frame if width not dividable by 16
1536                         yuv.y_height,   
1537                         BC_YUV420P,
1538                         frame->get_color_model(),
1539                         0,
1540                         -temp_frame->get_w(),
1541                         frame->get_w());
1542                 delete temp_frame;
1543         }
1544
1545         next_frame_position ++;
1546         
1547         return 0;               
1548 }
1549
1550
1551
1552 int FileOGG::ogg_decode_more_samples(sync_window_t *sw, long serialno)
1553 {
1554         ogg_page og;
1555         ogg_packet op;
1556         int done = 0;
1557         while (!done)
1558         {
1559                 while (ogg_stream_packetpeek(&tf->vo, NULL) != 1)
1560                 {
1561                         if (!ogg_get_next_page(sw, serialno, &og))
1562                         {
1563                                 printf("FileOGG: Cannot find next page while trying to decode more samples\n");
1564                                 return 0;
1565                         }
1566                         ogg_stream_pagein(&tf->vo, &og);
1567                 }
1568                 ogg_stream_packetout(&tf->vo, &op);
1569                 if(!vorbis_synthesis(&tf->vb, &op))
1570                 {
1571                         done = 1;       
1572                         vorbis_synthesis_blockin(&tf->vd, &tf->vb);
1573                 }
1574         }
1575         return 1;
1576 }
1577
1578 int FileOGG::set_audio_position(int64_t x)
1579 {
1580         next_sample_position = x + start_sample;
1581         return 0;
1582 }
1583
1584 int FileOGG::move_history(int from, int to, int len)
1585 {
1586         for(int i = 0; i < asset->channels; i++)
1587                 memmove(pcm_history[i] + to, pcm_history[i] + from, sizeof(float) * len);
1588         history_start = history_start + from - to;
1589         return 0;
1590
1591
1592 int FileOGG::read_samples(double *buffer, int64_t len)
1593 {
1594         float **vorbis_buffer;
1595         if (len <= 0) 
1596                 return 0;
1597 //      printf("Reading samples: Channel: %i, number of samples: %lli, reading at :%lli\n", file->current_channel, len, next_sample_position);
1598 //              printf("\tnext_sample_position: %lli, length: %i\n", next_sample_position, len);
1599 //              printf("\thistory_start: %lli, length: %i\n", history_start, history_size);
1600
1601         if(len > HISTORY_MAX)
1602         {
1603                 printf("FileOGG::read_samples max samples=%d\n", HISTORY_MAX);
1604                 return 1;
1605         }
1606
1607         if(!pcm_history)
1608         {
1609                 pcm_history = new float*[asset->channels];
1610                 for(int i = 0; i < asset->channels; i++)
1611                         pcm_history[i] = new float[HISTORY_MAX];
1612                 history_start = -100000000; // insane value to trigger reload
1613                 history_size = 0;
1614         }
1615
1616         int64_t hole_start = -1;
1617         int64_t hole_len = -1;
1618         int64_t hole_absstart = -1;
1619         int64_t hole_fill = 0;
1620
1621         if (history_start < next_sample_position && history_start + history_size > next_sample_position && history_start + history_size < next_sample_position + len) 
1622         {
1623 //              printf("a\n");
1624                 hole_fill = 1;
1625                 hole_start = history_start + history_size - next_sample_position;
1626                 hole_len = history_size - hole_start;
1627                 hole_absstart = next_sample_position + hole_start;
1628                 move_history(next_sample_position - history_start,
1629                                 0,
1630                                 hole_start); // 
1631                 
1632         } else
1633         if (next_sample_position < history_start && history_start < next_sample_position + len)
1634         {
1635 //              printf("b\n");
1636                 hole_fill = 1;
1637                 hole_start = 0;
1638                 hole_len = history_start - next_sample_position;
1639                 hole_absstart = next_sample_position;
1640 //              printf("hs: %lli, histstart: %lli, next_sample_position: %lli\n", history_size, history_start, next_sample_position);
1641 //              printf("to: 0, from: %lli, size: %lli\n", 
1642  //                             history_start - next_sample_position,
1643 //                              history_size - history_start + next_sample_position);
1644                 move_history(0, 
1645                                 history_start - next_sample_position,
1646                                 history_size - history_start + next_sample_position);
1647                         
1648         } else 
1649         if (next_sample_position >= history_start + history_size || next_sample_position + len <= history_start)
1650         {
1651 //              printf("c\n");
1652                 hole_fill = 1;
1653                 hole_start = 0;
1654                 hole_len = HISTORY_MAX;
1655                 hole_absstart = next_sample_position;
1656                 history_start = hole_absstart;
1657                 history_size = hole_len;
1658         }
1659         
1660         if (hole_fill)
1661         {
1662                 if (hole_start < 0 || hole_len <= 0 || hole_absstart < 0)
1663                 {
1664                         printf("FileOGG: Error at finding out what to read from file\n");
1665                         return 1;
1666                 }
1667                 
1668                 if (hole_absstart + hole_len > asset->audio_length + start_sample)
1669                 {
1670                         hole_len = asset->audio_length + start_sample - hole_absstart;
1671                         history_size = asset->audio_length + start_sample - history_start;
1672                 } else
1673                 {
1674                         history_size = HISTORY_MAX;
1675                 }
1676                 
1677                 
1678 //              printf("Decode samples at position: %lli, samples to read: %lli\n", hole_absstart, hole_len);
1679         
1680                 int64_t samples_read = 0;        
1681                 if (ogg_sample_position != hole_absstart)
1682                 {
1683                         ogg_sample_position = hole_absstart;
1684                         if (!ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, ogg_sample_position))
1685                         {
1686                                 printf("FileOGG:: Error while seeking to sample\n");
1687                                 return 1;
1688                         }
1689                 }
1690                 // now we have ogg_sample_positon aligned
1691                 int64_t samples_to_read = hole_len;
1692                 while (samples_read < hole_len)
1693                 {
1694                         int64_t waiting_samples = vorbis_synthesis_pcmout(&tf->vd, &vorbis_buffer);
1695                         int64_t takeout_samples;
1696                         if (waiting_samples > samples_to_read - samples_read)
1697                                 takeout_samples = samples_to_read - samples_read;
1698                         else 
1699                                 takeout_samples = waiting_samples;
1700
1701 //                      printf("takeout samples: %lli, samples_read: %lli\n", takeout_samples, samples_read);
1702
1703                         if(waiting_samples)
1704                         {
1705                                 for(int i = 0; i < asset->channels; i++)
1706                                 {
1707                                         float *input = vorbis_buffer[i];
1708                                         float *output = pcm_history[i] + hole_start;
1709                                         // TODO: use memcpy
1710                                         for(int j = 0; j < takeout_samples ; j++)
1711                                         {
1712                                                 output[j] = input[j];
1713                                         }
1714                                 }                                                                   
1715                         }
1716
1717                         vorbis_synthesis_read(&tf->vd, takeout_samples);
1718                         samples_read += takeout_samples;
1719                         ogg_sample_position += takeout_samples;
1720                         hole_start += takeout_samples;
1721                         
1722                         if (samples_read < hole_len)
1723                                 if (!ogg_decode_more_samples(tf->audiosync, tf->vo.serialno))
1724                                 {
1725                                         ogg_sample_position = -1;
1726                                         return 1;
1727                                 }
1728
1729
1730                 }
1731         }       
1732         
1733         // now we can be sure our history is correct, just copy it out
1734         if (next_sample_position < history_start || next_sample_position + len > history_start + history_size)
1735         {
1736                 printf("FileOGG:: History not aligned properly \n");
1737                 printf("\tnext_sample_position: " _LD ", length: " _LD "\n", next_sample_position, len);
1738                 printf("\thistory_start: " _LD ", length: " _LD "\n", history_start, history_size);
1739                 
1740                 return 1;
1741         }
1742         float *input = pcm_history[file->current_channel] + next_sample_position - history_start;
1743         for (int i = 0; i < len; i++)
1744                 buffer[i] = input[i];
1745          
1746         next_sample_position += len;
1747         return 0;
1748 }
1749
1750
1751 int FileOGG::write_audio_page()
1752 {
1753   int ret;
1754
1755   ret = fwrite(tf->apage, 1, tf->apage_len, stream);
1756   if(ret < tf->apage_len) {
1757     eprintf("error writing audio page\n"); 
1758   }
1759   tf->apage_valid = 0;
1760   tf->a_pkg -= ogg_page_packets((ogg_page *)&tf->apage);
1761   return ret;
1762 }
1763
1764 int FileOGG::write_video_page()
1765 {
1766   int ret;
1767
1768   ret = fwrite(tf->vpage, 1, tf->vpage_len, stream);
1769   if(ret < tf->vpage_len) {
1770     eprintf("error writing video page\n");
1771   }
1772   tf->vpage_valid = 0;
1773   tf->v_pkg -= ogg_page_packets((ogg_page *)&tf->vpage);
1774   return ret;
1775 }
1776
1777 void FileOGG::flush_ogg (int e_o_s)
1778 {
1779     int len;
1780     ogg_page og;
1781
1782         flush_lock->lock();
1783     /* flush out the ogg pages  */
1784     while(1) {
1785       /* Get pages for both streams, if not already present, and if available.*/
1786       if(asset->video_data && !tf->vpage_valid) {
1787         // this way seeking is much better,
1788         // not sure if 23 packets  is a good value. it works though
1789         int v_next=0;
1790         if(tf->v_pkg>22 && ogg_stream_flush(&tf->to, &og) > 0) {
1791           v_next=1;
1792         }
1793         else if(ogg_stream_pageout(&tf->to, &og) > 0) {
1794           v_next=1;
1795         }
1796         if(v_next) {
1797           len = og.header_len + og.body_len;
1798           if(tf->vpage_buffer_length < len) {
1799             tf->vpage = (unsigned char *)realloc(tf->vpage, len);
1800             tf->vpage_buffer_length = len;
1801           }
1802           tf->vpage_len = len;
1803           memcpy(tf->vpage, og.header, og.header_len);
1804           memcpy(tf->vpage+og.header_len , og.body, og.body_len);
1805
1806           tf->vpage_valid = 1;
1807           tf->videotime = theora_granule_time (&tf->td,
1808                   ogg_page_granulepos(&og));
1809         }
1810       }
1811       if(asset->audio_data && !tf->apage_valid) {
1812         // this way seeking is much better,
1813         // not sure if 23 packets  is a good value. it works though
1814         int a_next=0;
1815         if(tf->a_pkg>22 && ogg_stream_flush(&tf->vo, &og) > 0) {
1816           a_next=1;
1817         }
1818         else if(ogg_stream_pageout(&tf->vo, &og) > 0) {
1819           a_next=1;
1820         }
1821         if(a_next) {
1822           len = og.header_len + og.body_len;
1823           if(tf->apage_buffer_length < len) {
1824             tf->apage = (unsigned char *)realloc(tf->apage, len);
1825             tf->apage_buffer_length = len;
1826           }
1827           tf->apage_len = len;
1828           memcpy(tf->apage, og.header, og.header_len);
1829           memcpy(tf->apage+og.header_len , og.body, og.body_len);
1830
1831           tf->apage_valid = 1;
1832           tf->audiotime= vorbis_granule_time (&tf->vd, 
1833                   ogg_page_granulepos(&og));
1834         }
1835       }
1836
1837       if(!asset->audio_data && tf->vpage_valid) {
1838         write_video_page();
1839       }
1840       else if(!asset->video_data && tf->apage_valid) {
1841         write_audio_page();
1842       }
1843       /* We're using both. We can output only:
1844        *  a) If we have valid pages for both
1845        *  b) At EOS, for the remaining stream.
1846        */
1847       else if(tf->vpage_valid && tf->apage_valid) {
1848         /* Make sure they're in the right order. */
1849         if(tf->videotime <= tf->audiotime)
1850           write_video_page();
1851         else
1852           write_audio_page();
1853       } 
1854       else if(e_o_s && tf->vpage_valid) {
1855           write_video_page();
1856       }
1857       else if(e_o_s && tf->apage_valid) {
1858           write_audio_page();
1859       }
1860       else {
1861         break; /* Nothing more writable at the moment */
1862       }
1863     }
1864         flush_lock->unlock();
1865 }
1866
1867
1868 int FileOGG::write_samples_vorbis(double **buffer, int64_t len, int e_o_s)
1869 {
1870         float **vorbis_buffer;
1871         static int samples = 0;
1872         samples += len;
1873         if(e_o_s)
1874         {
1875                 vorbis_analysis_wrote (&tf->vd, 0);
1876         } else
1877         {
1878                 vorbis_buffer = vorbis_analysis_buffer (&tf->vd, len);
1879                 /* double to float conversion */
1880                 for(int i = 0; i<asset->channels; i++)
1881                 {
1882                         for (int j = 0; j < len; j++)
1883                         {
1884                                 vorbis_buffer[i][j] = buffer[i][j];
1885                         }
1886                 }
1887                 vorbis_analysis_wrote (&tf->vd, len);
1888         }
1889         while(vorbis_analysis_blockout (&tf->vd, &tf->vb) == 1)
1890         {
1891             /* analysis, assume we want to use bitrate management */
1892             vorbis_analysis (&tf->vb, NULL);
1893             vorbis_bitrate_addblock (&tf->vb);
1894             
1895             /* weld packets into the bitstream */
1896             while (vorbis_bitrate_flushpacket (&tf->vd, &tf->op))
1897             {
1898                 flush_lock->lock();
1899                 ogg_stream_packetin (&tf->vo, &tf->op);
1900                 tf->a_pkg++;
1901                 flush_lock->unlock();
1902             }
1903
1904         }
1905         flush_ogg(0);
1906         return 0;
1907
1908
1909 }
1910
1911 int FileOGG::write_samples(double **buffer, int64_t len)
1912 {
1913         if (len > 0)
1914                 return write_samples_vorbis(buffer, len, 0);
1915         return 0;
1916 }
1917
1918 int FileOGG::write_frames_theora(VFrame ***frames, int len, int e_o_s)
1919 {
1920         // due to clumsy theora's design we need to delay writing out by one frame
1921         // always stay one frame behind, so we can correctly encode e_o_s
1922         int result = 0;
1923         if(!stream) return 0;
1924         
1925         for(int j = 0; j < len && !result; j++)
1926         {
1927                 if (temp_frame) // encode previous frame if available
1928                 {
1929                         yuv_buffer yuv;
1930                         yuv.y_width = tf->ti.width;
1931                         yuv.y_height = tf->ti.height;
1932                         yuv.y_stride = temp_frame->get_bytes_per_line();
1933
1934                         yuv.uv_width = tf->ti.width / 2;
1935                         yuv.uv_height = tf->ti.height / 2;
1936                         yuv.uv_stride = temp_frame->get_bytes_per_line() /2;
1937
1938                         yuv.y = temp_frame->get_y();
1939                         yuv.u = temp_frame->get_u();
1940                         yuv.v = temp_frame->get_v();
1941                         int ret = theora_encode_YUVin (&tf->td, &yuv);
1942                         if (ret)
1943                         {
1944                                 printf("FileOGG: theora_encode_YUVin failed with code %i\n", ret);
1945                                 printf("yuv_buffer: y_width: %i, y_height: %i, y_stride: %i,"
1946                                         " uv_width: %i, uv_height: %i, uv_stride: %i\n",
1947                                         yuv.y_width, yuv.y_height, yuv.y_stride,
1948                                         yuv.uv_width, yuv.uv_height, yuv.uv_stride);
1949                         }
1950                         while(theora_encode_packetout (&tf->td, e_o_s, &tf->op)) {
1951                                 flush_lock->lock();
1952                                 ogg_stream_packetin (&tf->to, &tf->op);
1953                                 tf->v_pkg++;
1954                                 flush_lock->unlock();
1955             }
1956                         flush_ogg(0);  // eos flush is done later at close_file
1957                 }
1958 // If we have e_o_s, don't encode any new frames
1959                 if (e_o_s) 
1960                         break;
1961
1962                 if (!temp_frame)
1963                 {
1964                         temp_frame = new VFrame (0, 
1965                                                 -1,
1966                                                 tf->ti.width, 
1967                                                 tf->ti.height,
1968                                                 BC_YUV420P,
1969                                                 -1);
1970                 } 
1971                 VFrame *frame = frames[0][j];
1972                 int in_color_model = frame->get_color_model();
1973                 if (in_color_model == BC_YUV422P &&
1974                     temp_frame->get_w() == frame->get_w() &&
1975                     temp_frame->get_h() == frame->get_h() &&
1976                     temp_frame->get_bytes_per_line() == frame->get_bytes_per_line())
1977                 {
1978                         temp_frame->copy_from(frame);
1979                 } else
1980                 {
1981
1982                         BC_CModels::transfer(temp_frame->get_rows(),
1983                                 frame->get_rows(),
1984                                 temp_frame->get_y(),
1985                                 temp_frame->get_u(),
1986                                 temp_frame->get_v(),
1987                                 frame->get_y(),
1988                                 frame->get_u(),
1989                                 frame->get_v(),
1990                                 0,
1991                                 0,
1992                                 frame->get_w(),
1993                                 frame->get_h(),
1994                                 0,
1995                                 0,
1996                                 frame->get_w(),  // temp_frame can be larger than frame if width not dividable by 16
1997                                 frame->get_h(), 
1998                                 frame->get_color_model(),
1999                                 BC_YUV420P,
2000                                 0,
2001                                 frame->get_w(),
2002                                 temp_frame->get_w());
2003
2004                 }
2005         }                                               
2006                                 
2007         return 0;
2008 }
2009
2010
2011 int FileOGG::write_frames(VFrame ***frames, int len)
2012 {
2013         
2014         return write_frames_theora(frames, len, 0);
2015 }
2016
2017 OGGConfigAudio::OGGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
2018  : BC_Window(PROGRAM_NAME ": Audio Compression",
2019         parent_window->get_abs_cursor_x(1),
2020         parent_window->get_abs_cursor_y(1),
2021         350,
2022         250)
2023 {
2024         this->parent_window = parent_window;
2025         this->asset = asset;
2026 }
2027
2028 OGGConfigAudio::~OGGConfigAudio()
2029 {
2030
2031 }
2032
2033 void OGGConfigAudio::create_objects()
2034 {
2035 //      add_tool(new BC_Title(10, 10, _("There are no audio options for this format")));
2036
2037         int x = 10, y = 10;
2038         int x1 = 150;
2039         char string[BCTEXTLEN];
2040
2041         lock_window("OGGConfigAudio::create_objects");
2042         add_tool(fixed_bitrate = new OGGVorbisFixedBitrate(x, y, this));
2043         add_tool(variable_bitrate = new OGGVorbisVariableBitrate(x1, y, this));
2044
2045         y += 30;
2046         sprintf(string, "%d", asset->vorbis_min_bitrate);
2047         add_tool(new BC_Title(x, y, _("Min bitrate:")));
2048         add_tool(new OGGVorbisMinBitrate(x1, y, this, string));
2049
2050         y += 30;
2051         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
2052         sprintf(string, "%d", asset->vorbis_bitrate);
2053         add_tool(new OGGVorbisAvgBitrate(x1, y, this, string));
2054
2055         y += 30;
2056         add_tool(new BC_Title(x, y, _("Max bitrate:")));
2057         sprintf(string, "%d", asset->vorbis_max_bitrate);
2058         add_tool(new OGGVorbisMaxBitrate(x1, y, this, string));
2059
2060
2061         add_subwindow(new BC_OKButton(this));
2062         show_window(1);
2063         unlock_window();
2064 }
2065
2066 int OGGConfigAudio::close_event()
2067 {
2068         set_done(0);
2069         return 1;
2070 }
2071
2072 OGGVorbisFixedBitrate::OGGVorbisFixedBitrate(int x, int y, OGGConfigAudio *gui)
2073  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Average bitrate"))
2074 {
2075         this->gui = gui;
2076 }
2077 int OGGVorbisFixedBitrate::handle_event()
2078 {
2079         gui->asset->vorbis_vbr = 0;
2080         gui->variable_bitrate->update(0);
2081         return 1;
2082 }
2083
2084 OGGVorbisVariableBitrate::OGGVorbisVariableBitrate(int x, int y, OGGConfigAudio *gui)
2085  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
2086 {
2087         this->gui = gui;
2088 }
2089 int OGGVorbisVariableBitrate::handle_event()
2090 {
2091         gui->asset->vorbis_vbr = 1;
2092         gui->fixed_bitrate->update(0);
2093         return 1;
2094 }
2095
2096
2097 OGGVorbisMinBitrate::OGGVorbisMinBitrate(int x, 
2098         int y, 
2099         OGGConfigAudio *gui, 
2100         char *text)
2101  : BC_TextBox(x, y, 180, 1, text)
2102 {
2103         this->gui = gui;
2104 }
2105 int OGGVorbisMinBitrate::handle_event()
2106 {
2107         gui->asset->vorbis_min_bitrate = atol(get_text());
2108         return 1;
2109 }
2110
2111
2112
2113 OGGVorbisMaxBitrate::OGGVorbisMaxBitrate(int x, 
2114         int y, 
2115         OGGConfigAudio *gui,
2116         char *text)
2117  : BC_TextBox(x, y, 180, 1, text)
2118 {
2119         this->gui = gui;
2120 }
2121 int OGGVorbisMaxBitrate::handle_event()
2122 {
2123         gui->asset->vorbis_max_bitrate = atol(get_text());
2124         return 1;
2125 }
2126
2127
2128
2129 OGGVorbisAvgBitrate::OGGVorbisAvgBitrate(int x, int y, OGGConfigAudio *gui, char *text)
2130  : BC_TextBox(x, y, 180, 1, text)
2131 {
2132         this->gui = gui;
2133 }
2134 int OGGVorbisAvgBitrate::handle_event()
2135 {
2136         gui->asset->vorbis_bitrate = atol(get_text());
2137         return 1;
2138 }
2139
2140
2141
2142
2143
2144 OGGConfigVideo::OGGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
2145  : BC_Window(PROGRAM_NAME ": Video Compression",
2146         parent_window->get_abs_cursor_x(1),
2147         parent_window->get_abs_cursor_y(1),
2148         450,
2149         220)
2150 {
2151         this->parent_window = parent_window;
2152         this->asset = asset;
2153 }
2154
2155 OGGConfigVideo::~OGGConfigVideo()
2156 {
2157
2158 }
2159
2160 void OGGConfigVideo::create_objects()
2161 {
2162 //      add_tool(new BC_Title(10, 10, _("There are no video options for this format")));
2163         int x = 10, y = 10;
2164         int x1 = x + 150;
2165         int x2 = x + 300;
2166
2167         lock_window("OGGConfigVideo::create_objects");
2168         add_subwindow(new BC_Title(x, y + 5, _("Bitrate:")));
2169         add_subwindow(new OGGTheoraBitrate(x1, y, this));
2170         add_subwindow(fixed_bitrate = new OGGTheoraFixedBitrate(x2, y, this));
2171         y += 30;
2172
2173         add_subwindow(new BC_Title(x, y, _("Quality:")));
2174         add_subwindow(new BC_ISlider(x + 80, 
2175                 y,
2176                 0,
2177                 200,
2178                 200,
2179                 0,
2180                 63,
2181                 asset->theora_quality,
2182                 0,
2183                 0,
2184                 &asset->theora_quality));
2185
2186         
2187         add_subwindow(fixed_quality = new OGGTheoraFixedQuality(x2, y, this));
2188         y += 30;
2189
2190         add_subwindow(new BC_Title(x, y, _("Keyframe frequency:")));
2191         OGGTheoraKeyframeFrequency *keyframe_frequency = 
2192                 new OGGTheoraKeyframeFrequency(x1 + 60, y, this);
2193         keyframe_frequency->create_objects();
2194         y += 30;
2195         
2196         add_subwindow(new BC_Title(x, y, _("Keyframe force frequency:")));
2197         OGGTheoraKeyframeForceFrequency *keyframe_force_frequency = 
2198                 new OGGTheoraKeyframeForceFrequency(x1 + 60, y, this);
2199         keyframe_force_frequency->create_objects();
2200         y += 30;
2201
2202         add_subwindow(new BC_Title(x, y, _("Sharpness:")));
2203         OGGTheoraSharpness *sharpness = 
2204                 new OGGTheoraSharpness(x1 + 60, y, this);
2205         sharpness->create_objects();
2206         y += 30;
2207         
2208
2209         add_subwindow(new BC_OKButton(this));
2210         show_window(1);
2211         unlock_window();
2212 }
2213
2214
2215
2216
2217 int OGGConfigVideo::close_event()
2218 {
2219         set_done(0);
2220         return 1;
2221 }
2222
2223 OGGTheoraBitrate::OGGTheoraBitrate(int x, int y, OGGConfigVideo *gui)
2224  : BC_TextBox(x, y, 100, 1, gui->asset->theora_bitrate)
2225 {
2226         this->gui = gui;
2227 }
2228
2229
2230 int OGGTheoraBitrate::handle_event()
2231 {
2232         // TODO: MIN / MAX check
2233         gui->asset->theora_bitrate = atol(get_text());
2234         return 1;
2235 };
2236
2237
2238
2239
2240 OGGTheoraFixedBitrate::OGGTheoraFixedBitrate(int x, int y, OGGConfigVideo *gui)
2241  : BC_Radial(x, y, gui->asset->theora_fix_bitrate, _("Fixed bitrate"))
2242 {
2243         this->gui = gui;
2244 }
2245
2246 int OGGTheoraFixedBitrate::handle_event()
2247 {
2248         update(1);
2249         gui->asset->theora_fix_bitrate = 1;
2250         gui->fixed_quality->update(0);
2251         return 1;
2252 };
2253
2254 OGGTheoraFixedQuality::OGGTheoraFixedQuality(int x, int y, OGGConfigVideo *gui)
2255  : BC_Radial(x, y, !gui->asset->theora_fix_bitrate, _("Fixed quality"))
2256 {
2257         this->gui = gui;
2258 }
2259
2260 int OGGTheoraFixedQuality::handle_event()
2261 {
2262         update(1);
2263         gui->asset->theora_fix_bitrate = 0;
2264         gui->fixed_bitrate->update(0);
2265         return 1;
2266 };
2267
2268 OGGTheoraKeyframeFrequency::OGGTheoraKeyframeFrequency(int x, int y, OGGConfigVideo *gui)
2269  : BC_TumbleTextBox(gui, 
2270         (int64_t)gui->asset->theora_keyframe_frequency, 
2271         (int64_t)1,
2272         (int64_t)500,
2273         x, 
2274         y,
2275         40)
2276 {
2277         this->gui = gui;
2278 }
2279
2280 int OGGTheoraKeyframeFrequency::handle_event()
2281 {
2282         gui->asset->theora_keyframe_frequency = atol(get_text());
2283         return 1;
2284 }
2285
2286 OGGTheoraKeyframeForceFrequency::OGGTheoraKeyframeForceFrequency(int x, int y, OGGConfigVideo *gui)
2287  : BC_TumbleTextBox(gui, 
2288         (int64_t)gui->asset->theora_keyframe_frequency, 
2289         (int64_t)1,
2290         (int64_t)500,
2291         x, 
2292         y,
2293         40)
2294 {
2295         this->gui = gui;
2296 }
2297
2298 int OGGTheoraKeyframeForceFrequency::handle_event()
2299 {
2300         gui->asset->theora_keyframe_frequency = atol(get_text());
2301         return 1;
2302 }
2303
2304
2305 OGGTheoraSharpness::OGGTheoraSharpness(int x, int y, OGGConfigVideo *gui)
2306  : BC_TumbleTextBox(gui, 
2307         (int64_t)gui->asset->theora_sharpness, 
2308         (int64_t)0,
2309         (int64_t)2,
2310         x, 
2311         y,
2312         40)
2313 {
2314         this->gui = gui;
2315 }
2316
2317 int OGGTheoraSharpness::handle_event()
2318 {
2319         gui->asset->theora_sharpness = atol(get_text());
2320         return 1;
2321 }
2322
2323
2324 PackagingEngineOGG::PackagingEngineOGG()
2325 {
2326         packages = 0;
2327         default_asset = 0;
2328 }
2329
2330 PackagingEngineOGG::~PackagingEngineOGG()
2331 {
2332         if(packages)
2333         {
2334                 for(int i = 0; i < total_packages; i++)
2335                         delete packages[i];
2336                 delete [] packages;
2337         }
2338         if (default_asset)
2339                 delete default_asset;
2340 }
2341
2342
2343
2344 int PackagingEngineOGG::create_packages_single_farm(
2345                 EDL *edl,
2346                 Preferences *preferences,
2347                 Asset *default_asset, 
2348                 double total_start, 
2349                 double total_end)
2350 {
2351         this->total_start = total_start;
2352         this->total_end = total_end;
2353         this->edl = edl;
2354
2355         this->preferences = preferences;
2356
2357 // We make A COPY of the asset, because we set audio_data = 0 on local asset which is the same copy as default_asset... 
2358 // Should be taken care of somewhere else actually
2359         this->default_asset = new Asset(*default_asset);
2360
2361         audio_start = Units::to_int64(total_start * default_asset->sample_rate);
2362         video_start = Units::to_int64(total_start * default_asset->frame_rate);
2363         audio_position = audio_start;
2364         video_position = video_start;
2365         audio_end = Units::to_int64(total_end * default_asset->sample_rate);
2366         video_end = Units::to_int64(total_end * default_asset->frame_rate);
2367         current_package = 0;
2368
2369         double total_len = total_end - total_start;
2370 //printf("PackageDispatcher::create_packages: %f / %d = %f\n", total_len, total_packages, package_len);
2371
2372         total_packages = 0;
2373         if (default_asset->audio_data)
2374                 total_packages++;
2375         if (default_asset->video_data)
2376                 total_packages += preferences->renderfarm_job_count;
2377
2378         packages = new RenderPackage*[total_packages];
2379
2380         int local_current_package = 0;
2381         if (default_asset->audio_data)
2382         {
2383                 packages[local_current_package] = new RenderPackage;
2384                 sprintf(packages[current_package]->path, "%s.audio", default_asset->path);
2385                 local_current_package++;
2386         }
2387         
2388         if (default_asset->video_data)
2389         {
2390                 video_package_len = (total_len) / preferences->renderfarm_job_count;
2391                 int current_number;    // The number being injected into the filename.
2392                 int number_start;      // Character in the filename path at which the number begins
2393                 int total_digits;      // Total number of digits including padding the user specified.
2394
2395                 Render::get_starting_number(default_asset->path, 
2396                         current_number,
2397                         number_start, 
2398                         total_digits,
2399                         3);
2400
2401                 for(int i = 0; i < preferences->renderfarm_job_count; i++)
2402                 {
2403                         RenderPackage *package = packages[local_current_package] = new RenderPackage;
2404                         Render::create_filename(package->path, 
2405                                 default_asset->path, 
2406                                 current_number,
2407                                 total_digits,
2408                                 number_start);
2409                         current_number++;
2410                         local_current_package++;
2411                 }
2412         }
2413         return 0;
2414 }
2415
2416 RenderPackage* PackagingEngineOGG::get_package_single_farm(double frames_per_second, 
2417                 int client_number,
2418                 int use_local_rate)
2419 {
2420
2421 //printf("PackageDispatcher::get_package %ld %ld %ld %ld\n", audio_position, video_position, audio_end, video_end);
2422         if (current_package == total_packages)
2423                 return 0;
2424
2425         RenderPackage *result = 0;
2426         if (current_package == 0 && default_asset->audio_data)
2427         {
2428                 result = packages[0];
2429                 result->audio_start = audio_start;
2430                 result->video_start = video_start;
2431                 result->audio_end = audio_end;
2432                 result->video_end = video_end;
2433                 result->audio_do = 1;
2434                 result->video_do = 0;
2435         } else if (default_asset->video_data)
2436         {
2437                 // Do not do any scaling according to node speed, so we know we can get evenly distributed 'forced' keyframes
2438                 result = packages[current_package];
2439                 result->audio_do = 0;
2440                 result->video_do = 1;
2441
2442                 result->audio_start = audio_position;
2443                 result->video_start = video_position;
2444                 result->audio_end = audio_position + 
2445                         Units::round(video_package_len * default_asset->sample_rate);
2446                 result->video_end = video_position + 
2447                         Units::round(video_package_len * default_asset->frame_rate);
2448
2449 // Last package... take it all!
2450                 if (current_package == total_packages -1 ) 
2451                 {
2452                         result->audio_end = audio_end;
2453                         result->video_end = video_end;
2454                 }
2455
2456                 audio_position = result->audio_end;
2457                 video_position = result->video_end;
2458
2459         }
2460         
2461         current_package ++;
2462         return result;
2463
2464 }
2465
2466 void PackagingEngineOGG::get_package_paths(ArrayList<char*> *path_list)
2467 {
2468         for(int i = 0; i < total_packages; i++)
2469         {
2470                 path_list->append(strdup(packages[i]->path));
2471         }
2472 // We will mux to the the final file at the end!
2473         path_list->append(strdup(default_asset->path));
2474         path_list->set_free();
2475 }
2476
2477 int64_t PackagingEngineOGG::get_progress_max()
2478 {
2479         return Units::to_int64(default_asset->sample_rate * 
2480                         (total_end - total_start)) * 2+
2481                 Units::to_int64(preferences->render_preroll * 
2482                         total_packages *
2483                         default_asset->sample_rate);
2484 }
2485
2486 int PackagingEngineOGG::packages_are_done()
2487 {
2488
2489
2490 // Mux audio and video into one file    
2491
2492 // First fix our asset... have to workaround the bug of corruption of local asset
2493 //      Render::check_asset(edl, *default_asset);
2494
2495         Asset *video_asset = 0, *audio_asset = 0;
2496         File *audio_file_gen = 0, *video_file_gen = 0;
2497         FileOGG *video_file = 0, *audio_file = 0;
2498         ogg_stream_state audio_in_stream, video_in_stream;
2499         
2500         int local_current_package = 0;
2501         if (default_asset->audio_data)
2502         {
2503                 audio_asset = new Asset(packages[local_current_package]->path);
2504                 local_current_package++;
2505
2506                 audio_file_gen = new File();
2507                 audio_file_gen->open_file(preferences, audio_asset, 1, 0);
2508                 audio_file = (FileOGG*) audio_file_gen->file;
2509                 ogg_stream_init(&audio_in_stream, audio_file->tf->vo.serialno);
2510                 audio_file->ogg_seek_to_databegin(audio_file->tf->audiosync, audio_file->tf->vo.serialno);
2511         }
2512
2513         if (default_asset->video_data)
2514         {
2515                 video_asset = new Asset(packages[local_current_package]->path);
2516                 local_current_package++;
2517
2518                 video_file_gen = new File();
2519                 video_file_gen->open_file(preferences, video_asset, 1, 0);
2520                 video_file = (FileOGG*) video_file_gen->file;
2521                 ogg_stream_init(&video_in_stream, video_file->tf->to.serialno);
2522                 video_file->ogg_seek_to_databegin(video_file->tf->videosync, video_file->tf->to.serialno);
2523         }
2524
2525 // Output file
2526         File *output_file_gen = new File();
2527         output_file_gen->open_file(preferences, default_asset, 0, 1);
2528         FileOGG *output_file = (FileOGG*) output_file_gen->file;
2529
2530         //ogg_page og;    /* one Ogg bitstream page.  Vorbis packets are inside */
2531         ogg_packet op;  /* one raw packet of data for decode */
2532
2533
2534         int audio_ready = default_asset->audio_data;
2535         int video_ready = default_asset->video_data;
2536         int64_t video_packetno = 1;
2537         int64_t audio_packetno = 1;
2538         int64_t frame_offset = 0;
2539         int64_t current_frame = 0;
2540         while ((default_asset->audio_data && audio_ready) || (default_asset->video_data && video_ready))
2541         {
2542                 if (video_ready)
2543                 {
2544                         while (ogg_stream_packetpeek(&video_in_stream, NULL) != 1) // get as many pages as needed for one package
2545                         {
2546                                 if (!video_file->ogg_get_next_page(video_file->tf->videosync, video_file->tf->to.serialno, &video_file->tf->videopage))
2547                                 {
2548                                         // We are at the end of our file, see if it is more and open more if there is
2549                                         if (local_current_package < total_packages)
2550                                         {
2551                                                 frame_offset = current_frame +1;
2552                                                 ogg_stream_clear(&video_in_stream);
2553                                                 video_file_gen->close_file();
2554                                                 delete video_file_gen;
2555                                                 delete video_asset;
2556                                                 video_asset = new Asset(packages[local_current_package]->path);
2557                                                 local_current_package++;
2558
2559                                                 video_file_gen = new File();
2560                                                 video_file_gen->open_file(preferences, video_asset, 1, 0);
2561                                                 video_file = (FileOGG*) video_file_gen->file;
2562                                                 ogg_stream_init(&video_in_stream, video_file->tf->to.serialno);
2563                                                 video_file->ogg_seek_to_databegin(video_file->tf->videosync, video_file->tf->to.serialno);
2564
2565                                         } else
2566                                                 video_ready = 0;
2567                                         break;
2568                                 }
2569                                 ogg_stream_pagein(&video_in_stream, &video_file->tf->videopage);
2570                         }
2571                         while (ogg_stream_packetpeek(&video_in_stream, NULL) == 1) // get all packets out of the page
2572                         {
2573                                 ogg_stream_packetout(&video_in_stream, &op);
2574                                 if (local_current_package != total_packages) // keep it from closing the stream
2575                                         op.e_o_s = 0;
2576                                 if (video_packetno != 1)                     // if this is not the first video package do not start with b_o_s
2577                                         op.b_o_s = 0;
2578                                 else
2579                                         op.b_o_s = 1;
2580                                 op.packetno = video_packetno;
2581                                 video_packetno ++;
2582                                 int64_t granulepos = op.granulepos;
2583                                 if (granulepos != -1)
2584                                 {
2585                                 // Fix granulepos!      
2586                                         int64_t rel_iframe = granulepos >> video_file->theora_keyframe_granule_shift;
2587                                         int64_t rel_pframe = granulepos - (rel_iframe << video_file->theora_keyframe_granule_shift);
2588                                         int64_t rel_current_frame = rel_iframe + rel_pframe;
2589                                         current_frame = frame_offset + rel_current_frame;
2590                                         int64_t abs_iframe = current_frame - rel_pframe;
2591                                         
2592                                         op.granulepos = (abs_iframe << video_file->theora_keyframe_granule_shift) + rel_pframe;
2593                                         
2594 //                                      printf("iframe: %i, pframe: %i, granulepos: %i, op.packetno %lli, abs_iframe: %i\n", rel_iframe, rel_pframe, granulepos, op.packetno, abs_iframe);                              
2595                                 
2596                                 }
2597                                 ogg_stream_packetin (&output_file->tf->to, &op);
2598                                 output_file->tf->v_pkg++; 
2599                         }
2600                 }
2601                 if (audio_ready)
2602                 {
2603                         while (ogg_stream_packetpeek(&audio_in_stream, NULL) != 1) // get as many pages as needed for one package
2604                         {
2605                                 if (!audio_file->ogg_get_next_page(audio_file->tf->audiosync, audio_file->tf->vo.serialno, &audio_file->tf->audiopage))
2606                                 {
2607                                         audio_ready = 0;
2608                                         break;
2609                                 }
2610                                 ogg_stream_pagein(&audio_in_stream, &audio_file->tf->audiopage);
2611                         }
2612                         while (ogg_stream_packetpeek(&audio_in_stream, NULL) == 1) // get all packets out of the page
2613                         {
2614                                 ogg_stream_packetout(&audio_in_stream, &op);
2615                                 ogg_stream_packetin (&output_file->tf->vo, &op);
2616                                 audio_packetno++;
2617                                 output_file->tf->a_pkg++; 
2618                         }
2619                 }
2620                 
2621                 output_file->flush_ogg(0);
2622                 
2623         
2624         }
2625         
2626 // flush_ogg(1) is called on file closing time...       
2627 //      output_file->flush_ogg(1);
2628
2629 // Just prevent thet write_samples and write_frames are called
2630         output_file->final_write = 0;
2631                 
2632         if (default_asset->audio_data)
2633         {
2634                 ogg_stream_clear(&audio_in_stream);
2635                 audio_file_gen->close_file();
2636                 delete audio_file_gen;
2637                 delete audio_asset;
2638         }
2639         if (default_asset->video_data)
2640         {
2641                 ogg_stream_clear(&video_in_stream);
2642                 video_file_gen->close_file();
2643                 delete video_file_gen;
2644                 delete video_asset;
2645         }
2646
2647         output_file_gen->close_file();
2648         delete output_file_gen;
2649
2650 // Now delete the temp files
2651         for(int i = 0; i < total_packages; i++)
2652                 unlink(packages[i]->path);
2653
2654         return 0;
2655 }
2656
2657
2658