Skip to content

Commit

Permalink
Basic VAAPI support
Browse files Browse the repository at this point in the history
  • Loading branch information
lsiudut committed Apr 18, 2020
1 parent ffe7d09 commit 38fe128
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 4 deletions.
4 changes: 2 additions & 2 deletions gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN)
endif()

find_package(FFMPEG REQUIRED COMPONENTS avcodec avutil)
find_package(FFMPEG REQUIRED COMPONENTS avcodec avutil swscale)

set(RESOURCE_FILES "")

Expand Down Expand Up @@ -79,7 +79,7 @@ if(CHIAKI_ENABLE_CLI)
target_link_libraries(chiaki chiaki-cli-lib)
endif()

target_link_libraries(chiaki FFMPEG::avcodec FFMPEG::avutil)
target_link_libraries(chiaki FFMPEG::avcodec FFMPEG::avutil FFMPEG::swscale)
target_link_libraries(chiaki Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Multimedia Qt5::OpenGL Qt5::Svg)
if(APPLE)
target_link_libraries(chiaki Qt5::MacExtras)
Expand Down
4 changes: 4 additions & 0 deletions gui/include/videodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}

#include <cstdint>
Expand Down Expand Up @@ -60,6 +61,9 @@ class VideoDecoder: public QObject

AVCodec *codec;
AVCodecContext *codec_context;

enum AVPixelFormat hw_pix_fmt;
AVBufferRef *hw_device_ctx;
};

#endif // CHIAKI_VIDEODECODER_H
68 changes: 66 additions & 2 deletions gui/src/videodecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,71 @@
#include <videodecoder.h>

#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>

#include <QImage>

static enum AVPixelFormat hw_pix_fmt;

static enum AVPixelFormat get_hw_format(AVCodecContext *ctx,
const enum AVPixelFormat *pix_fmts)
{
const enum AVPixelFormat *p;

for (p = pix_fmts; *p != -1; p++) {
if (*p == hw_pix_fmt)
return *p;
}

fprintf(stderr, "Failed to get HW surface format.\n");
return AV_PIX_FMT_NONE;
}

VideoDecoder::VideoDecoder(ChiakiLog *log) : log(log)
{
enum AVHWDeviceType type = av_hwdevice_find_type_by_name("vaapi");
if (type == AV_HWDEVICE_TYPE_NONE) {
throw VideoDecoderException("Can't initialize vaapi");
}
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all();
avcodec_register_all();
#endif
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if(!codec)
throw VideoDecoderException("H264 Codec not available");

for(int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i);
if(!config) {
throw VideoDecoderException("avcodec_get_hw_config failed");
}
if(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
config->device_type == type) {
hw_pix_fmt = config->pix_fmt;
::hw_pix_fmt = config->pix_fmt;
CHIAKI_LOGE(log, "VAAPI pix_fmt = %u", hw_pix_fmt);
break;
}
}

codec_context = avcodec_alloc_context3(codec);
if(!codec_context)
throw VideoDecoderException("Failed to alloc codec context");


codec_context->get_format = get_hw_format;

if(av_hwdevice_ctx_create(&hw_device_ctx, type, NULL, NULL, 0) < 0)
throw VideoDecoderException("Failed to create hwdevice context");

codec_context->hw_device_ctx = av_buffer_ref(hw_device_ctx);

if(avcodec_open2(codec_context, codec, nullptr) < 0)
{
avcodec_free_context(&codec_context);
throw VideoDecoderException("Failed to open codec context");
}

}

VideoDecoder::~VideoDecoder()
Expand Down Expand Up @@ -98,10 +142,16 @@ AVFrame *VideoDecoder::PullFrame()

// always try to pull as much as possible and return only the very last frame
AVFrame *frame_last = nullptr;
AVFrame *frame = nullptr;
AVFrame *sw_frame = nullptr;
AVFrame *frame = nullptr;
while(true)
{
AVFrame *next_frame;
if(sw_frame)
{
av_frame_unref(sw_frame);
}
sw_frame = av_frame_alloc();
if(frame_last)
{
av_frame_unref(frame_last);
Expand All @@ -116,6 +166,20 @@ AVFrame *VideoDecoder::PullFrame()
frame_last = frame;
frame = next_frame;
int r = avcodec_receive_frame(codec_context, frame);
if(r == 0 && av_hwframe_transfer_data(sw_frame, frame, 0) < 0) {
CHIAKI_LOGE(log, "Failed to transfer frame from hardware memory");
} else if(sw_frame->width > 0) {
av_frame_unref(frame);
frame = av_frame_alloc();
frame->format = AV_PIX_FMT_YUV420P;
frame->width = sw_frame->width;
frame->height = sw_frame->height;
av_frame_get_buffer(frame, 32);

SwsContext* cc = sws_getContext(sw_frame->width, sw_frame->height, AV_PIX_FMT_NV12, sw_frame->width, sw_frame->height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
sws_scale(cc, sw_frame->data, sw_frame->linesize, 0, sw_frame->height, frame->data, frame->linesize);
av_frame_unref(sw_frame);
}
if(r != 0)
{
if(r != AVERROR(EAGAIN))
Expand Down

0 comments on commit 38fe128

Please sign in to comment.