libmp3splt
|
00001 /********************************************************** 00002 * 00003 * libmp3splt -- library based on mp3splt, 00004 * for mp3/ogg splitting without decoding 00005 * 00006 * Copyright (c) 2002-2005 M. Trotta - <mtrotta@users.sourceforge.net> 00007 * Copyright (c) 2005-2011 Alexandru Munteanu - <io_fx@yahoo.fr> 00008 * 00009 * Large parts of this files have been copied from the 'vcut' 1.6 00010 * program provided with 'vorbis-tools' : 00011 * vcut (c) 2000-2001 Michael Smith <msmith@xiph.org> 00012 * 00013 * Some parts from a more recent version of vcut : 00014 * (c) 2008 Michael Gold <mgold@ncf.ca> 00015 * 00016 * http://mp3splt.sourceforge.net 00017 * 00018 *********************************************************/ 00019 00020 /********************************************************** 00021 * 00022 * This program is free software; you can redistribute it and/or 00023 * modify it under the terms of the GNU General Public License 00024 * as published by the Free Software Foundation; either version 2 00025 * of the License, or (at your option) any later version. 00026 * 00027 * This program is distributed in the hope that it will be useful, 00028 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00029 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00030 * GNU General Public License for more details. 00031 * 00032 * You should have received a copy of the GNU General Public License 00033 * along with this program; if not, write to the Free Software 00034 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00035 * 02111-1307, 00036 * USA. 00037 * 00038 *********************************************************/ 00039 00045 #include <time.h> 00046 #include <string.h> 00047 #include <math.h> 00048 #include <locale.h> 00049 00050 #ifdef __WIN32__ 00051 #include <io.h> 00052 #include <fcntl.h> 00053 #endif 00054 00055 #include "splt.h" 00056 #include "ogg.h" 00057 00058 #define FIRST_GRANPOS 1 00059 00069 /****************************/ 00070 /* some function prototypes */ 00071 00072 splt_ogg_state *splt_ogg_info(FILE *in, splt_state *state, int *error); 00073 int splt_ogg_scan_silence(splt_state *state, short seconds, 00074 float threshold, float min, short output, ogg_page *page, 00075 ogg_int64_t granpos, int *error, long first_cut_granpos); 00076 00077 /****************************/ 00078 /* ogg utils */ 00079 00080 FILE *splt_ogg_open_file_read(splt_state *state, const char *filename, int *error) 00081 { 00082 FILE *file_input = NULL; 00083 00084 if (strcmp(filename,"o-") == 0) 00085 { 00086 file_input = stdin; 00087 #ifdef __WIN32__ 00088 _setmode(fileno(file_input), _O_BINARY); 00089 #endif 00090 } 00091 else 00092 { 00093 //we open the file 00094 file_input = splt_io_fopen(filename, "rb"); 00095 if (file_input == NULL) 00096 { 00097 splt_e_set_strerror_msg_with_data(state, filename); 00098 *error = SPLT_ERROR_CANNOT_OPEN_FILE; 00099 } 00100 } 00101 00102 return file_input; 00103 } 00104 00105 //gets the mp3 info and puts it in the state 00106 void splt_ogg_get_info(splt_state *state, FILE *file_input, int *error) 00107 { 00108 //checks if valid ogg file 00109 state->codec = splt_ogg_info(file_input, state, error); 00110 00111 //if error 00112 if ((*error < 0) || (state->codec == NULL)) 00113 { 00114 return; 00115 } 00116 else 00117 { 00118 //put file infos to client 00119 if (! splt_o_messages_locked(state)) 00120 { 00121 splt_ogg_state *oggstate = state->codec; 00122 00123 char ogg_infos[1024] = { '\0' }; 00124 snprintf(ogg_infos, 1023, 00125 _(" info: Ogg Vorbis Stream - %ld - %ld Kb/s - %d channels"), 00126 oggstate->vd->vi->rate, oggstate->vd->vi->bitrate_nominal/1024, 00127 oggstate->vd->vi->channels); 00128 00129 char total_time[256] = { '\0' }; 00130 int total_seconds = (int) splt_t_get_total_time(state) / 100; 00131 int minutes = total_seconds / 60; 00132 int seconds = total_seconds % 60; 00133 snprintf(total_time, 255, _(" - Total time: %dm.%02ds"), minutes, seconds%60); 00134 00135 splt_c_put_info_message_to_client(state, "%s%s\n", ogg_infos, total_time); 00136 } 00137 } 00138 } 00139 00140 static char *splt_ogg_trackstring(int number, int *error) 00141 { 00142 char *track = NULL; 00143 00144 if (number > 0) 00145 { 00146 int len = 0, i; 00147 len = ((int) (log10((double) (number)))) + 1; 00148 00149 if ((track = malloc(len + 1))==NULL) 00150 { 00151 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00152 return NULL; 00153 } 00154 memset(track, 0, len + 1); 00155 for (i=len-1; i >= 0; i--) 00156 { 00157 track[i] = ((number%10) | 0x30); 00158 number /= 10; 00159 } 00160 } 00161 00162 return track; 00163 } 00164 00165 //saves a packet 00166 static splt_v_packet *splt_ogg_save_packet(ogg_packet *packet, int *error) 00167 { 00168 splt_v_packet *p = NULL; 00169 00170 //if we have no header, we will have bytes < 0 00171 p = malloc(sizeof(splt_v_packet)); 00172 if (!p) 00173 { 00174 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00175 return p; 00176 } 00177 00178 p->length = packet->bytes; 00179 p->packet = malloc(p->length); 00180 if (! p->packet) 00181 { 00182 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00183 free(p); 00184 p = NULL; 00185 return p; 00186 } 00187 memcpy(p->packet, packet->packet, p->length); 00188 00189 return p; 00190 } 00191 00192 //frees a packet 00193 static void splt_ogg_free_packet(splt_v_packet **p) 00194 { 00195 if (p) 00196 { 00197 if (*p) 00198 { 00199 if((*p)->packet) 00200 { 00201 free((*p)->packet); 00202 (*p)->packet = NULL; 00203 } 00204 free(*p); 00205 *p = NULL; 00206 } 00207 } 00208 } 00209 00210 static long splt_ogg_get_blocksize(splt_ogg_state *oggstate, 00211 vorbis_info *vi, ogg_packet *op) 00212 { 00213 //if this < 0, there is a problem 00214 int this = vorbis_packet_blocksize(vi, op); 00215 int ret = (this + oggstate->prevW)/4; 00216 00217 oggstate->prevW = this; 00218 00219 return ret; 00220 } 00221 00222 static int splt_ogg_update_sync(splt_state *state, ogg_sync_state *sync_in, 00223 FILE *f, int *error) 00224 { 00225 char *buffer = ogg_sync_buffer(sync_in, SPLT_OGG_BUFSIZE); 00226 if (!buffer) 00227 { 00228 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00229 return -1; 00230 } 00231 int bytes = fread(buffer,1,SPLT_OGG_BUFSIZE,f); 00232 00233 if (ogg_sync_wrote(sync_in, bytes) != 0) 00234 { 00235 splt_e_set_error_data(state, splt_t_get_filename_to_split(state)); 00236 *error = SPLT_ERROR_INVALID; 00237 return -1; 00238 } 00239 00240 return bytes; 00241 } 00242 00243 /* Returns 0 for success, or -1 on failure. */ 00244 static int splt_ogg_write_pages_to_file(splt_state *state, 00245 ogg_stream_state *stream, FILE *file, int flush, int *error, 00246 const char *output_fname) 00247 { 00248 ogg_page page; 00249 00250 if (flush) 00251 { 00252 while (ogg_stream_flush(stream, &page)) 00253 { 00254 if (splt_io_fwrite(state, page.header, 1, page.header_len, file) < page.header_len) 00255 { 00256 goto write_error; 00257 } 00258 if (splt_io_fwrite(state, page.body, 1, page.body_len, file) < page.body_len) 00259 { 00260 goto write_error; 00261 } 00262 } 00263 } 00264 else 00265 { 00266 while (ogg_stream_pageout(stream, &page)) 00267 { 00268 if (splt_io_fwrite(state, page.header,1,page.header_len, file) < page.header_len) 00269 { 00270 goto write_error; 00271 } 00272 if (splt_io_fwrite(state, page.body,1,page.body_len, file) < page.body_len) 00273 { 00274 goto write_error; 00275 } 00276 } 00277 } 00278 00279 return 0; 00280 00281 write_error: 00282 splt_e_set_error_data(state, output_fname); 00283 *error = SPLT_ERROR_CANT_WRITE_TO_OUTPUT_FILE; 00284 return -1; 00285 } 00286 00287 static void splt_ogg_submit_headers_to_stream(ogg_stream_state *stream, 00288 splt_ogg_state *oggstate) 00289 { 00290 int i; 00291 for(i=0;i<3;i++) 00292 { 00293 ogg_packet p; 00294 p.bytes = oggstate->headers[i]->length; 00295 p.packet = oggstate->headers[i]->packet; 00296 p.b_o_s = ((i==0)?1:0); 00297 p.e_o_s = 0; 00298 p.granulepos=0; 00299 00300 ogg_stream_packetin(stream, &p); 00301 } 00302 } 00303 00304 /* Full cleanup of internal state and vorbis/ogg structures */ 00305 static void splt_ogg_v_free(splt_ogg_state *oggstate) 00306 { 00307 if(oggstate) 00308 { 00309 if(oggstate->packets) 00310 { 00311 splt_ogg_free_packet(&oggstate->packets[0]); 00312 splt_ogg_free_packet(&oggstate->packets[1]); 00313 free(oggstate->packets); 00314 oggstate->packets = NULL; 00315 } 00316 if(oggstate->headers) 00317 { 00318 int i; 00319 for(i=0; i < 3; i++) 00320 { 00321 splt_ogg_free_packet(&oggstate->headers[i]); 00322 } 00323 free(oggstate->headers); 00324 oggstate->headers = NULL; 00325 } 00326 vorbis_comment_clear(&oggstate->vc); 00327 if(oggstate->vb) 00328 { 00329 vorbis_block_clear(oggstate->vb); 00330 free(oggstate->vb); 00331 oggstate->vb = NULL; 00332 } 00333 if(oggstate->vd) 00334 { 00335 vorbis_dsp_clear(oggstate->vd); 00336 free(oggstate->vd); 00337 oggstate->vd = NULL; 00338 } 00339 //only free the input if different from stdin 00340 if(oggstate->stream_in && oggstate->in != stdin) 00341 { 00342 ogg_stream_clear(oggstate->stream_in); 00343 free(oggstate->stream_in); 00344 oggstate->stream_in = NULL; 00345 } 00346 if(oggstate->sync_in) 00347 { 00348 ogg_sync_clear(oggstate->sync_in); 00349 free(oggstate->sync_in); 00350 oggstate->sync_in = NULL; 00351 } 00352 if (oggstate->vi) 00353 { 00354 vorbis_info_clear(oggstate->vi); 00355 free(oggstate->vi); 00356 oggstate->vi = NULL; 00357 } 00358 free(oggstate); 00359 oggstate = NULL; 00360 } 00361 } 00362 00363 static splt_ogg_state *splt_ogg_v_new(int *error) 00364 { 00365 splt_ogg_state *oggstate = NULL; 00366 00367 if ((oggstate = malloc(sizeof(splt_ogg_state)))==NULL) 00368 { 00369 goto error; 00370 } 00371 memset(oggstate, 0, sizeof(splt_ogg_state)); 00372 if ((oggstate->sync_in = malloc(sizeof(ogg_sync_state)))==NULL) 00373 { 00374 goto error; 00375 } 00376 if ((oggstate->stream_in = malloc(sizeof(ogg_stream_state)))==NULL) 00377 { 00378 goto error; 00379 } 00380 if ((oggstate->vd = malloc(sizeof(vorbis_dsp_state)))==NULL) 00381 { 00382 goto error; 00383 } 00384 if ((oggstate->vi = malloc(sizeof(vorbis_info)))==NULL) 00385 { 00386 goto error; 00387 } 00388 if ((oggstate->vb = malloc(sizeof(vorbis_block)))==NULL) 00389 { 00390 goto error; 00391 } 00392 if ((oggstate->headers = malloc(sizeof(splt_v_packet)*3))==NULL) 00393 { 00394 goto error; 00395 } 00396 memset(oggstate->headers, 0, sizeof(splt_v_packet)*3); 00397 if ((oggstate->packets = malloc(sizeof(splt_v_packet)*2))==NULL) 00398 { 00399 goto error; 00400 } 00401 memset(oggstate->packets, 0, sizeof(splt_v_packet)*2); 00402 00403 return oggstate; 00404 00405 error: 00406 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00407 splt_ogg_v_free(oggstate); 00408 return NULL; 00409 } 00410 00411 //frees the splt_ogg_state structure, 00412 //used in the splt_t_state_free() function 00413 void splt_ogg_state_free(splt_state *state) 00414 { 00415 splt_ogg_state *oggstate = state->codec; 00416 if (oggstate) 00417 { 00418 ov_clear(&oggstate->vf); 00419 splt_ogg_v_free(oggstate); 00420 state->codec = NULL; 00421 } 00422 } 00423 00424 /****************************/ 00425 /* ogg tags */ 00426 00427 //puts tags in vc 00428 //what happens if 'vorbis_comment_add_tag(..)' fails ? 00429 //- ask vorbis developers 00430 static void splt_ogg_v_comment(splt_state *state, vorbis_comment *vc, char *artist, 00431 char *album, char *title, char *tracknum, char *date, char *genre, char *comment, 00432 int *error) 00433 { 00434 if (splt_o_get_int_option(state, SPLT_OPT_TAGS) == SPLT_TAGS_ORIGINAL_FILE && 00435 state->original_tags.tags_version == 0) 00436 { 00437 return; 00438 } 00439 00440 if (title != NULL) 00441 { 00442 vorbis_comment_add_tag(vc, "title", title); 00443 } 00444 if (artist != NULL) 00445 { 00446 vorbis_comment_add_tag(vc, "artist", artist); 00447 } 00448 if (album != NULL) 00449 { 00450 vorbis_comment_add_tag(vc, "album", album); 00451 } 00452 if (date != NULL) 00453 { 00454 if (strlen(date) > 0) 00455 { 00456 vorbis_comment_add_tag(vc, "date", date); 00457 } 00458 } 00459 if (genre != NULL) 00460 { 00461 vorbis_comment_add_tag(vc, "genre", genre); 00462 } 00463 if (tracknum != NULL) 00464 { 00465 vorbis_comment_add_tag(vc, "tracknumber", tracknum); 00466 } 00467 if (comment != NULL) 00468 { 00469 vorbis_comment_add_tag(vc, "comment", comment); 00470 } 00471 } 00472 00473 //macro used only in the following function splt_ogg_get_original_tags 00474 #define OGG_VERIFY_ERROR() \ 00475 if (err != SPLT_OK) \ 00476 { \ 00477 *tag_error = err; \ 00478 return; \ 00479 }; 00480 //get the original ogg tags and put them in the state 00481 void splt_ogg_get_original_tags(const char *filename, 00482 splt_state *state, int *tag_error) 00483 { 00484 splt_ogg_state *oggstate = state->codec; 00485 00486 vorbis_comment *vc_local = NULL; 00487 vc_local = ov_comment(&oggstate->vf,-1); 00488 int err = SPLT_OK; 00489 00490 char *a = NULL,*t = NULL,*al = NULL,*da = NULL, *g = NULL,*tr = NULL, 00491 *com = NULL; 00492 00493 int has_tags = SPLT_FALSE; 00494 00495 a = vorbis_comment_query(vc_local, "artist",0); 00496 if (a != NULL) 00497 { 00498 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_ARTIST, a); 00499 has_tags = SPLT_TRUE; 00500 OGG_VERIFY_ERROR(); 00501 } 00502 00503 t = vorbis_comment_query(vc_local, "title",0); 00504 if (t != NULL) 00505 { 00506 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_TITLE, t); 00507 has_tags = SPLT_TRUE; 00508 OGG_VERIFY_ERROR(); 00509 } 00510 00511 al = vorbis_comment_query(vc_local, "album",0); 00512 if (al != NULL) 00513 { 00514 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_ALBUM, al); 00515 has_tags = SPLT_TRUE; 00516 OGG_VERIFY_ERROR(); 00517 } 00518 00519 da = vorbis_comment_query(vc_local, "date",0); 00520 if (da != NULL) 00521 { 00522 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_YEAR, da); 00523 has_tags = SPLT_TRUE; 00524 OGG_VERIFY_ERROR(); 00525 } 00526 00527 g = vorbis_comment_query(vc_local, "genre",0); 00528 if (g != NULL) 00529 { 00530 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_GENRE, g); 00531 has_tags = SPLT_TRUE; 00532 OGG_VERIFY_ERROR(); 00533 } 00534 00535 tr = vorbis_comment_query(vc_local, "tracknumber",0); 00536 if (tr != NULL) 00537 { 00538 int track = atoi(tr); 00539 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_TRACK, &track); 00540 has_tags = SPLT_TRUE; 00541 OGG_VERIFY_ERROR(); 00542 } 00543 00544 com = vorbis_comment_query(vc_local, "comment",0); 00545 if (com != NULL) 00546 { 00547 err = splt_tu_set_original_tags_field(state, SPLT_TAGS_COMMENT, com); 00548 has_tags = SPLT_TRUE; 00549 OGG_VERIFY_ERROR(); 00550 } 00551 00552 splt_tu_set_original_tags_field(state, SPLT_TAGS_VERSION, &has_tags); 00553 } 00554 00555 //puts the ogg tags 00556 void splt_ogg_put_tags(splt_state *state, int *error) 00557 { 00558 splt_d_print_debug(state,"Setting ogg tags ...\n"); 00559 00560 splt_ogg_state *oggstate = state->codec; 00561 00562 vorbis_comment_clear(&oggstate->vc); 00563 00564 if (splt_o_get_int_option(state, SPLT_OPT_TAGS) == SPLT_NO_TAGS) 00565 { 00566 return; 00567 } 00568 00569 splt_tags *tags = splt_tu_get_current_tags(state); 00570 if (!tags) 00571 { 00572 return; 00573 } 00574 00575 char *track_string = splt_ogg_trackstring(tags->track, error); 00576 if (*error < 0) { return; } 00577 00578 char *artist_or_performer = splt_tu_get_artist_or_performer_ptr(tags); 00579 00580 vorbis_comment_init(&oggstate->vc); 00581 00582 splt_ogg_v_comment(state, &oggstate->vc, 00583 artist_or_performer, tags->album, tags->title, track_string, 00584 tags->year, tags->genre, tags->comment, error); 00585 00586 free(track_string); 00587 track_string = NULL; 00588 } 00589 00590 /****************************/ 00591 /* ogg infos */ 00592 00593 //Pull out and save the 3 header packets from the input file. 00594 //-returns -1 if error and error is set in '*error' 00595 static int splt_ogg_process_headers(splt_ogg_state *oggstate, int *error) 00596 { 00597 ogg_page page; 00598 ogg_packet packet; 00599 int bytes = 0; 00600 int i = 0; 00601 char *buffer = NULL; 00602 00603 ogg_sync_init(oggstate->sync_in); 00604 00605 vorbis_info_init(oggstate->vi); 00606 00607 int result = 0; 00608 while ((result = ogg_sync_pageout(oggstate->sync_in, &page))!=1) 00609 { 00610 buffer = ogg_sync_buffer(oggstate->sync_in, SPLT_OGG_BUFSIZE); 00611 if (buffer == NULL) 00612 { 00613 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00614 return -1; 00615 } 00616 bytes = fread(buffer, 1, SPLT_OGG_BUFSIZE, oggstate->in); 00617 if (bytes <= 0) 00618 { 00619 goto error_invalid_file; 00620 } 00621 if (ogg_sync_wrote(oggstate->sync_in, bytes) != 0) 00622 { 00623 goto error_invalid_file; 00624 } 00625 } 00626 00627 oggstate->serial = ogg_page_serialno(&page); 00628 //how to handle alloc memory problem ? 00629 ogg_stream_init(oggstate->stream_in, oggstate->serial); 00630 if(ogg_stream_pagein(oggstate->stream_in, &page) < 0) 00631 { 00632 goto error_invalid_file; 00633 } 00634 //ogg doc says 'usually this will not be a fatal error' 00635 if(ogg_stream_packetout(oggstate->stream_in, &packet)!=1) 00636 { 00637 goto error_invalid_file; 00638 } 00639 //if bad header 00640 if(vorbis_synthesis_headerin(oggstate->vi, &oggstate->vc, &packet) < 0) 00641 { 00642 goto error_invalid_file; 00643 } 00644 int packet_err = SPLT_OK; 00645 oggstate->headers[0] = splt_ogg_save_packet(&packet, &packet_err); 00646 if (packet_err < 0) 00647 { 00648 goto error; 00649 } 00650 00651 i=0; 00652 while(i<2) 00653 { 00654 while(i<2) 00655 { 00656 int res = ogg_sync_pageout(oggstate->sync_in, &page); 00657 //res == -1 is NOT a fatal error 00658 if(res == 0) 00659 { 00660 break; 00661 } 00662 00663 if(res == 1) 00664 { 00665 if (ogg_stream_pagein(oggstate->stream_in, &page) < 0) 00666 { 00667 goto error_invalid_file; 00668 } 00669 while(i<2) 00670 { 00671 res = ogg_stream_packetout(oggstate->stream_in, &packet); 00672 if(res==0) 00673 { 00674 break; 00675 } 00676 //ogg doc says 'usually this will not be a fatal error' 00677 if(res<0) 00678 { 00679 goto error_invalid_file; 00680 } 00681 00682 oggstate->headers[i+1] = splt_ogg_save_packet(&packet, &packet_err); 00683 if (packet_err < 0) 00684 { 00685 goto error; 00686 } 00687 //if bad header 00688 if (vorbis_synthesis_headerin(oggstate->vi,&oggstate->vc,&packet) < 0) 00689 { 00690 goto error_invalid_file; 00691 } 00692 i++; 00693 } 00694 } 00695 } 00696 00697 buffer=ogg_sync_buffer(oggstate->sync_in, SPLT_OGG_BUFSIZE); 00698 if (buffer == NULL) 00699 { 00700 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 00701 goto error; 00702 } 00703 bytes=fread(buffer,1,SPLT_OGG_BUFSIZE,oggstate->in); 00704 00705 if(bytes == 0 && i < 2) 00706 { 00707 goto error_invalid_file; 00708 } 00709 if (ogg_sync_wrote(oggstate->sync_in, bytes) != 0) 00710 { 00711 *error = SPLT_ERROR_INVALID; 00712 goto error; 00713 } 00714 } 00715 00716 return 0; 00717 00718 error_invalid_file: 00719 *error = SPLT_ERROR_INVALID; 00720 error: 00721 return -1; 00722 } 00723 00724 //returns ogg info 00725 splt_ogg_state *splt_ogg_info(FILE *in, splt_state *state, int *error) 00726 { 00727 splt_ogg_state *oggstate = state->codec; 00728 00729 oggstate = splt_ogg_v_new(error); 00730 if (oggstate == NULL) { return NULL; } 00731 00732 char *filename = splt_t_get_filename_to_split(state); 00733 00734 oggstate->in = in; 00735 oggstate->end = 0; 00736 00737 oggstate->total_blocksize = -1; 00738 oggstate->first_granpos = 0; 00739 00740 //open the file 00741 if (oggstate->in != stdin) 00742 { 00743 int ret = ov_open(oggstate->in, &oggstate->vf, NULL, 0); 00744 if(ret < 0) 00745 { 00746 splt_e_set_error_data(state,filename); 00747 switch (ret) 00748 { 00749 case OV_EREAD: 00750 *error = SPLT_ERROR_WHILE_READING_FILE; 00751 break; 00752 default: 00753 *error = SPLT_ERROR_INVALID; 00754 break; 00755 } 00756 splt_ogg_v_free(oggstate); 00757 return NULL; 00758 } 00759 //go at the start of the file 00760 rewind(oggstate->in); 00761 } 00762 00763 /* Read headers in, and save them */ 00764 if (splt_ogg_process_headers(oggstate, error) == -1) 00765 { 00766 if (*error == SPLT_ERROR_INVALID) 00767 { 00768 splt_e_set_error_data(state,filename); 00769 } 00770 splt_ogg_v_free(oggstate); 00771 return NULL; 00772 } 00773 00774 if (oggstate->in != stdin) 00775 { 00776 //read total time 00777 double total_time = ov_time_total(&oggstate->vf, -1) * 100; 00778 splt_t_set_total_time(state, total_time); 00779 oggstate->len = (ogg_int64_t) (oggstate->vi->rate * total_time); 00780 } 00781 00782 oggstate->cutpoint_begin = 0; 00783 //what to do if no memory ? 00784 //- we must free memory from 'vorbis_synthesis_init' ? 00785 vorbis_synthesis_init(oggstate->vd,oggstate->vi); 00786 vorbis_block_init(oggstate->vd,oggstate->vb); 00787 00788 srand(time(NULL)); 00789 00790 return oggstate; 00791 } 00792 00793 static long splt_ogg_compute_first_granulepos(splt_state *state, splt_ogg_state *oggstate, ogg_packet *packet, int bs) 00794 { 00795 long first_granpos = 0; 00796 00797 if (packet->granulepos >= 0) 00798 { 00799 /*fprintf(stdout,"oggstate->total_blocksize + bs = %ld\n",oggstate->total_blocksize + bs); 00800 fprintf(stdout,"packet granulepos = %ld\n",packet->granulepos); 00801 fflush(stdout);*/ 00802 00803 if ((packet->granulepos > oggstate->total_blocksize + bs) && 00804 (oggstate->total_blocksize > 0) && 00805 !packet->e_o_s && 00806 (oggstate->first_granpos == 0)) 00807 { 00808 first_granpos = packet->granulepos; 00809 oggstate->first_granpos = first_granpos; 00810 splt_c_put_info_message_to_client(state, 00811 _(" warning: unexpected position in ogg vorbis stream - split from 0.0 to EOF to fix.\n")); 00812 } 00813 00814 oggstate->total_blocksize = packet->granulepos; 00815 } 00816 else if (oggstate->total_blocksize == -1) 00817 { 00818 oggstate->total_blocksize = 0; 00819 } 00820 else { 00821 oggstate->total_blocksize += bs; 00822 /*fprintf(stdout,"blocksize = %d, total = %ld\n", bs, oggstate->total_blocksize); 00823 fflush(stdout);*/ 00824 } 00825 00826 return first_granpos; 00827 } 00828 00829 /****************************/ 00830 /* ogg split */ 00831 00832 /* Read stream until we get to the appropriate cut point. 00833 * 00834 * We need to do the following: 00835 * - Save the final two packets in the stream to temporary buffers. 00836 * These two packets then become the first two packets in the 2nd stream 00837 * (we need two packets because of the overlap-add nature of vorbis). 00838 * - For each packet, buffer it (it could be the 2nd last packet, we don't 00839 * know yet (but we could optimise this decision based on known maximum 00840 * block sizes, and call get_blocksize(), because this updates internal 00841 * state needed for sample-accurate block size calculations. 00842 */ 00843 static int splt_ogg_find_begin_cutpoint(splt_state *state, splt_ogg_state *oggstate, 00844 FILE *in, ogg_int64_t cutpoint, int *error, const char *filename, 00845 int save_end_point) 00846 { 00847 int eos=0; 00848 ogg_page page; 00849 ogg_packet packet; 00850 ogg_int64_t granpos, prevgranpos; 00851 00852 granpos = prevgranpos = 0; 00853 00854 int packet_err = SPLT_OK; 00855 00856 cutpoint += oggstate->first_granpos; 00857 00858 while (!eos) 00859 { 00860 while (!eos) 00861 { 00862 int result = ogg_sync_pageout(oggstate->sync_in, &page); 00863 00864 //result == -1 is NOT a fatal error 00865 if (result==0) 00866 { 00867 break; 00868 } 00869 else 00870 { 00871 //result==1 means that we have a good page 00872 if (result > 0) 00873 { 00874 granpos = ogg_page_granulepos(&page); 00875 00876 /*long page_number = ogg_page_pageno(&page); 00877 fprintf(stdout,"page number = %ld, granule position = %ld, cutpoint = %ld\n", 00878 page_number, granpos, cutpoint); 00879 fflush(stdout);*/ 00880 00881 if (ogg_stream_pagein(oggstate->stream_in, &page) == -1) 00882 { 00883 *error = SPLT_ERROR_INVALID; 00884 return -1; 00885 } 00886 00887 //for a broken ogg file with no 00888 //header, we have granpos > cutpoint the first time 00889 if (granpos < cutpoint) 00890 { 00891 while (1) 00892 { 00893 result = ogg_stream_packetout(oggstate->stream_in, &packet); 00894 00895 /*fprintf(stdout,"packet number = %ld packet granulepos = %ld\n", 00896 packet.packetno, packet.granulepos); 00897 fflush(stdout);*/ 00898 00899 if (result == 0) 00900 { 00901 break; 00902 } 00903 00904 //skip headers for overlap split - already processed once 00905 if (granpos == 0) 00906 { 00907 continue; 00908 } 00909 00910 if (result != -1) 00911 { 00912 int bs = splt_ogg_get_blocksize(oggstate, oggstate->vi, &packet); 00913 00914 cutpoint += splt_ogg_compute_first_granulepos(state, oggstate, &packet, bs); 00915 00916 /* We need to save the last packet in the first 00917 * stream - but we don't know when we're going 00918 * to get there. So we have to keep every packet 00919 * just in case. 00920 */ 00921 splt_ogg_free_packet(&oggstate->packets[0]); 00922 oggstate->packets[0] = splt_ogg_save_packet(&packet, &packet_err); 00923 if (packet_err < 0) { return -1; } 00924 } 00925 } 00926 00927 prevgranpos = granpos; 00928 } 00929 else 00930 { 00931 eos = 1; 00932 00933 while ((result = ogg_stream_packetout(oggstate->stream_in, &packet)) != 0) 00934 { 00935 //skip headers for overlap split - already processed once 00936 if (granpos == 0) 00937 { 00938 continue; 00939 } 00940 00941 //if == -1, we are out of sync; not a fatal error 00942 if (result != -1) 00943 { 00944 int bs = splt_ogg_get_blocksize(oggstate, oggstate->vi, &packet); 00945 prevgranpos += bs; 00946 00947 long old_first_granpos = oggstate->first_granpos; 00948 long first_granpos = splt_ogg_compute_first_granulepos(state, oggstate, &packet, bs); 00949 cutpoint += first_granpos; 00950 if (first_granpos != 0) 00951 { 00952 eos = 0; 00953 } 00954 if (old_first_granpos == 0) 00955 { 00956 prevgranpos += first_granpos; 00957 } 00958 00959 if (prevgranpos > cutpoint) 00960 { 00961 splt_ogg_free_packet(&oggstate->packets[1]); 00962 oggstate->packets[1] = splt_ogg_save_packet(&packet, &packet_err); 00963 if (packet_err < 0) { return -1; } 00964 eos = 1; 00965 break; 00966 } 00967 00968 splt_ogg_free_packet(&oggstate->packets[0]); 00969 oggstate->packets[0] = splt_ogg_save_packet(&packet, &packet_err); 00970 if (packet_err < 0) { return -1; } 00971 } 00972 } 00973 } 00974 00975 if (ogg_page_eos(&page)) 00976 { 00977 eos = 1; 00978 } 00979 } 00980 } 00981 } 00982 00983 if (!eos) 00984 { 00985 int sync_bytes = splt_ogg_update_sync(state, oggstate->sync_in, in, error); 00986 if (sync_bytes == 0) 00987 { 00988 eos = 1; 00989 } 00990 else if (sync_bytes == -1) 00991 { 00992 return -1; 00993 } 00994 } 00995 } 00996 00997 if (granpos < cutpoint) 00998 { 00999 *error = SPLT_ERROR_BEGIN_OUT_OF_FILE; 01000 return -1; 01001 } 01002 01003 /* Remaining samples in first packet */ 01004 oggstate->initialgranpos = prevgranpos - cutpoint; 01005 oggstate->cutpoint_begin = cutpoint; 01006 01007 return 0; 01008 } 01009 01010 /* Process second stream. 01011 * 01012 * We need to do more packet manipulation here, because we need to calculate 01013 * a new granulepos for every packet, since the old ones are now invalid. 01014 * Start by placing the modified first and second packets into the stream. 01015 * Then just proceed through the stream modifying packno and granulepos for 01016 * each packet, using the granulepos which we track block-by-block. 01017 */ 01018 //Warning ! cutpoint is not the end cutpoint, but the length between the 01019 //begin and the end 01020 static int splt_ogg_find_end_cutpoint(splt_state *state, ogg_stream_state *stream, 01021 FILE *in, FILE *f, ogg_int64_t cutpoint, int adjust, float threshold, 01022 int *error, const char *output_fname, int save_end_point, 01023 double *sec_split_time_length) 01024 { 01025 splt_c_put_progress_text(state,SPLT_PROGRESS_CREATE); 01026 01027 //TODO: eos not set on ripped streams on last split file 01028 01029 //for the progress 01030 int progress_adjust = 1; 01031 01032 splt_ogg_state *oggstate = state->codec; 01033 01034 ogg_packet packet; 01035 ogg_page page; 01036 int eos=0; 01037 int result = 0; 01038 ogg_int64_t page_granpos = 0, current_granpos = 0, prev_granpos = 0; 01039 ogg_int64_t packetnum = 0; /* Should this start from 0 or 2 ? */ 01040 01041 long first_cut_granpos = 0; 01042 01043 if (oggstate->packets[0] && oggstate->packets[1]) 01044 { 01045 // Check if we have the 2 packet, begin can be 0! 01046 packet.bytes = oggstate->packets[0]->length; 01047 packet.packet = oggstate->packets[0]->packet; 01048 packet.b_o_s = 0; 01049 packet.e_o_s = 0; 01050 packet.granulepos = FIRST_GRANPOS; 01051 packet.packetno = packetnum++; 01052 ogg_stream_packetin(stream,&packet); 01053 01054 packet.bytes = oggstate->packets[1]->length; 01055 packet.packet = oggstate->packets[1]->packet; 01056 packet.b_o_s = 0; 01057 packet.e_o_s = 0; 01058 packet.granulepos = oggstate->initialgranpos; 01059 packet.packetno = packetnum++; 01060 ogg_stream_packetin(stream,&packet); 01061 01062 if (ogg_stream_flush(stream, &page)!=0) 01063 { 01064 if (splt_io_fwrite(state, page.header,1,page.header_len,f) < page.header_len) 01065 { 01066 goto write_error; 01067 } 01068 if (splt_io_fwrite(state, page.body,1,page.body_len,f) < page.body_len) 01069 { 01070 goto write_error; 01071 } 01072 } 01073 01074 while (ogg_stream_flush(stream, &page) != 0) 01075 { 01076 // Might this happen for _really_ high bitrate modes, if we're 01077 // spectacularly unlucky? Doubt it, but let's check for it just 01078 // in case. 01079 // 01080 //fprintf(stderr, 'Warning: First audio packet didn't fit into page. File may not decode correctly\n")' 01081 if (splt_io_fwrite(state, page.header,1,page.header_len,f) < page.header_len) 01082 { 01083 goto write_error; 01084 } 01085 if (splt_io_fwrite(state, page.body,1,page.body_len,f) < page.body_len) 01086 { 01087 goto write_error; 01088 } 01089 } 01090 } 01091 //added because packetno = 3 was never written 01092 else 01093 { 01094 if (oggstate->packets[1]) 01095 { 01096 packet.bytes = oggstate->packets[1]->length; 01097 packet.packet = oggstate->packets[1]->packet; 01098 packet.b_o_s = 0; 01099 packet.e_o_s = 0; 01100 packet.granulepos = FIRST_GRANPOS; 01101 packet.packetno = packetnum++; 01102 ogg_stream_packetin(stream, &packet); 01103 01104 if (ogg_stream_flush(stream, &page)!=0) 01105 { 01106 if (splt_io_fwrite(state, page.header,1,page.header_len,f) < page.header_len) 01107 { 01108 goto write_error; 01109 } 01110 if (splt_io_fwrite(state, page.body,1,page.body_len,f) < page.body_len) 01111 { 01112 goto write_error; 01113 } 01114 } 01115 } 01116 01117 oggstate->initialgranpos = FIRST_GRANPOS; 01118 } 01119 01120 current_granpos = oggstate->initialgranpos; 01121 01122 int packet_err = SPLT_OK; 01123 01124 while (!eos) 01125 { 01126 while (!eos) 01127 { 01128 result = ogg_sync_pageout(oggstate->sync_in, &page); 01129 01130 //result == -1 is NOT a fatal error 01131 if (result==0) 01132 { 01133 break; 01134 } 01135 else 01136 { 01137 if (result != -1) 01138 { 01139 page_granpos = ogg_page_granulepos(&page) - oggstate->cutpoint_begin; 01140 01141 if (ogg_page_eos(&page)) 01142 { 01143 eos = 1; 01144 } 01145 01146 if (ogg_stream_pagein(oggstate->stream_in, &page) == -1) 01147 { 01148 *error = SPLT_ERROR_INVALID; 01149 return -1; 01150 } 01151 01152 // fprintf(stdout, "page_granpos = %ld\n", page_granpos - first_cut_granpos); 01153 // fprintf(stdout, "cutpoint = %ld\n", cutpoint - first_cut_granpos); 01154 // fflush(stdout); 01155 01156 if ((cutpoint == 0) || (page_granpos < cutpoint)) 01157 { 01158 while(1) 01159 { 01160 result = ogg_stream_packetout(oggstate->stream_in, &packet); 01161 01162 //result == -1 is not a fatal error 01163 if (result==0) 01164 { 01165 break; 01166 } 01167 else 01168 { 01169 if (result != -1) 01170 { 01171 int bs = splt_ogg_get_blocksize(oggstate, oggstate->vi, &packet); 01172 long first_granpos = splt_ogg_compute_first_granulepos(state, oggstate, &packet, bs); 01173 if (first_cut_granpos == 0) 01174 { 01175 first_cut_granpos = first_granpos; 01176 if (cutpoint != 0) 01177 { 01178 cutpoint += first_granpos; 01179 } 01180 } 01181 current_granpos += bs; 01182 01183 //we need to save the last packet, so save the current packet each time 01184 splt_ogg_free_packet(&oggstate->packets[0]); 01185 oggstate->packets[0] = splt_ogg_save_packet(&packet, &packet_err); 01186 01187 if (packet_err < 0) { return -1; } 01188 if (current_granpos > page_granpos) 01189 { 01190 current_granpos = page_granpos; 01191 } 01192 packet.granulepos = current_granpos; 01193 // fprintf(stdout,"granpos 1 = %ld\n", packet.granulepos); 01194 // fflush(stdout); 01195 packet.packetno = packetnum++; 01196 01197 //progress 01198 if ((splt_o_get_int_option(state,SPLT_OPT_SPLIT_MODE) 01199 == SPLT_OPTION_SILENCE_MODE) || 01200 (!splt_o_get_int_option(state,SPLT_OPT_AUTO_ADJUST))) 01201 { 01202 splt_c_update_progress(state, (double)page_granpos, 01203 (double)cutpoint, 01204 1,0,SPLT_DEFAULT_PROGRESS_RATE); 01205 } 01206 else 01207 { 01208 splt_c_update_progress(state, (double)page_granpos, 01209 (double)cutpoint, 01210 2,0,SPLT_DEFAULT_PROGRESS_RATE); 01211 } 01212 01213 ogg_stream_packetin(stream, &packet); 01214 01215 if (packet.packetno == 4 && packet.granulepos != -1) 01216 { 01217 if (splt_ogg_write_pages_to_file(state, stream,f, 1, 01218 error, output_fname)) { return -1; } 01219 } 01220 else 01221 { 01222 if (splt_ogg_write_pages_to_file(state, stream,f, 0, 01223 error, output_fname)) { return -1; } 01224 } 01225 } 01226 } 01227 } 01228 01229 prev_granpos = page_granpos; 01230 } 01231 else 01232 { 01233 if (adjust) 01234 { 01235 if (splt_ogg_scan_silence(state, 01236 (2 * adjust), threshold, 0.f, 0, &page, current_granpos, error, first_cut_granpos) > 0) 01237 { 01238 cutpoint = (splt_siu_silence_position(state->silence_list, 01239 oggstate->off) * oggstate->vi->rate); 01240 } 01241 else 01242 { 01243 cutpoint = (cutpoint + (adjust * oggstate->vi->rate)); 01244 } 01245 01246 if (first_cut_granpos == 0 && oggstate->first_granpos != 0) 01247 { 01248 first_cut_granpos = oggstate->first_granpos; 01249 cutpoint += first_cut_granpos; 01250 prev_granpos += first_cut_granpos; 01251 } 01252 01253 *sec_split_time_length = cutpoint / oggstate->vi->rate; 01254 01255 splt_siu_ssplit_free(&state->silence_list); 01256 adjust = 0; 01257 progress_adjust = 0; 01258 splt_c_put_progress_text(state, SPLT_PROGRESS_CREATE); 01259 01260 if (*error < 0) { return -1; } 01261 } 01262 else 01263 { 01264 eos = 1; /* We reached the second cutpoint */ 01265 } 01266 01267 while ((result = ogg_stream_packetout(oggstate->stream_in, &packet)) != 0) 01268 { 01269 //if == -1, we are out of sync; not a fatal error 01270 if (result != -1) 01271 { 01272 int bs; 01273 bs = splt_ogg_get_blocksize(oggstate, oggstate->vi, &packet); 01274 01275 long first_granpos = splt_ogg_compute_first_granulepos(state, oggstate, &packet, bs); 01276 if (first_cut_granpos == 0 && first_granpos != 0) 01277 { 01278 first_cut_granpos = first_granpos; 01279 cutpoint += first_granpos; 01280 prev_granpos += first_granpos; 01281 eos = 0; 01282 } 01283 01284 if (prev_granpos == -1) 01285 { 01286 prev_granpos = 0; 01287 } 01288 else if (prev_granpos == 0 && !packet.e_o_s) 01289 { 01290 prev_granpos = bs + first_cut_granpos; 01291 if (prev_granpos > current_granpos + first_cut_granpos) 01292 { 01293 prev_granpos = current_granpos + first_cut_granpos; 01294 } 01295 } 01296 else 01297 { 01298 prev_granpos += bs; 01299 } 01300 01301 current_granpos += bs; 01302 01303 if (prev_granpos >= cutpoint) 01304 { 01305 splt_ogg_free_packet(&oggstate->packets[1]); 01306 //don't save the last packet if exact split 01307 if (prev_granpos != cutpoint) 01308 { 01309 oggstate->packets[1] = splt_ogg_save_packet(&packet, &packet_err); 01310 } 01311 if (packet_err < 0) { return -1; } 01312 if (first_cut_granpos != 0) 01313 { 01314 packet.granulepos = current_granpos; 01315 } 01316 else 01317 { 01318 packet.granulepos = cutpoint; /* Set it! This 'truncates' the final packet, as needed. */ 01319 } 01320 //fprintf(stdout,"granpos 2 = %ld\n", packet.granulepos); 01321 //fflush(stdout); 01322 packet.e_o_s = 1; 01323 ogg_stream_packetin(stream, &packet); 01324 break; 01325 } 01326 else 01327 { 01328 if (first_cut_granpos != 0) 01329 { 01330 packet.granulepos = current_granpos; 01331 } 01332 else 01333 { 01334 packet.granulepos = prev_granpos - first_cut_granpos; 01335 } 01336 //fprintf(stdout,"granpos 3 = %ld\n", packet.granulepos); 01337 //fflush(stdout); 01338 packet.packetno = packetnum++; 01339 } 01340 01341 splt_ogg_free_packet(&oggstate->packets[0]); 01342 oggstate->packets[0] = splt_ogg_save_packet(&packet, &packet_err); 01343 if (packet_err < 0) { return -1; } 01344 01345 ogg_stream_packetin(stream, &packet); 01346 if (splt_ogg_write_pages_to_file(state, stream, f, 0, error, output_fname)) 01347 { 01348 return -1; 01349 } 01350 } 01351 } 01352 } 01353 01354 if(ogg_page_eos(&page)) 01355 { 01356 eos=1; 01357 } 01358 } 01359 } 01360 } 01361 01362 if (!eos) 01363 { 01364 int sync_bytes = splt_ogg_update_sync(state, oggstate->sync_in, in, error); 01365 if (sync_bytes == 0) 01366 { 01367 eos = 1; 01368 } 01369 else if (sync_bytes == -1) 01370 { 01371 return -1; 01372 } 01373 } 01374 } 01375 01376 if ((cutpoint == 0) || (page_granpos < cutpoint)) // End of file. We stop here 01377 { 01378 if (splt_ogg_write_pages_to_file(state, stream, f, 1, error, output_fname)) 01379 { 01380 return -1; 01381 } 01382 01383 oggstate->end = -1; // No more data available. Next processes aborted 01384 01385 return 0; 01386 } 01387 01388 if (splt_ogg_write_pages_to_file(state, stream, f, 0, error, output_fname)) 01389 { 01390 return -1; 01391 } 01392 01393 oggstate->initialgranpos = prev_granpos - cutpoint; 01394 oggstate->cutpoint_begin += cutpoint; 01395 01396 // fprintf(stdout,"prev_granpos = %ld\n",prev_granpos); 01397 // fprintf(stdout,"initial granpos = %ld\n",prev_granpos - cutpoint); 01398 // fprintf(stdout,"cutpoint begin = %ld\n", oggstate->cutpoint_begin); 01399 // fflush(stdout); 01400 01401 if (save_end_point) 01402 { 01403 oggstate->end = 1; 01404 } 01405 else 01406 { 01407 oggstate->end = 0; 01408 //if we don't save the end point, go at the start of the file 01409 rewind(oggstate->in); 01410 } 01411 01412 return 0; 01413 01414 write_error: 01415 splt_e_set_error_data(state, output_fname); 01416 *error = SPLT_ERROR_CANT_WRITE_TO_OUTPUT_FILE; 01417 return -1; 01418 } 01419 01420 //splits ogg 01421 double splt_ogg_split(const char *output_fname, splt_state *state, 01422 double sec_begin, double sec_end, short seekable, 01423 int adjust, float threshold, int *error, int save_end_point) 01424 { 01425 splt_ogg_state *oggstate = state->codec; 01426 01427 ogg_stream_state stream_out; 01428 ogg_packet header_comm; 01429 ogg_int64_t begin, end = 0, cutpoint = 0; 01430 01431 begin = (ogg_int64_t) (sec_begin * oggstate->vi->rate); 01432 01433 double sec_end_time = sec_end; 01434 01435 char *filename = splt_t_get_filename_to_split(state); 01436 01437 short sec_end_is_not_eof = 01438 !splt_u_fend_sec_is_bigger_than_total_time(state, sec_end); 01439 01440 if (sec_end_is_not_eof) 01441 { 01442 if (adjust) 01443 { 01444 if (sec_end_is_not_eof) 01445 { 01446 float gap = (float) adjust; 01447 if (sec_end > gap) 01448 { 01449 sec_end -= gap; 01450 } 01451 if (sec_end < sec_begin) 01452 { 01453 sec_end = sec_begin; 01454 } 01455 } 01456 else 01457 { 01458 adjust = 0; 01459 } 01460 } 01461 end = (ogg_int64_t) (sec_end * oggstate->vi->rate); 01462 cutpoint = end - begin; 01463 } 01464 01465 // First time we run this, no packets already saved. 01466 if (oggstate->end == 0) 01467 { 01468 // We must do this before. If an error occurs, we don't want to create empty files! 01469 //we find the begin cutpoint 01470 if (splt_ogg_find_begin_cutpoint(state, 01471 oggstate, oggstate->in, begin, error, filename, save_end_point) < 0) 01472 { 01473 return sec_end_time; 01474 } 01475 } 01476 01477 if (! splt_o_get_int_option(state, SPLT_OPT_PRETEND_TO_SPLIT)) 01478 { 01479 //- means stdout 01480 if (strcmp(output_fname, "-")==0) 01481 { 01482 oggstate->out = stdout; 01483 #ifdef __WIN32__ 01484 _setmode(fileno(oggstate->out), _O_BINARY); 01485 #endif 01486 } 01487 else 01488 { 01489 if (!(oggstate->out = splt_io_fopen(output_fname, "wb"))) 01490 { 01491 splt_e_set_strerror_msg_with_data(state, output_fname); 01492 *error = SPLT_ERROR_CANNOT_OPEN_DEST_FILE; 01493 return sec_end_time; 01494 } 01495 } 01496 } 01497 01498 /* gets random serial number*/ 01499 ogg_stream_init(&stream_out, rand()); 01500 01501 //vorbis memory leak ? 01502 vorbis_commentheader_out(&oggstate->vc, &header_comm); 01503 01504 int packet_err = SPLT_OK; 01505 splt_ogg_free_packet(&oggstate->headers[1]); 01506 oggstate->headers[1] = splt_ogg_save_packet(&header_comm, &packet_err); 01507 ogg_packet_clear(&header_comm); 01508 vorbis_comment_clear(&oggstate->vc); 01509 if (packet_err < 0) 01510 { 01511 *error = packet_err; 01512 ogg_stream_clear(&stream_out); 01513 return sec_end_time; 01514 } 01515 01516 splt_ogg_submit_headers_to_stream(&stream_out, oggstate); 01517 01518 if (splt_ogg_write_pages_to_file(state, &stream_out, oggstate->out, 1, 01519 error, output_fname) == -1) 01520 { 01521 goto end; 01522 } 01523 01524 //find end cutpoint and get error 01525 double sec_split_time_length = sec_end - sec_begin; 01526 splt_ogg_find_end_cutpoint(state, &stream_out, oggstate->in, 01527 oggstate->out, cutpoint, adjust, threshold, error, output_fname, 01528 save_end_point, &sec_split_time_length); 01529 sec_end_time = sec_begin + sec_split_time_length; 01530 01531 end: 01532 ogg_stream_clear(&stream_out); 01533 if (oggstate->out) 01534 { 01535 if (oggstate->out != stdout) 01536 { 01537 if (fclose(oggstate->out) != 0) 01538 { 01539 splt_e_set_strerror_msg_with_data(state, output_fname); 01540 *error = SPLT_ERROR_CANNOT_CLOSE_FILE; 01541 } 01542 } 01543 oggstate->out = NULL; 01544 } 01545 01546 if (*error >= 0) 01547 { 01548 if (oggstate->end == -1) 01549 { 01550 *error = SPLT_OK_SPLIT_EOF; 01551 return sec_end_time; 01552 } 01553 01554 *error = SPLT_OK_SPLIT; 01555 } 01556 01557 return sec_end_time; 01558 } 01559 01560 /****************************/ 01561 /* ogg scan for silence */ 01562 01563 //used by scan_silence 01564 static int splt_ogg_silence(splt_ogg_state *oggstate, vorbis_dsp_state *vd, float threshold) 01565 { 01566 float **pcm = NULL, sample; 01567 int samples, silence = 1; 01568 01569 while((samples=vorbis_synthesis_pcmout(vd,&pcm))>0) 01570 { 01571 if (silence) 01572 { 01573 int i, j; 01574 for (i=0; i < oggstate->vi->channels; i++) 01575 { 01576 float *mono=pcm[i]; 01577 if (!silence) 01578 { 01579 break; 01580 } 01581 for(j=0; j<samples; j++) 01582 { 01583 sample = fabs(mono[j]); 01584 oggstate->temp_level = oggstate->temp_level *0.999 + sample*0.001; 01585 if (sample > threshold) 01586 { 01587 silence = 0; 01588 } 01589 } 01590 } 01591 } 01592 vorbis_synthesis_read(vd, samples); 01593 } 01594 01595 return silence; 01596 } 01597 01598 int splt_ogg_scan_silence(splt_state *state, short seconds, 01599 float threshold, float min, short output, 01600 ogg_page *page, ogg_int64_t granpos, int *error, long first_cut_granpos) 01601 { 01602 splt_c_put_progress_text(state,SPLT_PROGRESS_SCAN_SILENCE); 01603 splt_ogg_state *oggstate = state->codec; 01604 01605 ogg_page og; 01606 ogg_packet op; 01607 vorbis_dsp_state vd; 01608 vorbis_block vb; 01609 ogg_int64_t end_position, begin_position, pos, end, begin, page_granpos; 01610 int eos=0, found = 0, shot, result = 0, len = 0 ; 01611 short first, flush = 0; 01612 off_t position = ftello(oggstate->in); // Some backups 01613 int saveW = oggstate->prevW; 01614 float th = splt_co_convert_from_dB(threshold); 01615 01616 ogg_stream_state os; 01617 ogg_stream_init(&os, oggstate->serial); 01618 01619 char *filename = splt_t_get_filename_to_split(state); 01620 01621 // We still have a page to process 01622 if (page) 01623 { 01624 memcpy(&og, page, sizeof(ogg_page)); 01625 result = 1; 01626 } 01627 01628 end_position = begin_position = pos = granpos; 01629 vorbis_synthesis_init(&vd, oggstate->vi); 01630 vorbis_block_init(&vd, &vb); 01631 01632 ogg_sync_state oy; 01633 ogg_sync_init(&oy); 01634 01635 int auto_adjust_option = splt_o_get_int_option(state,SPLT_OPT_AUTO_ADJUST); 01636 01637 int split_type = splt_o_get_int_option(state, SPLT_OPT_SPLIT_MODE); 01638 short option_silence_mode = (split_type == SPLT_OPTION_SILENCE_MODE); 01639 if (option_silence_mode) 01640 { 01641 memcpy(&oy, oggstate->sync_in, sizeof(*oggstate->sync_in)); 01642 01643 size_t storage_to_copy = oggstate->sync_in->storage * sizeof(unsigned char); 01644 01645 oy.data = malloc(storage_to_copy); 01646 if (oy.data == NULL) 01647 { 01648 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 01649 found = -1; 01650 goto function_end; 01651 } 01652 01653 memcpy(oy.data, oggstate->sync_in->data, storage_to_copy); 01654 } 01655 01656 if (seconds > 0) 01657 { 01658 end = (ogg_int64_t) (seconds * oggstate->vi->rate); 01659 } 01660 else 01661 { 01662 end = 0; 01663 } 01664 01665 begin = 0; 01666 first = output; 01667 shot = SPLT_DEFAULTSHOT; 01668 01669 oggstate->temp_level = 0.0; 01670 01671 short is_stream = SPLT_FALSE; 01672 long stream_time0 = 0; 01673 01674 while (!eos) 01675 { 01676 while (!eos) 01677 { 01678 if (result == 0) 01679 { 01680 break; 01681 } 01682 01683 if (result > 0) 01684 { 01685 if (ogg_page_eos(&og)) 01686 { 01687 eos = 1; 01688 } 01689 01690 page_granpos = ogg_page_granulepos(&og) - oggstate->cutpoint_begin; 01691 01692 if (pos == 0) 01693 { 01694 pos = page_granpos; 01695 } 01696 ogg_stream_pagein(&os, &og); 01697 01698 while (1) 01699 { 01700 result = ogg_stream_packetout(&os, &op); 01701 01702 /* need more data */ 01703 if (result == 0) 01704 { 01705 break; 01706 } 01707 01708 if (result > 0) 01709 { 01710 int bs = splt_ogg_get_blocksize(oggstate, oggstate->vi, &op); 01711 01712 //we currently loose the first packet when using the 01713 //auto adjust option because we are out of sync, 01714 //so we disable the continuity check 01715 if (!auto_adjust_option) 01716 { 01717 long first_granpos = 01718 splt_ogg_compute_first_granulepos(state, oggstate, &op, bs); 01719 if (first_cut_granpos == 0 && first_granpos != 0) 01720 { 01721 is_stream = SPLT_TRUE; 01722 first_cut_granpos = first_granpos; 01723 pos += first_cut_granpos; 01724 } 01725 } 01726 01727 pos += bs; 01728 if (pos > page_granpos) 01729 { 01730 pos = page_granpos; 01731 } 01732 begin += bs; 01733 01734 if (vorbis_synthesis(&vb, &op) == 0) 01735 { 01736 vorbis_synthesis_blockin(&vd, &vb); 01737 if ((!flush) && (splt_ogg_silence(oggstate, &vd, th))) 01738 { 01739 if (len == 0) 01740 { 01741 begin_position = pos; 01742 } 01743 if (first == 0) 01744 { 01745 len++; 01746 } 01747 if (shot < SPLT_DEFAULTSHOT) 01748 { 01749 shot+=2; 01750 } 01751 end_position = pos; 01752 } 01753 else 01754 { 01755 if (len > SPLT_DEFAULTSILLEN) 01756 { 01757 if ((flush) || (shot <= 0)) 01758 { 01759 float b_position, e_position; 01760 01761 double temp = (double) (begin_position - first_cut_granpos); 01762 temp /= oggstate->vi->rate; 01763 b_position = (float) temp; 01764 01765 temp = (double) (end_position - first_cut_granpos); 01766 temp /= oggstate->vi->rate; 01767 e_position = (float) temp; 01768 01769 if ((e_position - b_position - min) >= 0.f) 01770 { 01771 int err = SPLT_OK; 01772 if (splt_siu_ssplit_new(&state->silence_list, b_position, e_position, len, &err) == -1) 01773 { 01774 found = -1; 01775 goto function_end; 01776 } 01777 found++; 01778 } 01779 len = 0; 01780 shot = SPLT_DEFAULTSHOT; 01781 } 01782 } 01783 else 01784 { 01785 len = 0; 01786 } 01787 if (flush) 01788 { 01789 eos = 1; 01790 break; 01791 } 01792 if ((first) && (shot <= 0)) 01793 { 01794 first = 0; 01795 } 01796 if (shot > 0) 01797 { 01798 shot--; 01799 } 01800 } 01801 } 01802 else 01803 { 01804 *error = SPLT_ERROR_INVALID; 01805 splt_e_set_error_data(state,filename); 01806 found = -1; 01807 goto function_end; 01808 } 01809 } 01810 if (end) 01811 { 01812 if (begin > end) 01813 { 01814 flush = 1; 01815 } 01816 } 01817 if (found >= SPLT_MAXSILENCE) 01818 { 01819 eos = 1; 01820 } 01821 } 01822 } 01823 01824 result = ogg_sync_pageout(&oy, &og); 01825 //result == -1 is NOT a fatal error 01826 01827 // long page_number = ogg_page_pageno(&og); 01828 // fprintf(stdout,"X page number = %ld\n", page_number); 01829 // fflush(stdout); 01830 } 01831 01832 if (!eos) 01833 { 01834 int sync_bytes = splt_ogg_update_sync(state, &oy, oggstate->in, error); 01835 if (sync_bytes == 0) 01836 { 01837 eos = 1; 01838 } 01839 else if (sync_bytes == -1) 01840 { 01841 found = -1; 01842 goto function_end; 01843 } 01844 01845 result = ogg_sync_pageout(&oy, &og); 01846 //result == -1 is NOT a fatal error 01847 01848 // if (result != -1) 01849 // { 01850 // long page_number = ogg_page_pageno(&og); 01851 // fprintf(stdout,"Y page number = %ld\n", page_number); 01852 // fflush(stdout); 01853 // } 01854 01855 float level = splt_co_convert_to_dB(oggstate->temp_level); 01856 if (state->split.get_silence_level) 01857 { 01858 long time = (long) (((double) pos / oggstate->vi->rate) * 100.0); 01859 if (is_stream && stream_time0 == 0 && time != 0) 01860 { 01861 stream_time0 = time; 01862 // fprintf(stdout, "stream_time0 = %ld\n", stream_time0); 01863 // fflush(stdout); 01864 } 01865 01866 // fprintf(stdout, "level = %f, time = %ld, time - stream_time0 = %ld\n", 01867 // level, time, (long) (time - stream_time0)); 01868 // fflush(stdout); 01869 01870 state->split.get_silence_level(time - stream_time0, level, 01871 state->split.silence_level_client_data); 01872 } 01873 state->split.p_bar->silence_db_level = level; 01874 state->split.p_bar->silence_found_tracks = found; 01875 01876 if (option_silence_mode) 01877 { 01878 if (splt_t_split_is_canceled(state)) 01879 { 01880 eos = 1; 01881 } 01882 splt_c_update_progress(state,(double)pos * 100, 01883 (double)(oggstate->len), 01884 1,0,SPLT_DEFAULT_PROGRESS_RATE2); 01885 } 01886 else 01887 { 01888 splt_c_update_progress(state,(double)begin, 01889 (double)end, 2,0.5,SPLT_DEFAULT_PROGRESS_RATE2); 01890 } 01891 } 01892 } 01893 01894 function_end: 01895 01896 ogg_stream_clear(&os); 01897 01898 vorbis_block_clear(&vb); 01899 vorbis_dsp_clear(&vd); 01900 01901 if (option_silence_mode) 01902 { 01903 if (oy.data) 01904 { 01905 free(oy.data); 01906 oy.data = NULL; 01907 } 01908 } 01909 ogg_sync_clear(&oy); 01910 01911 oggstate->prevW = saveW; 01912 if (fseeko(oggstate->in, position, SEEK_SET) == -1) 01913 { 01914 splt_e_set_strerror_msg_with_data(state, filename); 01915 *error = SPLT_ERROR_SEEKING_FILE; 01916 found = -1; 01917 } 01918 01919 return found; 01920 } 01921 01933 void splt_pl_set_plugin_info(splt_plugin_info *info, int *error) 01934 { 01935 float plugin_version = 1.0; 01936 01937 //set plugin version 01938 info->version = plugin_version; 01939 01940 //set plugin name 01941 info->name = malloc(sizeof(char) * 40); 01942 if (info->name != NULL) 01943 { 01944 snprintf(info->name, 39, "ogg vorbis (libvorbis)"); 01945 } 01946 else 01947 { 01948 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 01949 return; 01950 } 01951 01952 //set plugin extension 01953 info->extension = malloc(sizeof(char) * (strlen(SPLT_OGGEXT)+2)); 01954 if (info->extension != NULL) 01955 { 01956 snprintf(info->extension, strlen(SPLT_OGGEXT)+1, SPLT_OGGEXT); 01957 } 01958 else 01959 { 01960 *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; 01961 return; 01962 } 01963 01964 info->upper_extension = splt_su_convert(info->extension, SPLT_TO_UPPERCASE, error); 01965 } 01966 01968 int splt_pl_check_plugin_is_for_file(splt_state *state, int *error) 01969 { 01970 char *filename = splt_t_get_filename_to_split(state); 01971 01972 //o- means stdin ogg format 01973 if ((filename != NULL) && (strcmp(filename,"o-")) == 0) 01974 { 01975 return SPLT_TRUE; 01976 } 01977 01978 int is_ogg = SPLT_FALSE; 01979 OggVorbis_File ogg_file; 01980 01981 FILE *file_input = NULL; 01982 01983 if ((file_input = splt_io_fopen(filename, "rb")) == NULL) 01984 { 01985 splt_e_set_strerror_msg_with_data(state, filename); 01986 *error = SPLT_ERROR_CANNOT_OPEN_FILE; 01987 } 01988 else 01989 { 01990 //check if the file is ogg vorbis 01991 if ((ov_test(file_input, &ogg_file, NULL, 0) + 1) == 1) 01992 { 01993 is_ogg = SPLT_TRUE; 01994 ov_clear(&ogg_file); 01995 } 01996 else 01997 { 01998 if (file_input != stdin) 01999 { 02000 if (fclose(file_input) != 0) 02001 { 02002 splt_e_set_strerror_msg_with_data(state, filename); 02003 *error = SPLT_ERROR_CANNOT_CLOSE_FILE; 02004 } 02005 } 02006 file_input = NULL; 02007 } 02008 } 02009 02010 return is_ogg; 02011 } 02012 02014 void splt_pl_init(splt_state *state, int *error) 02015 { 02016 FILE *file_input = NULL; 02017 char *filename = splt_t_get_filename_to_split(state); 02018 02019 if (splt_io_input_is_stdin(state)) 02020 { 02021 if (filename[1] == '\0') 02022 { 02023 splt_c_put_info_message_to_client(state, 02024 _(" warning: stdin 'o-' is supposed to be ogg stream.\n")); 02025 } 02026 } 02027 02028 //if we can open the file 02029 if ((file_input = splt_ogg_open_file_read(state, filename, error)) != NULL) 02030 { 02031 splt_ogg_get_info(state, file_input, error); 02032 if (*error >= 0) 02033 { 02034 splt_ogg_state *oggstate = state->codec; 02035 oggstate->off = splt_o_get_float_option(state,SPLT_OPT_PARAM_OFFSET); 02036 } 02037 } 02038 } 02039 02041 void splt_pl_end(splt_state *state, int *error) 02042 { 02043 splt_ogg_state_free(state); 02044 } 02045 02047 double splt_pl_split(splt_state *state, const char *final_fname, 02048 double begin_point, double end_point, int *error, int save_end_point) 02049 { 02050 splt_ogg_put_tags(state, error); 02051 02052 if (*error >= 0) 02053 { 02054 return splt_ogg_split(final_fname, state, 02055 begin_point, end_point, 02056 !state->options.option_input_not_seekable, 02057 state->options.parameter_gap, 02058 state->options.parameter_threshold, error, save_end_point); 02059 } 02060 02061 return end_point; 02062 } 02063 02065 int splt_pl_scan_silence(splt_state *state, int *error) 02066 { 02067 float offset = splt_o_get_float_option(state,SPLT_OPT_PARAM_OFFSET); 02068 float threshold = splt_o_get_float_option(state, SPLT_OPT_PARAM_THRESHOLD); 02069 float min_length = splt_o_get_float_option(state, SPLT_OPT_PARAM_MIN_LENGTH); 02070 int found = 0; 02071 02072 splt_ogg_state *oggstate = state->codec; 02073 oggstate->off = offset; 02074 02075 found = splt_ogg_scan_silence(state, 0, threshold, min_length, 1, NULL, 0, error, 0); 02076 if (*error < 0) { return -1; } 02077 02078 return found; 02079 } 02080 02082 void splt_pl_set_original_tags(splt_state *state, int *error) 02083 { 02084 splt_d_print_debug(state,"Taking ogg original tags... \n"); 02085 char *filename = splt_t_get_filename_to_split(state); 02086 splt_ogg_get_original_tags(filename, state, error); 02087 } 02088