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