From b97a4a36070e2912f137a2624d576f9f238bba96 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Mon, 28 Jun 2021 22:01:28 +0200 Subject: [PATCH] UTILS: Create the raw image data from a file directly TODO: Cut the constructor into private methods to have something more digest to read. --- src/AudioUtils.cc | 75 ++++++++++++++++++++++----------------- src/AudioUtils.hh | 4 +-- src/UI/AudioVisualizer.cc | 3 +- 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/AudioUtils.cc b/src/AudioUtils.cc index fb65325d..677da4de 100644 --- a/src/AudioUtils.cc +++ b/src/AudioUtils.cc @@ -37,8 +37,9 @@ DecoderOption::getDecalage() const noexcept return decalage; } -RawImageData -RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path) +RawImageData::RawImageData(const DecoderOption &opt, const QString &path) + : chunkData(nullptr, fftSampleDeleter) + , ctx(nullptr, rdftContextDeleter) { auto avFrameDeleter = [](AVFrame *ptr) noexcept -> void { if (ptr) @@ -63,6 +64,8 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path) double *data = nullptr; size_t size = 0; + /* Decode audio */ + if (!frame) { qCritical() << "Error allocating the frame"; throw std::runtime_error("out of memory: failed to allocate the frame"); @@ -108,19 +111,21 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path) } /* Prepare resampler */ - av_opt_set_int(swr.get(), "in_channel_count", codec_ctx->channels, 0); - av_opt_set_int(swr.get(), "out_channel_count", 1, 0); - av_opt_set_int(swr.get(), "in_channel_layout", static_cast<int64_t>(codec_ctx->channel_layout), - 0); - av_opt_set_int(swr.get(), "out_channel_layout", AV_CH_LAYOUT_MONO, 0); - av_opt_set_int(swr.get(), "in_sample_rate", codec_ctx->sample_rate, 0); - av_opt_set_int(swr.get(), "out_sample_rate", opt.getSampleRate(), 0); - av_opt_set_sample_fmt(swr.get(), "in_sample_fmt", codec_ctx->sample_fmt, 0); - av_opt_set_sample_fmt(swr.get(), "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0); - swr_init(swr.get()); - if (!swr_is_initialized(swr.get())) { - fprintf(stderr, "Resampler has not been properly initialized\n"); - throw std::runtime_error("failed to initialize resampler"); + { + SwrContext *s = swr.get(); + av_opt_set_int(s, "in_channel_count", codec_ctx->channels, 0); + av_opt_set_int(s, "out_channel_count", 1, 0); + av_opt_set_int(s, "in_channel_layout", static_cast<int64_t>(codec_ctx->channel_layout), 0); + av_opt_set_int(s, "out_channel_layout", AV_CH_LAYOUT_MONO, 0); + av_opt_set_int(s, "in_sample_rate", codec_ctx->sample_rate, 0); + av_opt_set_int(s, "out_sample_rate", opt.getSampleRate(), 0); + av_opt_set_sample_fmt(s, "in_sample_fmt", codec_ctx->sample_fmt, 0); + av_opt_set_sample_fmt(s, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0); + swr_init(s); + if (!swr_is_initialized(s)) { + qCritical() << "Resampler has not been properly initialized"; + throw std::runtime_error("failed to initialize resampler"); + } } /* Prepare to read data */ @@ -142,8 +147,9 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path) av_samples_alloc((uint8_t **)&buffer, NULL, 1, frame->nb_samples, AV_SAMPLE_FMT_DBL, 0); const int frame_count_int = swr_convert(swr.get(), (uint8_t **)&buffer, frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples); - assert(frame_count_int >= 0); - const size_t frame_count = (size_t)frame_count_int; + if (frame_count_int < 0) + throw std::runtime_error("error on frame count, is negative but should not be"); + const size_t frame_count = static_cast<size_t>(frame_count_int); /* Append resampled frames to data */ data = (double *)realloc(data, (size + (size_t)frame->nb_samples) * sizeof(double)); @@ -152,24 +158,27 @@ RawImageData::fromAudioFile(const DecoderOption &opt, const QString &path) size += frame_count; } - if (codec_ctx != NULL) - avcodec_close(codec_ctx); - if (format != NULL) - avformat_free_context(format); + /* Clean ressources */ + { + if (codec_ctx != NULL) + avcodec_close(codec_ctx); + if (format != NULL) + avformat_free_context(format); + } - return RawImageData(opt, data, size); -} + auto dataHolder = std::shared_ptr<double>(data, free); + + /* Constructor */ + { + width = (static_cast<int>((size - opt.getChunkSize()) / opt.getDecalage())); + height = (static_cast<int>(opt.getChunkSize())); + pixels = std::unique_ptr<uchar[]>(new uchar[static_cast<size_t>(width * height / 2)]()); + chunkData.reset(reinterpret_cast<FFTSample *>( + av_malloc_array(2 * opt.getChunkSize(), sizeof(FFTSample)))); + ctx.reset( + av_rdft_init((static_cast<int>(log2(static_cast<int>(opt.getChunkSize())))), DFT_R2C)); + } -RawImageData::RawImageData(const DecoderOption &opt, const double *const data, const size_t size) - : width(static_cast<int>((size - opt.getChunkSize()) / opt.getDecalage())) - , height(static_cast<int>(opt.getChunkSize())) - , pixels(new uchar[static_cast<size_t>(width * height / 2)]()) - , chunkData( - reinterpret_cast<FFTSample *>(av_malloc_array(2 * opt.getChunkSize(), sizeof(FFTSample))), - fftSampleDeleter) - , ctx(av_rdft_init((static_cast<int>(log2(static_cast<int>(opt.getChunkSize())))), DFT_R2C), - rdftContextDeleter) -{ if (!(pixels && chunkData && ctx)) throw std::runtime_error("can't create fft related structures or allocated memory"); diff --git a/src/AudioUtils.hh b/src/AudioUtils.hh index 7953909b..0e4f48a6 100644 --- a/src/AudioUtils.hh +++ b/src/AudioUtils.hh @@ -55,9 +55,7 @@ private: RDFTContextPtr ctx; public: - explicit RawImageData(const DecoderOption &opt, const double *const data, const size_t size); - - static RawImageData fromAudioFile(const DecoderOption &opt, const QString &path); + explicit RawImageData(const DecoderOption &opt, const QString &path); int getWidth() const noexcept; int getHeight() const noexcept; diff --git a/src/UI/AudioVisualizer.cc b/src/UI/AudioVisualizer.cc index ec0e03ff..d5e6aa70 100644 --- a/src/UI/AudioVisualizer.cc +++ b/src/UI/AudioVisualizer.cc @@ -31,8 +31,7 @@ AudioVisualizer::fromFile(const QString &filename) if (filename.isEmpty()) return nullptr; - Utils::RawImageData rawImage = - Utils::RawImageData::fromAudioFile(Utils::DecoderOption{}, filename); + Utils::RawImageData rawImage(Utils::DecoderOption{}, filename); QImage img = QImage(rawImage.releasePixels(), rawImage.getWidth(), rawImage.getHeight(), rawImage.getWidth(), QImage::Format_Grayscale8, Utils::RawImageData::pixelsDeleter, rawImage.releasePixels()) -- GitLab