Skip to content

File ffmpeg_utils.hpp

File List > illixr > vk > ffmpeg_utils.hpp

Go to the documentation of this file

#pragma once

#include "vulkan/vulkan.h"

#include 
#include 
extern "C" {
#include "libavcodec_illixr/avcodec.h"
#include "libavformat_illixr/avformat.h"
#include "libavutil_illixr/hwcontext.h"
#include "libavutil_illixr/hwcontext_vulkan.h"
#include "libavutil_illixr/opt.h"
#include "libavutil_illixr/pixdesc.h"
}

#define OFFLOAD_RENDERING_FFMPEG_ENCODER_NAME "hevc_nvenc"
#define OFFLOAD_RENDERING_BITRATE             100000000

namespace ILLIXR::vulkan::ffmpeg_utils {

static std::weak_ptr<vulkan::display_provider> display_provider_ffmpeg;

static void ffmpeg_lock_queue(struct AVHWDeviceContext* ctx, uint32_t queue_family, uint32_t index) {
    (void) ctx;
    (void) index;
    if (auto dp = display_provider_ffmpeg.lock()) {
        std::optional<vulkan::queue> queue;
        for (auto& q : dp->queues_) {
            if (q.second.family == queue_family) {
                queue = q.second;
                break;
            }
        }
        if (!queue) {
            throw std::runtime_error{"Failed to find queue with family " + std::to_string(queue_family)};
        }
        dp->lock_queue(queue->type);
    } else {
        throw std::runtime_error{"Weak pointer to display_provider is expired"};
    }
}

static void ffmpeg_unlock_queue(struct AVHWDeviceContext* ctx, uint32_t queue_family, uint32_t index) {
    (void) ctx;
    (void) index;
    if (auto dp = display_provider_ffmpeg.lock()) {
        std::optional<vulkan::queue> queue;
        for (auto& q : dp->queues_) {
            if (q.second.family == queue_family) {
                queue = q.second;
                break;
            }
        }
        if (!queue) {
            throw std::runtime_error{"Failed to find queue with family " + std::to_string(queue_family)};
        }
        dp->unlock_queue(queue->type);
    } else {
        throw std::runtime_error{"Weak pointer to display_provider is expired"};
    }
}

static std::optional<AVPixelFormat> get_pix_format_from_vk_format(VkFormat format) {
    switch (format) {
    case VK_FORMAT_R8G8B8A8_UNORM:
    case VK_FORMAT_R8G8B8A8_SRGB:
        return AV_PIX_FMT_RGBA;
    case VK_FORMAT_B8G8R8A8_UNORM:
    case VK_FORMAT_B8G8R8A8_SRGB:
        return AV_PIX_FMT_BGRA;
    default:
        break;
    }

    for (int fmt = AV_PIX_FMT_NONE; fmt < AV_PIX_FMT_NB; fmt++) {
        auto vk_fmt = av_vkfmt_from_pixfmt(static_cast<AVPixelFormat>(fmt));
        if (vk_fmt && *vk_fmt == format) {
            return static_cast<AVPixelFormat>(fmt);
        }
    }
    return std::nullopt;
}

static void AV_ASSERT_SUCCESS(int ret) {
    if (ret < 0) {
        char errbuf[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(ret, errbuf, AV_ERROR_MAX_STRING_SIZE);
        throw std::runtime_error{std::string{"FFmpeg error: "} + errbuf};
    }
}

struct ffmpeg_vk_frame {
    AVFrame*   frame    = nullptr;
    AVVkFrame* vk_frame = nullptr;
};
} // namespace ILLIXR::vulkan::ffmpeg_utils