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