Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c9000ef
Add optional OpenCL support
soreau May 21, 2019
c96a739
Various fixes
soreau May 22, 2019
f4f9242
Warn when unfavorable dimensions are found
soreau May 22, 2019
4c1e0ac
Add copyright headers to opencl source files
soreau May 22, 2019
fd07f0b
Choose hardware path for rgb to yuv conversion when applicable
soreau May 22, 2019
9ddad65
Fix bug
soreau May 22, 2019
c93ee70
Choose correct format when opencl is disabled and -t is specified
soreau May 22, 2019
d99dac4
s/yuv/nv12/
soreau May 22, 2019
f84d51c
Style nitpicks
soreau May 22, 2019
99faeff
Use yuv420p instead of nv12 when using sws_scale() since it is faster
soreau May 23, 2019
b698fbc
Fix memleak
soreau May 23, 2019
a81c014
Get rid of some #ifdef nonsense
soreau May 23, 2019
fdb6b0f
Make ret variable private again
soreau May 23, 2019
7d9befb
Use faster yuv420p when converting rgb in vaapi path without opencl
soreau May 23, 2019
1c71f0a
More error handling
soreau May 23, 2019
e65a480
More error handling
soreau May 23, 2019
6f5d0de
Switch opencl shader from nv12 to yuv420p and introduce --no-opencl o…
soreau May 27, 2019
1f96239
Fix pixel averaging
soreau May 27, 2019
ed653af
Fix vaapi encoding when opencl and sws_scale are not used
soreau May 27, 2019
9e19cd5
Use string literal for opencl program
soreau May 27, 2019
4ebb6a3
Move duplicated code into function
ammen99 May 28, 2019
ad7e3eb
Rename options
soreau May 28, 2019
5a9b073
Remove debug messages
soreau May 28, 2019
6ebad8e
Couple fixups
soreau May 28, 2019
7192114
Fixups
soreau May 28, 2019
fe3c2ae
Update README.md
soreau May 28, 2019
4ef0ae7
Allow user to specify opencl device
soreau Jun 1, 2019
b620a5c
Don't allocate more memory than needed
soreau Jun 1, 2019
889a972
Actually, reading 4 x the data gives better perf without vaapi
soreau Jun 1, 2019
4c67933
Fix-up
soreau Jun 8, 2019
cd01576
Remove which no longer causes segfault
soreau Jun 11, 2019
bd250b0
Update help and README.md
soreau Jul 12, 2019
6c1d4fa
Fix mistake in help
soreau Jul 12, 2019
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: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ To use gpu encoding, use a VAAPI codec (for ex. `h264_vaapi`) and specify a GPU
```
wf-recorder -f test-vaapi.mkv -c h264_vaapi -d /dev/dri/renderD128
```
Some drivers report support for rgb0 data for vaapi input but really only support yuv. In this case, use the `-t` or `--to-yuv` option in addition to the vaapi options to convert the data in software before sending it to the gpu.
Some drivers report support for rgb0 data for vaapi input but really only support yuv planar formats. In this case, use the `-t` or `--force-yuv` option in addition to the vaapi options to convert the data to yuv planar data before sending it to the gpu.

The `-e` option attempts to use OpenCL if wf-recorder was built with OpenCL support and `-t` or `--force-yuv` is specified, even without vaapi gpu encoding. Use `-e#` or `--opencl=#` to use a specific OpenCL device, where `#` is one of the devices listed.
3 changes: 2 additions & 1 deletion config.h.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#pragma once

#define DEFAULT_CODEC "@default_codec@"
#define DEFAULT_CODEC "@default_codec@"
#mesondefine HAVE_OPENCL
23 changes: 16 additions & 7 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ project(
'cpp',
version: '0.1',
license: 'MIT',
meson_version: '>=0.43.0',
meson_version: '>=0.47.0',
default_options: [
'cpp_std=c++11',
'c_std=c11',
Expand All @@ -17,17 +17,26 @@ conf_data = configuration_data()

conf_data.set('default_codec', get_option('default_codec'))

configure_file(input: 'config.h.in',
output: 'config.h',
configuration: conf_data)

include_directories(['.'])

add_project_arguments(['-Wno-deprecated-declarations'], language: 'cpp')

project_sources = ['src/frame-writer.cpp', 'src/main.cpp', 'src/pulse.cpp', 'src/averr.c']

wayland_client = dependency('wayland-client')
wayland_protos = dependency('wayland-protocols')

opencl = dependency('OpenCL', required : get_option('opencl'))

if opencl.found()
conf_data.set('HAVE_OPENCL', true)
project_sources += 'src/opencl.cpp'
endif

configure_file(input: 'config.h.in',
output: 'config.h',
configuration: conf_data)

libavutil = dependency('libavutil')
libavcodec = dependency('libavcodec')
libavformat = dependency('libavformat')
Expand Down Expand Up @@ -64,6 +73,6 @@ if scdoc.found()
endif

subdir('proto')
executable('wf-recorder', ['src/frame-writer.cpp', 'src/main.cpp', 'src/pulse.cpp', 'src/averr.c'],
dependencies: [wayland_client, wayland_protos, libavutil, libavcodec, libavformat, wf_protos, sws, threads, pulse, swr],
executable('wf-recorder', project_sources,
dependencies: [wayland_client, wayland_protos, libavutil, libavcodec, libavformat, wf_protos, sws, threads, pulse, swr, opencl],
install: true)
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
option('default_codec', type: 'string', value: 'libx264', description: 'Codec that will be used by default')
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
option('opencl', type: 'feature', value: 'auto', description: 'Enable OpenCL')
58 changes: 43 additions & 15 deletions src/frame-writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,9 @@ void FrameWriter::init_video_stream()
videoCodecCtx->pix_fmt = AV_PIX_FMT_VAAPI;
init_hw_accel();
videoCodecCtx->hw_frames_ctx = av_buffer_ref(hw_frame_context);
if (params.to_yuv)
init_sws(AV_PIX_FMT_NV12);

if (params.force_yuv)
init_sws(AV_PIX_FMT_YUV420P);
} else
{
videoCodecCtx->pix_fmt = choose_sw_format(codec);
Expand Down Expand Up @@ -320,13 +321,16 @@ FrameWriter::FrameWriter(const FrameWriterParams& _params) :
std::exit(-1);
}

#ifndef HAVE_OPENCL
if (params.opencl)
std::cerr << "This version of wf-recorder was built without OpenCL support. Ignoring OpenCL option." << std::endl;
#endif

init_codecs();

encoder_frame = av_frame_alloc();
if (hw_device_context && params.to_yuv) {
encoder_frame->format = AV_PIX_FMT_NV12;
} else if (hw_device_context) {
encoder_frame->format = get_input_format();
if (hw_device_context) {
encoder_frame->format = params.force_yuv ? AV_PIX_FMT_YUV420P : get_input_format();
} else {
encoder_frame->format = videoCodecCtx->pix_fmt;
}
Expand Down Expand Up @@ -355,6 +359,32 @@ FrameWriter::FrameWriter(const FrameWriterParams& _params) :
}
}

void FrameWriter::convert_pixels_to_yuv(const uint8_t *pixels,
const uint8_t *formatted_pixels, int stride[])
{
bool y_invert = (pixels != formatted_pixels);
bool converted_with_opencl = false;

#ifdef HAVE_OPENCL
if (params.opencl && params.force_yuv)
{
int r = opencl->do_frame(pixels, encoder_frame,
get_input_format(), y_invert);

converted_with_opencl = (r == 0);
}
#else
/* Silence compiler warning when opencl is disabled */
(void)(y_invert);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can move this inside the #ifdef

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of this is to not leave y_invert variable declared but not used in the case where opencl is disabled. If we put it inside the ifdef, the warning still happens.

#endif

if (!converted_with_opencl)
{
sws_scale(swsCtx, &formatted_pixels, stride, 0, params.height,
encoder_frame->data, encoder_frame->linesize);
}
}

void FrameWriter::add_frame(const uint8_t* pixels, int64_t usec, bool y_invert)
{
/* Calculate data after y-inversion */
Expand All @@ -371,13 +401,11 @@ void FrameWriter::add_frame(const uint8_t* pixels, int64_t usec, bool y_invert)

if (hw_device_context)
{
encoder_frame->data[0] = (uint8_t*)formatted_pixels;
encoder_frame->linesize[0] = stride[0];

if (params.to_yuv)
{
sws_scale(swsCtx, &formatted_pixels, stride, 0, params.height,
encoder_frame->data, encoder_frame->linesize);
if (params.force_yuv) {
convert_pixels_to_yuv(pixels, formatted_pixels, stride);
} else {
encoder_frame->data[0] = (uint8_t*) formatted_pixels;
encoder_frame->linesize[0] = stride[0];
}

if (av_hwframe_transfer_data(hw_frame, encoder_frame, 0))
Expand All @@ -397,8 +425,8 @@ void FrameWriter::add_frame(const uint8_t* pixels, int64_t usec, bool y_invert)
encoder_frame->buf[0] = NULL;
} else
{
sws_scale(swsCtx, &formatted_pixels, stride, 0, params.height,
encoder_frame->data, encoder_frame->linesize);
convert_pixels_to_yuv(pixels, formatted_pixels, stride);

/* Force ffmpeg to create a copy of the frame, if the codec needs it */
saved_buf0 = encoder_frame->buf[0];
encoder_frame->buf[0] = NULL;
Expand Down
26 changes: 25 additions & 1 deletion src/frame-writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ extern "C"
#include <libavutil/opt.h>
}

#include "config.h"

#ifdef HAVE_OPENCL
#include <memory>
#include "opencl.hpp"
class OpenCL;
#endif

enum InputFormat
{
INPUT_FORMAT_BGR0,
Expand All @@ -46,7 +54,9 @@ struct FrameWriterParams
bool enable_audio;
bool enable_ffmpeg_debug_output;

bool to_yuv;
bool opencl;
bool force_yuv;
int opencl_device;
};

class FrameWriter
Expand All @@ -73,6 +83,16 @@ class FrameWriter
AVFrame *encoder_frame = NULL;
AVFrame *hw_frame = NULL;

/**
* Convert the given pixels to YUV and store in encoder_frame.
* Calls OpenCL if it is enabled.
*
* @param formatted_pixels contains the same data as pixels but y-inverted
* if the input format requires y-inversion.
*/
void convert_pixels_to_yuv(const uint8_t *pixels,
const uint8_t *formatted_pixels, int stride[]);

SwrContext *swrCtx;
AVStream *audioStream;
AVCodecContext *audioCodecCtx;
Expand All @@ -90,6 +110,10 @@ public :
void add_audio(const void* buffer);
size_t get_audio_buffer_size();

#ifdef HAVE_OPENCL
std::unique_ptr<OpenCL> opencl;
#endif

~FrameWriter();
};

Expand Down
43 changes: 33 additions & 10 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@

#include "config.h"

#ifdef HAVE_OPENCL
std::unique_ptr<OpenCL> opencl;
#endif

std::mutex frame_writer_mutex, frame_writer_pending_mutex;
std::unique_ptr<FrameWriter> frame_writer;

Expand Down Expand Up @@ -310,6 +314,14 @@ static void write_loop(FrameWriterParams params, PulseReaderParams pulseParams)
params.height = buffer.height;
frame_writer = std::unique_ptr<FrameWriter> (new FrameWriter(params));

#ifdef HAVE_OPENCL
if (params.opencl && params.force_yuv)
{
frame_writer->opencl = std::move(opencl);
frame_writer->opencl->init(params.width, params.height);
}
#endif

if (params.enable_audio)
{
pulseParams.audio_frame_size = frame_writer->get_audio_buffer_size();
Expand Down Expand Up @@ -490,7 +502,7 @@ With no FILE, start recording the current screen.

-a, --audio [DEVICE] Starts recording the screen with audio.
[DEVICE] argument is optional.
In case you want to specify the pulseaudio device which will capture
In case you want to specify the pulseaudio device which will capture
the audio, you can run this command with the name of that device.
You can find your device by running: pactl list sinks | grep Name

Expand All @@ -500,8 +512,6 @@ With no FILE, start recording the current screen.
-d, --device Selects the device to use when encoding the video
Some drivers report support for rgb0 data for vaapi input but
really only support yuv.
Use the -t or --to-yuv option in addition to the vaapi options to
convert the data in software, before sending it to the gpu.

-f <filename>.ext By using the -f option the output file will have the name :
filename.ext and the file format will be determined by provided
Expand All @@ -521,14 +531,14 @@ With no FILE, start recording the current screen.
-p, --codec-param Change the codec parameters.
-p <option_name>=<option_value>

-t, to-yuv Use the -t or --to-yuv option in addition to the vaapi options to
convert the data in software, before sending it to the gpu.\n\n
-t, force-yuv Use the -t or --force-yuv option to force conversion of the data to
yuv format, before sending it to the gpu.\n\n
Examples:

Video Only:

- wf-recorder Records the video. Use Ctrl+C to stop recording.
The video file will be stored as recording.mp4 in the
The video file will be stored as recording.mp4 in the
current working directory.

- wf-recorder -f <filename>.ext Records the video. Use Ctrl+C to stop recording.
Expand All @@ -555,7 +565,9 @@ int main(int argc, char *argv[])
params.codec = DEFAULT_CODEC;
params.enable_ffmpeg_debug_output = false;
params.enable_audio = false;
params.to_yuv = false;
params.force_yuv = false;
params.opencl = false;
params.opencl_device = -1;

PulseReaderParams pulseParams;

Expand All @@ -573,15 +585,16 @@ int main(int argc, char *argv[])
{ "device", required_argument, NULL, 'd' },
{ "log", no_argument, NULL, 'l' },
{ "audio", optional_argument, NULL, 'a' },
{ "to-yuv", no_argument, NULL, 't' },
{ "help", no_argument, NULL, 'h' },
{ "force-yuv", no_argument, NULL, 't' },
{ "opencl", optional_argument, NULL, 'e' },
{ 0, 0, NULL, 0 }
};

int c, i;
std::string param;
size_t pos;
while((c = getopt_long(argc, argv, "o:f:g:c:p:d:la::t::h", opts, &i)) != -1)
while((c = getopt_long(argc, argv, "o:f:g:c:p:d:la::te::h", opts, &i)) != -1)
{
switch(c)
{
Expand Down Expand Up @@ -615,13 +628,18 @@ int main(int argc, char *argv[])
break;

case 't':
params.to_yuv = true;
params.force_yuv = true;
break;

case 'h':
help();
break;

case 'e':
params.opencl = true;
params.opencl_device = optarg ? atoi(optarg) : -1;
break;

case 'p':
param = optarg;
pos = param.find("=");
Expand Down Expand Up @@ -714,6 +732,11 @@ int main(int argc, char *argv[])

printf("selected region %d %d %d %d\n", selected_region.x, selected_region.y, selected_region.width, selected_region.height);

#ifdef HAVE_OPENCL
if (params.opencl && params.force_yuv)
opencl = std::unique_ptr<OpenCL> (new OpenCL(params.opencl_device));
#endif

timespec first_frame;
first_frame.tv_sec = -1;

Expand Down
Loading