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
00962         if (sample >= asset->audio_length + start_sample)
00963         {
00964                 printf("FileOGG: Illegal seek beyond end of samples\n");
00965                 return 0;
00966         }
00967         off_t educated_guess = filedata_begin + (file_length - filedata_begin) * (sample - start_sample) / asset->audio_length - READ_SIZE;
00968         if (educated_guess < 0) 
00969                 educated_guess = 0;
00970 //      printf("My educated guess: %lli\n", educated_guess); 
00971 // now see if we won
00972         read_buffer_at(stream, sw, READ_SIZE, educated_guess);
00973         ogg_sync_and_get_next_page(sw, serialno, og);
00974         int64_t end_sample = ogg_page_granulepos(og);
00975         // linear seek to the sample
00976         int64_t start_sample = 0;
00977 // TODO: Use bisection also
00978 //      printf("Next page granulepos: %lli, pagepos: %lli\n", end_sample, sw->file_pagepos_found);
00979         if (end_sample <= sample)
00980         {
00981         // scan forward
00982                 while (end_sample <= sample)
00983                 {
00984                         ogg_get_next_page(sw, serialno, og); 
00985                         start_sample = end_sample;
00986                         end_sample = ogg_page_granulepos(og);
00987                 }
00988                 ogg_get_prev_page(sw, serialno, og);
00989         } else
00990         {
00991         // scan backward
00992                 start_sample = end_sample;
00993                 while (start_sample > sample)
00994                 {
00995 //                      printf("get prev page: %lli pagepos:%lli\n", ogg_page_granulepos(og), sw->file_pagepos_found);
00996                         ogg_get_prev_page(sw, serialno, og);
00997                         end_sample = start_sample;
00998                         start_sample = ogg_page_granulepos(og);
00999                 }
01000         // go forward one page at the end
01001 
01002         }
01003         
01004 //      printf("For sample %lli we need to start decoding on page with granulepos: %lli\n", sample, ogg_page_granulepos(og));
01005         return 1;
01006 }
01007 
01008 // seeks, so next sample returned will be the correct one
01009 // sample here is still the vorbis sample number (= cinelerra sample number + start_sample)
01010 // reinits the decoding engine
01011 
01012 int FileOGG::ogg_seek_to_sample(sync_window_t *sw, long serialno, int64_t sample)
01013 {
01014         // MAYBE FIXME - find out if we really are decoding previous two packets or not
01015         // get to the sample
01016         ogg_page og;
01017         ogg_packet op;
01018 //      printf("Calling get page of sample\n");
01019         if (!ogg_get_page_of_sample(sw, serialno, &og, sample))
01020         {
01021                 printf("FileOGG: Seeking to sample's page failed\n");
01022                 return 0;
01023         }
01024 //      printf("Pagepos: %lli\n", sw->file_pagepos);
01025         vorbis_synthesis_restart(&tf->vd);
01026         ogg_stream_reset(&tf->vo);
01027         ogg_stream_pagein(&tf->vo, &og);
01028         int sync = 0;
01029 //      printf("seeking to sample : %lli , starting at page with gpos: %lli\n", sample, ogg_page_granulepos(&og));
01030         
01031         int64_t current_comming_sample = -1;
01032         while (1) 
01033         {
01034         
01035                 // make sure we have a packet ready
01036                 while (ogg_stream_packetpeek(&tf->vo, NULL) != 1)
01037                 {
01038                         if (!ogg_get_next_page(sw, serialno, &og))
01039                         {
01040                                 printf("FileOGG: Cannot find next page while seeking\n");
01041                                 return 0;
01042                         }
01043                         ogg_stream_pagein(&tf->vo, &og);
01044                 }
01045                 ogg_stream_packetout(&tf->vo, &op);
01046                 if (sync)
01047                 {
01048                         
01049                         if(!vorbis_synthesis(&tf->vb, &op))
01050                         {
01051                                 int ret= vorbis_synthesis_blockin(&tf->vd, &tf->vb);
01052                                 int64_t previous_comming_sample = current_comming_sample;
01053                                 current_comming_sample += vorbis_synthesis_pcmout(&tf->vd, NULL);
01054                                 if (current_comming_sample > sample)
01055                                 {
01056                                         vorbis_synthesis_read(&tf->vd, (sample - previous_comming_sample));
01057 //                                      printf("WE GOT IT, samples already decoded: %li\n", vorbis_synthesis_pcmout(&tf->vd,NULL));
01058                                         return 1; // YAY next sample read is going to be ours, sexy!
01059                                 } else
01060                                 {
01061                                         // discard decoded data before current sample
01062                                         vorbis_synthesis_read(&tf->vd, (current_comming_sample - previous_comming_sample));
01063                                         
01064                                 }
01065                         }
01066                 }
01067                 if (!sync && op.granulepos >= 0)
01068                 {
01069                         sync = 1;
01070                         current_comming_sample = op.granulepos;
01071                         if(!vorbis_synthesis(&tf->vb, &op))
01072                         {
01073                                 vorbis_synthesis_blockin(&tf->vd, &tf->vb);
01074                                 if (vorbis_synthesis_pcmout(&tf->vd, NULL) != 0)
01075                                 {
01076                                         printf("FileOGG: Something wrong while trying to seek\n");
01077                                         return 0;
01078                                 }
01079                         
01080                         }
01081                         
01082                 }
01083         }
01084         
01085         
01086         return 0;
01087 }
01088 
01089 int FileOGG::ogg_get_page_of_frame(sync_window_t *sw, long serialno, ogg_page *og, int64_t frame)
01090 {
01091         if (frame >= asset->video_length + start_frame)
01092         {
01093                 printf("FileOGG: Illegal seek beyond end of frames\n");
01094                 return 0;
01095         }
01096 //      printf("frame: %lli start frame: %lli\n", frame, start_frame);
01097 //      printf("file_length: %lli filedata_begin: %lli\n", file_length, filedata_begin);
01098         off_t educated_guess = filedata_begin + (file_length - filedata_begin) * (frame - start_frame) / asset->video_length - READ_SIZE/2;
01099 //      educated_guess += 100000;
01100         if (educated_guess > file_length - READ_SIZE)
01101                 educated_guess = file_length - READ_SIZE;
01102         if (educated_guess < filedata_begin) 
01103                 educated_guess = filedata_begin;
01104 //      printf("My educated guess: %lli\n", educated_guess); 
01105 // now see if we won
01106         read_buffer_at(stream, sw, READ_SIZE, educated_guess);
01107         ogg_sync_and_get_next_page(sw, serialno, og);
01108         int64_t pageend_frame;
01109         int read_back = 0;
01110         // find the page with "real" ending
01111         while ((pageend_frame = ogg_page_granulepos(og)) == -1)
01112         {
01113                 if (ogg_get_next_page(sw, serialno, og) == 0) 
01114                 {
01115                         read_back = 1;
01116                         break;
01117                 } 
01118         }
01119         pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
01120 
01121         // FIXME - MEDIUM PRIORITY: read back if we've gone too far and no page of our serialno at all can be found
01122 
01123         
01124         // linear seek to the sample
01125         int64_t start_frame = 0;
01126 // TODO: Use bisection also
01127 //      printf("Next page granulepos: %lli, pagepos: %lli\n", end_sample, sw->file_pagepos_found);
01128         int discard_packets = 0;
01129         int missp = 0;
01130         int missm = 0;
01131         if (pageend_frame <= frame)
01132         {
01133         // scan forward
01134                 while (pageend_frame < frame)
01135                 {
01136                         do {
01137                                 ogg_get_next_page(sw, serialno, og); 
01138                         } while (ogg_page_packets(og) == 0);
01139                         pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
01140                         missp++;
01141                 }
01142                 // go back if this frame starts on previous page
01143                 if (ogg_page_continued(og) && pageend_frame - ogg_page_packets(og) == frame - 1)
01144                 {
01145                         do {
01146                                 ogg_get_prev_page(sw, serialno, og); 
01147                         } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));          
01148                 }
01149                 pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
01150         } else
01151         {
01152         // scan backward
01153                 int64_t first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(og)) - ogg_page_packets(og) + 2;
01154                 if (!ogg_page_continued(og))
01155                         first_frame_on_page--;
01156                 while (first_frame_on_page > frame)
01157                 {
01158 //                      printf("get prev page: %lli pagepos:%lli\n", ogg_page_granulepos(og), sw->file_pagepos_found);
01159                         do {
01160                                 ogg_get_prev_page(sw, serialno, og); 
01161                         } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));          
01162                         missm++;
01163 //                      pageend_frame = theora_granule_frame(&tf->td, ogg_page_granulepos(og));
01164                         first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(og)) - ogg_page_packets(og) + 2;
01165                         if (!ogg_page_continued(og))
01166                                 first_frame_on_page--;
01167                 }
01168         }
01169 //      printf("Miss plus: %i, miss minus: %i\n", missp, missm);
01170 //      printf("last frame of page with frame : %lli\n", pageend_frame);
01171         return 1;                       
01172 }
01173 
01174 
01175 int FileOGG::ogg_seek_to_keyframe(sync_window_t *sw, long serialno, int64_t frame, int64_t *keyframe_number)
01176 {
01177         ogg_page og;
01178         ogg_packet op;
01179 //      printf("Searching for the proper position to start decoding frame %lli\n", frame);
01180         if (!ogg_get_page_of_frame(sw, serialno, &og, frame))
01181         {
01182                 printf("FileOGG: Seeking to frame failed\n");
01183                 return 0;
01184         }
01185         // TODO: if the frame we are looking for continoues on the next page, we don't need to do this
01186         // Now go to previous page in order to find out the granulepos
01187         // Don't do it in case this is the first page.
01188 //      printf("GP: %lli\n", ogg_page_granulepos(&og));
01189         int64_t granulepos, iframe, pframe;
01190         granulepos = ogg_page_granulepos(&og);
01191         iframe = granulepos >> theora_keyframe_granule_shift;
01192         pframe = granulepos - (iframe << theora_keyframe_granule_shift);
01193         // check if maybe iframe is known from this page already
01194         if (granulepos != -1 && iframe <= frame)
01195         {
01196                 // optimisation, iframe is already known from this page
01197         } else
01198         {
01199                 // get previous page so we will get the iframe number 
01200                 do {
01201                         ogg_get_prev_page(sw, serialno, &og); 
01202                 } while (ogg_page_packets(&og) == 0);           
01203 
01204                 granulepos = ogg_page_granulepos(&og);
01205                 iframe = granulepos >> theora_keyframe_granule_shift;
01206                 pframe = granulepos - (iframe << theora_keyframe_granule_shift);
01207         }
01208         int64_t first_frame_on_page = theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) - ogg_page_packets(&og) + 2;
01209         if (!ogg_page_continued(&og))
01210                 first_frame_on_page--;
01211         if (first_frame_on_page <= iframe)
01212         {
01213                 // optimisation, happens mainly in low-bitrate streams, it spares us one seek
01214         } else
01215         {
01216                 // get the page where keyframe starts
01217                 if (!ogg_get_page_of_frame(sw, serialno, &og, iframe))
01218                 {
01219                         printf("FileOGG: Seeking to keyframe failed\n");
01220                         return 0;
01221                 }
01222         }               
01223 //      printf("looking for frame: %lli, last frame of the page: %lli, last keyframe: %lli\n", frame, pframe+iframe, iframe);
01224         ogg_stream_reset(&tf->to);
01225         ogg_stream_pagein(&tf->to, &og);
01226         // Read until one frame before keyframe
01227 //      printf("c: %i\n", ogg_page_continued(&og));
01228         int numread = iframe - (theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) - ogg_page_packets(&og)) - 1;
01229         if (ogg_page_continued(&og))
01230                 numread--;
01231 //      printf("numread: %i\n", numread);
01232 //      printf("FileOGG:: Proper position: %lli\n", theora_granule_frame(&tf->td, ogg_page_granulepos(&og)) + numread - ogg_page_packets(&og));
01233         while (numread > 0)
01234         {
01235                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
01236                 {
01237                         if (!ogg_get_next_page(sw, serialno, &og))
01238                         {
01239                                 printf("FileOGG: Cannot find next page while seeking\n");
01240                                 return 0;
01241                         }
01242                         ogg_stream_pagein(&tf->to, &og);
01243                 }
01244                 ogg_stream_packetout(&tf->to, &op);
01245                 numread --;
01246         }
01247         *keyframe_number = iframe;
01248         return 1;
01249 }
01250 
01251 
01252 int FileOGG::check_sig(Asset *asset)
01253 {
01254         FILE *fd = fopen(asset->path, "rb");
01255 // Test for "OggS"
01256         fseek(fd, 0, SEEK_SET);
01257         char data[4];
01258         fread(data, 4, 1, fd);
01259         if(data[0] == 'O' &&
01260                 data[1] == 'g' &&
01261                 data[2] == 'g' &&
01262                 data[3] == 'S')
01263         {
01264                 fclose(fd);
01265                 printf("Yay, we have an ogg file\n");
01266                 return 1;
01267         }
01268         fclose(fd);
01269         return 0;
01270         
01271 }
01272 
01273 int FileOGG::close_file()
01274 {
01275 
01276         if (wr)
01277         {
01278                 if (asset->audio_data)
01279                         write_samples_vorbis(0, 0, 1); // set eos
01280                 if (asset->video_data)
01281                         write_frames_theora(0, 1, 1); // set eos
01282 
01283                 flush_ogg(1); // flush all
01284         
01285                 if (asset->audio_data)
01286                 {
01287                         vorbis_block_clear (&tf->vb);
01288                         vorbis_dsp_clear (&tf->vd);
01289                         vorbis_info_clear (&tf->vi);
01290                         ogg_stream_clear (&tf->vo);
01291                 }
01292                 if (asset->video_data)
01293                 {
01294                         theora_info_clear (&tf->ti);
01295                         ogg_stream_clear (&tf->to);
01296                         theora_clear (&tf->td);
01297                 }
01298                 
01299                 if (stream) fclose(stream);
01300                 stream = 0;
01301         } else if (rd) 
01302         {       
01303                 if (asset->audio_data)
01304                 {
01305                         vorbis_block_clear (&tf->vb);
01306                         vorbis_dsp_clear (&tf->vd);
01307                         vorbis_comment_clear (&tf->vc);
01308                         vorbis_info_clear (&tf->vi);
01309                         ogg_stream_clear (&tf->vo);
01310                 }
01311                 theora_comment_clear(&tf->tc);
01312                 if (asset->video_data)
01313                 {
01314                         theora_info_clear (&tf->ti);
01315                         theora_comment_clear (&tf->tc);
01316                         theora_clear (&tf->td);
01317                         ogg_stream_clear (&tf->to);
01318                 }
01319                 
01320                         
01321                 if (stream) fclose(stream);
01322                 stream = 0;
01323 
01324         }
01325 }
01326 
01327 int FileOGG::close_file_derived()
01328 {
01329 //printf("FileOGG::close_file_derived(): 1\n");
01330         if (stream) fclose(stream);
01331         stream = 0;
01332 }
01333 
01334 int64_t FileOGG::get_video_position()
01335 {
01336 //      printf("GVP\n");
01337         return next_frame_position - start_frame;
01338 }
01339 
01340 int64_t FileOGG::get_audio_position()
01341 {
01342         return next_sample_position - start_sample;
01343 }
01344 
01345 int FileOGG::set_video_position(int64_t x)
01346 {
01347 //      x=0;
01348 //      printf("SVP: %lli\n", x);
01349         
01350         next_frame_position = x + start_frame;
01351         return 1;
01352 }
01353 
01354 
01355 int FileOGG::colormodel_supported(int colormodel)
01356 {
01357 //      printf("CMS\n");
01358 
01359         if (colormodel == BC_YUV420P)
01360                 return BC_YUV420P;
01361         else
01362                 return colormodel;
01363 }
01364 int FileOGG::get_best_colormodel(Asset *asset, int driver)
01365 {
01366 
01367         return BC_YUV420P;
01368 }
01369 
01370 
01371 int FileOGG::read_frame(VFrame *frame)
01372 {
01373 
01374         if(!stream) return 1;
01375 
01376         
01377         // skip is cheaper than seek, do it...
01378         int decode_frames = 0;
01379         int expect_keyframe = 0;
01380         if (ogg_frame_position >= 0 && 
01381             next_frame_position >= ogg_frame_position && 
01382             next_frame_position - ogg_frame_position < 32)
01383         {
01384                 decode_frames = next_frame_position - ogg_frame_position;
01385         } else
01386         if (next_frame_position != ogg_frame_position)
01387         {
01388                 if (!ogg_seek_to_keyframe(tf->videosync, tf->to.serialno, next_frame_position, &ogg_frame_position))
01389                 {
01390                         printf("FileOGG:: Error while seeking to frame's keyframe (frame: %lli, keyframe: %lli)\n", next_frame_position, ogg_frame_position);
01391                         return 1;
01392                 }
01393 //              printf("For frame: %lli, keyframe is: %lli\n", next_frame_position,ogg_frame_position);
01394                 // skip frames must be > 0 here
01395                 decode_frames = next_frame_position - ogg_frame_position + 1; 
01396                 ogg_frame_position --; // ogg_frame_position is at last decoded frame, so it will point right 
01397                 if (decode_frames <= 0) 
01398                 {
01399                         printf("FileOGG:: Error while seeking to keyframe, wrong keyframe number (frame: %lli, keyframe: %lli)\n", next_frame_position, ogg_frame_position);
01400                         return 1;
01401                         
01402                 }
01403                 expect_keyframe = 1;
01404         }
01405 
01406 //      printf("Frames to decode: %i\n", decode_frames);
01407 
01408 // THIS IS WHAT CAUSES SLOWNESS OF SEEKING, but we can do nothing about it.
01409         while (decode_frames > 0)
01410         {
01411                 ogg_page og;
01412                 ogg_packet op;
01413                 while (ogg_stream_packetpeek(&tf->to, NULL) != 1)
01414                 {
01415                         if (!ogg_get_next_page(tf->videosync, tf->to.serialno, &og))
01416                         {
01417                                 printf("FileOGG: Cannot find next page while seeking\n");
01418                                 return 1;
01419                         }
01420                         ogg_stream_pagein(&tf->to, &og);
01421                 }
01422                 ogg_stream_packetout(&tf->to, &op);
01423                 if (expect_keyframe && !theora_packet_iskeyframe(&op))
01424                 {
01425                                 printf("FileOGG: Expecting keyframe, but didn't get it\n");
01426                         //      return 1; this is generally not a fatal error
01427                 }
01428                 expect_keyframe = 0;
01429                 
01430                 // decode
01431                 theora_decode_packetin(&tf->td, &op);
01432 
01433                 decode_frames --;
01434                 ogg_frame_position ++;
01435         }
01436         {
01437                 yuv_buffer yuv;
01438                 int ret = theora_decode_YUVout (&tf->td, &yuv);
01439                 if (ret)
01440                 {
01441                         printf("FileOGG: theora_decode_YUVout failed with code %i\n", ret);
01442                 }
01443 
01444 // Dirty magic 
01445 /*              yuv.y += yuv.y_stride * (yuv.y_height - 1);
01446                 yuv.u += yuv.uv_stride * (yuv.uv_height - 1);
01447                 yuv.v += yuv.uv_stride * (yuv.uv_height - 1);
01448                 yuv.y_stride = - yuv.y_stride;
01449                 yuv.uv_stride = - yuv.uv_stride;*/
01450                 VFrame *temp_frame = new VFrame(yuv.y, 
01451                                                 0,
01452                                                 yuv.u - yuv.y,
01453                                                 yuv.v - yuv.y,
01454                                                 - yuv.y_stride,
01455                                                 yuv.y_height,
01456                                                 BC_YUV420P,
01457                                                 - yuv.y_stride);
01458                 // copy into temp frame...
01459                 
01460                 cmodel_transfer(frame->get_rows(),
01461                         temp_frame->get_rows(),
01462                         frame->get_y(),
01463                         frame->get_u(),
01464                         frame->get_v(),
01465                         temp_frame->get_y(),
01466                         temp_frame->get_u(),
01467                         temp_frame->get_v(),
01468                         0,
01469                         0,
01470                         yuv.y_width,
01471                         yuv.y_height,
01472                         0,
01473                         0,
01474                         yuv.y_width,  // temp_frame can be larger than frame if width not dividable by 16
01475                         yuv.y_height,   
01476                         BC_YUV420P,
01477                         frame->get_color_model(),
01478                         0,
01479                         -temp_frame->get_w(),
01480                         frame->get_w());
01481                 delete temp_frame;
01482         }
01483 
01484         next_frame_position ++;
01485         
01486         return 0;               
01487 }
01488 
01489 
01490 
01491 int FileOGG::ogg_decode_more_samples(sync_window_t *sw, long serialno)
01492 {
01493         ogg_page og;
01494         ogg_packet op;
01495         int done = 0;
01496         while (!done)
01497         {
01498                 while (ogg_stream_packetpeek(&tf->vo, NULL) != 1)
01499                 {
01500                         if (!ogg_get_next_page(sw, serialno, &og))
01501                         {
01502                                 printf("FileOGG: Cannot find next page while trying to decode more samples\n");
01503                                 return 0;
01504                         }
01505                         ogg_stream_pagein(&tf->vo, &og);
01506                 }
01507                 ogg_stream_packetout(&tf->vo, &op);
01508                 if(!vorbis_synthesis(&tf->vb, &op))
01509                 {
01510                         done = 1;       
01511                         vorbis_synthesis_blockin(&tf->vd, &tf->vb);
01512                 }
01513         }
01514         return 1;
01515 }
01516 
01517 int FileOGG::set_audio_position(int64_t x)
01518 {
01519         next_sample_position = x + start_sample;
01520         return 0;
01521 }
01522 
01523 int FileOGG::move_history(int from, int to, int len)
01524 {
01525         for(int i = 0; i < asset->channels; i++)
01526                 memmove(pcm_history[i] + to, pcm_history[i] + from, sizeof(float) * len);
01527         history_start = history_start + from - to;
01528         return 0;
01529 } 
01530 
01531 int FileOGG::read_samples(double *buffer, int64_t len)
01532 {
01533         float **vorbis_buffer;
01534         if (len <= 0) 
01535                 return 0;
01536 //      printf("Reading samples: Channel: %i, number of samples: %lli, reading at :%lli\n", file->current_channel, len, next_sample_position);
01537 //              printf("\tnext_sample_position: %lli, length: %i\n", next_sample_position, len);
01538 //              printf("\thistory_start: %lli, length: %i\n", history_start, history_size);
01539 
01540         if(len > HISTORY_MAX)
01541         {
01542                 printf("FileOGG::read_samples max samples=%d\n", HISTORY_MAX);
01543                 return 1;
01544         }
01545 
01546         if(!pcm_history)
01547         {
01548                 pcm_history = new float*[asset->channels];
01549                 for(int i = 0; i < asset->channels; i++)
01550                         pcm_history[i] = new float[HISTORY_MAX];
01551                 history_start = -100000000; // insane value to trigger reload
01552                 history_size = 0;
01553         }
01554 
01555         int64_t hole_start = -1;
01556         int64_t hole_len = -1;
01557         int64_t hole_absstart = -1;
01558         int64_t hole_fill = 0;
01559 
01560         if (history_start < next_sample_position && history_start + history_size > next_sample_position && history_start + history_size < next_sample_position + len) 
01561         {
01562 //              printf("a\n");
01563                 hole_fill = 1;
01564                 hole_start = history_start + history_size - next_sample_position;
01565                 hole_len = history_size - hole_start;
01566                 hole_absstart = next_sample_position + hole_start;
01567                 move_history(next_sample_position - history_start,
01568                                 0,
01569                                 hole_start); // 
01570                 
01571         } else
01572         if (next_sample_position < history_start && history_start < next_sample_position + len)
01573         {
01574 //              printf("b\n");
01575                 hole_fill = 1;
01576                 hole_start = 0;
01577                 hole_len = history_start - next_sample_position;
01578                 hole_absstart = next_sample_position;
01579 //              printf("hs: %lli, histstart: %lli, next_sample_position: %lli\n", history_size, history_start, next_sample_position);
01580 //              printf("to: 0, from: %lli, size: %lli\n", 
01581  //                             history_start - next_sample_position,
01582 //                              history_size - history_start + next_sample_position);
01583                 move_history(0, 
01584                                 history_start - next_sample_position,
01585                                 history_size - history_start + next_sample_position);
01586                         
01587         } else 
01588         if (next_sample_position >= history_start + history_size || next_sample_position + len <= history_start)
01589         {
01590 //              printf("c\n");
01591                 hole_fill = 1;
01592                 hole_start = 0;
01593                 hole_len = HISTORY_MAX;
01594                 hole_absstart = next_sample_position;
01595                 history_start = hole_absstart;
01596                 history_size = hole_len;
01597         }
01598         
01599         if (hole_fill)
01600         {
01601                 if (hole_start < 0 || hole_len <= 0 || hole_absstart < 0)
01602                 {
01603                         printf("FileOGG: Error at finding out what to read from file\n");
01604                         return 1;
01605                 }
01606                 
01607                 if (hole_absstart + hole_len > asset->audio_length + start_sample)
01608                 {
01609                         hole_len = asset->audio_length + start_sample - hole_absstart;
01610                         history_size = asset->audio_length + start_sample - history_start;
01611                 } else
01612                 {
01613                         history_size = HISTORY_MAX;
01614                 }
01615                 
01616                 
01617 //              printf("Decode samples at position: %lli, samples to read: %lli\n", hole_absstart, hole_len);
01618         
01619                 int64_t samples_read = 0;        
01620                 if (ogg_sample_position != hole_absstart)
01621                 {
01622                         ogg_sample_position = hole_absstart;
01623                         if (!ogg_seek_to_sample(tf->audiosync, tf->vo.serialno, ogg_sample_position))
01624                         {
01625                                 printf("FileOGG:: Error while seeking to sample\n");
01626                                 return 1;
01627                         }
01628                 }
01629                 // now we have ogg_sample_positon aligned
01630                 int64_t samples_to_read = hole_len;
01631                 while (samples_read < hole_len)
01632                 {
01633                         int64_t waiting_samples = vorbis_synthesis_pcmout(&tf->vd, &vorbis_buffer);
01634                         int64_t takeout_samples;
01635                         if (waiting_samples > samples_to_read - samples_read)
01636                                 takeout_samples = samples_to_read - samples_read;
01637                         else 
01638                                 takeout_samples = waiting_samples;
01639 
01640                         int i, j;
01641 //                      printf("takeout samples: %lli, samples_read: %lli\n", takeout_samples, samples_read);
01642                         for(int i = 0; i < asset->channels; i++)
01643                         {
01644                                 float *input = vorbis_buffer[i];
01645                                 float *output = pcm_history[i] + hole_start;
01646                                 // TODO: use memcpy
01647                                 for(int j = 0; j < takeout_samples ; j++)
01648                                 {
01649                                         output[j] = input[j];
01650                                 }
01651                         }                                                                   
01652                         
01653                         vorbis_synthesis_read(&tf->vd, takeout_samples);
01654                         samples_read += takeout_samples;
01655                         ogg_sample_position += takeout_samples;
01656                         hole_start += takeout_samples;
01657                         
01658                         if (samples_read < hole_len)
01659                                 if (!ogg_decode_more_samples(tf->audiosync, tf->vo.serialno))
01660                                 {
01661                                         ogg_sample_position = -1;
01662                                         return 1;
01663                                 }
01664 
01665 
01666                 }
01667         }       
01668         
01669         // now we can be sure our history is correct, just copy it out
01670         if (next_sample_position < history_start || next_sample_position + len > history_start + history_size)
01671         {
01672                 printf("FileOGG:: History not aligned properly \n");
01673                 printf("\tnext_sample_position: %lli, length: %i\n", next_sample_position, len);
01674                 printf("\thistory_start: %lli, length: %i\n", history_start, history_size);
01675                 
01676                 return 1;
01677         }
01678         float *input = pcm_history[file->current_channel] + next_sample_position - history_start;
01679         for (int i = 0; i < len; i++)
01680                 buffer[i] = input[i];
01681          
01682         next_sample_position += len;
01683         return 0;
01684 }
01685 
01686 
01687 int FileOGG::write_audio_page()
01688 {
01689   int ret;
01690 
01691   ret = fwrite(tf->apage, 1, tf->apage_len, stream);
01692   if(ret < tf->apage_len) {
01693     fprintf(stderr,"error writing audio page\n"); 
01694   }
01695   tf->apage_valid = 0;
01696   return ret;
01697 }
01698 
01699 int FileOGG::write_video_page()
01700 {
01701   int ret;
01702 
01703   ret = fwrite(tf->vpage, 1, tf->vpage_len, stream);
01704   if(ret < tf->vpage_len) {
01705     fprintf(stderr,"error writing video page\n");
01706   }
01707   tf->vpage_valid = 0;
01708   return ret;
01709 }
01710 
01711 void FileOGG::flush_ogg (int e_o_s)
01712 {
01713     int len;
01714     ogg_page og;
01715 
01716         flush_lock->lock();
01717     /* flush out the ogg pages  */
01718     while(1) {
01719       /* Get pages for both streams, if not already present, and if available.*/
01720       if(asset->video_data && !tf->vpage_valid) {
01721         if(ogg_stream_pageout(&tf->to, &og) > 0) {
01722           len = og.header_len + og.body_len;
01723           if(tf->vpage_buffer_length < len) {
01724             tf->vpage = (unsigned char *)realloc(tf->vpage, len);
01725             tf->vpage_buffer_length = len;
01726           }
01727           tf->vpage_len = len;
01728           memcpy(tf->vpage, og.header, og.header_len);
01729           memcpy(tf->vpage+og.header_len , og.body, og.body_len);
01730 
01731           tf->vpage_valid = 1;
01732           tf->videotime = theora_granule_time (&tf->td,
01733                   ogg_page_granulepos(&og));
01734         }
01735       }
01736       if(asset->audio_data && !tf->apage_valid) {
01737         if(ogg_stream_pageout(&tf->vo, &og) > 0) {
01738           len = og.header_len + og.body_len;
01739           if(tf->apage_buffer_length < len) {
01740             tf->apage = (unsigned char *)realloc(tf->apage, len);
01741             tf->apage_buffer_length = len;
01742           }
01743           tf->apage_len = len;
01744           memcpy(tf->apage, og.header, og.header_len);
01745           memcpy(tf->apage+og.header_len , og.body, og.body_len);
01746 
01747           tf->apage_valid = 1;
01748           tf->audiotime= vorbis_granule_time (&tf->vd, 
01749                   ogg_page_granulepos(&og));
01750         }
01751       }
01752 
01753       if(!asset->audio_data && tf->vpage_valid) {
01754         write_video_page();
01755       }
01756       else if(!asset->video_data && tf->apage_valid) {
01757         write_audio_page();
01758       }
01759       /* We're using both. We can output only:
01760        *  a) If we have valid pages for both
01761        *  b) At EOS, for the remaining stream.
01762        */
01763       else if(tf->vpage_valid && tf->apage_valid) {
01764         /* Make sure they're in the right order. */
01765         if(tf->videotime <= tf->audiotime)
01766           write_video_page();
01767         else
01768           write_audio_page();
01769       } 
01770       else if(e_o_s && tf->vpage_valid) {
01771           write_video_page();
01772       }
01773       else if(e_o_s && tf->apage_valid) {
01774           write_audio_page();
01775       }
01776       else {
01777         break; /* Nothing more writable at the moment */
01778       }
01779     }
01780         flush_lock->unlock();
01781 }
01782 
01783 
01784 int FileOGG::write_samples_vorbis(double **buffer, int64_t len, int e_o_s)
01785 {
01786         int i,j, count = 0;
01787         float **vorbis_buffer;
01788         static int samples = 0;
01789         samples += len;
01790         if(e_o_s)
01791         {
01792                 vorbis_analysis_wrote (&tf->vd, 0);
01793         } else
01794         {
01795                 vorbis_buffer = vorbis_analysis_buffer (&tf->vd, len);
01796                 /* double to float conversion */
01797                 for(i = 0; i<asset->channels; i++)
01798                 {
01799                         for (j = 0; j < len; j++)
01800                         {
01801                                 vorbis_buffer[i][j] = buffer[i][j];
01802                         }
01803                 }
01804                 vorbis_analysis_wrote (&tf->vd, len);
01805         }
01806         while(vorbis_analysis_blockout (&tf->vd, &tf->vb) == 1)
01807         {
01808             /* analysis, assume we want to use bitrate management */
01809             vorbis_analysis (&tf->vb, NULL);
01810             vorbis_bitrate_addblock (&tf->vb);
01811             
01812             /* weld packets into the bitstream */
01813             while (vorbis_bitrate_flushpacket (&tf->vd, &tf->op))
01814             {
01815                 flush_lock->lock();
01816                 ogg_stream_packetin (&tf->vo, &tf->op);
01817                 flush_lock->unlock();
01818             }
01819 
01820         }
01821         flush_ogg(0);
01822         return 0;
01823 
01824 
01825 }
01826 
01827 int FileOGG::write_samples(double **buffer, int64_t len)
01828 {
01829         if (len > 0)
01830                 return write_samples_vorbis(buffer, len, 0);
01831         return 0;
01832 }
01833 
01834 int FileOGG::write_frames_theora(VFrame ***frames, int len, int e_o_s)
01835 {
01836         // due to clumsy theora's design we need to delay writing out by one frame
01837         // always stay one frame behind, so we can correctly encode e_o_s
01838 
01839         int i, j, result = 0;
01840 
01841         if(!stream) return 0;
01842 
01843         
01844         for(j = 0; j < len && !result; j++)
01845         {
01846                 if (temp_frame) // encode previous frame if available
01847                 {
01848                         yuv_buffer yuv;
01849                         yuv.y_width = tf->ti.width;
01850                         yuv.y_height = tf->ti.height;
01851                         yuv.y_stride = temp_frame->get_bytes_per_line();
01852 
01853                         yuv.uv_width = tf->ti.width / 2;
01854                         yuv.uv_height = tf->ti.height / 2;
01855                         yuv.uv_stride = temp_frame->get_bytes_per_line() /2;
01856 
01857                         yuv.y = temp_frame->get_y();
01858                         yuv.u = temp_frame->get_u();
01859                         yuv.v = temp_frame->get_v();
01860                         int ret = theora_encode_YUVin (&tf->td, &yuv);
01861                         if (ret)
01862                         {
01863                                 printf("FileOGG: theora_encode_YUVin failed with code %i\n", ret);
01864                                 printf("yuv_buffer: y_width: %i, y_height: %i, y_stride: %i, uv_width: %i, uv_height: %i, uv_stride: %i\n",
01865                                         yuv.y_width,
01866                                         yuv.y_height,
01867                                         yuv.y_stride,
01868                                         yuv.uv_width,
01869                                         yuv.uv_height,
01870                                         yuv.uv_stride);
01871                         }
01872                         while(theora_encode_packetout (&tf->td, e_o_s, &tf->op)) {
01873                                 flush_lock->lock();
01874                                 ogg_stream_packetin (&tf->to, &tf->op);
01875                                 flush_lock->unlock();
01876             }
01877                         flush_ogg(0);  // eos flush is done later at close_file
01878                 }
01879 // If we have e_o_s, don't encode any new frames
01880                 if (e_o_s) 
01881                         break;
01882 
01883                 if (!temp_frame)
01884                 {
01885                         temp_frame = new VFrame (0, 
01886                                                 tf->ti.width, 
01887                                                 tf->ti.height,
01888                                                 BC_YUV420P);
01889                 } 
01890                 VFrame *frame = frames[0][j];
01891                 int in_color_model = frame->get_color_model();
01892                 if (in_color_model == BC_YUV422P &&
01893                     temp_frame->get_w() == frame->get_w() &&
01894                     temp_frame->get_h() == frame->get_h() &&
01895                     temp_frame->get_bytes_per_line() == frame->get_bytes_per_line())
01896                 {
01897                         temp_frame->copy_from(frame);
01898                 } else
01899                 {
01900 
01901                         cmodel_transfer(temp_frame->get_rows(),
01902                                 frame->get_rows(),
01903                                 temp_frame->get_y(),
01904                                 temp_frame->get_u(),
01905                                 temp_frame->get_v(),
01906                                 frame->get_y(),
01907                                 frame->get_u(),
01908                                 frame->get_v(),
01909                                 0,
01910                                 0,
01911                                 frame->get_w(),
01912                                 frame->get_h(),
01913                                 0,
01914                                 0,
01915                                 frame->get_w(),  // temp_frame can be larger than frame if width not dividable by 16
01916                                 frame->get_h(), 
01917                                 frame->get_color_model(),
01918                                 BC_YUV420P,
01919                                 0,
01920                                 frame->get_w(),
01921                                 temp_frame->get_w());
01922 
01923                 }
01924         }                                               
01925                                 
01926         return 0;
01927 }
01928 
01929 
01930 int FileOGG::write_frames(VFrame ***frames, int len)
01931 {
01932         
01933         return write_frames_theora(frames, len, 0);
01934 }
01935 
01936 OGGConfigAudio::OGGConfigAudio(BC_WindowBase *parent_window, Asset *asset)
01937  : BC_Window(PROGRAM_NAME ": Audio Compression",
01938         parent_window->get_abs_cursor_x(1),
01939         parent_window->get_abs_cursor_y(1),
01940         350,
01941         250)
01942 {
01943         this->parent_window = parent_window;
01944         this->asset = asset;
01945 }
01946 
01947 OGGConfigAudio::~OGGConfigAudio()
01948 {
01949 
01950 }
01951 
01952 int OGGConfigAudio::create_objects()
01953 {
01954 //      add_tool(new BC_Title(10, 10, _("There are no audio options for this format")));
01955 
01956         int x = 10, y = 10;
01957         int x1 = 150;
01958         char string[BCTEXTLEN];
01959 
01960         add_tool(fixed_bitrate = new OGGVorbisFixedBitrate(x, y, this));
01961         add_tool(variable_bitrate = new OGGVorbisVariableBitrate(x1, y, this));
01962 
01963         y += 30;
01964         sprintf(string, "%d", asset->vorbis_min_bitrate);
01965         add_tool(new BC_Title(x, y, _("Min bitrate:")));
01966         add_tool(new OGGVorbisMinBitrate(x1, y, this, string));
01967 
01968         y += 30;
01969         add_tool(new BC_Title(x, y, _("Avg bitrate:")));
01970         sprintf(string, "%d", asset->vorbis_bitrate);
01971         add_tool(new OGGVorbisAvgBitrate(x1, y, this, string));
01972 
01973         y += 30;
01974         add_tool(new BC_Title(x, y, _("Max bitrate:")));
01975         sprintf(string, "%d", asset->vorbis_max_bitrate);
01976         add_tool(new OGGVorbisMaxBitrate(x1, y, this, string));
01977 
01978 
01979         add_subwindow(new BC_OKButton(this));
01980         show_window();
01981         flush();
01982         return 0;
01983 
01984 
01985 
01986 }
01987 
01988 int OGGConfigAudio::close_event()
01989 {
01990         set_done(0);
01991         return 1;
01992 }
01993 
01994 OGGVorbisFixedBitrate::OGGVorbisFixedBitrate(int x, int y, OGGConfigAudio *gui)
01995  : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Average bitrate"))
01996 {
01997         this->gui = gui;
01998 }
01999 int OGGVorbisFixedBitrate::handle_event()
02000 {
02001         gui->asset->vorbis_vbr = 0;
02002         gui->variable_bitrate->update(0);
02003         return 1;
02004 }
02005 
02006 OGGVorbisVariableBitrate::OGGVorbisVariableBitrate(int x, int y, OGGConfigAudio *gui)
02007  : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
02008 {
02009         this->gui = gui;
02010 }
02011 int OGGVorbisVariableBitrate::handle_event()
02012 {
02013         gui->asset->vorbis_vbr = 1;
02014         gui->fixed_bitrate->update(0);
02015         return 1;
02016 }
02017 
02018 
02019 OGGVorbisMinBitrate::OGGVorbisMinBitrate(int x, 
02020         int y, 
02021         OGGConfigAudio *gui, 
02022         char *text)
02023  : BC_TextBox(x, y, 180, 1, text)
02024 {
02025         this->gui = gui;
02026 }
02027 int OGGVorbisMinBitrate::handle_event()
02028 {
02029         gui->asset->vorbis_min_bitrate = atol(get_text());
02030         return 1;
02031 }
02032 
02033 
02034 
02035 OGGVorbisMaxBitrate::OGGVorbisMaxBitrate(int x, 
02036         int y, 
02037         OGGConfigAudio *gui,
02038         char *text)
02039  : BC_TextBox(x, y, 180, 1, text)
02040 {
02041         this->gui = gui;
02042 }
02043 int OGGVorbisMaxBitrate::handle_event()
02044 {
02045         gui->asset->vorbis_max_bitrate = atol(get_text());
02046         return 1;
02047 }
02048 
02049 
02050 
02051 OGGVorbisAvgBitrate::OGGVorbisAvgBitrate(int x, int y, OGGConfigAudio *gui, char *text)
02052  : BC_TextBox(x, y, 180, 1, text)
02053 {
02054         this->gui = gui;
02055 }
02056 int OGGVorbisAvgBitrate::handle_event()
02057 {
02058         gui->asset->vorbis_bitrate = atol(get_text());
02059         return 1;
02060 }
02061 
02062 
02063 
02064 
02065 
02066 OGGConfigVideo::OGGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
02067  : BC_Window(PROGRAM_NAME ": Video Compression",
02068         parent_window->get_abs_cursor_x(1),
02069         parent_window->get_abs_cursor_y(1),
02070         450,
02071         220)
02072 {
02073         this->parent_window = parent_window;
02074         this->asset = asset;
02075 }
02076 
02077 OGGConfigVideo::~OGGConfigVideo()
02078 {
02079 
02080 }
02081 
02082 int OGGConfigVideo::create_objects()
02083 {
02084 //      add_tool(new BC_Title(10, 10, _("There are no video options for this format")));
02085         int x = 10, y = 10;
02086         int x1 = x + 150;
02087         int x2 = x + 300;
02088 
02089         add_subwindow(new BC_Title(x, y + 5, _("Bitrate:")));
02090         add_subwindow(new OGGTheoraBitrate(x1, y, this));
02091         add_subwindow(fixed_bitrate = new OGGTheoraFixedBitrate(x2, y, this));
02092         y += 30;
02093 
02094         add_subwindow(new BC_Title(x, y, _("Quality:")));
02095         add_subwindow(new BC_ISlider(x + 80, 
02096                 y,
02097                 0,
02098                 200,
02099                 200,
02100                 0,
02101                 63,
02102                 asset->theora_quality,
02103                 0,
02104                 0,
02105                 &asset->theora_quality));
02106 
02107         
02108         add_subwindow(fixed_quality = new OGGTheoraFixedQuality(x2, y, this));
02109         y += 30;
02110 
02111         add_subwindow(new BC_Title(x, y, _("Keyframe frequency:")));
02112         OGGTheoraKeyframeFrequency *keyframe_frequency = 
02113                 new OGGTheoraKeyframeFrequency(x1 + 60, y, this);
02114         keyframe_frequency->create_objects();
02115         y += 30;
02116         
02117         add_subwindow(new BC_Title(x, y, _("Keyframe force frequency:")));
02118         OGGTheoraKeyframeForceFrequency *keyframe_force_frequency = 
02119                 new OGGTheoraKeyframeForceFrequency(x1 + 60, y, this);
02120         keyframe_force_frequency->create_objects();
02121         y += 30;
02122 
02123         add_subwindow(new BC_Title(x, y, _("Sharpness:")));
02124         OGGTheoraSharpness *sharpness = 
02125                 new OGGTheoraSharpness(x1 + 60, y, this);
02126         sharpness->create_objects();
02127         y += 30;
02128         
02129 
02130         add_subwindow(new BC_OKButton(this));
02131         return 0;
02132 }
02133 
02134 
02135 
02136 
02137 int OGGConfigVideo::close_event()
02138 {
02139         set_done(0);
02140         return 1;
02141 }
02142 
02143 OGGTheoraBitrate::OGGTheoraBitrate(int x, int y, OGGConfigVideo *gui)
02144  : BC_TextBox(x, y, 100, 1, gui->asset->theora_bitrate)
02145 {
02146         this->gui = gui;
02147 }
02148 
02149 
02150 int OGGTheoraBitrate::handle_event()
02151 {
02152         // TODO: MIN / MAX check
02153         gui->asset->theora_bitrate = atol(get_text());
02154         return 1;
02155 };
02156 
02157 
02158 
02159 
02160 OGGTheoraFixedBitrate::OGGTheoraFixedBitrate(int x, int y, OGGConfigVideo *gui)
02161  : BC_Radial(x, y, gui->asset->theora_fix_bitrate, _("Fixed bitrate"))
02162 {
02163         this->gui = gui;
02164 }
02165 
02166 int OGGTheoraFixedBitrate::handle_event()
02167 {
02168         update(1);
02169         gui->asset->theora_fix_bitrate = 1;
02170         gui->fixed_quality->update(0);
02171         return 1;
02172 };
02173 
02174 OGGTheoraFixedQuality::OGGTheoraFixedQuality(int x, int y, OGGConfigVideo *gui)
02175  : BC_Radial(x, y, !gui->asset->theora_fix_bitrate, _("Fixed quality"))
02176 {
02177         this->gui = gui;
02178 }
02179 
02180 int OGGTheoraFixedQuality::handle_event()
02181 {
02182         update(1);
02183         gui->asset->theora_fix_bitrate = 0;
02184         gui->fixed_bitrate->update(0);
02185         return 1;
02186 };
02187 
02188 OGGTheoraKeyframeFrequency::OGGTheoraKeyframeFrequency(int x, int y, OGGConfigVideo *gui)
02189  : BC_TumbleTextBox(gui, 
02190         (int64_t)gui->asset->theora_keyframe_frequency, 
02191         (int64_t)1,
02192         (int64_t)500,
02193         x, 
02194         y,
02195         40)
02196 {
02197         this->gui = gui;
02198 }
02199 
02200 int OGGTheoraKeyframeFrequency::handle_event()
02201 {
02202         gui->asset->theora_keyframe_frequency = atol(get_text());
02203         return 1;
02204 }
02205 
02206 OGGTheoraKeyframeForceFrequency::OGGTheoraKeyframeForceFrequency(int x, int y, OGGConfigVideo *gui)
02207  : BC_TumbleTextBox(gui, 
02208         (int64_t)gui->asset->theora_keyframe_frequency, 
02209         (int64_t)1,
02210         (int64_t)500,
02211         x, 
02212         y,
02213         40)
02214 {
02215         this->gui = gui;
02216 }
02217 
02218 int OGGTheoraKeyframeForceFrequency::handle_event()
02219 {
02220         gui->asset->theora_keyframe_frequency = atol(get_text());
02221         return 1;
02222 }
02223 
02224 
02225 OGGTheoraSharpness::OGGTheoraSharpness(int x, int y, OGGConfigVideo *gui)
02226  : BC_TumbleTextBox(gui, 
02227         (int64_t)gui->asset->theora_sharpness, 
02228         (int64_t)0,
02229         (int64_t)2,
02230         x, 
02231         y,
02232         40)
02233 {
02234         this->gui = gui;
02235 }
02236 
02237 int OGGTheoraSharpness::handle_event()
02238 {
02239         gui->asset->theora_sharpness = atol(get_text());
02240         return 1;
02241 }
02242 
02243 

Generated on Sun Jan 8 13:38:55 2006 for Cinelerra-svn by  doxygen 1.4.4