X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=ogg_afh.c;h=3056a819b209eff6118748b60137bc92dc684e5a;hb=2df9761968e46b0e12106f2a0586a3a69103c4f1;hp=a3e0f6911cea762eabe1bb59a09b277212643f4b;hpb=15fb206efa462125e3a3a4cab0e893c0ca1781ea;p=paraslash.git diff --git a/ogg_afh.c b/ogg_afh.c index a3e0f691..3056a819 100644 --- a/ogg_afh.c +++ b/ogg_afh.c @@ -28,23 +28,67 @@ #include "afh.h" #include "error.h" #include "string.h" -#include "fd.h" /** must be big enough to hold header */ #define CHUNK_SIZE 32768 static double chunk_time = 0.25; -static OggVorbis_File *oggvorbis_file; -static FILE *infile; -static int header_len, vi_channels; +FILE *audio_file; +static int header_len; static char *header; -static ssize_t *chunk_table, max_chunk_len, num_chunks; +static ssize_t *chunk_table; static struct audio_format_handler *af; -static long vi_sampling_rate, vi_bitrate, vi_bitrate_nominal; -static int ogg_compute_header_len(void) +static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource) { - int ret, len, in = fileno(infile); + FILE *f = datasource; + return fread(buf, size, nmemb, f); +} + +static int cb_seek(__a_unused void *datasource, ogg_int64_t offset, + int whence) +{ + FILE *f = datasource; + return fseek(f, offset, whence); +} + +/* don't do anything as vss still needs the open filehandle */ +static int cb_close(__a_unused void *datasource) +{ + return 0; +} + +long cb_tell(void *datasource) +{ + FILE *f = datasource; + return ftell(f); +} + +int ogg_open_callbacks(void *datasource, OggVorbis_File *vf, ov_callbacks c) +{ + int ret = ov_open_callbacks(datasource, vf, + NULL, /* no initial buffer */ + 0, /* no initial bytes */ + c); /* the ov_open_callbacks */ + + /* FIXME: provide better error codes */ + if (ret == OV_EREAD) + return -E_OGG_READ; + if (ret == OV_ENOTVORBIS) + return -E_OGG_READ; + if (ret == OV_EVERSION) + return -E_OGG_READ; + if (ret == OV_EBADHEADER) + return -E_OGG_READ; + if (ret < 0) + return -E_OGG_READ; + return 1; + +} + +static int ogg_compute_header_len(FILE *file) +{ + int ret, len, in = fileno(file); unsigned int serial; char *buf; ogg_page page; @@ -119,7 +163,7 @@ err1: return ret; } -static void tunetable(void) +static void tunetable(long unsigned num_chunks) { int i = 1, j = -1, lp = 1; while (i < num_chunks) { @@ -146,13 +190,15 @@ static void tunetable(void) /* * Alloc and fill array table of byte offsets. chunk_table[i] is the - * offset in the current infile at which the sample containing time i * - * CHUNK_TIME begins. + * offset in the current input file at which the sample containing time i * + * CHUNK_TIME begins. Always successful. */ -static void ogg_compute_chunk_table(double time_total) +static long unsigned ogg_compute_chunk_table(OggVorbis_File *of, + double time_total) { int i, ret, num; - ssize_t pos = 0, min = 0, old_pos; + ssize_t max_chunk_len, pos = 0, min = 0, old_pos; + long unsigned num_chunks; old_pos = 0; ret = 0; @@ -162,13 +208,12 @@ static void ogg_compute_chunk_table(double time_total) chunk_table = para_malloc(num * sizeof(size_t)); chunk_table[0] = 0; max_chunk_len = 0; - rewind(infile); for (i = 1; ret == 0; i++) { ogg_int64_t diff; - ret = ov_time_seek(oggvorbis_file, i * chunk_time); + ret = ov_time_seek(of, i * chunk_time); if (ret) break; - pos = ov_raw_tell(oggvorbis_file); + pos = ov_raw_tell(of); diff = pos - old_pos; max_chunk_len = PARA_MAX(max_chunk_len, diff); min = (i == 1)? diff : PARA_MIN(min, diff); @@ -181,26 +226,17 @@ static void ogg_compute_chunk_table(double time_total) } num_chunks = i - 1; chunk_table[i] = pos; - tunetable(); - PARA_INFO_LOG("%zu chunks (%fs), max chunk: %zd, min chunk: %zd\n", +// tunetable(num_chunks); + PARA_INFO_LOG("%lu chunks (%fs), max chunk: %zd, min chunk: %zd\n", num_chunks, chunk_time, max_chunk_len, min); - rewind(infile); + return num_chunks; } static void ogg_close_audio_file(void) { - if (oggvorbis_file) { - PARA_DEBUG_LOG("%s", "ov_clear\n"); - ov_clear(oggvorbis_file); - free(oggvorbis_file); - oggvorbis_file = NULL; - } free(header); - header = NULL; - header_len = 0; free(chunk_table); - chunk_table = NULL; - num_chunks = 0; + fclose(audio_file); } static int ogg_save_header(FILE *file, int len) @@ -210,9 +246,10 @@ static int ogg_save_header(FILE *file, int len) header = para_malloc(len); rewind(file); ret = read(fileno(file), header, len); - if (ret != len) - return -E_OGG_READ; - return 1; + if (ret == len) + return 1; + free(header); + return -E_OGG_READ; } /* @@ -225,48 +262,53 @@ static int ogg_get_file_info(FILE *file, char *info_str, long unsigned *frames, double time_total; vorbis_info *vi; ogg_int64_t raw_total; + long vi_sampling_rate, vi_bitrate; + OggVorbis_File of; + static const ov_callbacks ovc = { + .read_func = cb_read, + .seek_func = cb_seek, + .close_func = cb_close, + .tell_func = cb_tell + }; - infile = file; if (!file) return -E_OGG_NO_FILE; - ret = ogg_compute_header_len(); + ret = ogg_compute_header_len(file); if (ret < 0) return ret; ret = ogg_save_header(file, header_len); if (ret < 0) return ret; rewind(file); - oggvorbis_file = para_malloc(sizeof(OggVorbis_File)); - ret = ov_open(file, oggvorbis_file, NULL, 0); - if (ret < 0) { - free(oggvorbis_file); - free(header); - return -E_OGG_OPEN; - } + ret = ogg_open_callbacks(file, &of, ovc); + if (ret < 0) + goto err; ret = -E_OGG_INFO; - vi = ov_info(oggvorbis_file, 0); + vi = ov_info(&of, 0); if (!vi) goto err; - time_total = ov_time_total(oggvorbis_file, -1); - raw_total = ov_raw_total(oggvorbis_file, -1); + time_total = ov_time_total(&of, -1); + raw_total = ov_raw_total(&of, -1); *seconds = time_total; vi_sampling_rate = vi->rate; - vi_bitrate = ov_bitrate(oggvorbis_file, 0); - vi_bitrate_nominal = vi->bitrate_nominal; - vi_channels = vi->channels; - ogg_compute_chunk_table(time_total); - *frames = num_chunks; + vi_bitrate = ov_bitrate(&of, 0); + rewind(file); + *frames = ogg_compute_chunk_table(&of, time_total); + rewind(file); *vss_chunk_table = chunk_table; - sprintf(info_str, "audio_file_info1:%zu x %lu, %ldkHz, %d channels, %ldkbps\n" + sprintf(info_str, "audio_file_info1:%lu x %lu, %ldkHz, %d channels, %ldkbps\n" "audio_file_info2: \n" "audio_file_info3: \n", - num_chunks, (long unsigned) (chunk_time * 1000 * 1000), - vi_sampling_rate / 1000, vi_channels, vi_bitrate / 1000 + *frames, (long unsigned) (chunk_time * 1000 * 1000), + vi_sampling_rate / 1000, vi->channels, vi_bitrate / 1000 ); rewind(file); - return 1; + audio_file = file; + ret = 1; err: - ogg_close_audio_file(); + ov_clear(&of); /* keeps the file open */ + if (ret < 0) + free(header); return ret; }