Add experimental av1 support (only tested on amd)

This commit is contained in:
dec05eba 2023-11-11 13:36:45 +01:00
parent acdab088cf
commit f4f78b0684
2 changed files with 71 additions and 12 deletions

6
TODO
View File

@ -54,7 +54,7 @@ Intel is a bit weird with monitor capture and multiple monitors. If one of the m
Is that only the case when the primary monitor is rotated? Also the primary monitor becomes position 0, 0 so crtc (x11 randr) position doesn't match the drm pos. Maybe get monitor position and size from drm instead.
How about if multiple monitors are rotated?
Support vp8/vp9/av1. This is especially important on amd which on some distros (such as Manjaro) where hardware accelerated h264/hevc is disabled in the mesa package.
Support vp8/vp9. This is especially important on amd which on some distros (such as Manjaro) where hardware accelerated h264/hevc is disabled in the mesa package.
Support screen (all monitors) capture on amd/intel when no combined plane is found.
Use separate plane (which has offset and pitch) from combined plane instead of the combined plane.
@ -96,8 +96,6 @@ Remove follow focused option.
Fix kms capture on 10-bit setup (both x11 and wayland). It may already work automatically on amd/intel, but on nvidia the color conversion shader needs to be used to automatically map 10-bit to 8-bit.
Test vaapi av1 encoding (av1_vaapi) (which was recently added to ffmpeg master).
Overclocking (-oc) can overclock too much on some systems. Maybe remove the option?
Exit if X11/Wayland killed (if drm plane dead or something?)
@ -107,3 +105,5 @@ Use SRC_W and SRC_H for screen plane instead of crtc_w and crtc_h.
Make it possible to select which /dev/dri/card* to use, but that requires opengl to also use the same card. Not sure if that is possible for amd, intel and nvidia without using vulkan instead.
Support I915_FORMAT_MOD_Y_TILED_CCS (and other power saving modifiers, see https://trac.ffmpeg.org/ticket/8542). The only fix may be to use desktop portal for recording. This issue doesn't appear on x11 since these modifiers are not used by xorg server.
Test if p2 state can be worked around by using pure nvenc api and overwriting cuInit/cuCtxCreate* to not do anything. Cuda might be loaded when using nvenc but it might not be used, with certain record options? (such as h264 p5).

View File

@ -67,7 +67,8 @@ enum class VideoQuality {
enum class VideoCodec {
H264,
H265
H265,
AV1
};
enum class AudioCodec {
@ -501,6 +502,24 @@ static const AVCodec* find_h265_encoder(gsr_gpu_vendor vendor, const char *card_
return checked_success ? codec : nullptr;
}
static const AVCodec* find_av1_encoder(gsr_gpu_vendor vendor, const char *card_path) {
const AVCodec *codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "av1_nvenc" : "av1_vaapi");
if(!codec)
codec = avcodec_find_encoder_by_name(vendor == GSR_GPU_VENDOR_NVIDIA ? "nvenc_av1" : "vaapi_av1");
if(!codec)
return nullptr;
static bool checked = false;
static bool checked_success = true;
if(!checked) {
checked = true;
if(!check_if_codec_valid_for_hardware(codec, vendor, card_path))
checked_success = false;
}
return checked_success ? codec : nullptr;
}
static AVFrame* open_audio(AVCodecContext *audio_codec_context) {
AVDictionary *options = nullptr;
av_dict_set(&options, "strict", "experimental", 0);
@ -620,6 +639,15 @@ static void open_video(AVCodecContext *codec_context, VideoQuality video_quality
av_dict_set(&options, "profile", "high444p", 0);
break;
}
} else if(codec_context->codec_id == AV_CODEC_ID_AV1) {
switch(pixel_format) {
case PixelFormat::YUV420:
av_dict_set(&options, "rgb_mode", "yuv420", 0);
break;
case PixelFormat::YUV444:
av_dict_set(&options, "rgb_mode", "yuv444", 0);
break;
}
} else {
//av_dict_set(&options, "profile", "main10", 0);
//av_dict_set(&options, "pix_fmt", "yuv420p16le", 0);
@ -647,6 +675,10 @@ static void open_video(AVCodecContext *codec_context, VideoQuality video_quality
if(codec_context->codec_id == AV_CODEC_ID_H264) {
av_dict_set(&options, "profile", "high", 0);
av_dict_set_int(&options, "quality", 7, 0);
} else if(codec_context->codec_id == AV_CODEC_ID_AV1) {
av_dict_set(&options, "profile", "main", 0); // TODO: use professional instead?
av_dict_set(&options, "tier", "main", 0);
av_dict_set_int(&options, "quality", 7, 0);
} else {
av_dict_set(&options, "profile", "main", 0);
}
@ -666,7 +698,7 @@ static void open_video(AVCodecContext *codec_context, VideoQuality video_quality
}
static void usage_header() {
fprintf(stderr, "usage: gpu-screen-recorder -w <window_id|monitor|focused> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|h265] [-ac aac|opus|flac] [-oc yes|no] [-fm cfr|vfr] [-v yes|no] [-h|--help] [-o <output_file>] [-mf yes|no]\n");
fprintf(stderr, "usage: gpu-screen-recorder -w <window_id|monitor|focused> [-c <container_format>] [-s WxH] -f <fps> [-a <audio_input>] [-q <quality>] [-r <replay_buffer_size_sec>] [-k h264|h265|av1] [-ac aac|opus|flac] [-oc yes|no] [-fm cfr|vfr] [-v yes|no] [-h|--help] [-o <output_file>] [-mf yes|no]\n");
}
static void usage_full() {
@ -683,7 +715,7 @@ static void usage_full() {
fprintf(stderr, "\n");
fprintf(stderr, " -c Container format for output file, for example mp4, or flv. Only required if no output file is specified or if recording in replay buffer mode.\n");
fprintf(stderr, " If an output file is specified and -c is not used then the container format is determined from the output filename extension.\n");
fprintf(stderr, " Only containers that support h264 or hevc are supported, which means that only mp4, mkv, flv (and some others) are supported.\n");
fprintf(stderr, " Only containers that support h264, hevc or av1 are supported, which means that only mp4, mkv, flv (and some others) are supported.\n");
fprintf(stderr, " WebM is not supported yet.\n");
fprintf(stderr, "\n");
fprintf(stderr, " -s The size (area) to record at in the format WxH, for example 1920x1080. This option is only supported (and required) when -w is \"focused\".\n");
@ -702,7 +734,7 @@ static void usage_full() {
fprintf(stderr, " and the video will only be saved when the gpu-screen-recorder is closed. This feature is similar to Nvidia's instant replay feature.\n");
fprintf(stderr, " This option has be between 5 and 1200. Note that the replay buffer size will not always be precise, because of keyframes. Optional, disabled by default.\n");
fprintf(stderr, "\n");
fprintf(stderr, " -k Video codec to use. Should be either 'auto', 'h264' or 'h265'. Defaults to 'auto' which defaults to 'h265' unless recording at fps higher than 60. Defaults to 'h264' on intel.\n");
fprintf(stderr, " -k Video codec to use. Should be either 'auto', 'h264', 'h265', 'av1'. Defaults to 'auto' which defaults to 'h265' unless recording at fps higher than 60. Defaults to 'h264' on intel.\n");
fprintf(stderr, " Forcefully set to 'h264' if -c is 'flv'.\n");
fprintf(stderr, "\n");
fprintf(stderr, " -ac Audio codec to use. Should be either 'aac', 'opus' or 'flac'. Defaults to 'opus' for .mp4/.mkv files, otherwise defaults to 'aac'.\n");
@ -1248,8 +1280,10 @@ int main(int argc, char **argv) {
video_codec = VideoCodec::H264;
} else if(strcmp(video_codec_to_use, "h265") == 0) {
video_codec = VideoCodec::H265;
} else if(strcmp(video_codec_to_use, "av1") == 0) {
video_codec = VideoCodec::AV1;
} else if(strcmp(video_codec_to_use, "auto") != 0) {
fprintf(stderr, "Error: -k should either be either 'auto', 'h264' or 'h265', got: '%s'\n", video_codec_to_use);
fprintf(stderr, "Error: -k should either be either 'auto', 'h264', 'h265' or 'av1', got: '%s'\n", video_codec_to_use);
usage();
}
@ -1753,7 +1787,7 @@ int main(int argc, char **argv) {
}
}
//bool use_hevc = strcmp(window_str, "screen") == 0 || strcmp(window_str, "screen-direct") == 0;
// TODO: Allow hevc, vp9 and av1 in (enhanced) flv (supported since ffmpeg 6.1)
const bool is_flv = strcmp(file_extension.c_str(), "flv") == 0;
if(video_codec != VideoCodec::H264 && is_flv) {
video_codec_to_use = "h264";
@ -1769,6 +1803,9 @@ int main(int argc, char **argv) {
case VideoCodec::H265:
video_codec_f = find_h265_encoder(gpu_inf.vendor, card_path);
break;
case VideoCodec::AV1:
video_codec_f = find_av1_encoder(gpu_inf.vendor, card_path);
break;
}
if(!video_codec_auto && !video_codec_f && !is_flv) {
@ -1787,16 +1824,38 @@ int main(int argc, char **argv) {
video_codec_f = find_h264_encoder(gpu_inf.vendor, card_path);
break;
}
case VideoCodec::AV1: {
fprintf(stderr, "Warning: selected video codec av1 is not supported, trying h264 instead\n");
video_codec_to_use = "h264";
video_codec = VideoCodec::H264;
video_codec_f = find_h264_encoder(gpu_inf.vendor, card_path);
break;
}
}
}
if(!video_codec_f) {
const char *video_codec_name = video_codec == VideoCodec::H264 ? "h264" : "h265";
const char *video_codec_name = "";
switch(video_codec) {
case VideoCodec::H264: {
video_codec_name = "h265";
break;
}
case VideoCodec::H265: {
video_codec_name = "h265";
break;
}
case VideoCodec::AV1: {
video_codec_name = "av1";
break;
}
}
fprintf(stderr, "Error: your gpu does not support '%s' video codec. If you are sure that your gpu does support '%s' video encoding and you are using an AMD/Intel GPU,\n"
" then it's possible that your distro has disabled hardware accelerated video encoding for '%s' video codec.\n"
" This may be the case on corporate distros such as Manjaro.\n"
" You can test this by running 'vainfo | grep VAEntrypointEncSlice' to see if it matches any H264/HEVC profile. vainfo is part of libva-utils.\n"
" On such distros, you need to manually install mesa from source to enable H264/HEVC hardware acceleration, or use a more user friendly distro.\n", video_codec_name, video_codec_name, video_codec_name);
" You can test this by running 'vainfo | grep VAEntrypointEncSlice' to see if it matches any H264/HEVC/AV1 profile. vainfo is part of libva-utils.\n"
" On such distros, you need to manually install mesa from source to enable H264/HEVC/AV1 hardware acceleration, or use a more user friendly distro.\n", video_codec_name, video_codec_name, video_codec_name);
_exit(2);
}