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