_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;
}
/*
}
+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;
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,
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;
}