Skip to content

Conversation

@lalinsky
Copy link
Member

No description provided.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 28, 2025

Walkthrough

Adds an AVTX FFT backend (new header, implementation, and CMake wiring), extends FFmpeg discovery for avutil-tx, enables conditional build flags and config macro, and bumps packaged FFmpeg from 5.1.2 to 8.0 in the build script.

Changes

Cohort / File(s) Summary
Build script FFmpeg version bump
package/build.sh
Updated FFMPEG_VERSION to 8.0, FFMPEG_BUILD_TAG to v8.0-1, and tarball naming/URL to ffmpeg-8.0-audio-<TARGET>. No other script logic modified.
CMake FFT backend and option additions
CMakeLists.txt, src/CMakeLists.txt, config.h.in
Added avtx to FFT_LIB choices, introduced USE_AVTX (OFF default), default selection logic favoring avtx when available, and new conditional blocks to enable AVTX in src/CMakeLists.txt. Added cmakedefine USE_AVTX to config.h.in.
FFmpeg find module
cmake/modules/FindFFmpeg.cmake
Added discovery for LIBAVUTIL_TX (avutil tx.h), exposing FFMPEG_LIBAVUTIL_TX_INCLUDE_DIRS, FFMPEG_LIBAVUTIL_TX_LIBRARIES, and FFMPEG_LIBAVUTIL_TX_FOUND. Discovery is additive and optional.
FFT headers and wiring
src/fft_lib.h, src/fft_lib_avtx.h
Added conditional include of fft_lib_avtx.h when USE_AVTX is defined. Introduced new public header fft_lib_avtx.h declaring chromaprint::FFTLib API (ctor, dtor, Load, Compute).
AVTX FFT implementation
src/fft_lib_avtx.cpp
New implementation of chromaprint::FFTLib using av_tx RDFT: allocation, Hamming window setup, Load/Compute methods, av_tx init/uninit, and conversion to power spectrum; handles missing transform context gracefully.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Fix build with FFmpeg 8.0 #153 — Updates code to replace deprecated FFmpeg APIs for compatibility with FFmpeg 8.0, aligning with the FFmpeg 8.0 bump in the build script.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ffmpeg-8.0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbit in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbit in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbit gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbit read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbit help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbit ignore or @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbit summary or @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbit or @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

- Implement new fft_lib_avtx backend using libavutil/tx.h API
- Add avtx as FFT_LIB option with auto-detection for FFmpeg 8.0+
- Maintain backward compatibility with existing avfft backend
- Update CMake build system to handle both backends
- Add tx.h header detection in FindFFmpeg.cmake
- All tests pass with new avtx implementation
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e5b1aef and b801357.

📒 Files selected for processing (7)
  • CMakeLists.txt (3 hunks)
  • cmake/modules/FindFFmpeg.cmake (1 hunks)
  • config.h.in (1 hunks)
  • src/CMakeLists.txt (1 hunks)
  • src/fft_lib.h (1 hunks)
  • src/fft_lib_avtx.cpp (1 hunks)
  • src/fft_lib_avtx.h (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/fft_lib.h (4)
src/fft_lib_avfft.h (2)
  • FFTLib (18-33)
  • chromaprint (16-35)
src/fft_lib_fftw3.h (1)
  • FFTLib (26-42)
src/fft_lib_vdsp.h (1)
  • FFTLib (14-31)
src/fft.h (1)
  • FFT (19-47)
src/fft_lib_avtx.h (4)
src/fft_lib_avtx.cpp (6)
  • FFTLib (8-22)
  • FFTLib (24-29)
  • Load (31-36)
  • Load (31-31)
  • Compute (38-65)
  • Compute (38-38)
src/fft_lib_avfft.h (2)
  • chromaprint (16-35)
  • FFTLib (18-33)
src/fft_lib_avfft.cpp (1)
  • FFTLib (6-47)
src/fft.h (1)
  • chromaprint (15-49)
src/CMakeLists.txt (4)
src/fft_lib_avfft.cpp (1)
  • FFTLib (6-47)
src/fft_lib_avfft.h (2)
  • chromaprint (16-35)
  • FFTLib (18-33)
src/fft.h (1)
  • chromaprint (15-49)
src/fft_frame.h (1)
  • chromaprint (9-13)
CMakeLists.txt (4)
src/fft_lib_avfft.h (2)
  • FFTLib (18-33)
  • chromaprint (16-35)
src/fft_lib_avfft.cpp (3)
  • FFTLib (6-47)
  • FFTLib (8-18)
  • FFTLib (20-24)
src/fft_lib_vdsp.cpp (1)
  • FFTLib (7-48)
src/fft_lib_fftw3.cpp (1)
  • FFTLib (6-46)
src/fft_lib_avtx.cpp (2)
src/fft_lib_avtx.h (1)
  • FFTLib (17-34)
src/fft_lib_avfft.cpp (1)
  • FFTLib (6-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test-linux (fftw3)
  • GitHub Check: test-macos (vdsp)
  • GitHub Check: test-macos (kissfft)
🔇 Additional comments (10)
cmake/modules/FindFFmpeg.cmake (1)

105-105: AVTX wiring correct USE_AVTX block in src/CMakeLists.txt links ${FFMPEG_LIBAVUTIL_LIBRARIES} and includes ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS}, with LIBAVUTIL_TX_FOUND as the sole feature guard.

src/fft_lib_avtx.h (2)

7-11: C includes in extern "C" block look correct.

No issues here.


17-24: Zero out frame on AVTX init failure in Compute
Prevent stale data by replacing the early return with:

-    if (!m_tx_ctx || !m_tx_fn) return;
+    if (!m_tx_ctx || !m_tx_fn) {
+        std::fill(frame.begin(), frame.end(), 0.0f);
+        return;
+    }

Verify that FFTFrame supports begin()/end() and that a zeroed spectrum is appropriate downstream.

CMakeLists.txt (4)

16-16: Expose “avtx” in FFT_LIB choices — good.

Keeps cache UX consistent.


99-105: Backend flags initialized explicitly — good.

Prevents stale cache surprises.


106-111: Reasonable default: prefer avtx when available.

Helps migrate to FFmpeg 8 smoothly.


128-134: Backend gating and src wiring verified
src/CMakeLists.txt correctly adds fft_lib_avtx.cpp, links ${FFMPEG_LIBAVUTIL_LIBRARIES} and includes ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} when USE_AVTX is ON.

src/fft_lib_avtx.cpp (3)

31-36: Load path mirrors AVFFT semantics. LGTM.

Windowing and accumulation match the existing backend.


38-46: Guard against uninitialized TX context (good).

Early return prevents crashes when init failed.


52-56: DC/Nyquist handling matches AVFFT layout.

Correct mapping: bins 0 and N/2 are real-only.

Comment on lines +9 to +13
m_window = (float *) av_malloc(sizeof(float) * frame_size);
m_input = (float *) av_malloc(sizeof(float) * frame_size);
m_output = (AVComplexFloat *) av_malloc(sizeof(AVComplexFloat) * (frame_size / 2 + 1));
PrepareHammingWindow(m_window, m_window + frame_size, 1.0 / INT16_MAX);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Prefer av_malloc_array to avoid size_t overflow and consider OOM checks.

Small safety win; also verify INT16_MAX is visible in this TU (via or a transitive include).

-	m_window = (float *) av_malloc(sizeof(float) * frame_size);
-	m_input = (float *) av_malloc(sizeof(float) * frame_size);
-	m_output = (AVComplexFloat *) av_malloc(sizeof(AVComplexFloat) * (frame_size / 2 + 1));
+	m_window = (float *) av_malloc_array(frame_size, sizeof(float));
+	m_input = (float *) av_malloc_array(frame_size, sizeof(float));
+	m_output = (AVComplexFloat *) av_malloc_array(frame_size / 2 + 1, sizeof(AVComplexFloat));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
m_window = (float *) av_malloc(sizeof(float) * frame_size);
m_input = (float *) av_malloc(sizeof(float) * frame_size);
m_output = (AVComplexFloat *) av_malloc(sizeof(AVComplexFloat) * (frame_size / 2 + 1));
PrepareHammingWindow(m_window, m_window + frame_size, 1.0 / INT16_MAX);
m_window = (float *)av_malloc_array(frame_size, sizeof(float));
m_input = (float *)av_malloc_array(frame_size, sizeof(float));
m_output = (AVComplexFloat *)av_malloc_array(frame_size / 2 + 1, sizeof(AVComplexFloat));
PrepareHammingWindow(m_window, m_window + frame_size, 1.0 / INT16_MAX);
🤖 Prompt for AI Agents
In src/fft_lib_avtx.cpp around lines 9 to 13, replace raw av_malloc calls with
av_malloc_array to prevent size_t overflow and add null checks for each
allocation to handle OOM (log/error and early return/cleanup on failure); ensure
INT16_MAX is defined in this translation unit by including <cstdint> or <limits>
(or replace with std::numeric_limits<int16_t>::max()) so the
PrepareHammingWindow call uses a visible constant.

Comment on lines +24 to +29
FFTLib::~FFTLib() {
av_tx_uninit(&m_tx_ctx);
av_free(m_output);
av_free(m_input);
av_free(m_window);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Free-and-null to avoid dangling pointers.

av_freep nulls the pointer and is robust for repeated cleanup paths.

-	av_tx_uninit(&m_tx_ctx);
-	av_free(m_output);
-	av_free(m_input);
-	av_free(m_window);
+	av_tx_uninit(&m_tx_ctx);
+	av_freep((void**)&m_output);
+	av_freep((void**)&m_input);
+	av_freep((void**)&m_window);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
FFTLib::~FFTLib() {
av_tx_uninit(&m_tx_ctx);
av_free(m_output);
av_free(m_input);
av_free(m_window);
}
FFTLib::~FFTLib() {
av_tx_uninit(&m_tx_ctx);
av_freep((void**)&m_output);
av_freep((void**)&m_input);
av_freep((void**)&m_window);
}
🤖 Prompt for AI Agents
In src/fft_lib_avtx.cpp around lines 24 to 29, the destructor frees m_output,
m_input and m_window with av_free which can leave dangling pointers; replace
those calls with av_freep(&m_output), av_freep(&m_input) and av_freep(&m_window)
so the pointers are nulled and safe for repeated cleanup paths (leave
av_tx_uninit(&m_tx_ctx) as-is).

Comment on lines +49 to +64
auto input = m_output;
auto output = frame.begin();

// Handle DC component (index 0)
output[0] = input[0].re * input[0].re;

// Handle Nyquist frequency (index frame_size/2)
output[m_frame_size / 2] = input[m_frame_size / 2].re * input[m_frame_size / 2].re;

// Handle intermediate frequencies (indices 1 to frame_size/2-1)
output += 1;
input += 1;
for (size_t i = 1; i < m_frame_size / 2; i++) {
*output++ = input->re * input->re + input->im * input->im;
input++;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Tighten up output writes: use data(), precompute half, and (optionally) ensure capacity.

This improves clarity and avoids iterator arithmetic; resizing guards against misuse by callers.

-	auto input = m_output;
-	auto output = frame.begin();
-	
-	// Handle DC component (index 0)
-	output[0] = input[0].re * input[0].re;
-	
-	// Handle Nyquist frequency (index frame_size/2)
-	output[m_frame_size / 2] = input[m_frame_size / 2].re * input[m_frame_size / 2].re;
-	
-	// Handle intermediate frequencies (indices 1 to frame_size/2-1)
-	output += 1;
-	input += 1;
-	for (size_t i = 1; i < m_frame_size / 2; i++) {
-		*output++ = input->re * input->re + input->im * input->im;
-		input++;
-	}
+	const size_t half = m_frame_size / 2;
+	// Ensure capacity if caller didn't pre-size (optional; keep if consistent with other backends)
+	if (frame.size() < half + 1) frame.resize(half + 1);
+
+	const AVComplexFloat *in = m_output;
+	double *out = frame.data();
+
+	// DC and Nyquist
+	out[0]      = in[0].re     * in[0].re;
+	out[half]   = in[half].re  * in[half].re;
+
+	// Intermediate bins
+	in  += 1;
+	out += 1;
+	for (size_t i = 1; i < half; ++i) {
+		*out++ = in->re * in->re + in->im * in->im;
+		++in;
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auto input = m_output;
auto output = frame.begin();
// Handle DC component (index 0)
output[0] = input[0].re * input[0].re;
// Handle Nyquist frequency (index frame_size/2)
output[m_frame_size / 2] = input[m_frame_size / 2].re * input[m_frame_size / 2].re;
// Handle intermediate frequencies (indices 1 to frame_size/2-1)
output += 1;
input += 1;
for (size_t i = 1; i < m_frame_size / 2; i++) {
*output++ = input->re * input->re + input->im * input->im;
input++;
}
auto const size_t half = m_frame_size / 2;
// Ensure capacity if caller didn't pre-size (optional; keep if consistent with other backends)
if (frame.size() < half + 1)
frame.resize(half + 1);
auto const AVComplexFloat* in = m_output;
auto double* out = frame.data();
// DC and Nyquist
out[0] = in[0].re * in[0].re;
out[half] = in[half].re * in[half].re;
// Intermediate bins
in += 1;
out += 1;
for (size_t i = 1; i < half; ++i) {
*out++ = in->re * in->re + in->im * in->im;
+in;
}
🤖 Prompt for AI Agents
In src/fft_lib_avtx.cpp around lines 49 to 64, the code uses iterator arithmetic
for writes into frame and input which is fragile and less clear; change to use
frame.data() and m_output (or input) data pointers, precompute size_t half =
m_frame_size / 2, and write DC and Nyquist via frame_data[0] and
frame_data[half]; then loop i from 1 to half-1 and write to frame_data[i] using
input_data[i].re/im to compute magnitude squared. Also ensure frame has capacity
(e.g., resize or assert frame.size() >= half+1) before writing to avoid UB.

Comment on lines +12 to +14
#include "fft_frame.h"
#include "utils.h"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Make the header self-contained: include and .

Public API uses int16_t and size_t. Don’t rely on transitive includes.

Apply:

 #include "fft_frame.h"
 #include "utils.h"
+#include <cstddef>
+#include <cstdint>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#include "fft_frame.h"
#include "utils.h"
#include "fft_frame.h"
#include "utils.h"
#include <cstddef>
#include <cstdint>
🤖 Prompt for AI Agents
In src/fft_lib_avtx.h around lines 12 to 14, the header is not self-contained
because it uses int16_t and size_t from the public API but doesn't include
<cstdint> and <cstddef>; add #include <cstdint> and #include <cstddef> at the
top of this header (before or alongside the existing includes) so the types are
defined without relying on transitive includes.

av_tx_fn m_tx_fn;
};

}; // namespace chromaprint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Nit: drop the trailing semicolon after closing the namespace.

Not harmful, but inconsistent with existing headers.

-}; // namespace chromaprint
+} // namespace chromaprint
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}; // namespace chromaprint
} // namespace chromaprint
🤖 Prompt for AI Agents
In src/fft_lib_avtx.h around line 36, the namespace closing line currently ends
with an unnecessary trailing semicolon ("}; // namespace chromaprint"); remove
the extra semicolon so the namespace is closed as "} // namespace chromaprint"
to match existing header style and keep consistency.

Comment on lines +11 to +13
#ifdef USE_AVTX
#include "fft_lib_avtx.h"
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Include looks fine; add a global backend exclusivity check here.

To prevent multiple FFTLib class definitions, add a preprocessor guard (see suggestion in config.h.in comment).

Add near line 11 (after config.h):

#if (defined(USE_AVTX) + defined(USE_AVFFT) + defined(USE_FFTW3) + defined(USE_FFTW3F) + defined(USE_KISSFFT) + defined(USE_VDSP)) != 1
#error "Exactly one FFT backend (AVTX, AVFFT, FFTW3, FFTW3F, KISSFFT, vDSP) must be enabled."
#endif
🤖 Prompt for AI Agents
In src/fft_lib.h around lines 11 to 13, add a preprocessor exclusivity check
immediately after the existing config.h include to ensure exactly one FFT
backend macro is defined; implement the check that sums the defined backend
macros (USE_AVTX, USE_AVFFT, USE_FFTW3, USE_FFTW3F, USE_KISSFFT, USE_VDSP) and
triggers a compile-time #error when the sum is not equal to 1 so multiple or
zero backend definitions are caught early.

Comment on lines +17 to +21
if (ret < 0) {
// Handle initialization error - this should not happen with valid parameters
m_tx_ctx = NULL;
m_tx_fn = NULL;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initialization error handling in FFTLib::FFTLib() sets m_tx_ctx and m_tx_fn to NULL but doesn't release the memory allocated for m_window, m_input, and m_output. This creates a potential memory leak if initialization fails.

Consider either:

  1. Freeing these resources when initialization fails
  2. Throwing an exception to prevent object creation with invalid state
  3. Adding error checking in Compute() to ensure allocated resources are properly used

This would ensure consistent resource management throughout the object's lifecycle.

Suggested change
if (ret < 0) {
// Handle initialization error - this should not happen with valid parameters
m_tx_ctx = NULL;
m_tx_fn = NULL;
}
if (ret < 0) {
// Handle initialization error - this should not happen with valid parameters
m_tx_ctx = NULL;
m_tx_fn = NULL;
// Free allocated resources to prevent memory leaks
if (m_window) free(m_window);
if (m_input) free(m_input);
if (m_output) free(m_output);
m_window = NULL;
m_input = NULL;
m_output = NULL;
}

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

}
}

}; // namespace chromaprint No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file is missing a newline at the end, which can trigger warnings in some compilers and version control systems. Adding a newline character at the end of the file would follow standard coding practices and prevent potential issues during compilation or when viewing diffs.

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@lalinsky lalinsky merged commit a4a7338 into master Aug 28, 2025
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant