Skip to content

Commit

Permalink
add av1 encoding support
Browse files Browse the repository at this point in the history
  • Loading branch information
mmozeiko committed Oct 19, 2024
1 parent dd3eed1 commit 4bd1a60
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Changelog
=========

##### 2024.10.18
* add native arm64 Windows support
* add AV1 codec for encoding - 8-bit and 10-bit main profile

##### 2024.09.15
* record application local audio for window capture (Windows 10 "20H1" and up)
* allow to disable yellow capture border indicator (Windows 11)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Features
* press <kbd>Ctrl + Shift + PrintScreen</kbd> to select & record fixed region on current monitor
* press any of previous combinations to stop recording
* right or double-click on tray icon to change settings
* video encoded using [H264/AVC][] or [H265/HEVC][], with 10-bit support for HEVC
* video encoded using [H264/AVC][], [H265/HEVC][] or [AV1][], with 10-bit support for HEVC and AV1
* audio encoded using [AAC][] or [FLAC][]
* for window capture record full window area (including title bar/borders) or just the client area
* window capture can record **application local audio**, no other system/process audio included
Expand Down Expand Up @@ -107,5 +107,6 @@ a compiled binary, for any purpose, commercial or non-commercial, and by any mea
[paletteuse]: https://ffmpeg.org/ffmpeg-filters.html#paletteuse
[H264/AVC]: https://en.wikipedia.org/wiki/Advanced_Video_Coding
[H265/HEVC]: https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding
[AV1]: https://en.wikipedia.org/wiki/AV1
[AAC]: https://en.wikipedia.org/wiki/Advanced_Audio_Coding
[FLAC]: https://en.wikipedia.org/wiki/FLAC
14 changes: 13 additions & 1 deletion wcap_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#define CONFIG_VIDEO_H264 0
#define CONFIG_VIDEO_H265 1
#define CONFIG_VIDEO_AV1 2

#define CONFIG_VIDEO_BASE 0
#define CONFIG_VIDEO_MAIN 1
Expand Down Expand Up @@ -151,14 +152,15 @@ static BOOL Config_ShowDialog(Config* C);
static const DWORD gAudioBitrates[] = { 96, 128, 160, 192, 0 };
static const DWORD gAudioSamplerates[] = { 44100, 48000, 0 };

static const LPCWSTR gVideoCodecs[] = { L"H264", L"H265", NULL};
static const LPCWSTR gVideoCodecs[] = { L"H264", L"H265", L"AV1", NULL};
static const LPCWSTR gVideoProfiles[] = { L"Base", L"Main", L"High", L"Main10", NULL };
static const LPCWSTR gAudioCodecs[] = { L"AAC", L"FLAC", NULL };

static const int gValidVideoProfiles[][4] =
{
{ CONFIG_VIDEO_BASE, CONFIG_VIDEO_MAIN, CONFIG_VIDEO_HIGH, -1 },
{ CONFIG_VIDEO_MAIN, CONFIG_VIDEO_MAIN_10, -1 },
{ CONFIG_VIDEO_MAIN, CONFIG_VIDEO_MAIN_10, -1 },
};

// currently open dialog window
Expand Down Expand Up @@ -194,6 +196,15 @@ static void Config__UpdateVideoProfiles(HWND Window, DWORD Codec)
ComboBox_AddString(Control, L"Main (8-bit)");
ComboBox_AddString(Control, L"Main10 (10-bit)");

ComboBox_SetItemData(Control, 0, CONFIG_VIDEO_MAIN);
ComboBox_SetItemData(Control, 1, CONFIG_VIDEO_MAIN_10);
ComboBox_SetCurSel(Control, 1);
}
else if (Codec == CONFIG_VIDEO_AV1)
{
ComboBox_AddString(Control, L"Main (8-bit)");
ComboBox_AddString(Control, L"Main (10-bit)");

ComboBox_SetItemData(Control, 0, CONFIG_VIDEO_MAIN);
ComboBox_SetItemData(Control, 1, CONFIG_VIDEO_MAIN_10);
ComboBox_SetCurSel(Control, 1);
Expand Down Expand Up @@ -444,6 +455,7 @@ static LRESULT CALLBACK Config__DialogProc(HWND Window, UINT Message, WPARAM WPa

SendDlgItemMessageW(Window, ID_VIDEO_CODEC, CB_ADDSTRING, 0, (LPARAM)L"H264 / AVC");
SendDlgItemMessageW(Window, ID_VIDEO_CODEC, CB_ADDSTRING, 0, (LPARAM)L"H265 / HEVC");
SendDlgItemMessageW(Window, ID_VIDEO_CODEC, CB_ADDSTRING, 0, (LPARAM)L"AV1");

SendDlgItemMessageW(Window, ID_AUDIO_CODEC, CB_ADDSTRING, 0, (LPARAM)L"AAC");
SendDlgItemMessageW(Window, ID_AUDIO_CODEC, CB_ADDSTRING, 0, (LPARAM)L"FLAC");
Expand Down
47 changes: 30 additions & 17 deletions wcap_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,43 +331,52 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons
const GUID* Container;
const GUID* Codec;
UINT32 Profile;
const GUID* MediaFormatYUV;
DXGI_FORMAT ConvertFormat;
const GUID* VideoInputFormat;
if (Config->Config->VideoCodec == CONFIG_VIDEO_H264)
{
MediaFormatYUV = &MFVideoFormat_NV12;
ConvertFormat = DXGI_FORMAT_NV12;

VideoInputFormat = &MFVideoFormat_NV12;
Container = Config->Config->FragmentedOutput ? &MFTranscodeContainerType_FMPEG4 : &MFTranscodeContainerType_MPEG4;
Codec = &MFVideoFormat_H264;
Profile = ((UINT32[]) { eAVEncH264VProfile_Base, eAVEncH264VProfile_Main, eAVEncH264VProfile_High })[Config->Config->VideoProfile];

}
else if (Config->Config->VideoCodec == CONFIG_VIDEO_H265 && Config->Config->VideoProfile == CONFIG_VIDEO_MAIN)
{
MediaFormatYUV = &MFVideoFormat_NV12;
ConvertFormat = DXGI_FORMAT_NV12;

VideoInputFormat = &MFVideoFormat_NV12;
Container = &MFTranscodeContainerType_MPEG4;
Codec = &MFVideoFormat_HEVC;
Profile = eAVEncH265VProfile_Main_420_8;

}
else // Config->Config->VideoCodec == CONFIG_VIDEO_H265 && Config->Config->VideoProfile == CONFIG_VIDEO_MAIN_10
else if (Config->Config->VideoCodec == CONFIG_VIDEO_H265 && Config->Config->VideoProfile == CONFIG_VIDEO_MAIN_10)
{
MediaFormatYUV = &MFVideoFormat_P010;
ConvertFormat = DXGI_FORMAT_P010;

VideoInputFormat = &MFVideoFormat_P010;
Container = &MFTranscodeContainerType_MPEG4;
Codec = &MFVideoFormat_HEVC;
Profile = eAVEncH265VProfile_Main_420_10;
}
else if (Config->Config->VideoCodec == CONFIG_VIDEO_AV1 && Config->Config->VideoProfile == CONFIG_VIDEO_MAIN)
{
VideoInputFormat = &MFVideoFormat_NV12;
Container = &MFTranscodeContainerType_MPEG4;
Codec = &MFVideoFormat_AV1;
Profile = eAVEncAV1VProfile_Main_420_8;
}
else if (Config->Config->VideoCodec == CONFIG_VIDEO_AV1 && Config->Config->VideoProfile == CONFIG_VIDEO_MAIN_10)
{
VideoInputFormat = &MFVideoFormat_P010;
Container = &MFTranscodeContainerType_MPEG4;
Codec = &MFVideoFormat_AV1;
Profile = eAVEncAV1VProfile_Main_420_10;
}
else
{
Assert(0);
}

// make sure MFT video encoder exists, some vendors wrongly allow SinkWriter to be created for invalid configuration
{
bool Ok = false;

MFT_REGISTER_TYPE_INFO InputType = { MFMediaType_Video, *MediaFormatYUV };
MFT_REGISTER_TYPE_INFO InputType = { MFMediaType_Video, *VideoInputFormat };
MFT_REGISTER_TYPE_INFO OutputType = { MFMediaType_Video, *Codec };

IMFAttributes* EnumAttributes;
Expand Down Expand Up @@ -422,7 +431,9 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons
}

// https://github.com/mpv-player/mpv/blob/release/0.38/video/csputils.c#L150-L153
bool IsHD = (OutputWidth >= 1280) || (OutputHeight > 576) || Config->Config->VideoCodec == CONFIG_VIDEO_H265;
bool IsHD = (OutputWidth >= 1280) || (OutputHeight > 576)
|| Config->Config->VideoCodec == CONFIG_VIDEO_H265
|| Config->Config->VideoCodec == CONFIG_VIDEO_AV1;

// output file
{
Expand Down Expand Up @@ -486,7 +497,7 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons
IMFMediaType* Type;
HR(MFCreateMediaType(&Type));
HR(IMFMediaType_SetGUID(Type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video));
HR(IMFMediaType_SetGUID(Type, &MF_MT_SUBTYPE, MediaFormatYUV));
HR(IMFMediaType_SetGUID(Type, &MF_MT_SUBTYPE, VideoInputFormat));
HR(IMFMediaType_SetUINT32(Type, &MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive));
HR(IMFMediaType_SetUINT64(Type, &MF_MT_FRAME_RATE, MFT64(Config->FramerateNum, Config->FramerateDen)));
HR(IMFMediaType_SetUINT64(Type, &MF_MT_FRAME_SIZE, MFT64(OutputWidth, OutputHeight)));
Expand Down Expand Up @@ -637,6 +648,8 @@ BOOL Encoder_Start(Encoder* Encoder, ID3D11Device* Device, LPWSTR FileName, cons
YuvColorSpace ColorSpace = IsHD ? YuvColorSpace_BT709 : YuvColorSpace_BT601;
YuvConvert_Create(&Encoder->Convert, Device, Encoder->Resize.OutputTexture, OutputWidth, OutputHeight, ColorSpace, Config->Config->ImprovedColorConversion);

DXGI_FORMAT ConvertFormat = IsEqualGUID(VideoInputFormat, &MFVideoFormat_NV12) ? DXGI_FORMAT_NV12 : DXGI_FORMAT_P010;

for (size_t OutputIndex = 0; OutputIndex < ENCODER_VIDEO_BUFFER_COUNT; OutputIndex++)
{
YuvConvertOutput_Create(&Encoder->ConvertOutput[OutputIndex], Device, OutputWidth, OutputHeight, ConvertFormat);
Expand Down

0 comments on commit 4bd1a60

Please sign in to comment.