Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compatibility with FFmpeg 5.0 #325

Merged
merged 1 commit into from
Mar 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 79 additions & 1 deletion av/src/AudioDecoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ignition::common::AudioDecoderPrivate
public: AVCodecContext *codecCtx;

/// \brief libavcodec audio codec.
public: AVCodec *codec;
public: const AVCodec *codec;

/// \brief Index of the audio stream.
public: int audioStream;
Expand Down Expand Up @@ -77,8 +77,12 @@ void AudioDecoder::Cleanup()
/////////////////////////////////////////////////
bool AudioDecoder::Decode(uint8_t **_outBuffer, unsigned int *_outBufferSize)
{
#if LIBAVFORMAT_VERSION_MAJOR < 59
AVPacket *packet, packet1;
int bytesDecoded = 0;
#else
AVPacket *packet;
#endif
unsigned int maxBufferSize = 0;
AVFrame *decodedFrame = nullptr;

Expand Down Expand Up @@ -121,6 +125,53 @@ bool AudioDecoder::Decode(uint8_t **_outBuffer, unsigned int *_outBufferSize)
{
if (packet->stream_index == this->data->audioStream)
{
#if LIBAVFORMAT_VERSION_MAJOR >= 59
// Inspired from
// https://github.com/FFmpeg/FFmpeg/blob/n5.0/doc/examples/decode_audio.c#L71

// send the packet with the compressed data to the decoder
int ret = avcodec_send_packet(this->data->codecCtx, packet);
if (ret < 0)
{
ignerr << "Error submitting the packet to the decoder" << std::endl;
return false;
}

// read all the output frames
// (in general there may be any number of them)
while (ret >= 0)
{
ret = avcodec_receive_frame(this->data->codecCtx, decodedFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
ignerr << "Error during decoding" << std::endl;
return false;
}

// Total size of the data. Some padding can be added to
// decodedFrame->data[0], which is why we can't use
// decodedFrame->linesize[0].
int size = decodedFrame->nb_samples *
av_get_bytes_per_sample(this->data->codecCtx->sample_fmt) *
this->data->codecCtx->channels;

// Resize the audio buffer as necessary
if (*_outBufferSize + size > maxBufferSize)
{
maxBufferSize += size * 5;
*_outBuffer = reinterpret_cast<uint8_t*>(realloc(*_outBuffer,
maxBufferSize * sizeof(*_outBuffer[0])));
}

memcpy(*_outBuffer + *_outBufferSize, decodedFrame->data[0],
size);
*_outBufferSize += size;
}
#else
int gotFrame = 0;

packet1 = *packet;
Expand Down Expand Up @@ -163,6 +214,7 @@ bool AudioDecoder::Decode(uint8_t **_outBuffer, unsigned int *_outBufferSize)
packet1.data += bytesDecoded;
packet1.size -= bytesDecoded;
}
#endif
}
av_packet_unref(packet);
}
Expand Down Expand Up @@ -224,8 +276,13 @@ bool AudioDecoder::SetFile(const std::string &_filename)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#if LIBAVFORMAT_VERSION_MAJOR >= 59
if (this->data->formatCtx->streams[i]->codecpar->codec_type == // NOLINT(*)
AVMEDIA_TYPE_AUDIO)
#else
if (this->data->formatCtx->streams[i]->codec->codec_type == // NOLINT(*)
AVMEDIA_TYPE_AUDIO)
#endif
#ifndef _WIN32
# pragma GCC diagnostic pop
#endif
Expand All @@ -249,14 +306,35 @@ bool AudioDecoder::SetFile(const std::string &_filename)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#if LIBAVFORMAT_VERSION_MAJOR < 59
this->data->codecCtx = this->data->formatCtx->streams[
this->data->audioStream]->codec;
#endif
#ifndef _WIN32
# pragma GCC diagnostic pop
#endif

// Find a decoder
#if LIBAVFORMAT_VERSION_MAJOR >= 59
this->data->codec = avcodec_find_decoder(this->data->formatCtx->streams[
this->data->audioStream]->codecpar->codec_id);
if (!this->data->codec)
{
ignerr << "Failed to find the codec" << std::endl;
return false;
}
this->data->codecCtx = avcodec_alloc_context3(this->data->codec);
if (!this->data->codecCtx)
{
ignerr << "Failed to allocate the codec context" << std::endl;
return false;
}
// Copy all relevant parameters from codepar to codecCtx
avcodec_parameters_to_context(this->data->codecCtx,
this->data->formatCtx->streams[this->data->audioStream]->codecpar);
#else
this->data->codec = avcodec_find_decoder(this->data->codecCtx->codec_id);
#endif

if (this->data->codec == nullptr)
{
Expand Down
4 changes: 3 additions & 1 deletion av/src/AudioDecoder_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ TEST(AudioDecoder, IGN_UTILS_TEST_DISABLED_ON_WIN32(CheerFile))
audio.Decode(&dataBuffer, &dataBufferSize);
// In Ubuntu trusty the buffer size double for ogg decoding.
// This check is suitable for both older and newer versions of Ubuntu.
// With ffmpeg 5.0 the value changed again (third value)
EXPECT_TRUE(dataBufferSize == 4989184u ||
dataBufferSize == 4989184u * 2u);
dataBufferSize == 4989184u * 2u ||
dataBufferSize == 9975224u);
}

// MP3
Expand Down
2 changes: 1 addition & 1 deletion av/src/Video.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void Video::Cleanup()
/////////////////////////////////////////////////
bool Video::Load(const std::string &_filename)
{
AVCodec *codec = nullptr;
const AVCodec * codec = nullptr;
this->dataPtr->videoStream = -1;

if (this->dataPtr->formatCtx || this->dataPtr->avFrame ||
Expand Down
6 changes: 3 additions & 3 deletions av/src/VideoEncoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class IGNITION_COMMON_AV_HIDDEN ignition::common::VideoEncoderPrivate
/// Find a suitable encoder for the given codec ID.
/// \param[in] _codecId ID of the codec we seek the encoder for.
/// \return The matched encoder (or nullptr on failure).
public: AVCodec* FindEncoder(AVCodecID _codecId);
public: const AVCodec* FindEncoder(AVCodecID _codecId);

/// \brief Get a pointer to the frame that contains the encoder input. This
/// mainly serves for uploading the frame to GPU buffer if HW acceleration is
Expand All @@ -123,7 +123,7 @@ class IGNITION_COMMON_AV_HIDDEN ignition::common::VideoEncoderPrivate
};

/////////////////////////////////////////////////
AVCodec* VideoEncoderPrivate::FindEncoder(AVCodecID _codecId)
const AVCodec* VideoEncoderPrivate::FindEncoder(AVCodecID _codecId)
{
#ifdef IGN_COMMON_BUILD_HW_VIDEO
if (this->hwEncoder)
Expand Down Expand Up @@ -367,7 +367,7 @@ bool VideoEncoder::Start(
}
else
{
AVOutputFormat *outputFormat = av_guess_format(nullptr,
const AVOutputFormat *outputFormat = av_guess_format(nullptr,
this->dataPtr->filename.c_str(), nullptr);

if (!outputFormat)
Expand Down