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