00001 #include "asset.h"
00002 #include "byteorder.h"
00003 #include "clip.h"
00004 #include "file.h"
00005 #include "filevorbis.h"
00006 #include "guicast.h"
00007 #include "language.h"
00008 #include "mwindow.inc"
00009 #include "mainerror.h"
00010
00011 #include <errno.h>
00012 #include <stdio.h>
00013 #include <string.h>
00014 #include <unistd.h>
00015
00016 FileVorbis::FileVorbis(Asset *asset, File *file)
00017 : FileBase(asset, file)
00018 {
00019 reset_parameters();
00020 if(asset->format == FILE_UNKNOWN) asset->format = FILE_VORBIS;
00021 asset->byte_order = 0;
00022 }
00023
00024 FileVorbis::~FileVorbis()
00025 {
00026 close_file();
00027 }
00028
00029 void FileVorbis::get_parameters(BC_WindowBase *parent_window,
00030 Asset *asset,
00031 BC_WindowBase* &format_window,
00032 int audio_options,
00033 int video_options)
00034 {
00035 if(audio_options)
00036 {
00037 VorbisConfigAudio *window = new VorbisConfigAudio(parent_window, asset);
00038 format_window = window;
00039 window->create_objects();
00040 window->run_window();
00041 delete window;
00042 }
00043 }
00044
00045 int FileVorbis::check_sig(Asset *asset)
00046 {
00047
00048 return 0;
00049 FILE *fd = fopen(asset->path, "rb");
00050 OggVorbis_File vf;
00051
00052
00053 fseek(fd, 4, SEEK_SET);
00054 char data[4];
00055 fread(data, 4, 1, fd);
00056 if(data[0] == 'm' &&
00057 data[1] == 'd' &&
00058 data[2] == 'a' &&
00059 data[3] == 't')
00060 {
00061 fclose(fd);
00062 return 0;
00063 }
00064
00065 fseek(fd, 0, SEEK_SET);
00066
00067 if(ov_open(fd, &vf, NULL, 0) < 0)
00068 {
00069
00070 ov_clear(&vf);
00071 if(fd) fclose(fd);
00072 return 0;
00073 }
00074 else
00075 {
00076 ov_clear(&vf);
00077 return 1;
00078 }
00079 }
00080
00081 int FileVorbis::reset_parameters_derived()
00082 {
00083 fd = 0;
00084 bzero(&vf, sizeof(vf));
00085 pcm_history = 0;
00086 pcm_history_float = 0;
00087 }
00088
00089
00090
00091
00092 int FileVorbis::open_file(int rd, int wr)
00093 {
00094 int result = 0;
00095 this->rd = rd;
00096 this->wr = wr;
00097
00098
00099 if(rd)
00100 {
00101
00102 if(!(fd = fopen(asset->path, "rb")))
00103 {
00104 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
00105 result = 1;
00106 }
00107 else
00108 {
00109
00110 if(ov_open(fd, &vf, NULL, 0) < 0)
00111 {
00112 eprintf("Invalid bitstream in %s\n", asset->path);
00113 result = 1;
00114 }
00115 else
00116 {
00117
00118 vorbis_info *vi = ov_info(&vf, -1);
00119 asset->channels = vi->channels;
00120 if(!asset->sample_rate)
00121 asset->sample_rate = vi->rate;
00122
00123 asset->audio_length = ov_pcm_total(&vf,-1);
00124
00125 asset->audio_data = 1;
00126
00127
00128
00129
00130 }
00131 }
00132 }
00133
00134 if(wr)
00135 {
00136 if(!(fd = fopen(asset->path, "wb")))
00137 {
00138 eprintf("Error while opening \"%s\" for writing. \n%m\n", asset->path);
00139 result = 1;
00140 }
00141 else
00142 {
00143 vorbis_info_init(&vi);
00144 if(!asset->vorbis_vbr)
00145 result = vorbis_encode_init(&vi,
00146 asset->channels,
00147 asset->sample_rate,
00148 asset->vorbis_max_bitrate,
00149 asset->vorbis_bitrate,
00150 asset->vorbis_min_bitrate);
00151 else
00152 {
00153 result = vorbis_encode_setup_managed(&vi,
00154 asset->channels,
00155 asset->sample_rate,
00156 asset->vorbis_max_bitrate,
00157 asset->vorbis_bitrate,
00158 asset->vorbis_min_bitrate);
00159 result |= vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE_AVG, NULL);
00160 result |= vorbis_encode_setup_init(&vi);
00161 }
00162
00163 if(!result)
00164 {
00165 vorbis_analysis_init(&vd, &vi);
00166 vorbis_block_init(&vd, &vb);
00167 vorbis_comment_init(&vc);
00168 srand(time(NULL));
00169 ogg_stream_init(&os, rand());
00170
00171 ogg_packet header;
00172 ogg_packet header_comm;
00173 ogg_packet header_code;
00174 vorbis_analysis_headerout(&vd,
00175 &vc,
00176 &header,
00177 &header_comm,
00178 &header_code);
00179 ogg_stream_packetin(&os,
00180 &header);
00181 ogg_stream_packetin(&os,
00182 &header_comm);
00183 ogg_stream_packetin(&os,
00184 &header_code);
00185
00186 while(1)
00187 {
00188 int result = ogg_stream_flush(&os, &og);
00189 if(result == 0) break;
00190 fwrite(og.header, 1, og.header_len, fd);
00191 fwrite(og.body, 1, og.body_len, fd);
00192 }
00193 }
00194 }
00195 }
00196
00197
00198 return result;
00199 }
00200
00201 #define FLUSH_VORBIS \
00202 while(vorbis_analysis_blockout(&vd, &vb) == 1) \
00203 { \
00204 vorbis_analysis(&vb, NULL); \
00205 vorbis_bitrate_addblock(&vb); \
00206 while(vorbis_bitrate_flushpacket(&vd, &op)) \
00207 { \
00208 ogg_stream_packetin(&os, &op); \
00209 int done = 0; \
00210 while(1) \
00211 { \
00212 int result = ogg_stream_pageout(&os, &og); \
00213 if(!result) break; \
00214 fwrite(og.header, 1, og.header_len, fd); \
00215 fwrite(og.body, 1, og.body_len, fd); \
00216 if(ogg_page_eos(&og)) break; \
00217 } \
00218 } \
00219 }
00220
00221
00222 int FileVorbis::close_file()
00223 {
00224 if(fd)
00225 {
00226 if(wr)
00227 {
00228 vorbis_analysis_wrote(&vd, 0);
00229 FLUSH_VORBIS
00230
00231 ogg_stream_clear(&os);
00232 vorbis_block_clear(&vb);
00233 vorbis_dsp_clear(&vd);
00234 vorbis_comment_clear(&vc);
00235 vorbis_info_clear(&vi);
00236 fclose(fd);
00237 }
00238
00239 if(rd)
00240 {
00241
00242 ov_clear(&vf);
00243 }
00244 fd = 0;
00245 }
00246
00247 if(pcm_history)
00248 {
00249 for(int i = 0; i < asset->channels; i++)
00250 delete [] pcm_history[i];
00251 delete [] pcm_history;
00252 }
00253 if(pcm_history_float)
00254 {
00255 for(int i = 0; i < asset->channels; i++)
00256 delete [] pcm_history_float[i];
00257 delete [] pcm_history_float;
00258 }
00259
00260 reset_parameters();
00261 FileBase::close_file();
00262 return 0;
00263 }
00264
00265
00266 int FileVorbis::write_samples(double **buffer, int64_t len)
00267 {
00268 if(!fd) return 0;
00269 int result = 0;
00270
00271 float **vorbis_buffer = vorbis_analysis_buffer(&vd, len);
00272 for(int i = 0; i < asset->channels; i++)
00273 {
00274 float *output = vorbis_buffer[i];
00275 double *input = buffer[i];
00276 for(int j = 0; j < len; j++)
00277 {
00278 output[j] = input[j];
00279 }
00280 }
00281 vorbis_analysis_wrote(&vd, len);
00282
00283 FLUSH_VORBIS
00284
00285 return result;
00286 }
00287
00288 int FileVorbis::read_samples(double *buffer, int64_t len)
00289 {
00290 if(!fd) return 0;
00291
00292
00293
00294
00295
00296
00297 float **vorbis_output;
00298 int bitstream;
00299 int accumulation = 0;
00300
00301 int decode_start = 0;
00302 int decode_len = 0;
00303
00304 if(len > 0x100000)
00305 {
00306 eprintf("FileVorbis::read_samples max samples=%d\n", HISTORY_MAX);
00307 return 1;
00308 }
00309
00310 if(!pcm_history)
00311 {
00312 pcm_history = new double*[asset->channels];
00313 for(int i = 0; i < asset->channels; i++)
00314 pcm_history[i] = new double[HISTORY_MAX];
00315 history_start = 0;
00316 history_size = 0;
00317 }
00318
00319
00320 if(file->current_sample < history_start ||
00321 file->current_sample > history_start + history_size)
00322 {
00323 history_size = 0;
00324 history_start = file->current_sample;
00325 decode_start = file->current_sample;
00326 decode_len = len;
00327 }
00328 else
00329
00330 if(file->current_sample + len > history_start + history_size)
00331 {
00332 if(file->current_sample + len > history_start + HISTORY_MAX)
00333 {
00334 int diff = file->current_sample + len - (history_start + HISTORY_MAX);
00335 for(int i = 0; i < asset->channels; i++)
00336 {
00337 double *temp = pcm_history[i];
00338 for(int j = 0; j < HISTORY_MAX - diff; j++)
00339 {
00340 temp[j] = temp[j + diff];
00341 }
00342 }
00343 history_start += diff;
00344 history_size -= diff;
00345 }
00346
00347
00348 decode_start = history_start + history_size;
00349 decode_len = file->current_sample + len - (history_start + history_size);
00350 }
00351
00352
00353
00354 if(history_start + history_size != ov_pcm_tell(&vf))
00355 {
00356
00357 ov_pcm_seek(&vf, history_start + history_size);
00358 }
00359
00360 while(accumulation < decode_len)
00361 {
00362 int result = ov_read_float(&vf,
00363 &vorbis_output,
00364 decode_len - accumulation,
00365 &bitstream);
00366
00367 if(!result) break;
00368
00369 for(int i = 0; i < asset->channels; i++)
00370 {
00371 double *output = pcm_history[i] + history_size;
00372 float *input = vorbis_output[i];
00373 for(int j = 0; j < result; j++)
00374 output[j] = input[j];
00375 }
00376 history_size += result;
00377 accumulation += result;
00378 }
00379
00380
00381
00382
00383
00384
00385 double *input = pcm_history[file->current_channel] +
00386 file->current_sample -
00387 history_start;
00388 for(int i = 0; i < len; i++)
00389 buffer[i] = input[i];
00390
00391
00392
00393
00394
00395
00396
00397 return 0;
00398 }
00399
00400 int FileVorbis::prefer_samples_float()
00401 {
00402 return 1;
00403 }
00404
00405 int FileVorbis::read_samples_float(float *buffer, int64_t len)
00406 {
00407 if(!fd) return 0;
00408
00409
00410
00411
00412
00413
00414 float **vorbis_output;
00415 int bitstream;
00416 int accumulation = 0;
00417
00418 int decode_start = 0;
00419 int decode_len = 0;
00420
00421 if(len > 0x100000)
00422 {
00423 eprintf("FileVorbis::read_samples max samples=%d\n", HISTORY_MAX);
00424 return 1;
00425 }
00426
00427 if(!pcm_history_float)
00428 {
00429 pcm_history_float = new float*[asset->channels];
00430 for(int i = 0; i < asset->channels; i++)
00431 pcm_history_float[i] = new float[HISTORY_MAX];
00432 history_start = 0;
00433 history_size = 0;
00434 }
00435
00436
00437 if(file->current_sample < history_start ||
00438 file->current_sample > history_start + history_size)
00439 {
00440 history_size = 0;
00441 history_start = file->current_sample;
00442 decode_start = file->current_sample;
00443 decode_len = len;
00444 }
00445 else
00446
00447 if(file->current_sample + len > history_start + history_size)
00448 {
00449 if(file->current_sample + len > history_start + HISTORY_MAX)
00450 {
00451 int diff = file->current_sample + len - (history_start + HISTORY_MAX);
00452 for(int i = 0; i < asset->channels; i++)
00453 {
00454 float *temp = pcm_history_float[i];
00455
00456
00457
00458
00459 bcopy(temp, temp + diff, (HISTORY_MAX - diff) * sizeof(float));
00460 }
00461 history_start += diff;
00462 history_size -= diff;
00463 }
00464
00465
00466 decode_start = history_start + history_size;
00467 decode_len = file->current_sample + len - (history_start + history_size);
00468 }
00469
00470
00471
00472 if(history_start + history_size != ov_pcm_tell(&vf))
00473 {
00474
00475 ov_pcm_seek(&vf, history_start + history_size);
00476 }
00477
00478 while(accumulation < decode_len)
00479 {
00480 int result = ov_read_float(&vf,
00481 &vorbis_output,
00482 decode_len - accumulation,
00483 &bitstream);
00484
00485 if(!result) break;
00486
00487 for(int i = 0; i < asset->channels; i++)
00488 {
00489 float *output = pcm_history_float[i] + history_size;
00490 float *input = vorbis_output[i];
00491
00492
00493 bcopy(input, output, result * sizeof(float));
00494 }
00495 history_size += result;
00496 accumulation += result;
00497 }
00498
00499
00500
00501
00502
00503
00504 float *input = pcm_history_float[file->current_channel] +
00505 file->current_sample -
00506 history_start;
00507
00508
00509 bcopy(input, buffer, len * sizeof(float));
00510
00511
00512
00513
00514
00515
00516
00517 return 0;
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529 VorbisConfigAudio::VorbisConfigAudio(BC_WindowBase *parent_window,
00530 Asset *asset)
00531 : BC_Window(PROGRAM_NAME ": Audio Compression",
00532 parent_window->get_abs_cursor_x(1),
00533 parent_window->get_abs_cursor_y(1),
00534 350,
00535 170,
00536 -1,
00537 -1,
00538 0,
00539 0,
00540 1)
00541 {
00542 this->parent_window = parent_window;
00543 this->asset = asset;
00544 }
00545
00546 VorbisConfigAudio::~VorbisConfigAudio()
00547 {
00548 }
00549
00550 int VorbisConfigAudio::create_objects()
00551 {
00552 int x = 10, y = 10;
00553 int x1 = 150;
00554 char string[BCTEXTLEN];
00555
00556 add_tool(fixed_bitrate = new VorbisFixedBitrate(x, y, this));
00557 add_tool(variable_bitrate = new VorbisVariableBitrate(x1, y, this));
00558
00559 y += 30;
00560 sprintf(string, "%d", asset->vorbis_min_bitrate);
00561 add_tool(new BC_Title(x, y, _("Min bitrate:")));
00562 add_tool(new VorbisMinBitrate(x1, y, this, string));
00563
00564 y += 30;
00565 add_tool(new BC_Title(x, y, _("Avg bitrate:")));
00566 sprintf(string, "%d", asset->vorbis_bitrate);
00567 add_tool(new VorbisAvgBitrate(x1, y, this, string));
00568
00569 y += 30;
00570 add_tool(new BC_Title(x, y, _("Max bitrate:")));
00571 sprintf(string, "%d", asset->vorbis_max_bitrate);
00572 add_tool(new VorbisMaxBitrate(x1, y, this, string));
00573
00574
00575 add_subwindow(new BC_OKButton(this));
00576 show_window();
00577 flush();
00578 return 0;
00579 }
00580
00581 int VorbisConfigAudio::close_event()
00582 {
00583 set_done(0);
00584 return 1;
00585 }
00586
00587
00588
00589
00590
00591 VorbisFixedBitrate::VorbisFixedBitrate(int x, int y, VorbisConfigAudio *gui)
00592 : BC_Radial(x, y, !gui->asset->vorbis_vbr, _("Fixed bitrate"))
00593 {
00594 this->gui = gui;
00595 }
00596 int VorbisFixedBitrate::handle_event()
00597 {
00598 gui->asset->vorbis_vbr = 0;
00599 gui->variable_bitrate->update(0);
00600 return 1;
00601 }
00602
00603 VorbisVariableBitrate::VorbisVariableBitrate(int x, int y, VorbisConfigAudio *gui)
00604 : BC_Radial(x, y, gui->asset->vorbis_vbr, _("Variable bitrate"))
00605 {
00606 this->gui = gui;
00607 }
00608 int VorbisVariableBitrate::handle_event()
00609 {
00610 gui->asset->vorbis_vbr = 1;
00611 gui->fixed_bitrate->update(0);
00612 return 1;
00613 }
00614
00615
00616 VorbisMinBitrate::VorbisMinBitrate(int x,
00617 int y,
00618 VorbisConfigAudio *gui,
00619 char *text)
00620 : BC_TextBox(x, y, 180, 1, text)
00621 {
00622 this->gui = gui;
00623 }
00624 int VorbisMinBitrate::handle_event()
00625 {
00626 gui->asset->vorbis_min_bitrate = atol(get_text());
00627 return 1;
00628 }
00629
00630
00631
00632 VorbisMaxBitrate::VorbisMaxBitrate(int x,
00633 int y,
00634 VorbisConfigAudio *gui,
00635 char *text)
00636 : BC_TextBox(x, y, 180, 1, text)
00637 {
00638 this->gui = gui;
00639 }
00640 int VorbisMaxBitrate::handle_event()
00641 {
00642 gui->asset->vorbis_max_bitrate = atol(get_text());
00643 return 1;
00644 }
00645
00646
00647
00648 VorbisAvgBitrate::VorbisAvgBitrate(int x, int y, VorbisConfigAudio *gui, char *text)
00649 : BC_TextBox(x, y, 180, 1, text)
00650 {
00651 this->gui = gui;
00652 }
00653 int VorbisAvgBitrate::handle_event()
00654 {
00655 gui->asset->vorbis_bitrate = atol(get_text());
00656 return 1;
00657 }
00658
00659
00660
00661