mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-17 17:17:40 +02:00
avoid using AVCodecContext->frame_size as the one and only frame size
It can be 0 in case of variable frame size support. Signed-off-by: Michael Niedermayer <michaelni@gmx.at> Signed-off-by: Benjamin Drung <bdrung@debian.org>
This commit is contained in:
parent
813f8450ea
commit
9755771524
@ -147,10 +147,9 @@ private:
|
|||||||
|
|
||||||
AVFormatContext * mEncFormatCtx; // libavformat's context for our output file
|
AVFormatContext * mEncFormatCtx; // libavformat's context for our output file
|
||||||
AVOutputFormat * mEncFormatDesc; // describes our output file to libavformat
|
AVOutputFormat * mEncFormatDesc; // describes our output file to libavformat
|
||||||
|
int default_frame_size;
|
||||||
AVStream * mEncAudioStream; // the output audio stream (may remain NULL)
|
AVStream * mEncAudioStream; // the output audio stream (may remain NULL)
|
||||||
AVCodecContext * mEncAudioCodecCtx; // the encoder for the output audio stream
|
AVCodecContext * mEncAudioCodecCtx; // the encoder for the output audio stream
|
||||||
int mEncAudioEncodedBufSiz;
|
|
||||||
AVFifoBuffer * mEncAudioFifo; // FIFO to write incoming audio samples into
|
AVFifoBuffer * mEncAudioFifo; // FIFO to write incoming audio samples into
|
||||||
uint8_t * mEncAudioFifoOutBuf; // buffer to read _out_ of the FIFO into
|
uint8_t * mEncAudioFifoOutBuf; // buffer to read _out_ of the FIFO into
|
||||||
int mEncAudioFifoOutBufSiz;
|
int mEncAudioFifoOutBufSiz;
|
||||||
@ -176,7 +175,6 @@ ExportFFmpeg::ExportFFmpeg()
|
|||||||
mEncAudioStream = NULL; // the output audio stream (may remain NULL)
|
mEncAudioStream = NULL; // the output audio stream (may remain NULL)
|
||||||
mEncAudioCodecCtx = NULL; // the encoder for the output audio stream
|
mEncAudioCodecCtx = NULL; // the encoder for the output audio stream
|
||||||
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
|
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
|
||||||
mEncAudioEncodedBufSiz = 4*MAX_AUDIO_PACKET_SIZE;
|
|
||||||
mEncAudioFifoOutBuf = NULL; // buffer to read _out_ of the FIFO into
|
mEncAudioFifoOutBuf = NULL; // buffer to read _out_ of the FIFO into
|
||||||
mEncAudioFifoOutBufSiz = 0;
|
mEncAudioFifoOutBufSiz = 0;
|
||||||
|
|
||||||
@ -497,12 +495,11 @@ bool ExportFFmpeg::InitCodecs(AudacityProject *project)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLogDebug(wxT("FFmpeg : Audio Output Codec Frame Size: %d samples."), mEncAudioCodecCtx->frame_size);
|
default_frame_size = mEncAudioCodecCtx->frame_size;
|
||||||
|
if (default_frame_size == 0)
|
||||||
|
default_frame_size = 1024; // arbitrary non zero value;
|
||||||
|
|
||||||
if ((mEncAudioCodecCtx->codec_id >= CODEC_ID_PCM_S16LE) && (mEncAudioCodecCtx->codec_id <= CODEC_ID_PCM_DVD))
|
wxLogDebug(wxT("FFmpeg : Audio Output Codec Frame Size: %d samples."), mEncAudioCodecCtx->frame_size);
|
||||||
{
|
|
||||||
mEncAudioEncodedBufSiz = FF_MIN_BUFFER_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The encoder may require a minimum number of raw audio samples for each encoding but we can't
|
// The encoder may require a minimum number of raw audio samples for each encoding but we can't
|
||||||
// guarantee we'll get this minimum each time an audio frame is decoded from the input file so
|
// guarantee we'll get this minimum each time an audio frame is decoded from the input file so
|
||||||
@ -524,7 +521,7 @@ bool ExportFFmpeg::InitCodecs(AudacityProject *project)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encode_audio(AVCodecContext *avctx, AVPacket *pkt, int16_t *audio_samples)
|
static int encode_audio(AVCodecContext *avctx, AVPacket *pkt, int16_t *audio_samples, int nb_samples)
|
||||||
{
|
{
|
||||||
int i, ch, buffer_size, ret, got_output = 0, nEncodedBytes;
|
int i, ch, buffer_size, ret, got_output = 0, nEncodedBytes;
|
||||||
void *samples = NULL;
|
void *samples = NULL;
|
||||||
@ -535,13 +532,10 @@ static int encode_audio(AVCodecContext *avctx, AVPacket *pkt, int16_t *audio_sam
|
|||||||
if (!frame)
|
if (!frame)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
frame->nb_samples = avctx->frame_size;
|
frame->nb_samples = nb_samples;
|
||||||
frame->format = avctx->sample_fmt;
|
frame->format = avctx->sample_fmt;
|
||||||
frame->channel_layout = avctx->channel_layout;
|
frame->channel_layout = avctx->channel_layout;
|
||||||
|
|
||||||
if (frame->nb_samples == 0)
|
|
||||||
frame->nb_samples = 1024; //arbitrary non zero number of samples
|
|
||||||
|
|
||||||
buffer_size = av_samples_get_buffer_size(NULL, avctx->channels, frame->nb_samples,
|
buffer_size = av_samples_get_buffer_size(NULL, avctx->channels, frame->nb_samples,
|
||||||
avctx->sample_fmt, 0);
|
avctx->sample_fmt, 0);
|
||||||
if (buffer_size < 0) {
|
if (buffer_size < 0) {
|
||||||
@ -612,8 +606,7 @@ bool ExportFFmpeg::Finalize()
|
|||||||
av_init_packet(&pkt);
|
av_init_packet(&pkt);
|
||||||
|
|
||||||
nEncodedBytes = 0;
|
nEncodedBytes = 0;
|
||||||
int nAudioFrameSizeOut = mEncAudioCodecCtx->frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
|
int nAudioFrameSizeOut = default_frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
|
||||||
if (mEncAudioCodecCtx->frame_size <= 1) nAudioFrameSizeOut = mEncAudioEncodedBufSiz;
|
|
||||||
|
|
||||||
if (nAudioFrameSizeOut > mEncAudioFifoOutBufSiz || nFifoBytes > mEncAudioFifoOutBufSiz) {
|
if (nAudioFrameSizeOut > mEncAudioFifoOutBufSiz || nFifoBytes > mEncAudioFifoOutBufSiz) {
|
||||||
wxLogError(wxT("FFmpeg : ERROR - Too much remaining data."));
|
wxLogError(wxT("FFmpeg : ERROR - Too much remaining data."));
|
||||||
@ -627,7 +620,7 @@ bool ExportFFmpeg::Finalize()
|
|||||||
{
|
{
|
||||||
// Fill audio buffer with zeroes. If codec tries to read the whole buffer,
|
// Fill audio buffer with zeroes. If codec tries to read the whole buffer,
|
||||||
// it will just read silence. If not - who cares?
|
// it will just read silence. If not - who cares?
|
||||||
memset(mEncAudioFifoOutBuf,0,nAudioFrameSizeOut);
|
memset(mEncAudioFifoOutBuf,0,mEncAudioFifoOutBufSiz);
|
||||||
const AVCodec *codec = mEncAudioCodecCtx->codec;
|
const AVCodec *codec = mEncAudioCodecCtx->codec;
|
||||||
|
|
||||||
// We have an incomplete buffer of samples left. Is it OK to encode it?
|
// We have an incomplete buffer of samples left. Is it OK to encode it?
|
||||||
@ -640,12 +633,12 @@ bool ExportFFmpeg::Finalize()
|
|||||||
|| gPrefs->Read(wxT("/FileFormats/OverrideSmallLastFrame"), true)
|
|| gPrefs->Read(wxT("/FileFormats/OverrideSmallLastFrame"), true)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int nFrameSizeTmp = mEncAudioCodecCtx->frame_size;
|
int frame_size = default_frame_size;
|
||||||
|
|
||||||
// The last frame is going to contain a smaller than usual number of samples.
|
// The last frame is going to contain a smaller than usual number of samples.
|
||||||
// For codecs without CODEC_CAP_SMALL_LAST_FRAME use normal frame size
|
// For codecs without CODEC_CAP_SMALL_LAST_FRAME use normal frame size
|
||||||
if (mEncAudioCodecCtx->frame_size > 1 && codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)
|
if (codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME)
|
||||||
mEncAudioCodecCtx->frame_size = nFifoBytes / (mEncAudioCodecCtx->channels * sizeof(int16_t));
|
frame_size = nFifoBytes / (mEncAudioCodecCtx->channels * sizeof(int16_t));
|
||||||
|
|
||||||
wxLogDebug(wxT("FFmpeg : Audio FIFO still contains %d bytes, writing %d sample frame ..."),
|
wxLogDebug(wxT("FFmpeg : Audio FIFO still contains %d bytes, writing %d sample frame ..."),
|
||||||
nFifoBytes, frame_size);
|
nFifoBytes, frame_size);
|
||||||
@ -657,16 +650,14 @@ bool ExportFFmpeg::Finalize()
|
|||||||
if (av_fifo_generic_read(mEncAudioFifo, nFifoBytes, NULL, mEncAudioFifoOutBuf) == 0)
|
if (av_fifo_generic_read(mEncAudioFifo, nFifoBytes, NULL, mEncAudioFifoOutBuf) == 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
nEncodedBytes = encode_audio(mEncAudioCodecCtx, &pkt, (int16_t*)mEncAudioFifoOutBuf);
|
nEncodedBytes = encode_audio(mEncAudioCodecCtx, &pkt, (int16_t*)mEncAudioFifoOutBuf, frame_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
mEncAudioCodecCtx->frame_size = nFrameSizeTmp; // restore the native frame size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now flush the encoder.
|
// Now flush the encoder.
|
||||||
if (nEncodedBytes <= 0)
|
if (nEncodedBytes <= 0)
|
||||||
nEncodedBytes = encode_audio(mEncAudioCodecCtx, &pkt, NULL);
|
nEncodedBytes = encode_audio(mEncAudioCodecCtx, &pkt, NULL, 0);
|
||||||
|
|
||||||
if (nEncodedBytes <= 0)
|
if (nEncodedBytes <= 0)
|
||||||
break;
|
break;
|
||||||
@ -724,8 +715,7 @@ bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, int frameSize)
|
|||||||
AVPacket pkt;
|
AVPacket pkt;
|
||||||
int nBytesToWrite = 0;
|
int nBytesToWrite = 0;
|
||||||
uint8_t * pRawSamples = NULL;
|
uint8_t * pRawSamples = NULL;
|
||||||
int nAudioFrameSizeOut = mEncAudioCodecCtx->frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
|
int nAudioFrameSizeOut = default_frame_size * mEncAudioCodecCtx->channels * sizeof(int16_t);
|
||||||
if (mEncAudioCodecCtx->frame_size <= 1) nAudioFrameSizeOut = mEncAudioEncodedBufSiz;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
nBytesToWrite = frameSize;
|
nBytesToWrite = frameSize;
|
||||||
@ -755,8 +745,8 @@ bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, int frameSize)
|
|||||||
|
|
||||||
int ret= encode_audio(mEncAudioCodecCtx,
|
int ret= encode_audio(mEncAudioCodecCtx,
|
||||||
&pkt, // out
|
&pkt, // out
|
||||||
(int16_t*)mEncAudioFifoOutBuf); // in
|
(int16_t*)mEncAudioFifoOutBuf, // in
|
||||||
if (mEncAudioCodecCtx->frame_size == 1) { wxASSERT(pkt.size == mEncAudioEncodedBufSiz); }
|
default_frame_size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
wxLogError(wxT("FFmpeg : ERROR - Can't encode audio frame."));
|
wxLogError(wxT("FFmpeg : ERROR - Can't encode audio frame."));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user