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