A previous commit activated dynamic chunks for the aac audio format
handler, so the virtual streaming system no longer consults the chunk
table stored in the audio file table of the osl database.
However, the code to open or add an audio file still assumes that
there is a chunk table and bails out if it can't find it. This patch
changes aft.c to do without a chunk table if the audio format handler
supports dynamic chunks. The afh_supports_dynamic_chunks() helper
needs to be made public because of this.
With chunk tables being optional, the ->get_file_info method of the
audio format handler can safely set ->chunk_table to NULL. It still
needs to compute the maximum chunk size though.
-static int aac_find_stsz(char *buf, size_t buflen, off_t *skip)
+static int aac_find_stsz(char *buf, size_t buflen, size_t *skip)
PARA_INFO_LOG("no meta data\n");
}
PARA_INFO_LOG("no meta data\n");
}
-static ssize_t aac_compute_chunk_table(struct afh_info *afhi,
- char *map, size_t numbytes)
+static ssize_t aac_compute_chunk_info(struct afh_info *afhi,
+ char *map, size_t numbytes, mp4AudioSpecificConfig *mp4ASC)
- size_t sum = 0;
- off_t skip;
+ size_t skip;
+ float tmp = mp4ASC->sbr_present_flag == 1? 2047 : 1023;
+ struct timeval total;
+ long unsigned ms;
+ afhi->chunk_table = NULL;
ret = aac_find_stsz(map, numbytes, &skip);
if (ret < 0)
return ret;
afhi->chunks_total = ret;
ret = aac_find_stsz(map, numbytes, &skip);
if (ret < 0)
return ret;
afhi->chunks_total = ret;
+ afhi->max_chunk_size = 0;
PARA_DEBUG_LOG("sz table has %" PRIu32 " entries\n", afhi->chunks_total);
PARA_DEBUG_LOG("sz table has %" PRIu32 " entries\n", afhi->chunks_total);
- afhi->chunk_table = para_malloc((afhi->chunks_total + 1) * sizeof(size_t));
for (i = 1; i <= afhi->chunks_total; i++) {
for (i = 1; i <= afhi->chunks_total; i++) {
if (skip + 4 > numbytes)
break;
if (skip + 4 > numbytes)
break;
- sum += read_u32_be(map + skip);
- afhi->chunk_table[i] = sum;
+ val = read_u32_be(map + skip);
+ afhi->max_chunk_size = PARA_MAX(afhi->max_chunk_size, val);
-// if (i < 10 || i + 10 > afhi->chunks_total)
-// PARA_DEBUG_LOG("offset #%d: %zu\n", i, afhi->chunk_table[i]);
- return skip;
-}
-
-static int aac_set_chunk_tv(struct afh_info *afhi,
- mp4AudioSpecificConfig *mp4ASC, uint32_t *seconds)
-{
- float tmp = mp4ASC->sbr_present_flag == 1? 2047 : 1023;
- struct timeval total;
- long unsigned ms;
ms = 1000.0 * afhi->chunks_total * tmp / mp4ASC->samplingFrequency;
ms2tv(ms, &total);
ms = 1000.0 * afhi->chunks_total * tmp / mp4ASC->samplingFrequency;
ms2tv(ms, &total);
afhi->chunks_total, tv2ms(&afhi->chunk_tv));
if (ms < 1000)
return -E_MP4ASC;
afhi->chunks_total, tv2ms(&afhi->chunk_tv));
if (ms < 1000)
return -E_MP4ASC;
+ afhi->seconds_total = ms / 1000;
+ ret = aac_find_entry_point(map, numbytes, &skip);
+ if (ret < 0)
+ return ret;
+ ret = (numbytes - ret) * 8;
+ ret += (afhi->channels * afhi->seconds_total * 500); /* avoid rounding error */
+ afhi->bitrate = ret / (afhi->channels * afhi->seconds_total * 1000);
static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd,
struct afh_info *afhi)
{
static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd,
struct afh_info *afhi)
{
size_t skip;
ssize_t ret;
unsigned long rate = 0, decoder_len;
size_t skip;
ssize_t ret;
unsigned long rate = 0, decoder_len;
goto out;
if (!channels)
goto out;
goto out;
if (!channels)
goto out;
+ afhi->channels = channels;
+ afhi->frequency = rate;
PARA_DEBUG_LOG("rate: %lu, channels: %d\n", rate, channels);
ret = -E_MP4ASC;
if (NeAACDecAudioSpecificConfig((unsigned char *)map + skip,
PARA_DEBUG_LOG("rate: %lu, channels: %d\n", rate, channels);
ret = -E_MP4ASC;
if (NeAACDecAudioSpecificConfig((unsigned char *)map + skip,
goto out;
if (!mp4ASC.samplingFrequency)
goto out;
goto out;
if (!mp4ASC.samplingFrequency)
goto out;
- ret = aac_compute_chunk_table(afhi, map, numbytes);
- if (ret < 0)
- goto out;
- skip = ret;
- ret = aac_set_chunk_tv(afhi, &mp4ASC, &afhi->seconds_total);
- if (ret < 0)
- goto out;
- ret = aac_find_entry_point(map + skip, numbytes - skip, &skip);
+ ret = aac_compute_chunk_info(afhi, map, numbytes, &mp4ASC);
- afhi->chunk_table[0] = ret;
- for (i = 1; i<= afhi->chunks_total; i++)
- afhi->chunk_table[i] += ret;
- set_max_chunk_size(afhi);
- afhi->channels = channels;
- afhi->frequency = rate;
- ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */
- ret += (channels * afhi->seconds_total * 500); /* avoid rounding error */
- afhi->bitrate = ret / (channels * afhi->seconds_total * 1000);
ret = 1;
out:
if (handle)
ret = 1;
out:
if (handle)
int afh_rewrite_tags(int audio_format_id, void *map, size_t mapsize,
struct taginfo *tags, int output_fd, const char *filename);
void set_max_chunk_size(struct afh_info *afhi);
int afh_rewrite_tags(int audio_format_id, void *map, size_t mapsize,
struct taginfo *tags, int output_fd, const char *filename);
void set_max_chunk_size(struct afh_info *afhi);
+bool afh_supports_dynamic_chunks(int audio_format_id);
-static bool afh_supports_dynamic_chunks(int audio_format_id)
+/**
+ * Tell whether an audio format handler provides chunk tables.
+ *
+ * Each audio format handler either provides a chunk table or supports dynamic
+ * chunks.
+ *
+ * \param audio_format_id Offset in the afl array.
+ *
+ * \return True if dynamic chunks are supported, false if the audio format
+ * handler provides chunk tables.
+ */
+bool afh_supports_dynamic_chunks(int audio_format_id)
{
return afl[audio_format_id].get_chunk;
}
{
return afl[audio_format_id].get_chunk;
}
afhi->tags.comment = afhi->tags.album + strlen(afhi->tags.album) + 1;
}
afhi->tags.comment = afhi->tags.album + strlen(afhi->tags.album) + 1;
}
+/* Only used for saving the chunk table, but not for loading. */
static unsigned sizeof_chunk_table(struct afh_info *afhi)
{
static unsigned sizeof_chunk_table(struct afh_info *afhi)
{
+ if (!afhi || !afhi->chunk_table)
return 0;
return 4 * (afhi->chunks_total + 1);
}
return 0;
return 4 * (afhi->chunks_total + 1);
}
+ if (!afhi->chunk_table)
+ return;
for (n = 0; n <= afhi->chunks_total; n++)
write_u32(buf + 4 * n, afhi->chunk_table[n]);
}
for (n = 0; n <= afhi->chunks_total; n++)
write_u32(buf + 4 * n, afhi->chunk_table[n]);
}
static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct)
{
int i;
static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct)
{
int i;
- afhi->chunk_table = para_malloc(sizeof_chunk_table(afhi));
+ if (!ct->data || ct->size < 4) {
+ afhi->chunk_table = NULL;
+ return;
+ }
+ sz = PARA_MIN(((size_t)afhi->chunks_total + 1) * 4, ct->size) + 1;
+ afhi->chunk_table = para_malloc(sz);
for (i = 0; i <= afhi->chunks_total && i * 4 + 3 < ct->size; i++)
afhi->chunk_table[i] = read_u32(ct->data + 4 * i);
}
for (i = 0; i <= afhi->chunks_total && i * 4 + 3 < ct->size; i++)
afhi->chunk_table[i] = read_u32(ct->data + 4 * i);
}
d->afhi.chunk_table = afd->afhi.chunk_table = NULL;
ret = osl(osl_open_disk_object(audio_file_table, current_aft_row,
AFTCOL_CHUNKS, &chunk_table_obj));
d->afhi.chunk_table = afd->afhi.chunk_table = NULL;
ret = osl(osl_open_disk_object(audio_file_table, current_aft_row,
AFTCOL_CHUNKS, &chunk_table_obj));
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ if (!afh_supports_dynamic_chunks(d->afsi.audio_format_id))
+ return ret;
+ PARA_INFO_LOG("no chunk table for %s\n", d->path);
+ chunk_table_obj.data = NULL;
+ chunk_table_obj.size = 0;
+ } else {
+ PARA_INFO_LOG("chunk table: %zu bytes\n", chunk_table_obj.size);
+ }
ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd);
if (ret < 0)
goto out;
ret = mmap_full_file(d->path, O_RDONLY, &map.data, &map.size, &afd->fd);
if (ret < 0)
goto out;
ret = save_afd(afd);
out:
free(afd->afhi.chunk_table);
ret = save_afd(afd);
out:
free(afd->afhi.chunk_table);
- osl_close_disk_object(&chunk_table_obj);
+ if (chunk_table_obj.data)
+ osl_close_disk_object(&chunk_table_obj);
if (ret < 0) {
PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret));
ret = score_delete(current_aft_row);
if (ret < 0) {
PARA_ERROR_LOG("%s: %s\n", d->path, para_strerror(-ret));
ret = score_delete(current_aft_row);
&objs[AFTCOL_AFHI]));
if (ret < 0)
goto out;
&objs[AFTCOL_AFHI]));
if (ret < 0)
goto out;
+ /* truncate the file to size zero if there is no chunk table */
ret = osl(osl_update_object(audio_file_table, row, AFTCOL_CHUNKS,
&objs[AFTCOL_CHUNKS]));
if (ret < 0)
ret = osl(osl_update_object(audio_file_table, row, AFTCOL_CHUNKS,
&objs[AFTCOL_CHUNKS]));
if (ret < 0)