/* if we don't know the size in advance */
#define AU_UNKNOWN_SIZE ((uint32_t)(~0))
-/* the specification requires an annotation field of at least eight bytes */
-#define AU_DEFAULT_HEADER_SIZE (24+8)
static const AVCodecTag codec_au_tags[] = {
{ AV_CODEC_ID_PCM_MULAW, 1 },
{ AV_CODEC_ID_NONE, 0 },
};
+static const AVCodecTag *const au_codec_tags[] = { codec_au_tags, NULL };
+
#if CONFIG_AU_DEMUXER
static int au_probe(const AVProbeData *p)
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
while (size-- > 0) {
+ if (avio_feof(pb)) {
+ av_bprint_finalize(&bprint, NULL);
+ av_freep(&key);
+ return AVERROR_EOF;
+ }
c = avio_r8(pb);
switch(state) {
case PARSE_KEY:
av_log(s, AV_LOG_ERROR, "Memory error while parsing AU metadata.\n");
} else {
av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
- for (i = 0; i < FF_ARRAY_ELEMS(keys) && key != NULL; i++) {
+ for (i = 0; i < FF_ARRAY_ELEMS(keys); i++) {
if (av_strcasecmp(keys[i], key) == 0) {
av_dict_set(&(s->metadata), keys[i], value, AV_DICT_DONT_STRDUP_VAL);
- av_freep(&key);
value = NULL;
+ break;
}
}
}
return 0;
}
-AVInputFormat ff_au_demuxer = {
+const AVInputFormat ff_au_demuxer = {
.name = "au",
.long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
.read_probe = au_probe,
.read_header = au_read_header,
.read_packet = ff_pcm_read_packet,
.read_seek = ff_pcm_read_seek,
- .codec_tag = (const AVCodecTag* const []) { codec_au_tags, 0 },
+ .codec_tag = au_codec_tags,
};
#endif /* CONFIG_AU_DEMUXER */
#include "rawenc.h"
-static int au_get_annotations(AVFormatContext *s, char **buffer)
+static int au_get_annotations(AVFormatContext *s, AVBPrint *annotations)
{
static const char keys[][7] = {
"Title",
int cnt = 0;
AVDictionary *m = s->metadata;
AVDictionaryEntry *t = NULL;
- AVBPrint bprint;
-
- av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED);
for (int i = 0; i < FF_ARRAY_ELEMS(keys); i++) {
t = av_dict_get(m, keys[i], NULL, 0);
if (t != NULL) {
if (cnt++)
- av_bprint_chars(&bprint, '\n', 1);
- av_bprint_append_data(&bprint, keys[i], strlen(keys[i]));
- av_bprint_chars(&bprint, '=', 1);
- av_bprint_append_data(&bprint, t->value, strlen(t->value));
+ av_bprint_chars(annotations, '\n', 1);
+ av_bprintf(annotations, "%s=%s", keys[i], t->value);
}
}
- /* pad with 0's */
- av_bprint_append_data(&bprint, "\0\0\0\0\0\0\0\0", 8);
- return av_bprint_finalize(&bprint, buffer);
+ /* The specification requires the annotation field to be zero-terminated
+ * and its length to be a multiple of eight, so pad with 0's */
+ av_bprint_chars(annotations, '\0', 8);
+ return av_bprint_is_complete(annotations) ? 0 : AVERROR(ENOMEM);
}
static int au_write_header(AVFormatContext *s)
AUContext *au = s->priv_data;
AVIOContext *pb = s->pb;
AVCodecParameters *par = s->streams[0]->codecpar;
- char *annotations = NULL;
-
- au->header_size = AU_DEFAULT_HEADER_SIZE;
+ AVBPrint annotations;
if (s->nb_streams != 1) {
av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
return AVERROR(EINVAL);
}
- if (av_dict_count(s->metadata) > 0) {
- ret = au_get_annotations(s, &annotations);
- if (ret < 0)
- return ret;
- if (annotations != NULL) {
- au->header_size = (24 + strlen(annotations) + 8) & ~7;
- if (au->header_size < AU_DEFAULT_HEADER_SIZE)
- au->header_size = AU_DEFAULT_HEADER_SIZE;
- }
- }
+ av_bprint_init(&annotations, 0, INT_MAX - 24);
+ ret = au_get_annotations(s, &annotations);
+ if (ret < 0)
+ goto fail;
+ au->header_size = 24 + annotations.len & ~7;
+
ffio_wfourcc(pb, ".snd"); /* magic number */
avio_wb32(pb, au->header_size); /* header size */
avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */
avio_wb32(pb, par->codec_tag); /* codec ID */
avio_wb32(pb, par->sample_rate);
avio_wb32(pb, par->channels);
- if (annotations != NULL) {
- avio_write(pb, annotations, au->header_size - 24);
- av_freep(&annotations);
- } else {
- avio_wb64(pb, 0); /* annotation field */
- }
+ avio_write(pb, annotations.str, annotations.len & ~7);
- return 0;
+fail:
+ av_bprint_finalize(&annotations, NULL);
+
+ return ret;
}
static int au_write_trailer(AVFormatContext *s)
return 0;
}
-AVOutputFormat ff_au_muxer = {
+const AVOutputFormat ff_au_muxer = {
.name = "au",
.long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
.mime_type = "audio/basic",
.write_header = au_write_header,
.write_packet = ff_raw_write_packet,
.write_trailer = au_write_trailer,
- .codec_tag = (const AVCodecTag* const []) { codec_au_tags, 0 },
+ .codec_tag = au_codec_tags,
.flags = AVFMT_NOTIMESTAMPS,
};