From f50dd1b71b291e8bcb44c4ecf28e4cca1a050358 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sat, 10 Oct 2009 14:42:51 +0200 Subject: [PATCH] wma afh chunk time fixes --- error.h | 5 +++- wma_afh.c | 81 +++++++++++++++++++++++++++++++------------------------ 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/error.h b/error.h index 33d09f28..a99512fd 100644 --- a/error.h +++ b/error.h @@ -34,10 +34,13 @@ DEFINE_ERRLIST_OBJECT_ENUM; #define SERVER_COMMAND_LIST_ERRORS #define AFS_COMMAND_LIST_ERRORS #define AUDIOD_COMMAND_LIST_ERRORS -#define WMA_AFH_ERRORS extern const char **para_errlist[]; +#define WMA_AFH_ERRORS \ + PARA_ERROR(NO_WMA, "asf/wma format not recognized"), \ + + #define WMA_COMMON_ERRORS \ PARA_ERROR(WMA_NO_GUID, "audio stream guid not found"), \ PARA_ERROR(WMA_BAD_ASF_HEADER, "invalid asf header"), \ diff --git a/wma_afh.c b/wma_afh.c index 9e5f5c60..dc7994e0 100644 --- a/wma_afh.c +++ b/wma_afh.c @@ -27,30 +27,25 @@ _f + (_ba) + WMA_FRAME_SKIP < (_buf) + (_size); \ _f += (_ba) + WMA_FRAME_SKIP) +/* + * Must be called on a frame boundary, e.g. start + header_len. + * \return Frame count, superframe count via *num_superframes. + */ static int count_frames(const char *buf, int buf_size, int block_align, - long unsigned *num_superframes) + int *num_superframes) { - int count = 0, step = block_align + WMA_FRAME_SKIP; - const uint8_t *p = (uint8_t *)buf + WMA_FRAME_SKIP; + int fc = 0, sfc = 0; /* frame count, superframe count */ + const uint8_t *p; - if (buf_size <= WMA_FRAME_SKIP) { - if (num_superframes) - *num_superframes = 0; - return 0; - } - count = 0; - step = block_align + WMA_FRAME_SKIP; - p = (uint8_t *)buf + WMA_FRAME_SKIP; - - FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, block_align) - count += p[WMA_FRAME_SKIP] & 0x0f; - PARA_DEBUG_LOG("%d frames\n", count); - if (num_superframes) { - *num_superframes = buf_size / step; - PARA_DEBUG_LOG("%lu superframes\n", *num_superframes); + FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, block_align) { + fc += p[WMA_FRAME_SKIP] & 0x0f; + sfc++; } - return count; + PARA_INFO_LOG("%d frames, %d superframes\n", fc, sfc); + if (num_superframes) + *num_superframes = sfc; + return fc; } /* @@ -185,31 +180,45 @@ static void read_asf_tags(const char *buf, int buf_size, struct taginfo *ti) } +static void set_chunk_tv(int num_frames, int num_chunks, int frequency, + struct timeval *result) +{ + uint64_t x = (uint64_t)num_frames * 1000 * 1000 + / frequency / num_chunks; + + result->tv_sec = x / 1000 / 1000; + result->tv_usec = x % (1000 * 1000); + PARA_INFO_LOG("%d chunks, chunk time: %lums\n", num_chunks, + tv2ms(result)); +} + +/* Must be called on a frame boundary. */ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align, struct afh_info *afhi) { const uint8_t *f, *start = (uint8_t *)buf; int i, j, frames_per_chunk, chunk_time; size_t ct_size = 250; - int count = 0, num_frames; + int ret, count = 0, num_frames, num_superframes; afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t)); afhi->chunk_table[0] = 0; afhi->chunk_table[1] = afhi->header_len; num_frames = count_frames(buf, buf_size, block_align, - &afhi->chunks_total); - PARA_INFO_LOG("%d frames\n", num_frames); + &num_superframes); + ret = -E_NO_WMA; + if (num_frames == 0 || num_superframes == 0) + goto fail; afhi->seconds_total = num_frames * 2048 /* FIXME */ / afhi->frequency; - frames_per_chunk = num_frames / afhi->chunks_total; + frames_per_chunk = num_frames / num_superframes; + PARA_INFO_LOG("%d frames per chunk\n", frames_per_chunk); i = 0; j = 1; - start += afhi->header_len; - buf_size -= afhi->header_len; FOR_EACH_FRAME(f, start, buf_size, block_align) { count += f[WMA_FRAME_SKIP] & 0x0f; - while (count > j * frames_per_chunk && f > start) { + while (count > j * frames_per_chunk) { j++; if (j >= ct_size) { ct_size *= 2; @@ -217,18 +226,15 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, int block_align, afhi->chunk_table, ct_size * sizeof(uint32_t)); } - PARA_DEBUG_LOG("ct[%d]: %zu\n", j, f - start); - afhi->chunk_table[j] = f - start + afhi->header_len; + afhi->chunk_table[j] = f - start + afhi->header_len + block_align + WMA_FRAME_SKIP; } } afhi->chunks_total = j; - chunk_time = num_frames * 1000 / afhi->frequency * 2048 - / afhi->chunks_total; - PARA_INFO_LOG("ct: %d\n", chunk_time); - afhi->chunk_tv.tv_sec = chunk_time / 1000; - afhi->chunk_tv.tv_usec = (chunk_time % 1000) * 1000; - //set_chunk_tv(num_frames, j, afhi->frequency, &afhi->chunk_tv); + set_chunk_tv(num_frames * 2048, j + 10 /* FIXME */, afhi->frequency, &afhi->chunk_tv); return 1; +fail: + free(afhi->chunk_table); + return ret; } static int wma_get_file_info(char *map, size_t numbytes, __a_unused int fd, @@ -240,13 +246,18 @@ static int wma_get_file_info(char *map, size_t numbytes, __a_unused int fd, ret = read_asf_header(map, numbytes, &ahi); if (ret < 0) return ret; + if (ret == 0) + return -E_NO_WMA; afhi->bitrate = ahi.bit_rate / 1000; + if (ahi.sample_rate == 0) + return -E_NO_WMA; afhi->frequency = ahi.sample_rate; afhi->channels = ahi.channels; afhi->header_len = ahi.header_len; afhi->header_offset = 0; + wma_make_chunk_table(map + ahi.header_len, numbytes - ahi.header_len, + ahi.block_align, afhi); read_asf_tags(map, ahi.header_len, &afhi->tags); - wma_make_chunk_table(map, numbytes, ahi.block_align, afhi); return 0; } -- 2.39.2