Skip to content

Commit 92e4fa4

Browse files
committed
Error
1 parent e7a2d3e commit 92e4fa4

File tree

5 files changed

+60
-20
lines changed

5 files changed

+60
-20
lines changed

CMakeLists.txt

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,30 @@ endif()
2121
list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
2222
find_package(nanobind CONFIG REQUIRED)
2323

24+
# Find MLX
25+
execute_process(
26+
COMMAND "${Python_EXECUTABLE}" -c "import mlx; print(mlx.__path__[0])"
27+
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE MLX_PYTHON_DIR
28+
RESULT_VARIABLE MLX_RESULT)
29+
30+
if(MLX_RESULT)
31+
message(FATAL_ERROR "MLX not found. Install with: pip install mlx")
32+
endif()
33+
34+
# MLX include and library paths
35+
set(MLX_INCLUDE_DIR "${MLX_PYTHON_DIR}/include")
36+
set(MLX_LIB_DIR "${MLX_PYTHON_DIR}/lib")
37+
38+
# Find MLX library
39+
find_library(MLX_LIBRARY
40+
NAMES mlx
41+
PATHS "${MLX_LIB_DIR}"
42+
NO_DEFAULT_PATH
43+
REQUIRED)
44+
45+
message(STATUS "MLX include dir: ${MLX_INCLUDE_DIR}")
46+
message(STATUS "MLX library: ${MLX_LIBRARY}")
47+
2448
# Apple frameworks
2549
find_library(AVFOUNDATION_FRAMEWORK AVFoundation REQUIRED)
2650
find_library(COREVIDEO_FRAMEWORK CoreVideo REQUIRED)
@@ -42,9 +66,13 @@ nanobind_add_module(
4266
${SOURCES}
4367
)
4468

45-
target_include_directories(_viteo PRIVATE src/native/include)
69+
target_include_directories(_viteo PRIVATE
70+
src/native/include
71+
${MLX_INCLUDE_DIR}
72+
)
4673

4774
target_link_libraries(_viteo PRIVATE
75+
${MLX_LIBRARY}
4876
${AVFOUNDATION_FRAMEWORK}
4977
${COREVIDEO_FRAMEWORK}
5078
${COREMEDIA_FRAMEWORK}
@@ -54,6 +82,15 @@ target_link_libraries(_viteo PRIVATE
5482
${COREIMAGE_FRAMEWORK}
5583
)
5684

85+
# Set rpath to find MLX library at runtime
86+
# Use @loader_path to find MLX relative to the module location
87+
set_target_properties(_viteo PROPERTIES
88+
BUILD_RPATH "${MLX_LIB_DIR}"
89+
INSTALL_RPATH "@loader_path/mlx/lib"
90+
BUILD_WITH_INSTALL_RPATH FALSE
91+
INSTALL_RPATH_USE_LINK_PATH TRUE
92+
)
93+
5794
# Enable Objective-C++ for .mm files
5895
set_source_files_properties(
5996
src/native/src/frame_extractor.mm
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <string>
55
#include <cstdint>
66
#include <vector>
7+
#include <mlx/mlx.h>
78

89
namespace viteo {
910

@@ -16,7 +17,7 @@ class FrameExtractor {
1617
/// Open video file for extraction
1718
bool open(const std::string& path);
1819

19-
/// Get next frame as BGRA data (returns nullptr when done)
20+
/// Get next frame as MLX array (returns empty array when done)
2021
uint8_t* next_frame();
2122

2223
/// Reset to beginning or specific frame index

src/native/src/bindings.cpp

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,17 @@ namespace nb = nanobind;
77
using namespace viteo;
88

99
/// Create MLX array from raw BGRA buffer
10-
nb::object create_mlx_array(uint8_t* data, int height, int width) {
11-
if (!data) return nb::none();
10+
mlx::core::array create_mlx_array(uint8_t* data, int height, int width) {
11+
auto arr = mlx::core::array(
12+
data,
13+
mlx::core::Shape{ (int32_t)height, (int32_t)width, int32_t(4) },
14+
mlx::core::uint8
15+
);
1216

13-
// Import MLX
14-
nb::object mlx = nb::module_::import_("mlx.core");
15-
nb::object mx_array = mlx.attr("array");
16-
nb::object mx_uint8 = mlx.attr("uint8");
17+
// Eval the array
18+
mlx::core::eval({arr});
1719

18-
// Create memory view
19-
size_t size = height * width * 4;
20-
nb::object memview = nb::steal(PyMemoryView_FromMemory(
21-
reinterpret_cast<char*>(data), size, PyBUF_READ
22-
));
23-
24-
// Create MLX array and reshape
25-
nb::object arr = mx_array(memview, mx_uint8);
26-
return arr.attr("reshape")(nb::make_tuple(height, width, 4));
20+
return arr;
2721
}
2822

2923
NB_MODULE(_viteo, m) {
@@ -34,13 +28,12 @@ NB_MODULE(_viteo, m) {
3428
.def("open", &FrameExtractor::open, nb::arg("path"),
3529
"Open video file for extraction")
3630
.def("next_frame",
37-
[](FrameExtractor& self) -> nb::object {
31+
[](FrameExtractor& self) -> mlx::core::array {
3832
uint8_t* frame_data;
3933
{
4034
nb::gil_scoped_release release;
4135
frame_data = self.next_frame();
4236
}
43-
if (!frame_data) return nb::none();
4437
return create_mlx_array(frame_data, self.height(), self.width());
4538
},
4639
"Get next frame as MLX array (None when done)")
@@ -52,7 +45,7 @@ NB_MODULE(_viteo, m) {
5245
.def_prop_ro("total_frames", &FrameExtractor::total_frames, "Total frames")
5346
.def("__iter__", [](nb::object self) { return self; })
5447
.def("__next__",
55-
[](FrameExtractor& self) -> nb::object {
48+
[](FrameExtractor& self) -> mlx::core::array {
5649
uint8_t* frame_data;
5750
{
5851
nb::gil_scoped_release release;

src/native/src/frame_extractor.mm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ bool open(const std::string& path) {
132132
isOpen = true;
133133
if (!setupReader(0)) return false;
134134

135+
DEBUG_LOG("Video opened successfully");
135136
return prefetchFrame();
136137
}
137138
}
@@ -233,22 +234,26 @@ void copyFrameData(CVImageBufferRef imageBuffer, uint8_t* dst) {
233234

234235
bool prefetchFrame() {
235236
if (!isOpen || !reader || !output) {
237+
DEBUG_LOG("Cannot prefetch frame, extractor not open");
236238
return false;
237239
}
238240

239241
@autoreleasepool {
240242
if (reader.status != AVAssetReaderStatusReading) {
243+
DEBUG_LOG("Reader not in reading state");
241244
return false;
242245
}
243246

244247
CMSampleBufferRef sampleBuffer = [output copyNextSampleBuffer];
245248
if (!sampleBuffer) {
249+
DEBUG_LOG("No more samples available");
246250
return false;
247251
}
248252

249253
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
250254
if (!imageBuffer) {
251255
CFRelease(sampleBuffer);
256+
DEBUG_LOG("Failed to get image buffer from sample");
252257
return false;
253258
}
254259

@@ -258,6 +263,7 @@ bool prefetchFrame() {
258263

259264
CFRelease(sampleBuffer);
260265
has_prefetched_frame = true;
266+
DEBUG_LOG("Prefetched frame " << currentFrame);
261267

262268
return true;
263269
}
@@ -269,11 +275,13 @@ bool prefetchFrame() {
269275
return nullptr;
270276
}
271277

278+
DEBUG_LOG("Swapping frame buffers for frame " << currentFrame);
272279
std::swap(frame_buffer, prefetch_buffer);
273280
currentFrame++;
274281

275282
prefetchFrame();
276283

284+
DEBUG_LOG("Returning frame buffer " << (currentFrame - 1));
277285
return frame_buffer.data();
278286
}
279287

src/viteo/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
process_frame(frame)
1717
"""
1818
import pathlib
19+
import mlx.core as mx
1920
from _viteo import FrameExtractor as _FrameExtractor
2021
from typing import Optional
2122

0 commit comments

Comments
 (0)