Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vpdq] Fix macOS build #1605

Merged
merged 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions vpdq/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,6 @@ Once you are in the container proceed to [**Building**](#building).
- make
- FFmpeg and libav* libraries

> **Note for macos:**
>
> Currently, the built-in Apple clang g++ does not work for building this implementation. Installing GCC and updating the [`CMake`](./cpp/CMakeLists.txt) CXX to use that version of g++ as a workaround is recommended.

### Install FFmpeg

[FFmpeg](https://ffmpeg.org/) and its [libav* libraries](https://trac.ffmpeg.org/wiki/Using%20libav*) must be installed before building.
Expand Down
1 change: 0 additions & 1 deletion vpdq/cpp/vpdq/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ set(VPDQSOURCES
cpp/hashing/filehasher.cpp
cpp/hashing/ffmpegutils.cpp
cpp/hashing/ffmpegwrapper.cpp
cpp/hashing/hasher.cpp
cpp/hashing/matchTwoHash.cpp
cpp/io/vpdqio.cpp
)
Expand Down
11 changes: 9 additions & 2 deletions vpdq/cpp/vpdq/cpp/hashing/filehasher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// ================================================================

#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <memory>
Expand Down Expand Up @@ -137,8 +138,14 @@ class FFmpegHasher {
// no error. we're good.
}

// Get the current frame number from the video codec context
auto const frameNumber = m_video->codecContext->frame_number - 1;
// AVCodecContext::frame_number was deprecated in FFmpeg 6.0
// in favor of AVCodecContext::frame_num
#if LIBAVCODEC_VERSION_MAJOR >= 60
const auto codecFrameNumber = m_video->codecContext->frame_num;
#else
const auto codecFrameNumber = m_video->codecContext->frame_number;
#endif
const int64_t frameNumber{int64_t{codecFrameNumber} - 1};

if (frameNumber % m_frameMod == 0) {
AVFramePtr targetFrame{};
Expand Down
146 changes: 0 additions & 146 deletions vpdq/cpp/vpdq/cpp/hashing/hasher.cpp

This file was deleted.

122 changes: 122 additions & 0 deletions vpdq/cpp/vpdq/cpp/hashing/hasher.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@
#ifndef HASHER_H
#define HASHER_H

#include <algorithm>
#include <atomic>
#include <cmath>
#include <condition_variable>
#include <cstdio>
#include <fstream>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>

#include <vpdq/cpp/hashing/bufferhasher.h>
#include <vpdq/cpp/hashing/ffmpegwrapper.h>
#include <vpdq/cpp/hashing/vpdqHashType.h>

Expand Down Expand Up @@ -137,6 +147,118 @@ class VpdqHasher {
void consumer();
};

/** @brief Hash a frame using PDQ.
*
* @param frame The frame to be hashed.
* @param frameNumber The metadata from the video the frame is from.
*
* @return The vdpdq hash of the frame.
**/
template <typename TFrame>
vpdqFeature hashFrame(TFrame& frame, const VideoMetadata& video_metadata) {
auto phasher = FrameBufferHasherFactory::createFrameHasher(
video_metadata.height, video_metadata.width);

int quality;
pdq::hashing::Hash256 pdqHash;
auto const is_hashing_successful =
phasher->hashFrame(frame.get_buffer_ptr(), pdqHash, quality);
if (!is_hashing_successful) {
throw std::runtime_error(
std::string{"Failed to hash frame buffer. Frame: "} +
std::to_string(frame.get_frame_number()) +
" Frame width or height smaller than the minimum hashable dimension");
}
return vpdqFeature{
pdqHash,
static_cast<int>(frame.get_frame_number()),
quality,
static_cast<float>(frame.get_frame_number()) / video_metadata.framerate};
}

template <typename TFrame>
VpdqHasher<TFrame>::VpdqHasher(
size_t thread_count, VideoMetadata video_metadata)
: m_done_hashing(false), m_video_metadata(video_metadata) {
// Set thread count if specified
if (thread_count == 0) {
thread_count = std::thread::hardware_concurrency();
}

m_multithreaded = (thread_count != 1);

// Create consumer hasher threads if multithreading
if (m_multithreaded) {
consumer_threads.reserve(thread_count);
for (size_t thread_idx{0}; thread_idx < thread_count; ++thread_idx) {
consumer_threads.emplace_back(std::thread(&VpdqHasher::consumer, this));
}
}
}

template <typename TFrame>
void VpdqHasher<TFrame>::push_back(TFrame&& frame) {
if (m_multithreaded) {
{
std::lock_guard<std::mutex> lock(m_queue_mutex);
m_queue.push(std::move(frame));
m_queue_condition.notify_one();
}
} else {
hasher(frame);
}
}

template <typename TFrame>
std::vector<vpdqFeature> VpdqHasher<TFrame>::finish() {
if (m_multithreaded) {
{
std::lock_guard<std::mutex> lock(m_queue_mutex);
m_done_hashing = true;
}

m_queue_condition.notify_all();
for (auto& thread : consumer_threads) {
thread.join();
}
}

// Sort out of order frames by frame number
std::sort(
std::begin(m_result),
std::end(m_result),
[](const vpdqFeature& a, const vpdqFeature& b) {
return a.frameNumber < b.frameNumber;
});

return m_result;
}

template <typename TFrame>
void VpdqHasher<TFrame>::hasher(TFrame& frame) {
auto hashedFrame = hashFrame(frame, m_video_metadata);
{
std::lock_guard<std::mutex> lock(m_result_mutex);
m_result.push_back(std::move(hashedFrame));
}
}

template <typename TFrame>
void VpdqHasher<TFrame>::consumer() {
while (true) {
std::unique_lock<std::mutex> lock(m_queue_mutex);
m_queue_condition.wait(
lock, [this] { return !m_queue.empty() || m_done_hashing; });
if (m_queue.empty() && m_done_hashing) {
break;
}
auto frame = std::move(m_queue.front());
m_queue.pop();
lock.unlock();
hasher(frame);
}
}

// Explicit template instantiation for all frame types.
template class VpdqHasher<GenericFrame>;
template class VpdqHasher<ffmpeg::FFmpegFrame>;
Expand Down