},
{
.name = "aac",
-#if defined(HAVE_MP4V2)
+#if defined(HAVE_FAAD)
.init = aac_afh_init,
#endif
},
if (afl[format].init)
return format;
}
-
}
/** Iterate over each supported audio format. */
}
}
+/**
+ * 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;
+}
+
/**
* Guess the audio format judging from filename.
*
/**
* Get one chunk of audio data.
*
+ * This implicitly calls the ->open method of the audio format handler at the
+ * first call.
+ *
* \param chunk_num The number of the chunk to get.
* \param afhi Describes the audio file.
+ * \param audio_format_id Determines the afh.
* \param map The memory mapped audio file.
+ * \param mapsize Passed to the afh's ->open() method.
* \param buf Result pointer.
* \param len The length of the chunk in bytes.
+ * \param afh_context Value/result, determines whether ->open() is called.
*
* Upon return, \a buf will point so memory inside \a map. The returned buffer
* must therefore not be freed by the caller.
+ *
+ * \return Standard.
*/
-void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi,
- void *map, const char **buf, size_t *len)
+__must_check int afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi,
+ uint8_t audio_format_id, const void *map, size_t mapsize,
+ const char **buf, size_t *len, void **afh_context)
{
- size_t pos = afhi->chunk_table[chunk_num];
- *buf = map + pos;
- *len = get_chunk_len(chunk_num, afhi);
+ struct audio_format_handler *afh = afl + audio_format_id;
+
+ if (afh_supports_dynamic_chunks(audio_format_id)) {
+ int ret;
+
+ if (!*afh_context) {
+ ret = afh->open(map, mapsize, afh_context);
+ if (ret < 0)
+ return ret;
+ }
+ ret = afl[audio_format_id].get_chunk(chunk_num, *afh_context,
+ buf, len);
+ if (ret < 0) {
+ afh->close(*afh_context);
+ *afh_context = NULL;
+ }
+ return ret;
+ } else {
+ size_t pos = afhi->chunk_table[chunk_num];
+ *buf = map + pos;
+ *len = get_chunk_len(chunk_num, afhi);
+ return 0;
+ }
+}
+
+/**
+ * Deallocate resources allocated due to dynamic chunk handling.
+ *
+ * This function should be called if afh_get_chunk() was called at least once.
+ * It is OK to call it even for audio formats which do not support dynamic
+ * chunks, in which case the function does nothing.
+ *
+ * \param afh_context As returned from the ->open method of the afh.
+ * \param audio_format_id Determines the afh.
+ */
+void afh_close(void *afh_context, uint8_t audio_format_id)
+{
+ struct audio_format_handler *afh = afl + audio_format_id;
+
+ if (!afh_supports_dynamic_chunks(audio_format_id))
+ return;
+ if (!afh->close)
+ return;
+ if (!afh_context)
+ return;
+ afh->close(afh_context);
}
/**
*
* \param approx_chunk_num Upper bound for the chunk number to return.
* \param afhi Needed for the chunk table.
+ * \param audio_format_id Determines the afh.
*
- * \return The first non-empty chunk <= \a approx_chunk_num.
+ * \return For audio format handlers which support dynamic chunks, the function
+ * returns the given chunk number. Otherwise it returns the first non-empty
+ * chunk <= \a approx_chunk_num.
*
* \sa \ref afh_get_chunk().
*/
int32_t afh_get_start_chunk(int32_t approx_chunk_num,
- const struct afh_info *afhi)
+ const struct afh_info *afhi, uint8_t audio_format_id)
{
int32_t k;
+ if (afh_supports_dynamic_chunks(audio_format_id))
+ return approx_chunk_num;
+
for (k = PARA_MAX(0, approx_chunk_num); k >= 0; k--)
if (get_chunk_len(k, afhi) > 0)
return k;