diff --git a/av/src/AudioDecoder.cc b/av/src/AudioDecoder.cc index ad73e48b8..9ad5c406a 100644 --- a/av/src/AudioDecoder.cc +++ b/av/src/AudioDecoder.cc @@ -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; @@ -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; @@ -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(realloc(*_outBuffer, + maxBufferSize * sizeof(*_outBuffer[0]))); + } + + memcpy(*_outBuffer + *_outBufferSize, decodedFrame->data[0], + size); + *_outBufferSize += size; + } +#else int gotFrame = 0; packet1 = *packet; @@ -163,6 +214,7 @@ bool AudioDecoder::Decode(uint8_t **_outBuffer, unsigned int *_outBufferSize) packet1.data += bytesDecoded; packet1.size -= bytesDecoded; } +#endif } av_packet_unref(packet); } @@ -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 @@ -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) { diff --git a/av/src/AudioDecoder_TEST.cc b/av/src/AudioDecoder_TEST.cc index 687741e56..32ec49efd 100644 --- a/av/src/AudioDecoder_TEST.cc +++ b/av/src/AudioDecoder_TEST.cc @@ -126,10 +126,12 @@ TEST(AudioDecoder, IGN_UTILS_TEST_DISABLED_ON_WIN32(CheerFile)) EXPECT_EQ(audio.SampleRate(), 44100); audio.Decode(&dataBuffer, &dataBufferSize); - // In Ubuntu trusty the buffer size double for ogg decoding. + // In Ubuntu trusty (ffmpeg ) 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 diff --git a/av/src/Video.cc b/av/src/Video.cc index d53f56fe8..701bf578a 100644 --- a/av/src/Video.cc +++ b/av/src/Video.cc @@ -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 || diff --git a/av/src/VideoEncoder.cc b/av/src/VideoEncoder.cc index cd6449df7..e98882db6 100644 --- a/av/src/VideoEncoder.cc +++ b/av/src/VideoEncoder.cc @@ -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 @@ -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) @@ -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)