From ab430ea4460aba050d97d3e3a712a3b6dd809db9 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 15 Jul 2024 00:41:04 +0100 Subject: [PATCH 1/4] Fix build with FFmpeg 7 --- libmusly/CMakeLists.txt | 5 -- libmusly/decoders/libav.cpp | 136 +++++++++++------------------------- 2 files changed, 42 insertions(+), 99 deletions(-) diff --git a/libmusly/CMakeLists.txt b/libmusly/CMakeLists.txt index d6d3680..98151df 100644 --- a/libmusly/CMakeLists.txt +++ b/libmusly/CMakeLists.txt @@ -16,11 +16,6 @@ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/external") PROPERTIES COMPILE_FLAGS "-DLIBMUSLY_EXTERNAL ${LIBMUSLY_EXTERNAL_FLAGS}") endif() -if(EXISTS "${LIBAV_INCLUDE_DIRS}/libavutil/channel_layout.h") - set_source_files_properties(decoders/libav.cpp - PROPERTIES COMPILE_FLAGS "-DHAVE_AVUTIL_CHANNEL_LAYOUT") -endif() - if(USE_OPENMP AND OPENMP_FOUND) # disable OpenMP for kiss FFT, it slows things down terribly set_source_files_properties(kissfft/kiss_fft.c diff --git a/libmusly/decoders/libav.cpp b/libmusly/decoders/libav.cpp index a78b904..90f93ae 100644 --- a/libmusly/decoders/libav.cpp +++ b/libmusly/decoders/libav.cpp @@ -20,37 +20,13 @@ extern "C" { #include #include -#ifdef HAVE_AVUTIL_CHANNEL_LAYOUT #include -#endif } #include "minilog.h" #include "resampler.h" #include "libav.h" -// We define some macros to be compatible to different libav versions -// without spreading #if and #else all over the place. -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 45, 101) -#define AV_FRAME_ALLOC avcodec_alloc_frame -#define AV_FRAME_UNREF avcodec_get_frame_defaults -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 28, 0) -#define AV_FRAME_FREE(X) av_free(*(X)) -#else -#define AV_FRAME_FREE avcodec_free_frame -#endif -#else -#define AV_FRAME_ALLOC av_frame_alloc -#define AV_FRAME_UNREF av_frame_unref -#define AV_FRAME_FREE av_frame_free -#endif - -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 7, 0) -#define AV_PACKET_UNREF av_free_packet -#else -#define AV_PACKET_UNREF av_packet_unref -#endif - namespace musly { namespace decoders { @@ -58,12 +34,6 @@ MUSLY_DECODER_REGIMPL(libav, 0); libav::libav() { -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) - av_register_all(); -#endif -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100) - avcodec_register_all(); -#endif } int @@ -177,13 +147,7 @@ libav::decodeto_22050hz_mono_float( AVStream *st = fmtx->streams[audio_stream_idx]; // find a decoder for the stream -#if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 14, 0)) || ((LIBAVCODEC_VERSION_MICRO >= 100) && (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 33, 100))) - // old libav version (libavcodec < 57.14 for libav, < 57.33 for ffmpeg): - // stream has a codec context we can use - AVCodecContext *decx = st->codec; - #define AVCODEC_FREE_CONTEXT(x) -#else - // new libav version: need to create codec context for stream + // need to create codec context for stream AVCodecParameters *decp = st->codecpar; AVCodecContext *decx = avcodec_alloc_context3(NULL); if (!decx) { @@ -200,71 +164,63 @@ libav::decodeto_22050hz_mono_float( avformat_close_input(&fmtx); return std::vector(0); } - #if LIBAVCODEC_VERSION_MICRO >= 100 - #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58,3,102) - // only available in ffmpeg, deprecated after 58 - av_codec_set_pkt_timebase(decx, st->time_base); - #endif - #endif - #define AVCODEC_FREE_CONTEXT(x) avcodec_free_context(x) -#endif - AVCodec *dec = avcodec_find_decoder(decx->codec_id); + const AVCodec *dec = avcodec_find_decoder(decx->codec_id); if (!dec) { MINILOG(logERROR) << "Could not find codec."; - AVCODEC_FREE_CONTEXT(&decx); + avcodec_free_context(&decx); avformat_close_input(&fmtx); return std::vector(0); } // open the decoder // (kindly ask for stereo downmix and floats, but not all decoders care) - decx->request_channel_layout = AV_CH_LAYOUT_STEREO_DOWNMIX; decx->request_sample_fmt = AV_SAMPLE_FMT_FLT; #ifdef _OPENMP #pragma omp critical #endif { - avret = avcodec_open2(decx, dec, NULL); + AVDictionary *options = NULL; + av_dict_set(&options, "downmix", "stereo", 0); + avret = avcodec_open2(decx, dec, &options); } if (avret < 0) { MINILOG(logERROR) << "Could not open codec."; - AVCODEC_FREE_CONTEXT(&decx); + avcodec_free_context(&decx); avformat_close_input(&fmtx); return std::vector(0); } // Currently only mono and stereo files are supported. - if ((decx->channels != 1) && (decx->channels != 2)) { + if ((decx->ch_layout.nb_channels != 1) && (decx->ch_layout.nb_channels != 2)) { MINILOG(logWARNING) << "Unsupported number of channels: " - << decx->channels; + << decx->ch_layout.nb_channels; - AVCODEC_FREE_CONTEXT(&decx); + avcodec_free_context(&decx); avformat_close_input(&fmtx); return std::vector(0); } // allocate a frame - AVFrame* frame = AV_FRAME_ALLOC(); + AVFrame* frame = av_frame_alloc(); if (!frame) { MINILOG(logWARNING) << "Could not allocate frame"; - AVCODEC_FREE_CONTEXT(&decx); + avcodec_free_context(&decx); avformat_close_input(&fmtx); return std::vector(0); } // allocate and initialize a packet - AVPacket pkt; - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; + AVPacket* pkt = av_packet_alloc(); + pkt->data = NULL; + pkt->size = 0; int got_frame = 0; // configuration const int input_stride = av_get_bytes_per_sample(decx->sample_fmt); - const int num_planes = av_sample_fmt_is_planar(decx->sample_fmt) ? decx->channels : 1; + const int num_planes = av_sample_fmt_is_planar(decx->sample_fmt) ? decx->ch_layout.nb_channels : 1; const int output_stride = sizeof(float) * num_planes; int decode_samples; // how many samples to decode; zero to decode all @@ -296,7 +252,7 @@ libav::decodeto_22050hz_mono_float( // fault when trying to access frame->data[i] for i > 0 further below) if ((excerpt_start > 0) and (av_seek_frame(fmtx, audio_stream_idx, excerpt_start * st->time_base.den / st->time_base.num, - AVSEEK_FLAG_BACKWARD || AVSEEK_FLAG_ANY) >= 0)) { + AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)) { // skipping went fine: decode only what's needed decode_samples = excerpt_length * decx->sample_rate; excerpt_start = 0; @@ -333,7 +289,7 @@ libav::decodeto_22050hz_mono_float( // excerpt_start tells us up to how many seconds to cut from the beginning. // read packets - const int channels = decx->channels; + const int channels = decx->ch_layout.nb_channels; const int sample_rate = decx->sample_rate; float* buffer = NULL; int buffersize = 0; @@ -344,35 +300,29 @@ libav::decodeto_22050hz_mono_float( { // skip all frames that are not part of the audio stream, and spurious // frames possibly found after seeking (wrong channels / sample_rate) - while (((avret = av_read_frame(fmtx, &pkt)) >= 0) - && ((pkt.stream_index != audio_stream_idx) || - (decx->channels != channels) || + while (((avret = av_read_frame(fmtx, pkt)) >= 0) + && ((pkt->stream_index != audio_stream_idx) || + (decx->ch_layout.nb_channels != channels) || (decx->sample_rate != sample_rate))) { - AV_PACKET_UNREF(&pkt); + av_packet_unref(pkt); MINILOG(logTRACE) << "Skipping frame..."; } if (avret < 0) { // stop decoding if av_read_frame() failed - AV_PACKET_UNREF(&pkt); + av_packet_unref(pkt); break; } - uint8_t* data = pkt.data; - int size = pkt.size; - while (pkt.size > 0) { + uint8_t* data = pkt->data; + int size = pkt->size; + while (pkt->size > 0) { // try to decode a frame - AV_FRAME_UNREF(frame); + av_frame_unref(frame); int len = 0; got_frame = 0; -#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101) - len = avcodec_decode_audio4(decx, frame, &got_frame, &pkt); - if (len < 0) { - avret = AVERROR(EINVAL); - } -#else avret = avcodec_receive_frame(decx, frame); if (avret == 0) { got_frame = 1; @@ -381,14 +331,13 @@ libav::decodeto_22050hz_mono_float( avret = 0; } if (avret == 0) { - avret = avcodec_send_packet(decx, &pkt); + avret = avcodec_send_packet(decx, pkt); if (avret == 0) { - len = pkt.size; + len = pkt->size; } else if (avret == AVERROR(EAGAIN)) { avret = 0; } } -#endif if (avret < 0) { MINILOG(logWARNING) << "Error decoding an audio frame"; @@ -400,8 +349,8 @@ libav::decodeto_22050hz_mono_float( // if too many frames failed decoding, abort MINILOG(logERROR) << "Too many errors, aborting."; - AV_FRAME_FREE(&frame); - AV_PACKET_UNREF(&pkt); + av_frame_free(&frame); + av_packet_unref(pkt); avformat_close_input(&fmtx); if (buffer) { delete[] buffer; @@ -414,7 +363,7 @@ libav::decodeto_22050hz_mono_float( // if we got a frame if (got_frame) { // do we need to increase the buffer size? - int input_samples = frame->nb_samples*decx->channels; + int input_samples = frame->nb_samples*decx->ch_layout.nb_channels; if (input_samples > buffersize) { if (buffer) { delete[] buffer; @@ -434,8 +383,8 @@ libav::decodeto_22050hz_mono_float( input_samples / num_planes) < 0) { MINILOG(logERROR) << "Strange sample format. Abort."; - AV_FRAME_FREE(&frame); - AV_PACKET_UNREF(&pkt); + av_frame_free(&frame); + av_packet_unref(pkt); avformat_close_input(&fmtx); if (buffer) { delete[] buffer; @@ -445,7 +394,7 @@ libav::decodeto_22050hz_mono_float( } // inplace downmix to mono, if required - if (decx->channels == 2) { + if (decx->ch_layout.nb_channels == 2) { for (int i = 0; i < frame->nb_samples; i++) { buffer[i] = (buffer[i*2] + buffer[i*2+1]) / 2.0f; } @@ -457,13 +406,13 @@ libav::decodeto_22050hz_mono_float( } // consume the packet - pkt.data += len; - pkt.size -= len; + pkt->data += len; + pkt->size -= len; } - pkt.data = data; - pkt.size = size; + pkt->data = data; + pkt->size = size; - AV_PACKET_UNREF(&pkt); + av_packet_unref(pkt); } MINILOG(logTRACE) << "Decoding loop finished."; @@ -514,13 +463,12 @@ libav::decodeto_22050hz_mono_float( if (buffer) { delete[] buffer; } - AV_FRAME_FREE(&frame); + av_frame_free(&frame); #ifdef _OPENMP #pragma omp critical #endif { - avcodec_close(decx); - AVCODEC_FREE_CONTEXT(&decx); + avcodec_free_context(&decx); avformat_close_input(&fmtx); } -- 2.45.2