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