#define RF64_NEVER 0
#define RF64_ALWAYS 1
-#define PEAK_BUFFER_SIZE 1024
-
typedef enum {
PEAK_OFF = 0,
PEAK_ON,
int64_t maxpts;
int16_t *peak_maxpos, *peak_maxneg;
uint32_t peak_num_frames;
- uint32_t peak_outbuf_size;
+ unsigned peak_outbuf_size;
uint32_t peak_outbuf_bytes;
+ unsigned size_increment;
uint8_t *peak_output;
int last_duration;
int write_bext;
ff_end_tag(s->pb, bext);
}
-static av_cold void peak_free_buffers(AVFormatContext *s)
+static av_cold void wav_deinit(AVFormatContext *s)
{
WAVMuxContext *wav = s->priv_data;
par->codec_id != AV_CODEC_ID_PCM_S16LE &&
par->codec_id != AV_CODEC_ID_PCM_U8 &&
par->codec_id != AV_CODEC_ID_PCM_U16LE) {
- AVCodec *codec = avcodec_find_decoder(s->streams[0]->codecpar->codec_id);
- av_log(s, AV_LOG_ERROR, "%s codec not supported for Peak Chunk\n",
- codec ? codec->name : "NONE");
+ av_log(s, AV_LOG_ERROR, "Codec %s not supported for Peak Chunk\n",
+ avcodec_get_name(par->codec_id));
return -1;
}
"Writing 16 bit peak for 8 bit audio does not make sense\n");
return AVERROR(EINVAL);
}
+ if (par->channels > INT_MAX / (wav->peak_bps * wav->peak_ppv))
+ return AVERROR(ERANGE);
+ wav->size_increment = par->channels * wav->peak_bps * wav->peak_ppv;
wav->peak_maxpos = av_mallocz_array(par->channels, sizeof(*wav->peak_maxpos));
wav->peak_maxneg = av_mallocz_array(par->channels, sizeof(*wav->peak_maxneg));
- wav->peak_output = av_malloc(PEAK_BUFFER_SIZE);
- if (!wav->peak_maxpos || !wav->peak_maxneg || !wav->peak_output)
+ if (!wav->peak_maxpos || !wav->peak_maxneg)
goto nomem;
- wav->peak_outbuf_size = PEAK_BUFFER_SIZE;
-
return 0;
nomem:
av_log(s, AV_LOG_ERROR, "Out of memory\n");
- peak_free_buffers(s);
return AVERROR(ENOMEM);
}
-static void peak_write_frame(AVFormatContext *s)
+static int peak_write_frame(AVFormatContext *s)
{
WAVMuxContext *wav = s->priv_data;
AVCodecParameters *par = s->streams[0]->codecpar;
+ unsigned new_size = wav->peak_outbuf_bytes + wav->size_increment;
+ uint8_t *tmp;
int c;
- if (!wav->peak_output)
- return;
+ if (new_size > INT_MAX) {
+ wav->write_peak = PEAK_OFF;
+ return AVERROR(ERANGE);
+ }
+ tmp = av_fast_realloc(wav->peak_output, &wav->peak_outbuf_size, new_size);
+ if (!tmp) {
+ wav->write_peak = PEAK_OFF;
+ return AVERROR(ENOMEM);
+ }
+ wav->peak_output = tmp;
for (c = 0; c < par->channels; c++) {
wav->peak_maxneg[c] = -wav->peak_maxneg[c];
wav->peak_maxpos[c] =
FFMAX(wav->peak_maxpos[c], wav->peak_maxneg[c]);
- if (wav->peak_outbuf_size - wav->peak_outbuf_bytes <
- wav->peak_format * wav->peak_ppv) {
- wav->peak_outbuf_size += PEAK_BUFFER_SIZE;
- wav->peak_output = av_realloc(wav->peak_output,
- wav->peak_outbuf_size);
- if (!wav->peak_output) {
- av_log(s, AV_LOG_ERROR, "No memory for peak data\n");
- return;
- }
- }
-
if (wav->peak_format == PEAK_FORMAT_UINT8) {
wav->peak_output[wav->peak_outbuf_bytes++] =
wav->peak_maxpos[c];
wav->peak_maxneg[c] = 0;
}
wav->peak_num_frames++;
+
+ return 0;
}
static int peak_write_chunk(AVFormatContext *s)
char timestamp[28];
/* Peak frame of incomplete block at end */
- if (wav->peak_block_pos)
- peak_write_frame(s);
+ if (wav->peak_block_pos) {
+ int ret = peak_write_frame(s);
+ if (ret < 0)
+ return ret;
+ }
memset(timestamp, 0, sizeof(timestamp));
if (!(s->flags & AVFMT_FLAG_BITEXACT)) {
/* format header */
fmt = ff_start_tag(pb, "fmt ");
if (ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0) < 0) {
- const AVCodecDescriptor *desc = avcodec_descriptor_get(s->streams[0]->codecpar->codec_id);
- av_log(s, AV_LOG_ERROR, "%s codec not supported in WAVE format\n",
- desc ? desc->name : "unknown");
+ av_log(s, AV_LOG_ERROR, "Codec %s not supported in WAVE format\n",
+ avcodec_get_name(s->streams[0]->codecpar->codec_id));
return AVERROR(ENOSYS);
}
ff_end_tag(pb, fmt);
wav->data = ff_start_tag(pb, "data");
}
- avio_flush(pb);
-
return 0;
}
if (++c == s->streams[0]->codecpar->channels) {
c = 0;
if (++wav->peak_block_pos == wav->peak_block_size) {
- peak_write_frame(s);
+ int ret = peak_write_frame(s);
+ if (ret < 0)
+ return ret;
wav->peak_block_pos = 0;
}
}
int rf64 = 0;
int ret = 0;
- avio_flush(pb);
-
if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
if (wav->write_peak != PEAK_ONLY && avio_tell(pb) - wav->data < UINT32_MAX) {
ff_end_tag(pb, wav->data);
- avio_flush(pb);
}
if (wav->write_peak && wav->peak_output) {
ret = peak_write_chunk(s);
- avio_flush(pb);
}
/* update file size */
avio_seek(pb, 4, SEEK_SET);
avio_wl32(pb, (uint32_t)(file_size - 8));
avio_seek(pb, file_size, SEEK_SET);
-
- avio_flush(pb);
} else {
av_log(s, AV_LOG_ERROR,
"Filesize %"PRId64" invalid for wav, output file will be broken\n",
file_size);
}
-
- number_of_samples = av_rescale(wav->maxpts - wav->minpts + wav->last_duration,
- s->streams[0]->codecpar->sample_rate * (int64_t)s->streams[0]->time_base.num,
- s->streams[0]->time_base.den);
+ number_of_samples = av_rescale_q(wav->maxpts - wav->minpts + wav->last_duration,
+ s->streams[0]->time_base,
+ av_make_q(1, s->streams[0]->codecpar->sample_rate));
if(s->streams[0]->codecpar->codec_tag != 0x01) {
/* Update num_samps in fact chunk */
} else {
avio_wl32(pb, number_of_samples);
avio_seek(pb, file_size, SEEK_SET);
- avio_flush(pb);
}
}
avio_wl32(pb, -1);
avio_seek(pb, file_size, SEEK_SET);
- avio_flush(pb);
}
}
- if (wav->write_peak)
- peak_free_buffers(s);
-
return ret;
}
.version = LIBAVUTIL_VERSION_INT,
};
-AVOutputFormat ff_wav_muxer = {
+const AVOutputFormat ff_wav_muxer = {
.name = "wav",
.long_name = NULL_IF_CONFIG_SMALL("WAV / WAVE (Waveform Audio)"),
.mime_type = "audio/x-wav",
.write_header = wav_write_header,
.write_packet = wav_write_packet,
.write_trailer = wav_write_trailer,
+ .deinit = wav_deinit,
.flags = AVFMT_TS_NONSTRICT,
- .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+ .codec_tag = ff_wav_codec_tags_list,
.priv_class = &wav_muxer_class,
};
#endif /* CONFIG_WAV_MUXER */
avio_write(pb, ff_w64_guid_wave, sizeof(ff_w64_guid_wave));
start_guid(pb, ff_w64_guid_fmt, &start);
if ((ret = ff_put_wav_header(s, pb, s->streams[0]->codecpar, 0)) < 0) {
- AVCodec *codec = avcodec_find_decoder(s->streams[0]->codecpar->codec_id);
- av_log(s, AV_LOG_ERROR, "%s codec not supported\n",
- codec ? codec->name : "NONE");
+ av_log(s, AV_LOG_ERROR, "Codec %s not supported\n",
+ avcodec_get_name(s->streams[0]->codecpar->codec_id));
return ret;
}
end_guid(pb, start);
}
avio_seek(pb, file_size, SEEK_SET);
- avio_flush(pb);
}
return 0;
}
-AVOutputFormat ff_w64_muxer = {
+const AVOutputFormat ff_w64_muxer = {
.name = "w64",
.long_name = NULL_IF_CONFIG_SMALL("Sony Wave64"),
.extensions = "w64",
.write_packet = wav_write_packet,
.write_trailer = w64_write_trailer,
.flags = AVFMT_TS_NONSTRICT,
- .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 },
+ .codec_tag = ff_wav_codec_tags_list,
};
#endif /* CONFIG_W64_MUXER */