aac_afh: Don't create chunk tables any more.
authorAndre Noll <maan@tuebingen.mpg.de>
Sat, 24 Dec 2016 15:02:36 +0000 (16:02 +0100)
committerAndre Noll <maan@tuebingen.mpg.de>
Sat, 25 Mar 2017 10:54:36 +0000 (11:54 +0100)
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.

aac_afh.c
afh.h
afh_common.c
aft.c

index bcf7b78..b555244 100644 (file)
--- a/aac_afh.c
+++ b/aac_afh.c
@@ -149,7 +149,7 @@ static int aac_afh_get_chunk(long unsigned chunk_num, void *afh_context,
        *len = ss;
        return 1;
 }
-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)
 {
        int i;
 
@@ -279,37 +279,30 @@ static void aac_get_taginfo(char *buf, size_t buflen, struct afh_info *afhi)
        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)
 {
        int ret, i;
-       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;
+       afhi->max_chunk_size = 0;
        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++) {
+               uint32_t val;
                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);
                skip += 4;
-//             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);
@@ -319,7 +312,13 @@ static int aac_set_chunk_tv(struct afh_info *afhi,
                afhi->chunks_total, tv2ms(&afhi->chunk_tv));
        if (ms < 1000)
                return -E_MP4ASC;
-       *seconds = ms / 1000;
+       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);
        return 1;
 }
 
@@ -329,7 +328,6 @@ static int aac_set_chunk_tv(struct afh_info *afhi,
 static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd,
                struct afh_info *afhi)
 {
-       int i;
        size_t skip;
        ssize_t ret;
        unsigned long rate = 0, decoder_len;
@@ -348,6 +346,8 @@ static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd,
                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,
@@ -355,25 +355,9 @@ static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd,
                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);
        if (ret < 0)
                goto out;
-       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)
diff --git a/afh.h b/afh.h
index 6b91691..6dc5a3f 100644 (file)
--- a/afh.h
+++ b/afh.h
@@ -158,3 +158,4 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re
 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);
index a1021ee..78e3779 100644 (file)
@@ -109,7 +109,18 @@ void afh_init(void)
        }
 }
 
-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;
 }
diff --git a/aft.c b/aft.c
index 4e2e1f8..7d3a6e0 100644 (file)
--- a/aft.c
+++ b/aft.c
@@ -409,9 +409,10 @@ static void load_afhi(const char *buf, struct afh_info *afhi)
        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)
 {
-       if (!afhi)
+       if (!afhi || !afhi->chunk_table)
                return 0;
        return 4 * (afhi->chunks_total + 1);
 }
@@ -420,6 +421,8 @@ static void save_chunk_table(struct afh_info *afhi, char *buf)
 {
        uint32_t n;
 
+       if (!afhi->chunk_table)
+               return;
        for (n = 0; n <= afhi->chunks_total; n++)
                write_u32(buf + 4 * n, afhi->chunk_table[n]);
 }
@@ -427,8 +430,14 @@ static void save_chunk_table(struct afh_info *afhi, char *buf)
 static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct)
 {
        int i;
+       size_t sz;
 
-       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);
 }
@@ -1061,8 +1070,15 @@ again:
        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;
@@ -1092,7 +1108,8 @@ again:
        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);
@@ -1743,6 +1760,7 @@ static int com_add_callback(struct afs_callback_arg *aca)
                        &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)