Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

fileogg.C

Go to the documentation of this file.
00001         
00002 #include "clip.h"
00003 #include "asset.h"
00004 #include "bcsignals.h"
00005 #include "byteorder.h"
00006 #include "edit.h"
00007 #include "file.h"
00008 #include "fileogg.h"
00009 #include "guicast.h"
00010 #include "language.h"
00011 #include "mwindow.inc"
00012 #include "quicktime.h"
00013 #include "vframe.h"
00014 #include "videodevice.inc"
00015 #include "cmodel_permutation.h"
00016 #include "interlacemodes.h"
00017 
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 #include <unistd.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 
00025 #define READ_SIZE 66000
00026 
00027 /* This code was aspired by ffmpeg2theora */
00028 /* Special thanks for help on this code goes out to j@v2v.cc */
00029 
00030 
00031 FileOGG::FileOGG(Asset *asset, File *file)
00032  : FileBase(asset, file)
00033 {
00034         if(asset->format == FILE_UNKNOWN)
00035                 asset->format = FILE_OGG;
00036         asset->byte_order = 0;
00037         reset_parameters();
00038 }
00039 
00040 FileOGG::~FileOGG()
00041 {
00042         if (tf) 
00043         {
00044 
00045                 if (tf->videosync) 
00046                 {
00047                         ogg_sync_clear(&tf->videosync->sync);
00048                         delete tf->videosync;
00049                         theora_info_clear(&tf->ti);
00050                         theora_comment_clear(&tf->tc);
00051                 }
00052                 if (tf->audiosync) 
00053                 {
00054                         ogg_sync_clear(&tf->audiosync->sync);
00055                         delete tf->audiosync;
00056                         vorbis_info_clear(&tf->vi);
00057                         vorbis_comment_clear(&tf->vc);
00058                 }
00059                 delete tf;
00060         }
00061         if (temp_frame) delete temp_frame;
00062         if (stream) close_file();
00063         if(pcm_history)
00064         {
00065                 for(int i = 0; i < asset->channels; i++)
00066                         delete [] pcm_history[i];
00067                 delete [] pcm_history;
00068         }
00069 
00070         if (flush_lock) delete flush_lock;
00071 }
00072 
00073 void FileOGG::get_parameters(BC_WindowBase *parent_window,
00074         Asset *asset,
00075         BC_WindowBase* &format_window,
00076         int audio_options,
00077         int video_options)
00078 {
00079         if(audio_options)
00080         {
00081                 OGGConfigAudio *window = new OGGConfigAudio(parent_window, asset);
00082                 format_window = window;
00083                 window->create_objects();
00084                 window->run_window();
00085                 delete window;
00086         }
00087         else
00088         if(video_options)
00089         {
00090                 OGGConfigVideo *window = new OGGConfigVideo(parent_window, asset);
00091                 format_window = window;
00092                 window->create_objects();
00093                 window->run_window();
00094                 delete window;
00095         }
00096 }
00097 
00098 int FileOGG::reset_parameters_derived()
00099 {
00100         tf = 0;
00101         temp_frame = 0;
00102         stream = 0;
00103         flush_lock = 0;
00104         pcm_history = 0;
00105 
00106 }
00107 
00108 int read_buffer(FILE *in, sync_window_t *sw, int buflen)
00109 {
00110         char *buffer = ogg_sync_buffer(&sw->sync, buflen);
00111 //      printf("reading range: %lli - %lli\n", sw->file_bufpos, sw->file_bufpos + buflen);
00112         sw->wlen = fread(buffer, 1, buflen, in);
00113         ogg_sync_wrote(&sw->sync, sw->wlen);
00114 //      printf("XX data: %c %c %c %c\n", sw->sync.data[0], sw->sync.data[1], sw->sync.data[2], sw->sync.data[3]);
00115         sw->file_bufpos += sw->wlen;
00116 //      printf("sb: %i\n",buffer);
00117         return (sw->wlen);
00118 }
00119 
00120 int read_buffer_at(FILE *in, sync_window_t *sw, int buflen, off_t filepos)
00121 {
00122 //      printf("seeking to %lli %lli\n", filepos, sw->file_bufpos);
00123         fseeko(in, filepos, SEEK_SET);
00124 //      if (sw->file_bufpos != filepos)
00125 //      {
00126                 sw->file_bufpos = filepos;
00127                 sw->file_pagepos = filepos; // this one is not valid until sync_pageseek!
00128                 ogg_sync_reset(&sw->sync);
00129                         
00130 //      }
00131         return read_buffer(in, sw, buflen);
00132 }
00133 
00134 int take_page_out_autoadvance(FILE *in, sync_window_t *sw, ogg_page *og)
00135 {
00136         while (1)
00137         {
00138                 int ret = ogg_sync_pageout(&sw->sync, og);
00139                 if (ret > 0)
00140                 {
00141 //              printf("fpa: %lli\n", sw->file_pagepos);
00142                         sw->file_pagepos += og->header_len + og->body_len; // advance 'virtual' position
00143 //              printf("ret2: %i %i\n",ret, og->header_len + og->body_len); 
00144                         return ret;
00145                 }
00146                 else if (ret < 0)
00147                 {
00148                         printf("FileOGG: Taking page out on nonsynced stream!\n");
00149                         return ret;
00150                         
00151                 } else
00152                 {
00153                         // need more data for page
00154                         if (read_buffer(in, sw, READ_SIZE) == 0) 
00155                         {
00156                                 printf("FileOGG: There is no more data in the file we are reading from\n");
00157                                 return 0;  // No more data
00158                         }
00159                 }
00160         }
00161         
00162 }
00163 
00164 
00165 // we never need to autoadvance when syncing, since our read chunks are larger than 
00166 // maximum page size
00167 int sync_and_take_page_out(sync_window_t *sw, ogg_page *page)
00168 {
00169         page->header_len = 0;
00170         page->body_len = 0;
00171         page->header = 0;
00172         page->body = 0;
00173         int ret = ogg_sync_pageseek(&sw->sync, page);
00174         if (ret < 0)
00175         {
00176                 sw->file_pagepos -= ret;
00177         }
00178         else if (ret > 0)
00179         {
00180                 sw->file_pagepos += ret;
00181 //              printf("ret: %i %i\n",ret, page->header_len + page->body_len); 
00182         }
00183         return ret;
00184 }
00185 
00186 
00187 int FileOGG::open_file(int rd, int wr)
00188 {
00189         this->rd = rd;
00190         this->wr = wr;
00191         if (!tf)
00192         {
00193                 tf = new theoraframes_info_t;
00194                 tf->audiosync = 0;
00195                 tf->videosync = 0;
00196         }
00197 
00198 TRACE("FileOGG::open_file 10")
00199         if(wr)
00200         {
00201 TRACE("FileOGG::open_file 20")
00202 
00203                 if((stream = fopen(asset->path, "w+b")) == 0)
00204                 {
00205                         perror(_("FileOGG::open_file rdwr"));
00206                         return 1;
00207                 }
00208 
00209                 tf->audio_bytesout = 0;
00210                 tf->video_bytesout = 0;
00211                 tf->videotime = 0;
00212                 tf->audiotime = 0;
00213 
00214                 tf->vpage_valid = 0;
00215                 tf->apage_valid = 0;
00216                 tf->apage_buffer_length = 0;
00217                 tf->vpage_buffer_length = 0;
00218                 tf->apage = NULL;
00219                 tf->vpage = NULL;
00220 
00221 
00222                 /* yayness.  Set up Ogg output stream */
00223                 srand (time (NULL));
00224 
00225                 if(asset->video_data)
00226                 {
00227                         ogg_stream_init (&tf->to, rand ());    /* oops, add one ot the above */
00228                 
00229                         theora_info_init (&tf->ti);
00230                         
00231                         tf->ti.frame_width = asset->width; 
00232                         tf->ti.frame_height = asset->height;
00233                         
00234                         tf->ti.width = ((asset->width + 15) >>4)<<4; // round up to the nearest multiple of 16 
00235                         tf->ti.height = ((asset->height + 15) >>4)<<4; // round up to the nearest multiple of 16
00236                         if (tf->ti.width != tf->ti.frame_width || tf->ti.height != tf->ti.frame_height)
00237                                 printf("FileOGG: WARNING: Encoding theora when width or height are not dividable by 16 is suboptimal\n");
00238                         
00239                         tf->ti.offset_x = 0;
00240                         tf->ti.offset_y = tf->ti.height - tf->ti.frame_height;
00241                         tf->ti.fps_numerator = (unsigned int)(asset->frame_rate * 1000000);
00242                         tf->ti.fps_denominator = 1000000;
00243                         
00244                         if (asset->aspect_ratio > 0)
00245                         {
00246                                 // Cinelerra uses frame aspect ratio, theora uses pixel aspect ratio
00247                                 float pixel_aspect = asset->aspect_ratio / asset->width * asset->height;
00248                                 tf->ti.aspect_numerator = (unsigned int)(pixel_aspect * 1000000);
00249                                 tf->ti.aspect_denominator = 1000000;
00250                         } else
00251                         {
00252                                 tf->ti.aspect_numerator = 1000000;
00253                                 tf->ti.aspect_denominator = 1000000;
00254                         }
00255                         if(EQUIV(asset->frame_rate, 25) || EQUIV(asset->frame_rate, 50))
00256                                 tf->ti.colorspace = OC_CS_ITU_REC_470BG;
00257                         else if((asset->frame_rate > 29 && asset->frame_rate < 31) || (asset->frame_rate > 59 && asset->frame_rate < 61) )
00258                                 tf->ti.colorspace = OC_CS_ITU_REC_470M;
00259                         else
00260                                 tf->ti.colorspace = OC_CS_UNSPECIFIED;
00261 
00262                         if (asset->theora_fix_bitrate)
00263                         {
00264                                 tf->ti.target_bitrate = asset->theora_bitrate; 
00265                                 tf->ti.quality = 0;
00266                         } else
00267                         {
00268                                 tf->ti.target_bitrate = 0;
00269                                 tf->ti.quality = asset->theora_quality;     // video quality 0-63
00270                         }
00271                         tf->ti.dropframes_p = 0;
00272                         tf->ti.quick_p = 1;
00273                         tf->ti.keyframe_auto_p = 1;
00274                         tf->ti.keyframe_frequency = asset->theora_keyframe_frequency;
00275                         tf->ti.keyframe_frequency_force = asset->theora_keyframe_force_frequency;
00276                         tf->ti.keyframe_data_target_bitrate = (unsigned int) (tf->ti.target_bitrate * 1.5) ;
00277                         tf->ti.keyframe_auto_threshold = 80;
00278                         tf->ti.keyframe_mindistance = 8;
00279                         tf->ti.noise_sensitivity = 1;           
00280                         tf->ti.sharpness = 2;
00281                         
00282                                         
00283                         if (theora_encode_init (&tf->td, &tf->ti))
00284                         {
00285                                 printf("FileOGG: initialization of theora codec failed\n");
00286                         }
00287                 }
00288                 /* init theora done */
00289 
00290                 /* initialize Vorbis too, if we have audio. */
00291                 if(asset->audio_data)
00292                 {
00293                         ogg_stream_init (&tf->vo, rand ());    
00294                         vorbis_info_init (&tf->vi);
00295                         /* Encoding using a VBR quality mode.  */
00296                         int ret;
00297                         if(!asset->vorbis_vbr) 
00298                         {
00299                                 ret = vorbis_encode_init(&tf->vi, 
00300                                                         asset->channels, 
00301                                                         asset->sample_rate, 
00302                                                         asset->vorbis_max_bitrate, 
00303                                                         asset->vorbis_bitrate,
00304                                                         asset->vorbis_min_bitrate); 
00305                         } else
00306                         {
00307                                 // Set true VBR as demonstrated by http://svn.xiph.org/trunk/vorbis/doc/vorbisenc/examples.html
00308                                 ret = vorbis_encode_setup_managed(&tf->vi,
00309                                         asset->channels, 
00310                                         asset->sample_rate, 
00311                                         -1, 
00312                                         asset->vorbis_bitrate, 
00313                                         -1);
00314                                 ret |= vorbis_encode_ctl(&tf->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
00315                                 ret |= vorbis_encode_setup_init(&tf->vi);
00316                         }
00317 
00318                         if (ret)
00319                         {
00320                                 fprintf (stderr,
00321                                         "The Vorbis encoder could not set up a mode according to\n"
00322                                         "the requested quality or bitrate.\n\n");
00323                                 return 1;
00324                         }
00325 
00326                         vorbis_comment_init (&tf->vc); // comment is cleared lateron 
00327                         vorbis_comment_add_tag (&tf->vc, "ENCODER", PACKAGE_STRING);
00328                         /* set up the analysis state and auxiliary encoding storage */
00329                         vorbis_analysis_init (&tf->vd, &tf->vi);
00330                         vorbis_block_init (&tf->vd, &tf->vb);
00331 
00332                 }
00333                 /* audio init done */
00334 
00335                 /* write the bitstream header packets with proper page interleave */
00336 
00337                 /* first packet will get its own page automatically */
00338                 if(asset->video_data)
00339                 {
00340                         theora_encode_header (&tf->td, &tf->op);
00341                         ogg_stream_packetin (&tf->to, &tf->op);
00342                         if (ogg_stream_pageout (&tf->to, &tf->og) != 1)
00343                         {
00344                                 fprintf (stderr, "Internal Ogg library error.\n");
00345                                 return 1;
00346                         }
00347                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
00348                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
00349 
00350                         /* create the remaining theora headers */
00351                         theora_comment_init (&tf->tc);
00352                         theora_comment_add_tag (&tf->tc, "ENCODER", PACKAGE_STRING);
00353                         theora_encode_comment (&tf->tc, &tf->op);
00354                         ogg_stream_packetin (&tf->to, &tf->op);
00355                         theora_comment_clear(&tf->tc);
00356                         theora_encode_tables (&tf->td, &tf->op);
00357                         ogg_stream_packetin (&tf->to, &tf->op);
00358                 }
00359                 if(asset->audio_data)
00360                 {
00361                         ogg_packet header;
00362                         ogg_packet header_comm;
00363                         ogg_packet header_code;
00364 
00365                         vorbis_analysis_headerout (&tf->vd, &tf->vc, &header,
00366                                        &header_comm, &header_code);
00367                         ogg_stream_packetin (&tf->vo, &header);    /* automatically placed in its own page */
00368                         vorbis_comment_clear(&tf->vc);
00369                         if (ogg_stream_pageout (&tf->vo, &tf->og) != 1)
00370                         {
00371                                 fprintf (stderr, "Internal Ogg library error.\n");
00372                                 return 1;
00373                         }
00374                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
00375                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
00376 
00377                         /* remaining vorbis header packets */
00378                         ogg_stream_packetin (&tf->vo, &header_comm);
00379                         ogg_stream_packetin (&tf->vo, &header_code);
00380                 }
00381 
00382                 /* Flush the rest of our headers. This ensures
00383                  * the actual data in each stream will start
00384                  * on a new page, as per spec. */
00385                 while (1 && asset->video_data)
00386                 {
00387                         int result = ogg_stream_flush (&tf->to, &tf->og);
00388                         if (result < 0)
00389                         {
00390                                 /* can't get here */
00391                                 fprintf (stderr, "Internal Ogg library error.\n");
00392                                 return 1;
00393                         }
00394                         if (result == 0)
00395                                 break;
00396                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
00397                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
00398                 }
00399                 while (1 && asset->audio_data)
00400                 {
00401                         int result = ogg_stream_flush (&tf->vo, &tf->og);
00402                         if (result < 0)
00403                         {
00404                                 /* can't get here */
00405                                 fprintf (stderr, "Internal Ogg library error.\n");
00406                                 return 1;
00407                         }
00408                         if (result == 0)
00409                                 break;
00410                         fwrite (tf->og.header, 1, tf->og.header_len, stream);
00411                         fwrite (tf->og.body, 1, tf->og.body_len, stream);
00412                 }
00413                 flush_lock = new Mutex("OGGFile::Flush lock");
00414 //              printf("End of headers at position: %lli\n", ftello(stream));
00415         } else
00416         if (rd)
00417         {
00418                 TRACE("FileOGG::open_file 30")
00419                 if((stream = fopen(asset->path, "rb")) == 0)
00420                 {
00421                         perror(_("FileOGG::open_file rdwr"));
00422                         return 1;
00423                 }
00424                 /* get file length */
00425                 struct stat file_stat;
00426                 stat(asset->path, &file_stat);
00427                 file_length = file_stat.st_size;
00428                 /* start up Ogg stream synchronization layer */
00429                 /* oy is used just here to parse header, we use separate syncs for video and audio*/
00430                 sync_window_t oy;
00431                 ogg_sync_init(&oy.sync);
00432                 // make sure we init the position structures to zero
00433                 read_buffer_at(stream, &oy, READ_SIZE, 0);
00434 
00435                 /* init supporting Vorbis structures needed in header parsing */
00436                 vorbis_info_init(&tf->vi);
00437                 vorbis_comment_init(&tf->vc);
00438 
00439                 /* init supporting Theora structures needed in header parsing */
00440                 theora_comment_init(&tf->tc);
00441                 theora_info_init(&tf->ti);
00442 
00443                 TRACE("FileOGG::open_file 40")
00444 
00445                 /* Ogg file open; parse the headers */
00446                 /* Only interested in Vorbis/Theora streams */
00447                 int stateflag = 0;
00448                 int theora_p = 0;
00449                 int vorbis_p = 0;
00450                 while(!stateflag)
00451                 {
00452 //                      TRACE("FileOGG::open_file 50")
00453 
00454 //                      int ret = read_buffer(stream, &oy, 4096);
00455                         TRACE("FileOGG::open_file 60")
00456 //                      if(ret == 0)
00457 //                              break;
00458                         
00459                         while(take_page_out_autoadvance(stream, &oy, &tf->og) > 0)
00460                         {
00461                                 ogg_stream_state test;
00462 
00463                                 /* is this a mandated initial header? If not, stop parsing */
00464                                 if(!ogg_page_bos(&tf->og))
00465                                 {
00466                                         /* don't leak the page; get it into the appropriate stream */
00467                                 //      queue_page(&tf->og);
00468                                         if(theora_p)ogg_stream_pagein(&tf->to, &tf->og);
00469                                         if(vorbis_p)ogg_stream_pagein(&tf->vo, &tf->og);
00470                                 
00471                                         stateflag = 1;
00472                                         break;
00473                                 }
00474 
00475                                 ogg_stream_init(&test, ogg_page_serialno(&tf->og));
00476                                 ogg_stream_pagein(&test, &tf->og);
00477                                 ogg_stream_packetout(&test, &tf->op);
00478 
00479                                 /* identify the codec: try theora */
00480                                 if(!theora_p && theora_decode_header(&tf->ti, &tf->tc, &tf->op)>=0)
00481                                 {
00482                                         /* it is theora */
00483                                         memcpy(&tf->to, &test, sizeof(test));
00484                                         theora_p = 1;
00485         // find out granule shift - from liboggz's oggz_auto.c
00486                                         unsigned char * header = tf->op.packet;
00487                                         theora_keyframe_granule_shift = (char) ((header[40] & 0x03) << 3);
00488                                         theora_keyframe_granule_shift |= (header[41] & 0xe0) >> 5;
00489 
00490                                 } else if(!vorbis_p && vorbis_synthesis_headerin(&tf->vi, &tf->vc, &tf->op)>=0)
00491                                 {
00492                                         /* it is vorbis */
00493                                         memcpy(&tf->vo, &test, sizeof(test));
00494                                         vorbis_p = 1;
00495                                 } else 
00496                                 {
00497                                         /* whatever it is, we don't care about it */
00498                                         ogg_stream_clear(&test);
00499                                 }
00500                         }
00501                 /* fall through to non-bos page parsing */
00502                 }
00503 
00504                 /* we're expecting more header packets. */
00505                 while((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3))
00506                 {
00507                         int ret;
00508 
00509                         /* look for further theora headers */
00510                         while(theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&tf->to, &tf->op)))
00511                         {
00512                                 if(ret < 0)
00513                                 {
00514                                         fprintf(stderr,"FileOGG: Error parsing Theora stream headers; corrupt stream?\n");
00515                                         return 1;
00516                                 }
00517                                 if(theora_decode_header(&tf->ti, &tf->tc, &tf->op))
00518                                 {
00519                                         printf("FileOGG: Error parsing Theora stream headers; corrupt stream?\n");
00520                                         return 1;
00521                                 }
00522                                 theora_p++;
00523                                 if(theora_p == 3) 
00524                                         break;
00525                         }
00526 
00527                         /* look for more vorbis header packets */
00528                         while(vorbis_p && (vorbis_p < 3) && (ret = ogg_stream_packetout(&tf->vo, &tf->op)))
00529                         {
00530                                 if(ret<0)
00531                                 {
00532                                         fprintf(stderr,"FileOGG: Error parsing Vorbis stream headers; corrupt stream?\n");
00533                                         return 1;
00534                                 }
00535                                 if (vorbis_synthesis_headerin(&tf->vi, &tf->vc, &tf->op))
00536                                 {
00537                                         fprintf(stderr,"FileOGG: Error parsing Vorbis stream headers; corrupt stream?\n");
00538                                         return 1;
00539                                 }
00540                                 vorbis_p++;
00541                                 if (vorbis_p == 3)
00542                                         break;
00543                         }
00544 
00545                         if (vorbis_p == 3 && theora_p == 3) 
00546                                 break;
00547                         /* The header pages/packets will arrive before anything else we
00548                             care about, or the stream is not obeying spec */
00549 
00550                         if(take_page_out_autoadvance(stream, &oy, &tf->og) > 0)
00551                         {
00552 //                              queue_page(&tf->og); /* demux into the appropriate stream */
00553                                 if(theora_p) ogg_stream_pagein(&tf->to, &tf->og);
00554                                 if(vorbis_p) ogg_stream_pagein(&tf->vo, &tf->og);
00555 
00556                         } else
00557                         {
00558                                 fprintf(stderr,"FileOGG: End of file while searching for codec headers.\n");
00559                                 return 1;
00560                         }
00561                 }
00562                 // Remember where the real data begins for later seeking purposes
00563                 filedata_begin = oy.file_pagepos; 
00564 
00565 //printf("FileOGG::Data pages begin at %lli\n", filedata_begin);
00566 
00567                 /* and now we have it all.  initialize decoders */
00568                 if(theora_p)
00569                 {
00570                         int ret;
00571 
00572 // WORKAROUND for bug in alpha4 version of theora:
00573                         tf->td.internal_encode = 0;
00574 
00575                         ret = theora_decode_init(&tf->td, &tf->ti);
00576                         double fps = (double)tf->ti.fps_numerator/tf->ti.fps_denominator;
00577 /*                      printf("FileOGG: Ogg logical stream %x is Theora %dx%d %.02f fps\n",
00578                                 (unsigned int)tf->to.serialno, tf->ti.width, tf->ti.height, 
00579                                 fps);
00580 */
00581 /*
00582 Not yet available in alpha4, we assume 420 for now
00583 
00584                         switch(tf->ti.pixelformat)
00585                         {
00586                                 case OC_PF_420: printf(" 4:2:0 video\n"); break;
00587                                 case OC_PF_422: printf(" 4:2:2 video\n"); break;
00588                                 case OC_PF_444: printf(" 4:4:4 video\n"); break;
00589                                 case OC_PF_RSVD:
00590                                 default:
00591                                         printf(" video\n  (UNKNOWN Chroma sampling!)\n");
00592                                 break;
00593                         }
00594 */
00595 
00596                         theora_cmodel = BC_YUV420P;
00597                         
00598                         if(tf->ti.width!=tf->ti.frame_width || tf->ti.height!=tf->ti.frame_height)
00599                                 printf("FileOGG::  Frame content is %dx%d with offset (%d,%d), We do not support this yet.\n",
00600                                 tf->ti.frame_width, tf->ti.frame_height, tf->ti.offset_x, tf->ti.offset_y);
00601 
00602                         tf->videosync = new sync_window_t;
00603                         ogg_sync_init(&tf->videosync->sync);
00604                         tf->videosync->wlen = 0;
00605 
00606                         ret = ogg_get_first_page(tf->videosync, tf->to.serialno, &tf->videopage);
00607                         ogg_packet op;
00608 
00609                         // we have headers already decoded, so just skip them
00610                         ogg_stream_reset(&tf->to);
00611                         ogg_stream_pagein(&tf->to, &tf->videopage);
00612                         while (1)
00613                         {
00614                                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
00615                                 {
00616                                         if (!ogg_get_next_page(tf->videosync, tf->to.serialno, &tf->videopage))
00617                                         {
00618                                                 printf("FileOGG: Cannot find next page while looking for first non-header packet\n");
00619                                                 return 1;
00620                                         }
00621                                         ogg_stream_pagein(&tf->to, &tf->videopage);
00622                                 }
00623                                 ogg_stream_packetout(&tf->to, &op);
00624                                 if (!theora_packet_isheader(&op))
00625                                         break;
00626                         }
00627                         // now get to the page of the finish of the first packet
00628                         while (ogg_page_packets(&tf->videopage) == 0) 
00629                         {
00630                                 if (ogg_page_granulepos(&tf->videopage) != -1)
00631                                 {
00632                                         printf("FileOGG: Broken ogg file - broken page: ogg_page_packets == 0 and granulepos != -1\n");
00633                                         return 1;
00634                                 }
00635                                 ogg_get_next_page(tf->videosync, tf->to.serialno, &tf->videopage);
00636                         }
00637                         // FIXME - LOW PRIORITY - start counting at first decodable keyframe!
00638                         // but then we have to fix a/v sync somehow
00639                         start_frame = (int64_t) (theora_granule_frame (&tf->td, ogg_page_granulepos(&tf->videopage)) - ogg_page_packets(&tf->videopage)) + 1;
00640 
00641                         ret = ogg_get_last_page(tf->videosync, tf->to.serialno, &tf->videopage);
00642                         last_frame = (int64_t) (theora_granule_frame (&tf->td, ogg_page_granulepos(&tf->videopage)));
00643                         asset->video_length = last_frame - start_frame + 1;
00644 //                      printf("FileOGG:: first frame: %lli, last frame: %lli, video length: %lli\n", start_frame, last_frame, asset->video_length);
00645                         
00646                         asset->layers = 1;
00647                         // FIXME - LOW PRIORITY Cinelerra does not honor the frame_width and frame_height
00648                         asset->width = tf->ti.width;
00649                         asset->height = tf->ti.height;
00650 // Don't want a user configured frame rate to get destroyed
00651                         if(!asset->frame_rate)
00652                                 asset->frame_rate = fps;
00653 // All theora material is noninterlaced by definition
00654                         if(!asset->interlace_mode)
00655                                 asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
00656 
00657         /*              ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 0 +start_frame);
00658                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 1 +start_frame);
00659                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 5 +start_frame);
00660                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 206 +start_frame);
00661                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 207 +start_frame);
00662                         ogg_get_page_of_frame(tf->videosync, tf->to.serialno, &og, 208 +start_frame);
00663 
00664                         int64_t kf;
00665                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 0 + start_frame, &kf);
00666                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 1 + start_frame, &kf);
00667                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 5 + start_frame, &kf);
00668                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 66 + start_frame, &kf);
00669                         //printf("Keyframe: %lli\n", kf);
00670                         ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, 1274 + start_frame, &kf);
00671 */
00672         
00673                         set_video_position(0); // make sure seeking is done to the first sample
00674                         ogg_frame_position = -10;
00675                         asset->video_data = 1;
00676                         strncpy(asset->vcodec, "theo", 4);
00677 
00678 
00679 //                  report_colorspace(&ti);
00680 //                  dump_comments(&tc);
00681                 } else 
00682                 {
00683                         /* tear down the partial theora setup */
00684                         theora_info_clear(&tf->ti);
00685                         theora_comment_clear(&tf->tc);
00686                 }
00687                 if(vorbis_p)
00688                 {
00689                         vorbis_synthesis_init(&tf->vd, &tf->vi);
00690                         vorbis_block_init(&tf->vd, &tf->vb);
00691 /*                      fprintf(stderr,"FileOGG: Ogg logical stream %x is Vorbis %d channel %d Hz audio.\n",
00692                                 (unsigned int)tf->vo.serialno, tf->vi.channels, (int)tf->vi.rate);
00693 */                      
00694                         /* init audio_sync structure */
00695                         tf->audiosync = new sync_window_t;
00696                         ogg_sync_init(&tf->audiosync->sync);
00697                         tf->audiosync->wlen = 0;
00698 
00699                         int ret2 = ogg_get_first_page(tf->audiosync, tf->vo.serialno, &tf->audiopage);
00700                         int result;
00701                         ogg_packet op;
00702                         ogg_stream_reset(&tf->vo);
00703                         // FIXME - LOW PRIORITY should be getting pages until one has granulepos, probably never happens in pracitce
00704                         ogg_stream_pagein(&tf->vo, &tf->audiopage);
00705                         ogg_int64_t accumulated = 0;
00706                         long        lastblock = -1;
00707                         while((result = ogg_stream_packetout(&tf->vo, &op)))
00708                         {
00709                                 if(result > 0)
00710                                 { // ignore holes 
00711                                         long thisblock =  vorbis_packet_blocksize(&tf->vi, &op);
00712                                         if(lastblock != -1)
00713                                                 accumulated += (lastblock + thisblock) >> 2;
00714                                         lastblock = thisblock;
00715                                 }
00716                         }
00717                         start_sample = ogg_page_granulepos(&tf->audiopage) - accumulated;
00718 /*
00719                         printf("Begin: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
00720                                         tf->audiosync->file_pagepos_found,
00721                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
00722                                         ogg_page_granulepos(&tf->audiopage), 
00723                                         ogg_page_serialno(&tf->audiopage));
00724                         while (ogg_get_next_page(tf->audiosync, tf->vo.serialno, &tf->audiopage))
00725                                 printf("At byte: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
00726                                         tf->audiosync->file_pagepos_found,
00727                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
00728                                         ogg_page_granulepos(&tf->audiopage), 
00729                                         ogg_page_serialno(&tf->audiopage));
00730 */
00731 
00732                         int ret = ogg_get_last_page(tf->audiosync, tf->vo.serialno, &tf->audiopage);
00733                         last_sample = ogg_page_granulepos(&tf->audiopage);
00734                         asset->audio_length = last_sample - start_sample;
00735                                                 
00736 /*                      printf("FileOGG:: First sample: %lli, last_sample: %lli\n", start_sample, last_sample);
00737                         printf("FileOGG:: audio length: samples: %lli, playing time: %f\n", asset->audio_length, 1.0 * asset->audio_length / tf->vi.rate);
00738 */                      
00739 /*                      printf("End: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
00740                                         tf->audiosync->file_pagepos_found,
00741                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
00742                                         ogg_page_granulepos(&tf->audiopage), 
00743                                         ogg_page_serialno(&tf->audiopage));
00744                         while (ogg_get_prev_page(tf->audiosync, tf->vo.serialno, &tf->audiopage))
00745                                 printf("At byte: %lli, To byte: %lli,  granule: %lli, serialno: %x\n", 
00746                                         tf->audiosync->file_pagepos_found,
00747                                         tf->audiosync->file_pagepos_found + tf->audiopage.body_len + tf->audiopage.header_len,
00748                                         ogg_page_granulepos(&tf->audiopage), 
00749                                         ogg_page_serialno(&tf->audiopage));
00750 */
00751                         
00752 /*                      ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 0);
00753                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 1);
00754                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 50);
00755                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 5000);
00756                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 30000);
00757                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 50000);
00758                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 90000);
00759                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 95999);
00760                         ogg_get_page_of_sample(tf->audiosync, tf->vo.serialno, &tf->audiopage, 96000);
00761                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 0);
00762                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 1);
00763                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 5000);
00764                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 30000);
00765                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 50000);
00766                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 90000);
00767                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 95999);
00768                         ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, 96000);
00769 */                      
00770                         asset->channels = tf->vi.channels;
00771                         if(!asset->sample_rate)
00772                                 asset->sample_rate = tf->vi.rate;
00773                         asset->audio_data = 1;
00774                         
00775 
00776                         ogg_sample_position = -10;
00777                         set_audio_position(0); // make sure seeking is done to the first sample
00778                         strncpy(asset->acodec, "vorb", 4);
00779 
00780 
00781                 } else 
00782                 {
00783                         /* tear down the partial vorbis setup */
00784                         vorbis_info_clear(&tf->vi);
00785                         vorbis_comment_clear(&tf->vc);
00786                 }
00787                 ogg_sync_clear(&oy.sync);
00788         }
00789         return 0;
00790 }
00791 
00792 int FileOGG::ogg_get_prev_page(sync_window_t *sw, long serialno, ogg_page *og)
00793 {
00794         char *buffer;
00795         ogg_page page;
00796         off_t filepos = sw->file_pagepos_found - READ_SIZE;
00797         int first_page_offset = 0;
00798         int done = 0;   
00799         int read_len = READ_SIZE;
00800 
00801 //      printf("fp: %lli pagepos found: %lli\n", filepos, sw->file_pagepos_found);
00802         while (!done)
00803         {
00804                 if (filepos < 0)
00805                 {
00806 //                      read_len = read_len - (filedata_begin - filepos);
00807                         read_len = read_len + filepos;
00808                         filepos = 0;
00809                 }
00810                 if (read_len <= 0) 
00811                         return 0;
00812                 int have_read = read_buffer_at(stream, sw, read_len, filepos);
00813                 
00814 //              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);
00815 //              printf("Buffer position: %lli\n", sw->file_bufpos);
00816 //              printf("SS: storage: %i, fill: %i, returned: %i\n", sw->sync.storage, sw->sync.fill, sw->sync.returned);
00817 //              printf("US: unsynced%i, headrebytes: %i, bodybyes: %i\n", sw->sync.unsynced, sw->sync.headerbytes, sw->sync.bodybytes);
00818 //              printf("data: %c %c %c %c\n", sw->sync.data[0], sw->sync.data[1], sw->sync.data[2], sw->sync.data[3]);
00819                 if (!have_read) 
00820                         return 0;
00821                 
00822 // read all pages in the buffer
00823                 int page_offset = 0;
00824                 int page_length = 0;
00825                 int first_page = 1;
00826                 while (first_page || page_length) 
00827                 {
00828                         // if negative, skip bytes
00829                         while ((page_length = sync_and_take_page_out(sw, &page)) < 0)
00830                         {
00831                                 page_offset -= page_length;
00832                                                 
00833 //                              if (filepos == 0)
00834 //                                      printf("BBBb page_len: %i\n", page_length);
00835                         }
00836 //                      if (filepos == 0 && page_length)
00837 //                      {
00838 //                              printf("AAAAAAAAAAAAAAAAAAAAAAAAAaaa\n");
00839 //                              printf("pp: %lli %x\n", sw->file_pagepos, ogg_page_serialno(&page));
00840 //                      }
00841                         if (first_page)
00842                                 first_page_offset = page_offset;
00843                         first_page = 0;
00844 //                      printf("pl: %i, serial: %x iscem: %x\n", page_length, ogg_page_serialno(&page), serialno);
00845                         if (page_length && ogg_page_serialno(&page) == serialno)
00846                         {
00847                                 // we will copy every page until last page in this buffer
00848                                 done = 1;
00849                                 
00850                                 sw->file_pagepos_found = sw->file_pagepos - page.header_len - page.body_len;
00851 //                              printf("got it : %lli %i %i\n", sw->file_pagepos, page.header_len, page.body_len);
00852                                 memcpy(og, &page, sizeof(page));
00853                         }
00854                 }
00855                 off_t old_filepos = filepos;
00856 //              printf("fpo: %i\n", first_page_offset);
00857                 filepos = filepos + first_page_offset - READ_SIZE;
00858         }
00859         
00860 //      printf("finished\n");
00861         if (done) 
00862                 return 1;
00863         else 
00864                 return 0;
00865 }
00866 
00867 int FileOGG::ogg_get_last_page(sync_window_t *sw, long serialno, ogg_page *og)
00868 {
00869         char *buffer;
00870         ogg_page page;
00871         off_t filepos = file_length - READ_SIZE;
00872         if (filepos < 0) 
00873                 filepos = 0;
00874 
00875         int first_page_offset = 0;
00876         int done = 0;   
00877         while (!done && filepos >= 0)
00878         {
00879                 int readlen;
00880                 readlen = read_buffer_at(stream, sw, READ_SIZE, filepos);
00881 
00882 // read all pages in the buffer
00883                 int page_offset = 0;
00884                 int page_length = 0;
00885                 int first_page = 1;
00886                 while (first_page || page_length) 
00887                 {
00888                         // if negative, skip bytes
00889                         while ((page_length = sync_and_take_page_out(sw, &page)) < 0)
00890                                         page_offset -= page_length;
00891                         if (first_page)
00892                                 first_page_offset = page_offset;
00893                         first_page = 0;
00894                         if (page_length && ogg_page_serialno(&page) == serialno)
00895                         {
00896                                 // we will copy every page until last page in this buffer
00897                                 done = 1;
00898                                 sw->file_pagepos_found = sw->file_pagepos - page.header_len - page.body_len;
00899                                 memcpy(og, &page, sizeof(page));
00900                         }
00901                 }
00902                 filepos = filepos + first_page_offset - READ_SIZE;              
00903         }
00904         
00905         if (done) 
00906                 return 1;
00907         else 
00908                 return 0;
00909 }
00910 
00911 int FileOGG::ogg_get_first_page(sync_window_t *sw, long serialno, ogg_page *og)
00912 {
00913 //      printf("FileOGG:: Seeking to first page at %lli\n", filedata_begin);
00914         read_buffer_at(stream, sw, READ_SIZE, 0);
00915 // we don't even need to sync since we _know_ it is right
00916         return (ogg_get_next_page(sw, serialno, og));
00917 }
00918 
00919 int FileOGG::ogg_get_next_page(sync_window_t *sw, long serialno, ogg_page *og)
00920 {
00921         while (take_page_out_autoadvance(stream, sw, og) > 0)
00922         { 
00923                 if (ogg_page_serialno(og) == serialno)
00924                 {
00925                         sw->file_pagepos_found = sw->file_pagepos - og->header_len - og->body_len;
00926                         return 1;
00927                 }
00928         }
00929         return 0;
00930 }
00931 
00932 int FileOGG::ogg_sync_and_get_next_page(sync_window_t *sw, long serialno, ogg_page *og)
00933 {
00934 // TODO: Put better error reporting inhere
00935         int ret;
00936         while ((ret = sync_and_take_page_out(sw, og)) < 0)
00937         {
00938                 // do nothing;
00939         }
00940         if (ret == 0) 
00941                 return 0;
00942         if (ogg_page_serialno(og) == serialno)
00943         {
00944                 sw->file_pagepos_found = sw->file_pagepos - og->header_len - og->body_len;
00945                 return 1;
00946         }
00947         while (ogg_get_next_page(sw, serialno, og))
00948                 if (ogg_page_serialno(og) == serialno)
00949                 {
00950                         sw->file_pagepos_found = sw->file_pagepos - og->header_len - og->body_len;
00951                         return 1;
00952                 }
00953         
00954         return 0;
00955 }
00956 // Returns:
00957 // >= 0, number of sample within a page
00958 // <  0 error
00959 int FileOGG::ogg_get_page_of_sample(sync_window_t *sw, long serialno, ogg_page *og, int64_t sample)
00960 {
00961 // First make an educated guess about position
</