From: Andre Noll Date: Sat, 19 Sep 2009 10:11:12 +0000 (+0200) Subject: Merge branch 'master' into next X-Git-Tag: v0.4.0~25^2~1 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=ef81b9f4f0fa6a26043c68d429c0deeb7c949351 Merge branch 'master' into next Conflicts: ogg_afh.c --- ef81b9f4f0fa6a26043c68d429c0deeb7c949351 diff --cc fecdec_filter.c index 7fe87437,74e1b4f5..ca9dcd73 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@@ -4,10 -4,8 +4,10 @@@ * Licensed under the GPL v2. For licencing details see COPYING. */ - /** \file fecdec_filter.c A filter fec-decodes an audio stream. */ + /** \file fecdec_filter.c A filter that fec-decodes an audio stream. */ +#include + #include #include "para.h" #include "error.h" diff --cc ogg_afh.c index 4e64f062,11214c89..4583caab --- a/ogg_afh.c +++ b/ogg_afh.c @@@ -9,191 -9,109 +9,103 @@@ #include #include #include - #include ++#include #include "para.h" - #include "error.h" #include "afh.h" + #include "error.h" #include "string.h" - /** must be big enough to hold header */ - #define CHUNK_SIZE 32768 - static double chunk_time = 0.25; - - /** describes a memory-mapped ogg vorbis file */ - struct ogg_datasource { - /** the memory mapping */ - char *map; - /** this size of the mapping */ - off_t numbytes; - /** the current position in the mapping */ - off_t fpos; - }; - - static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource) - { - struct ogg_datasource *ods = datasource; - size_t copy, ret; - - if (!size) - return 0; - - assert(ods->numbytes >= ods->fpos); - ret = ods->numbytes - ods->fpos; - copy = PARA_MIN(ret, size * nmemb); - ret = copy / size; - if (!ret) - return 0; - memcpy(buf, ods->map + ods->fpos, copy); - // PARA_INFO_LOG("size: %zd, nmemb: %zd, ret: %zd\n", size, nmemb, ret); - ods->fpos += ret * size; - return ret; - } - - static int cb_seek(void *datasource, ogg_int64_t offset, - int whence) + /* Taken from decoder_example.c of libvorbis-1.2.3. */ + static int read_vorbis_comment(ogg_sync_state *oss, ogg_stream_state *stream, + vorbis_info *vi, vorbis_comment *vc) { - struct ogg_datasource *ods = datasource; - switch (whence) { - case SEEK_SET: - if (offset >= 0 && offset <= ods->numbytes) { - ods->fpos = offset; - return 0; - } - errno = EINVAL; - return -1; - break; - case SEEK_END: - if (offset <= 0 && -offset <= ods->numbytes) { - ods->fpos = ods->numbytes + offset; - return 0; - } - errno = EINVAL; - return -1; - break; - case SEEK_CUR: - if ((offset >= 0 && offset + ods->fpos > ods->numbytes) || - (offset < 0 && offset + ods->fpos < 0)) { - errno = EINVAL; - return -1; + ogg_page page; + ogg_packet packet; + int i = 0; + + while (i < 2) { + while (i < 2) { + int ret = ogg_sync_pageout(oss, &page); + if (ret == 0) + break; /* Need more data */ + if (ret != 1) + continue; + /* + * We can ignore any errors here as they'll also become + * apparent at packetout. + */ + ogg_stream_pagein(stream, &page); + while (i < 2) { + ret = ogg_stream_packetout(stream, &packet); + if (ret == 0) + break; + if (ret < 0) + return -E_STREAM_PACKETOUT; + ret = vorbis_synthesis_headerin(vi, vc, + &packet); + if (ret < 0) + return -E_VORBIS; + i++; + } } - ods->fpos += offset; - return 0; } - errno = EINVAL; - return -1; - } - - /* don't do anything as vss still needs the open filehandle */ - static int cb_close(__a_unused void *datasource) - { - return 0; - } - - static long cb_tell(void *datasource) - { - struct ogg_datasource *ods = datasource; - return (unsigned long)ods->fpos; - } - - static 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 */ - - if (ret == OV_EREAD) - return -E_OGG_READ; - if (ret == OV_ENOTVORBIS) - return -E_VORBIS; - if (ret == OV_EVERSION) - return -E_OGG_VERSION; - if (ret == OV_EBADHEADER) - return -E_OGG_BAD_HEADER; - if (ret < 0) - return -E_OGG_UNKNOWN_ERROR; return 1; - } - static int ogg_compute_header_len(char *map, size_t numbytes, - struct afh_info *afhi) + static int read_vorbis_info(ogg_sync_state *oss, struct afh_info *afhi) { - int ret; - size_t len = PARA_MIN(numbytes, (size_t)CHUNK_SIZE); - int serial; - char *buf; - - ogg_page page; - ogg_packet packet; vorbis_comment vc; vorbis_info vi; - ogg_stream_state *stream_in = para_malloc(sizeof(ogg_stream_state)); - ogg_stream_state *stream_out = para_malloc(sizeof(ogg_stream_state)); - ogg_sync_state *sync_in = para_malloc(sizeof(ogg_sync_state)); + ogg_packet packet; + ogg_stream_state stream; + ogg_page page; + int ret; - char *taginfo; - ogg_sync_init(sync_in); vorbis_info_init(&vi); vorbis_comment_init(&vc); - buf = ogg_sync_buffer(sync_in, (long)len); - memcpy(buf, map, len); - ogg_sync_wrote(sync_in, (long)len); + ret = -E_SYNC_PAGEOUT; - if (ogg_sync_pageout(sync_in, &page) <= 0) { - free(stream_in); - free(stream_out); - goto err1; - } - serial = ogg_page_serialno(&page); - ogg_stream_init(stream_in, serial); - ogg_stream_init(stream_out, serial); - ret = ogg_stream_pagein(stream_in, &page); - if (ret < 0) { - ret = -E_STREAM_PAGEIN; - goto err2; - } - ret = ogg_stream_packetout(stream_in, &packet); - if (ret != 1) { - ret = -E_STREAM_PACKETOUT; - goto err2; - } + if (ogg_sync_pageout(oss, &page) != 1) + goto out; + + ret = ogg_page_serialno(&page); + ogg_stream_init(&stream, ret); + + ret = -E_STREAM_PAGEIN; + if (ogg_stream_pagein(&stream, &page) < 0) + goto out; + + ret = -E_STREAM_PACKETOUT; + if (ogg_stream_packetout(&stream, &packet) != 1) + goto out; + ret = -E_VORBIS; if (vorbis_synthesis_headerin(&vi, &vc, &packet) < 0) - goto err2; - PARA_DEBUG_LOG("channels: %i, rate: %li\n", vi.channels, vi.rate); - ogg_stream_packetin(stream_out, &packet); - ret = ogg_sync_pageout(sync_in, &page); - if (ret <= 0) { - ret = -E_SYNC_PAGEOUT; - goto err2; - } - ogg_stream_pagein(stream_in, &page); - ogg_stream_packetout(stream_in, &packet); - ogg_stream_packetin(stream_out, &packet); - - ret = ogg_sync_pageout(sync_in, &page); - if (ret <= 0) { - ret = -E_SYNC_PAGEOUT; - goto err2; - } - ogg_stream_pagein(stream_in, &page); - ogg_stream_packetout(stream_in, &packet); - ogg_stream_packetin(stream_out, &packet); + goto out; + if (vi.rate == 0) + goto out; + afhi->channels = vi.channels; + afhi->frequency = vi.rate; + afhi->bitrate = vi.bitrate_nominal / 1000; + PARA_DEBUG_LOG("channels: %i, sampling rate: %i, bitrate: %i\n", + afhi->channels, afhi->frequency, afhi->bitrate); + ret = read_vorbis_comment(oss, &stream, &vi, &vc); + if (ret < 0) + goto out; - taginfo = make_taginfo( - vorbis_comment_query(&vc, "title", 0), - vorbis_comment_query(&vc, "artist", 0), - vorbis_comment_query(&vc, "album", 0), - vorbis_comment_query(&vc, "year", 0), - vorbis_comment_query(&vc, "comment", 0) - ); - PARA_DEBUG_LOG("tag info: %s\n", taginfo); - afhi->info_string = make_message("%s:\n%s", - status_item_list[SI_AUDIO_FILE_INFO], taginfo); - free(taginfo); ++ afhi->tags.artist = para_strdup(vorbis_comment_query(&vc, "artist", 0)); ++ afhi->tags.title = para_strdup(vorbis_comment_query(&vc, "title", 0)); ++ afhi->tags.album = para_strdup(vorbis_comment_query(&vc, "album", 0)); ++ afhi->tags.year = para_strdup(vorbis_comment_query(&vc, "year", 0)); ++ afhi->tags.comment = para_strdup(vorbis_comment_query(&vc, "comment", 0)); - afhi->header_len = 0; - while (ogg_stream_flush(stream_out, &page)) - afhi->header_len += page.body_len + page.header_len; - PARA_DEBUG_LOG("header_len = %d\n", afhi->header_len); afhi->header_offset = 0; + afhi->header_len = oss->returned; ret = 1; - err2: - ogg_stream_destroy(stream_in); - ogg_stream_destroy(stream_out); - err1: - ogg_sync_destroy(sync_in); + out: vorbis_info_clear(&vi); vorbis_comment_clear(&vc); + ogg_stream_clear(&stream); return ret; } @@@ -251,38 -131,66 +125,64 @@@ static void set_chunk_tv(int num_frames static int ogg_get_file_info(char *map, size_t numbytes, __a_unused int fd, struct afh_info *afhi) { - int ret; - vorbis_info *vi; - OggVorbis_File of; - const ov_callbacks ovc = { - .read_func = cb_read, - .seek_func = cb_seek, - .close_func = cb_close, - .tell_func = cb_tell - }; - struct ogg_datasource ods = {.map = map, .numbytes = numbytes, .fpos = 0}; - - ret = ogg_compute_header_len(map, numbytes, afhi); - if (ret < 0) - return ret; - ret = ogg_open_callbacks(&ods, &of, ovc); + ogg_sync_state oss; + ogg_page op; + long len = numbytes; + char *buf; + int ret, i, j, frames_per_chunk, ct_size; + long long unsigned num_frames = 0; + - afhi->info_string = NULL; + ogg_sync_init(&oss); + ret = -E_OGG_SYNC; + buf = ogg_sync_buffer(&oss, len); + if (!buf) + goto out; + memcpy(buf, map, len); + ret = -E_OGG_SYNC; + if (ogg_sync_wrote(&oss, len) < 0) + goto out; + ret = read_vorbis_info(&oss, afhi); if (ret < 0) - goto err; - ret = -E_OGG_INFO; - vi = ov_info(&of, 0); - if (!vi) - goto err; - afhi->seconds_total = ov_time_total(&of, -1); - afhi->frequency = vi->rate; - afhi->bitrate = ov_bitrate(&of, 0) / 1000; - afhi->channels = vi->channels; - afhi->chunks_total = ogg_compute_chunk_table(&of, afhi, afhi->seconds_total); - afhi->chunk_tv.tv_sec = 0; - afhi->chunk_tv.tv_usec = 250 * 1000; - ogg_get_vorbis_comments(&of, afhi); - ret = 1; - err: - ov_clear(&of); /* keeps the file open */ + goto out; + oss.returned = 0; + oss.fill = numbytes; + /* count ogg packages and get duration of the file */ + for (i = 0; ogg_sync_pageseek(&oss, &op) > 0; i++) + num_frames = ogg_page_granulepos(&op); + PARA_INFO_LOG("%d pages, %llu frames\n", i, num_frames); + ret = -E_OGG_EMPTY; + if (i == 0) + goto out; + afhi->seconds_total = num_frames / afhi->frequency; + /* use roughly one page per chunk */ + frames_per_chunk = num_frames / i; + PARA_INFO_LOG("%lu seconds, %d frames/chunk\n", + afhi->seconds_total, frames_per_chunk); + ct_size = 250; + afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t)); + afhi->chunk_table[0] = 0; + afhi->chunk_table[1] = afhi->header_len; + oss.returned = afhi->header_len; + oss.fill = numbytes; + for (i = 0, j = 1; ogg_sync_pageseek(&oss, &op) > 0; i++) { + int granule = ogg_page_granulepos(&op); + + while (granule > j * frames_per_chunk) { + j++; + if (j >= ct_size) { + ct_size *= 2; + afhi->chunk_table = para_realloc( + afhi->chunk_table, + ct_size * sizeof(uint32_t)); + } + afhi->chunk_table[j] = oss.returned; + } + } + afhi->chunks_total = j; + set_chunk_tv(num_frames, j, afhi->frequency, &afhi->chunk_tv); - tv_scale(3, &afhi->chunk_tv, &afhi->eof_tv); + ret = 0; + out: + ogg_sync_clear(&oss); return ret; }