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
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
00971
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
00976 int64_t start_sample = 0;
00977
00978
00979 if (end_sample <= sample)
00980 {
00981
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
00992 start_sample = end_sample;
00993 while (start_sample > sample)
00994 {
00995
00996 ogg_get_prev_page(sw, serialno, og);
00997 end_sample = start_sample;
00998 start_sample = ogg_page_granulepos(og);
00999 }
01000
01001
01002 }
01003
01004
01005 return 1;
01006 }
01007
01008
01009
01010
01011
01012 int FileOGG::ogg_seek_to_sample(sync_window_t *sw, long serialno, int64_t sample)
01013 {
01014
01015
01016 ogg_page og;
01017 ogg_packet op;
01018
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
01025 vorbis_synthesis_restart(&tf->vd);
01026 ogg_stream_reset(&tf->vo);
01027 ogg_stream_pagein(&tf->vo, &og);
01028 int sync = 0;
01029
01030
01031 int64_t current_comming_sample = -1;
01032 while (1)
01033 {
01034
01035
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
01058 return 1;
01059 } else
01060 {
01061
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
01097
01098 off_t educated_guess = filedata_begin + (file_length - filedata_begin) * (frame - start_frame) / asset->video_length - READ_SIZE/2;
01099
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
01105
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
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
01122
01123
01124
01125 int64_t start_frame = 0;
01126
01127
01128 int discard_packets = 0;
01129 int missp = 0;
01130 int missm = 0;
01131 if (pageend_frame <= frame)
01132 {
01133
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
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
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
01159 do {
01160 ogg_get_prev_page(sw, serialno, og);
01161 } while (ogg_page_packets(og) == 0 && ogg_page_continued(og));
01162 missm++;
01163
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
01170
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
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
01186
01187
01188
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
01194 if (granulepos != -1 && iframe <= frame)
01195 {
01196
01197 } else
01198 {
01199
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
01214 } else
01215 {
01216
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
01224 ogg_stream_reset(&tf->to);
01225 ogg_stream_pagein(&tf->to, &og);
01226
01227
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
01232
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
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);
01280 if (asset->video_data)
01281 write_frames_theora(0, 1, 1);
01282
01283 flush_ogg(1);
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
01330 if (stream) fclose(stream);
01331 stream = 0;
01332 }
01333
01334 int64_t FileOGG::get_video_position()
01335 {
01336
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
01348
01349
01350 next_frame_position = x + start_frame;
01351 return 1;
01352 }
01353
01354
01355 int FileOGG::colormodel_supported(int colormodel)
01356 {
01357
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
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
01394
01395 decode_frames = next_frame_position - ogg_frame_position + 1;
01396 ogg_frame_position --;
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
01407
01408
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
01427 }
01428 expect_keyframe = 0;
01429
01430
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
01445
01446
01447
01448
01449
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
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,
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
01537
01538
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;
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
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
01575 hole_fill = 1;
01576 hole_start = 0;
01577 hole_len = history_start - next_sample_position;
01578 hole_absstart = next_sample_position;
01579
01580
01581
01582
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
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
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
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
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
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
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
01718 while(1) {
01719
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
01760
01761
01762
01763 else if(tf->vpage_valid && tf->apage_valid) {
01764
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;
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
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
01809 vorbis_analysis (&tf->vb, NULL);
01810 vorbis_bitrate_addblock (&tf->vb);
01811
01812
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
01837
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)
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);
01878 }
01879
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(),
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
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
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
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