replay: use VideoToolbox HW decoder on Mac (#23832)

* replay: support VideoToolbox HW decoding

* rename flag

* remove debug assert
old-commit-hash: dc7de79dc9
taco
Willem Melching 3 years ago committed by GitHub
parent b9a0e6ff9b
commit 760564da61
  1. 26
      selfdrive/ui/replay/framereader.cc
  2. 6
      selfdrive/ui/replay/framereader.h
  3. 2
      selfdrive/ui/replay/main.cc
  4. 2
      selfdrive/ui/replay/replay.h
  5. 2
      selfdrive/ui/replay/route.cc

@ -6,6 +6,14 @@
#include "cereal/visionipc/visionbuf.h" #include "cereal/visionipc/visionbuf.h"
#ifdef __APPLE__
#define HW_DEVICE_TYPE AV_HWDEVICE_TYPE_VIDEOTOOLBOX
#define HW_PIX_FMT AV_PIX_FMT_VIDEOTOOLBOX
#else
#define HW_DEVICE_TYPE AV_HWDEVICE_TYPE_CUDA
#define HW_PIX_FMT AV_PIX_FMT_CUDA
#endif
namespace { namespace {
struct buffer_data { struct buffer_data {
@ -30,7 +38,7 @@ enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *
for (const enum AVPixelFormat *p = pix_fmts; *p != -1; p++) { for (const enum AVPixelFormat *p = pix_fmts; *p != -1; p++) {
if (*p == *hw_pix_fmt) return *p; if (*p == *hw_pix_fmt) return *p;
} }
rWarning("Please run replay with the --no-cuda flag!"); rWarning("Please run replay with the --no-hw-decoder flag!");
// fallback to YUV420p // fallback to YUV420p
*hw_pix_fmt = AV_PIX_FMT_NONE; *hw_pix_fmt = AV_PIX_FMT_NONE;
return AV_PIX_FMT_YUV420P; return AV_PIX_FMT_YUV420P;
@ -57,15 +65,15 @@ FrameReader::~FrameReader() {
} }
} }
bool FrameReader::load(const std::string &url, bool no_cuda, std::atomic<bool> *abort, bool local_cache, int chunk_size, int retries) { bool FrameReader::load(const std::string &url, bool no_hw_decoder, std::atomic<bool> *abort, bool local_cache, int chunk_size, int retries) {
FileReader f(local_cache, chunk_size, retries); FileReader f(local_cache, chunk_size, retries);
std::string data = f.read(url, abort); std::string data = f.read(url, abort);
if (data.empty()) return false; if (data.empty()) return false;
return load((std::byte *)data.data(), data.size(), no_cuda, abort); return load((std::byte *)data.data(), data.size(), no_hw_decoder, abort);
} }
bool FrameReader::load(const std::byte *data, size_t size, bool no_cuda, std::atomic<bool> *abort) { bool FrameReader::load(const std::byte *data, size_t size, bool no_hw_decoder, std::atomic<bool> *abort) {
input_ctx = avformat_alloc_context(); input_ctx = avformat_alloc_context();
if (!input_ctx) return false; if (!input_ctx) return false;
@ -106,9 +114,9 @@ bool FrameReader::load(const std::byte *data, size_t size, bool no_cuda, std::at
height = decoder_ctx->height; height = decoder_ctx->height;
visionbuf_compute_aligned_width_and_height(width, height, &aligned_width, &aligned_height); visionbuf_compute_aligned_width_and_height(width, height, &aligned_width, &aligned_height);
if (has_cuda_device && !no_cuda) { if (has_hw_decoder && !no_hw_decoder) {
if (!initHardwareDecoder(AV_HWDEVICE_TYPE_CUDA)) { if (!initHardwareDecoder(HW_DEVICE_TYPE)) {
rWarning("No CUDA capable device was found. fallback to CPU decoding."); rWarning("No device with hardware decoder found. fallback to CPU decoding.");
} else { } else {
nv12toyuv_buffer.resize(getYUVSize()); nv12toyuv_buffer.resize(getYUVSize());
} }
@ -151,7 +159,7 @@ bool FrameReader::initHardwareDecoder(AVHWDeviceType hw_device_type) {
int ret = av_hwdevice_ctx_create(&hw_device_ctx, hw_device_type, nullptr, nullptr, 0); int ret = av_hwdevice_ctx_create(&hw_device_ctx, hw_device_type, nullptr, nullptr, 0);
if (ret < 0) { if (ret < 0) {
hw_pix_fmt = AV_PIX_FMT_NONE; hw_pix_fmt = AV_PIX_FMT_NONE;
has_cuda_device = false; has_hw_decoder = false;
rWarning("Failed to create specified HW device %d.", ret); rWarning("Failed to create specified HW device %d.", ret);
return false; return false;
} }
@ -219,7 +227,7 @@ AVFrame *FrameReader::decodeFrame(AVPacket *pkt) {
} }
bool FrameReader::copyBuffers(AVFrame *f, uint8_t *rgb, uint8_t *yuv) { bool FrameReader::copyBuffers(AVFrame *f, uint8_t *rgb, uint8_t *yuv) {
if (hw_pix_fmt == AV_PIX_FMT_CUDA) { if (hw_pix_fmt == HW_PIX_FMT) {
uint8_t *y = yuv ? yuv : nv12toyuv_buffer.data(); uint8_t *y = yuv ? yuv : nv12toyuv_buffer.data();
uint8_t *u = y + width * height; uint8_t *u = y + width * height;
uint8_t *v = u + (width / 2) * (height / 2); uint8_t *v = u + (width / 2) * (height / 2);

@ -19,8 +19,8 @@ class FrameReader {
public: public:
FrameReader(); FrameReader();
~FrameReader(); ~FrameReader();
bool load(const std::string &url, bool no_cuda = false, std::atomic<bool> *abort = nullptr, bool local_cache = false, int chunk_size = -1, int retries = 0); bool load(const std::string &url, bool no_hw_decoder = false, std::atomic<bool> *abort = nullptr, bool local_cache = false, int chunk_size = -1, int retries = 0);
bool load(const std::byte *data, size_t size, bool no_cuda = false, std::atomic<bool> *abort = nullptr); bool load(const std::byte *data, size_t size, bool no_hw_decoder = false, std::atomic<bool> *abort = nullptr);
bool get(int idx, uint8_t *rgb, uint8_t *yuv); bool get(int idx, uint8_t *rgb, uint8_t *yuv);
int getRGBSize() const { return aligned_width * aligned_height * 3; } int getRGBSize() const { return aligned_width * aligned_height * 3; }
int getYUVSize() const { return width * height * 3 / 2; } int getYUVSize() const { return width * height * 3 / 2; }
@ -48,5 +48,5 @@ private:
AVBufferRef *hw_device_ctx = nullptr; AVBufferRef *hw_device_ctx = nullptr;
std::vector<uint8_t> nv12toyuv_buffer; std::vector<uint8_t> nv12toyuv_buffer;
int prev_idx = -1; int prev_idx = -1;
inline static std::atomic<bool> has_cuda_device = true; inline static std::atomic<bool> has_hw_decoder = true;
}; };

@ -16,7 +16,7 @@ int main(int argc, char *argv[]) {
{"no-cache", REPLAY_FLAG_NO_FILE_CACHE, "turn off local cache"}, {"no-cache", REPLAY_FLAG_NO_FILE_CACHE, "turn off local cache"},
{"qcam", REPLAY_FLAG_QCAMERA, "load qcamera"}, {"qcam", REPLAY_FLAG_QCAMERA, "load qcamera"},
{"yuv", REPLAY_FLAG_SEND_YUV, "send yuv frame"}, {"yuv", REPLAY_FLAG_SEND_YUV, "send yuv frame"},
{"no-cuda", REPLAY_FLAG_NO_CUDA, "disable CUDA"}, {"no-hw-decoder", REPLAY_FLAG_NO_HW_DECODER, "disable HW video decoding"},
{"no-vipc", REPLAY_FLAG_NO_VIPC, "do not output video"}, {"no-vipc", REPLAY_FLAG_NO_VIPC, "do not output video"},
}; };

@ -18,7 +18,7 @@ enum REPLAY_FLAGS {
REPLAY_FLAG_NO_FILE_CACHE = 0x0020, REPLAY_FLAG_NO_FILE_CACHE = 0x0020,
REPLAY_FLAG_QCAMERA = 0x0040, REPLAY_FLAG_QCAMERA = 0x0040,
REPLAY_FLAG_SEND_YUV = 0x0080, REPLAY_FLAG_SEND_YUV = 0x0080,
REPLAY_FLAG_NO_CUDA = 0x0100, REPLAY_FLAG_NO_HW_DECODER = 0x0100,
REPLAY_FLAG_FULL_SPEED = 0x0200, REPLAY_FLAG_FULL_SPEED = 0x0200,
REPLAY_FLAG_NO_VIPC = 0x0400, REPLAY_FLAG_NO_VIPC = 0x0400,
}; };

@ -117,7 +117,7 @@ void Segment::loadFile(int id, const std::string file) {
bool success = false; bool success = false;
if (id < MAX_CAMERAS) { if (id < MAX_CAMERAS) {
frames[id] = std::make_unique<FrameReader>(); frames[id] = std::make_unique<FrameReader>();
success = frames[id]->load(file, flags & REPLAY_FLAG_NO_CUDA, &abort_, local_cache, 20 * 1024 * 1024, 3); success = frames[id]->load(file, flags & REPLAY_FLAG_NO_HW_DECODER, &abort_, local_cache, 20 * 1024 * 1024, 3);
} else { } else {
log = std::make_unique<LogReader>(); log = std::make_unique<LogReader>();
success = log->load(file, &abort_, local_cache, 0, 3); success = log->load(file, &abort_, local_cache, 0, 3);

Loading…
Cancel
Save