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
00028
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
00112 sw->wlen = fread(buffer, 1, buflen, in);
00113 ogg_sync_wrote(&sw->sync, sw->wlen);
00114
00115 sw->file_bufpos += sw->wlen;
00116
00117 return (sw->wlen);
00118 }
00119
00120 int read_buffer_at(FILE *in, sync_window_t *sw, int buflen, off_t filepos)
00121 {
00122
00123 fseeko(in, filepos, SEEK_SET);
00124
00125
00126 sw->file_bufpos = filepos;
00127 sw->file_pagepos = filepos;
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
00142 sw->file_pagepos += og->header_len + og->body_len;
00143
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
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;
00158 }
00159 }
00160 }
00161
00162 }
00163
00164
00165
00166
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
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
00223 srand (time (NULL));
00224
00225 if(asset->video_data)
00226 {
00227 ogg_stream_init (&tf->to, rand ());
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;
00235 tf->ti.height = ((asset->height + 15) >>4)<<4;
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
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;
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
00289
00290
00291 if(asset->audio_data)
00292 {
00293 ogg_stream_init (&tf->vo, rand ());
00294 vorbis_info_init (&tf->vi);
00295
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
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);
00327 vorbis_comment_add_tag (&tf->vc, "ENCODER", PACKAGE_STRING);
00328
00329 vorbis_analysis_init (&tf->vd, &tf->vi);
00330 vorbis_block_init (&tf->vd, &tf->vb);
00331
00332 }
00333
00334
00335
00336
00337
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
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);
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
00378 ogg_stream_packetin (&tf->vo, &header_comm);
00379 ogg_stream_packetin (&tf->vo, &header_code);
00380 }
00381
00382
00383
00384
00385 while (1 && asset->video_data)
00386 {
00387 int result = ogg_stream_flush (&tf->to, &tf->og);
00388 if (result < 0)
00389 {
00390
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
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
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
00425 struct stat file_stat;
00426 stat(asset->path, &file_stat);
00427 file_length = file_stat.st_size;
00428
00429
00430 sync_window_t oy;
00431 ogg_sync_init(&oy.sync);
00432
00433 read_buffer_at(stream, &oy, READ_SIZE, 0);
00434
00435
00436 vorbis_info_init(&tf->vi);
00437 vorbis_comment_init(&tf->vc);
00438
00439
00440 theora_comment_init(&tf->tc);
00441 theora_info_init(&tf->ti);
00442
00443 TRACE("FileOGG::open_file 40")
00444
00445
00446
00447 int stateflag = 0;
00448 int theora_p = 0;
00449 int vorbis_p = 0;
00450 while(!stateflag)
00451 {
00452
00453
00454
00455 TRACE("FileOGG::open_file 60")
00456
00457
00458
00459 while(take_page_out_autoadvance(stream, &oy, &tf->og) > 0)
00460 {
00461 ogg_stream_state test;
00462
00463
00464 if(!ogg_page_bos(&tf->og))
00465 {
00466
00467
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
00480 if(!theora_p && theora_decode_header(&tf->ti, &tf->tc, &tf->op)>=0)
00481 {
00482
00483 memcpy(&tf->to, &test, sizeof(test));
00484 theora_p = 1;
00485
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
00493 memcpy(&tf->vo, &test, sizeof(test));
00494 vorbis_p = 1;
00495 } else
00496 {
00497
00498 ogg_stream_clear(&test);
00499 }
00500 }
00501
00502 }
00503
00504
00505 while((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3))
00506 {
00507 int ret;
00508
00509
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
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
00548
00549
00550 if(take_page_out_autoadvance(stream, &oy, &tf->og) > 0)
00551 {
00552
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
00563 filedata_begin = oy.file_pagepos;
00564
00565
00566
00567
00568 if(theora_p)
00569 {
00570 int ret;
00571
00572
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
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
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
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
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
00638
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
00645
00646 asset->layers = 1;
00647
00648 asset->width = tf->ti.width;
00649 asset->height = tf->ti.height;
00650
00651 if(!asset->frame_rate)
00652 asset->frame_rate = fps;
00653
00654 if(!asset->interlace_mode)
00655 asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 set_video_position(0);
00674 ogg_frame_position = -10;
00675 asset->video_data = 1;
00676 strncpy(asset->vcodec, "theo", 4);
00677
00678
00679
00680
00681 } else
00682 {
00683
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
00692
00693
00694
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
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 {
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
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
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
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
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);
00778 strncpy(asset->acodec, "vorb", 4);
00779
00780
00781 } else
00782 {
00783
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
00802 while (!done)
00803 {
00804 if (filepos < 0)
00805 {
00806
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
00815
00816
00817
00818
00819 if (!have_read)
00820 return 0;
00821
00822
00823 int page_offset = 0;
00824 int page_length = 0;
00825 int first_page = 1;
00826 while (first_page || page_length)
00827 {
00828
00829 while ((page_length = sync_and_take_page_out(sw, &page)) < 0)
00830 {
00831 page_offset -= page_length;
00832
00833
00834
00835 }
00836
00837
00838
00839
00840
00841 if (first_page)
00842 first_page_offset = page_offset;
00843 first_page = 0;
00844
00845 if (page_length && ogg_page_serialno(&page) == serialno)
00846 {
00847
00848 done = 1;
00849
00850 sw->file_pagepos_found = sw->file_pagepos - page.header_len - page.body_len;
00851
00852 memcpy(og, &page, sizeof(page));
00853 }
00854 }
00855 off_t old_filepos = filepos;
00856
00857 filepos = filepos + first_page_offset - READ_SIZE;
00858 }
00859
00860
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
00883 int page_offset = 0;
00884 int page_length = 0;
00885 int first_page = 1;
00886 while (first_page || page_length)
00887 {
00888
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
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
00914 read_buffer_at(stream, sw, READ_SIZE, 0);
00915
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
00935 int ret;
00936 while ((ret = sync_and_take_page_out(sw, og)) < 0)
00937 {
00938
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
00957
00958
00959 int FileOGG::ogg_get_page_of_sample(sync_window_t *sw, long serialno, ogg_page *og, int64_t sample)
00960 {
00961