libmp3splt
plugins/ogg.c
Go to the documentation of this file.
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