/*
* (C) 2006-2021 see Authors.txt
*
* This file is part of MPC-BE.
*
* MPC-BE is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* MPC-BE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define HAVE_AV_CONFIG_H
#include <Windows.h>
#include <time.h> // for the _time64 workaround
#include <algorithm>
#include <mpc_defines.h>
#include "DSUtil/FileVersion.h"
#include "ffmpegContext.h"
#pragma warning(push)
#pragma warning(disable: 4005)
#pragma warning(disable: 5033)
extern "C" {
#include <ExtLib/ffmpeg/libavcodec/avcodec.h>
// This is kind of an hack but it avoids using a C++ keyword as a struct member name
#define class classFFMPEG
#include <ExtLib/ffmpeg/libavcodec/mpegvideo.h>
#include <ExtLib/ffmpeg/libavcodec/h264dec.h>
#include <ExtLib/ffmpeg/libavcodec/ffv1.h>
#undef class
}
#pragma warning(pop)
static const WORD PCID_ATI_UVD [] = {
0x94C7, // ATI Radeon HD 2350
0x94C1, // ATI Radeon HD 2400 XT
0x94CC, // ATI Radeon HD 2400 Series
0x958A, // ATI Radeon HD 2600 X2 Series
0x9588, // ATI Radeon HD 2600 XT
0x9405, // ATI Radeon HD 2900 GT
0x9400, // ATI Radeon HD 2900 XT
0x9611, // ATI Radeon 3100 Graphics
0x9610, // ATI Radeon HD 3200 Graphics
0x9614, // ATI Radeon HD 3300 Graphics
0x95C0, // ATI Radeon HD 3400 Series (and others)
0x95C5, // ATI Radeon HD 3400 Series (and others)
0x95C4, // ATI Radeon HD 3400 Series (and others)
0x94C3, // ATI Radeon HD 3410
0x9589, // ATI Radeon HD 3600 Series (and others)
0x9598, // ATI Radeon HD 3600 Series (and others)
0x9591, // ATI Radeon HD 3600 Series (and others)
0x9501, // ATI Radeon HD 3800 Series (and others)
0x9505, // ATI Radeon HD 3800 Series (and others)
0x9507, // ATI Radeon HD 3830
0x9513, // ATI Radeon HD 3850 X2
0x9515, // ATI Radeon HD 3850 AGP
0x950F, // ATI Radeon HD 3850 X2
};
static bool CheckPCID(DWORD pcid, const WORD* pPCIDs, size_t count)
{
WORD wPCID = (WORD)pcid;
for (size_t i = 0; i < count; i++) {
if (wPCID == pPCIDs[i]) {
return true;
}
}
return false;
}
// === H264 functions
int FFH264CheckCompatibility(int nWidth, int nHeight, struct AVCodecContext* pAVCtx,
DWORD nPCIVendor, DWORD nPCIDevice, UINT64 VideoDriverVersion)
{
const H264Context* h = (H264Context*)pAVCtx->priv_data;
const SPS* sps = h264_getSPS(h);
int video_is_level51 = 0;
int no_level51_support = 1;
int too_much_ref_frames = 0;
const int max_ref_frames_dpb41 = std::min(11, 8388608/(nWidth * nHeight));
if (sps) {
if (sps->bit_depth_luma > 8 || sps->chroma_format_idc > 1) {
return DXVA_HIGH_BIT;
}
if (sps->profile_idc > 100) {
return DXVA_PROFILE_HIGHER_THAN_HIGH;
}
video_is_level51 = sps->level_idc >= 51 ? 1 : 0;
int max_ref_frames = max_ref_frames_dpb41; // default value is calculate
if (nPCIVendor == PCIV_nVidia) {
// nVidia cards support level 5.1 since drivers v7.15.11.7800 for Vista/7
if (VideoDriverVersion >= FileVersion::Ver(7, 15, 11, 7800).value) {
no_level51_support = 0;
max_ref_frames = 16;
}
} else if (nPCIVendor == PCIV_ATI && !CheckPCID(nPCIDevice, PCID_ATI_UVD, std::size(PCID_ATI_UVD))) {
WCHAR path[MAX_PATH] = { 0 };
GetSystemDirectoryW(path, MAX_PATH);
wcscat(path, L"\\drivers\\atikmdag.sys\0");
UINT64 atikmdag_ver = FileVersion::GetVer(path).value;
if (atikmdag_ver) {
// file version 8.1.1.1016 - Catalyst 10.4, WinVista & Win7
if (atikmdag_ver >= FileVersion::Ver(8, 1, 1, 1016).value) {
no_level51_support = 0;
max_ref_frames = 16;
}
} else {
// driver version 8.14.1.6105 - Catalyst 10.4; TODO - verify this information
if (VideoDriverVersion >= FileVersion::Ver(8, 14, 1, 6105).value) {
no_level51_support = 0;
max_ref_frames = 16;
}
}
} else if (nPCIVendor == PCIV_S3_Graphics || nPCIVendor == PCIV_Intel) {
no_level51_support = 0;
max_ref_frames = 16;
}
// Check maximum allowed number reference frames
if (sps->ref_frame_count > max_ref_frames) {
too_much_ref_frames = 1;
}
}
int Flags = 0;
if (video_is_level51 * no_level51_support) {
Flags |= DXVA_UNSUPPORTED_LEVEL;
}
if (too_much_ref_frames) {
Flags |= DXVA_TOO_MANY_REF_FRAMES;
}
return Flags;
}
void FillAVCodecProps(struct AVCodecContext* pAVCtx, BITMAPINFOHEADER* pBMI)
{
// fill "Pixel format" properties
if (pAVCtx->pix_fmt == AV_PIX_FMT_NONE) {
switch (pAVCtx->codec_id) {
case AV_CODEC_ID_LAGARITH:
if (pAVCtx->extradata_size >= 4) {
switch (GETU32(pAVCtx->extradata)) { // "lossy_option"
case 0:
switch (pAVCtx->bits_per_coded_sample) {
case 32: pAVCtx->pix_fmt = AV_PIX_FMT_RGBA; break;
default:
case 24: pAVCtx->pix_fmt = AV_PIX_FMT_RGB24; break;
case 16: pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P; break;
case 12: pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P; break;
}
break;
case 1:
pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P;
break;
case 2:
pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P;
break;
}
}
break;
case AV_CODEC_ID_PRORES:
switch (pAVCtx->codec_tag) {
case FCC('apch'): // Apple ProRes 422 High Quality
case FCC('apcn'): // Apple ProRes 422 Standard Definition
case FCC('apcs'): // Apple ProRes 422 LT
case FCC('apco'): // Apple ProRes 422 Proxy
case FCC('icpf'): // unknown type after matroska splitter
pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P10LE;
break;
case FCC('ap4h'): // Apple ProRes 4444
case FCC('ap4x'): // Apple ProRes 4444 XQ
pAVCtx->pix_fmt = AV_PIX_FMT_YUV444P12LE;
break;
}
break;
case AV_CODEC_ID_PNG:
case AV_CODEC_ID_JPEG2000:
if (pBMI->biBitCount > 32) {
pAVCtx->pix_fmt = AV_PIX_FMT_RGB48BE;
} else {
pAVCtx->pix_fmt = AV_PIX_FMT_RGBA; // and other RGB formats, but it is not important here
}
break;
case AV_CODEC_ID_HQ_HQA:
pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P;
break;
case AV_CODEC_ID_HQX:
pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P16; // or AV_PIX_FMT_YUV444P16
break;
case AV_CODEC_ID_CFHD:
pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P10; // most common format
break;
case AV_CODEC_ID_MJPEG:
pAVCtx->pix_fmt = AV_PIX_FMT_YUVJ422P; // most common format
pAVCtx->color_range = AVCOL_RANGE_JPEG;
break;
case AV_CODEC_ID_DNXHD:
pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P; // most common format
break;
case AV_CODEC_ID_MAGICYUV:
if (pAVCtx->extradata_size >= 32 && *(DWORD*)pAVCtx->extradata == FCC('MAGY')) {
int hsize = GETU32(pAVCtx->extradata + 4);
if (hsize >= 32 && pAVCtx->extradata[8] == 7) {
switch (pAVCtx->extradata[9]) {
case 0x65: pAVCtx->pix_fmt = AV_PIX_FMT_GBRP; break;
case 0x66: pAVCtx->pix_fmt = AV_PIX_FMT_GBRAP; break;
case 0x67: pAVCtx->pix_fmt = AV_PIX_FMT_YUV444P; break;
case 0x68: pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P; break;
case 0x69: pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P; break;
case 0x6a: pAVCtx->pix_fmt = AV_PIX_FMT_YUVA444P; break;
case 0x6b: pAVCtx->pix_fmt = AV_PIX_FMT_GRAY8; break;
case 0x6c: pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P10; break;
case 0x6d: pAVCtx->pix_fmt = AV_PIX_FMT_GBRP10; break;
case 0x6e: pAVCtx->pix_fmt = AV_PIX_FMT_GBRAP10; break;
case 0x6f: pAVCtx->pix_fmt = AV_PIX_FMT_GBRP12; break;
case 0x70: pAVCtx->pix_fmt = AV_PIX_FMT_GBRAP12; break;
case 0x73: pAVCtx->pix_fmt = AV_PIX_FMT_GRAY10; break;
}
}
}
else if (pAVCtx->extradata_size >= 8) {
switch (GETU32(pAVCtx->extradata + 4)) {
case FCC('M8RG'): pAVCtx->pix_fmt = AV_PIX_FMT_GBRP; break;
case FCC('M8RA'): pAVCtx->pix_fmt = AV_PIX_FMT_GBRAP; break;
case FCC('M8Y4'): pAVCtx->pix_fmt = AV_PIX_FMT_YUV444P; break;
case FCC('M8Y2'): pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P; break;
case FCC('M8Y0'): pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P; break;
case FCC('M8YA'): pAVCtx->pix_fmt = AV_PIX_FMT_YUVA444P; break;
case FCC('M8G0'): pAVCtx->pix_fmt = AV_PIX_FMT_GRAY8; break;
case FCC('M0Y2'): pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P10; break;
case FCC('M0RG'): pAVCtx->pix_fmt = AV_PIX_FMT_GBRP10; break;
case FCC('M0RA'): pAVCtx->pix_fmt = AV_PIX_FMT_GBRAP10; break;
case FCC('M2RG'): pAVCtx->pix_fmt = AV_PIX_FMT_GBRP12; break;
case FCC('M2RA'): pAVCtx->pix_fmt = AV_PIX_FMT_GBRAP12; break;
case FCC('M0R0'): pAVCtx->pix_fmt = AV_PIX_FMT_GRAY10; break;
}
}
break;
case AV_CODEC_ID_FFV1:
if (pAVCtx->priv_data) {
const FFV1Context* h = (FFV1Context*)pAVCtx->priv_data;
if (h->version > 0) { // extra data has been parse
if (h->colorspace == 0) {
if (pAVCtx->bits_per_raw_sample <= 8) { // <=8 bit and transparency
switch (16 * h->chroma_h_shift + h->chroma_v_shift) {
case 0x00: pAVCtx->pix_fmt = AV_PIX_FMT_YUV444P; break;
case 0x01: pAVCtx->pix_fmt = AV_PIX_FMT_YUV440P; break;
case 0x10: pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P; break;
case 0x11: pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P; break;
case 0x20: pAVCtx->pix_fmt = AV_PIX_FMT_YUV411P; break;
case 0x22: pAVCtx->pix_fmt = AV_PIX_FMT_YUV410P; break;
}
}
else if (pAVCtx->bits_per_raw_sample <= 10) { // 9, 10 bit and transparency
switch (16 * h->chroma_h_shift + h->chroma_v_shift) {
case 0x00: pAVCtx->pix_fmt = AV_PIX_FMT_YUV444P10; break;
case 0x10: pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P10; break;
case 0x11: pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P10; break;
}
}
else if (pAVCtx->bits_per_raw_sample <= 16) { // 12, 14, 16 bit and transparency
switch (16 * h->chroma_h_shift + h->chroma_v_shift) {
case 0x00: pAVCtx->pix_fmt = AV_PIX_FMT_YUV444P16; break;
case 0x10: pAVCtx->pix_fmt = AV_PIX_FMT_YUV422P16; break;
case 0x11: pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P16; break;
}
}
}
else if (h->colorspace == 1) {
pAVCtx->pix_fmt = AV_PIX_FMT_RGBA; // and other RGB formats, but it is not important here
}
}
}
break;
case AV_CODEC_ID_RPZA:
case AV_CODEC_ID_CINEPAK:
case AV_CODEC_ID_MSRLE:
case AV_CODEC_ID_MSVIDEO1:
case AV_CODEC_ID_8BPS:
case AV_CODEC_ID_QTRLE:
case AV_CODEC_ID_TSCC:
case AV_CODEC_ID_CSCD:
case AV_CODEC_ID_VMNC:
case AV_CODEC_ID_FLASHSV2:
case AV_CODEC_ID_MSS1:
case AV_CODEC_ID_G2M:
pAVCtx->pix_fmt = AV_PIX_FMT_RGB24; // and other RGB formats, but it is not important here
break;
}
if (pAVCtx->pix_fmt == AV_PIX_FMT_NONE) {
pAVCtx->pix_fmt = AV_PIX_FMT_YUV420P; // most common format
av_log(nullptr, AV_LOG_WARNING, "FillAVCodecProps: Unknown pixel format for %s, use AV_PIX_FMT_YUV420P.\n", pAVCtx->codec->name);
}
}
}
bool IsATIUVD(DWORD nPCIVendor, DWORD nPCIDevice)
{
return (nPCIVendor == PCIV_ATI && CheckPCID(nPCIDevice, PCID_ATI_UVD, std::size(PCID_ATI_UVD)));
}
BOOL DXVACheckFramesize(int width, int height, DWORD nPCIVendor, DWORD nPCIDevice, UINT64 VideoDriverVersion)
{
width = (width + 15) & ~15; // (width + 15) / 16 * 16;
height = (height + 15) & ~15; // (height + 15) / 16 * 16;
if (nPCIVendor == PCIV_nVidia) {
if (VideoDriverVersion >= FileVersion::Ver(9, 18, 13, 2018).value) {
// For Nvidia graphics cards with support for 4k, you must install the driver v320.18 or newer.
return TRUE;
}
if (width <= 2032 && height <= 2032 && width * height <= 8190 * 16 * 16) {
// tested H.264, VC-1 and MPEG-2 on VP4 (feature set C) (G210M, GT220)
return TRUE;
}
}
else if (nPCIVendor == PCIV_ATI) {
if (VideoDriverVersion >= FileVersion::Ver(8, 17, 10, 1404).value) { // aticfx32.dll/aticfx64.dll (v8.17.10.1404)
// For AMD graphics cards with support for 4k, you must install the Catalyst v15.7.1 or newer
return TRUE;
}
if (width <= 2048 && height <= 2304 && width * height <= 2048 * 2048) {
// tested H.264 on UVD 2.2 (HD5670, HD5770, HD5850)
// it may also work if width = 2064, but unstable
return TRUE;
}
}
else if (nPCIVendor == PCIV_Intel && VideoDriverVersion >= FileVersion::Ver(10, 18, 10, 4061).value) {
// For Intel graphics cards with support for 4k, you must install the driver v15.33.32.4061 or newer.
return TRUE;
}
else if ((width <= 1920 && height <= 1088)
|| (width <= 720 && height <= 1280)) {
return TRUE;
}
return FALSE;
}
↑ V1037 Two or more case-branches perform the same actions. Check lines: 204, 217
↑ V793 It is odd that the result of the 'video_is_level51 * no_level51_support' statement is a part of the condition. Perhaps, this statement should have been compared with something else.
↑ V1059 Macro name overrides the 'class' keyword. This may lead to undefined behavior.