Support YUV 4:4:4 formats

This commit is contained in:
ns6089 2024-05-15 16:22:42 +03:00 committed by Cameron Gutman
parent ff332d45f8
commit da0244c538
12 changed files with 332 additions and 42 deletions

View file

@ -374,6 +374,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
parser.addToggleOption("keep-awake", "prevent display sleep while streaming"); parser.addToggleOption("keep-awake", "prevent display sleep while streaming");
parser.addToggleOption("performance-overlay", "show performance overlay"); parser.addToggleOption("performance-overlay", "show performance overlay");
parser.addToggleOption("hdr", "HDR streaming"); parser.addToggleOption("hdr", "HDR streaming");
parser.addToggleOption("yuv444", "YUV 4:4:4 sampling, if supported");
parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys()); parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys());
parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys()); parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys());
parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys()); parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys());
@ -425,7 +426,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
} }
} else if (displaySet || parser.isSet("fps")) { } else if (displaySet || parser.isSet("fps")) {
preferences->bitrateKbps = preferences->getDefaultBitrate( preferences->bitrateKbps = preferences->getDefaultBitrate(
preferences->width, preferences->height, preferences->fps); preferences->width, preferences->height, preferences->fps, preferences->enableYUV444);
} }
// Resolve --packet-size option // Resolve --packet-size option
@ -494,6 +495,9 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
// Resolve --hdr and --no-hdr options // Resolve --hdr and --no-hdr options
preferences->enableHdr = parser.getToggleOptionValue("hdr", preferences->enableHdr); preferences->enableHdr = parser.getToggleOptionValue("hdr", preferences->enableHdr);
// Resolve --yuv444 and --no-yuv444 options
preferences->enableYUV444 = parser.getToggleOptionValue("yuv444", preferences->enableYUV444);
// Resolve --capture-system-keys option // Resolve --capture-system-keys option
if (parser.isSet("capture-system-keys")) { if (parser.isSet("capture-system-keys")) {
preferences->captureSysKeysMode = mapValue(m_CaptureSysKeysModeMap, parser.getChoiceOptionValue("capture-system-keys")); preferences->captureSysKeysMode = mapValue(m_CaptureSysKeysModeMap, parser.getChoiceOptionValue("capture-system-keys"));

View file

@ -283,7 +283,8 @@ Flickable {
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width, StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height, StreamingPreferences.height,
StreamingPreferences.fps); StreamingPreferences.fps,
StreamingPreferences.enableYUV444);
slider.value = StreamingPreferences.bitrateKbps slider.value = StreamingPreferences.bitrateKbps
} }
@ -448,7 +449,8 @@ Flickable {
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width, StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height, StreamingPreferences.height,
StreamingPreferences.fps); StreamingPreferences.fps,
StreamingPreferences.enableYUV444);
slider.value = StreamingPreferences.bitrateKbps slider.value = StreamingPreferences.bitrateKbps
} }
@ -1615,6 +1617,31 @@ Flickable {
qsTr("HDR streaming is not supported on this PC.") qsTr("HDR streaming is not supported on this PC.")
} }
CheckBox {
id: enableYUV444
width: parent.width
text: qsTr("Enable YUV 4:4:4 (Experimental)")
font.pointSize: 12
checked: StreamingPreferences.enableYUV444
onCheckedChanged: {
StreamingPreferences.enableYUV444 = checked
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height,
StreamingPreferences.fps,
StreamingPreferences.enableYUV444);
slider.value = StreamingPreferences.bitrateKbps
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: enabled ?
qsTr("Good for streaming desktop and text-heavy games, not very good for fast-paced games.")
:
qsTr("YUV 4:4:4 is not supported on this PC.")
}
CheckBox { CheckBox {
id: enableMdns id: enableMdns
width: parent.width width: parent.width

View file

@ -23,6 +23,7 @@
#define SER_AUDIOCFG "audiocfg" #define SER_AUDIOCFG "audiocfg"
#define SER_VIDEOCFG "videocfg" #define SER_VIDEOCFG "videocfg"
#define SER_HDR "hdr" #define SER_HDR "hdr"
#define SER_YUV444 "yuv444"
#define SER_VIDEODEC "videodec" #define SER_VIDEODEC "videodec"
#define SER_WINDOWMODE "windowmode" #define SER_WINDOWMODE "windowmode"
#define SER_MDNS "mdns" #define SER_MDNS "mdns"
@ -117,7 +118,8 @@ void StreamingPreferences::reload()
width = settings.value(SER_WIDTH, 1280).toInt(); width = settings.value(SER_WIDTH, 1280).toInt();
height = settings.value(SER_HEIGHT, 720).toInt(); height = settings.value(SER_HEIGHT, 720).toInt();
fps = settings.value(SER_FPS, 60).toInt(); fps = settings.value(SER_FPS, 60).toInt();
bitrateKbps = settings.value(SER_BITRATE, getDefaultBitrate(width, height, fps)).toInt(); enableYUV444 = settings.value(SER_YUV444, false).toBool();
bitrateKbps = settings.value(SER_BITRATE, getDefaultBitrate(width, height, fps, enableYUV444)).toInt();
enableVsync = settings.value(SER_VSYNC, true).toBool(); enableVsync = settings.value(SER_VSYNC, true).toBool();
gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool(); gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool();
playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool(); playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool();
@ -322,6 +324,7 @@ void StreamingPreferences::save()
settings.setValue(SER_SHOWPERFOVERLAY, showPerformanceOverlay); settings.setValue(SER_SHOWPERFOVERLAY, showPerformanceOverlay);
settings.setValue(SER_AUDIOCFG, static_cast<int>(audioConfig)); settings.setValue(SER_AUDIOCFG, static_cast<int>(audioConfig));
settings.setValue(SER_HDR, enableHdr); settings.setValue(SER_HDR, enableHdr);
settings.setValue(SER_YUV444, enableYUV444);
settings.setValue(SER_VIDEOCFG, static_cast<int>(videoCodecConfig)); settings.setValue(SER_VIDEOCFG, static_cast<int>(videoCodecConfig));
settings.setValue(SER_VIDEODEC, static_cast<int>(videoDecoderSelection)); settings.setValue(SER_VIDEODEC, static_cast<int>(videoDecoderSelection));
settings.setValue(SER_WINDOWMODE, static_cast<int>(windowMode)); settings.setValue(SER_WINDOWMODE, static_cast<int>(windowMode));
@ -337,7 +340,7 @@ void StreamingPreferences::save()
settings.setValue(SER_KEEPAWAKE, keepAwake); settings.setValue(SER_KEEPAWAKE, keepAwake);
} }
int StreamingPreferences::getDefaultBitrate(int width, int height, int fps) int StreamingPreferences::getDefaultBitrate(int width, int height, int fps, bool yuv444)
{ {
// Don't scale bitrate linearly beyond 60 FPS. It's definitely not a linear // Don't scale bitrate linearly beyond 60 FPS. It's definitely not a linear
// bitrate increase for frame rate once we get to values that high. // bitrate increase for frame rate once we get to values that high.
@ -385,5 +388,10 @@ int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
} }
} }
if (yuv444) {
// This is rough estimation based on the fact that 4:4:4 doubles the amount of raw YUV data compared to 4:2:0
resolutionFactor *= 2;
}
return qRound(resolutionFactor * frameRateFactor) * 1000; return qRound(resolutionFactor * frameRateFactor) * 1000;
} }

View file

@ -12,7 +12,7 @@ public:
static StreamingPreferences* get(QQmlEngine *qmlEngine = nullptr); static StreamingPreferences* get(QQmlEngine *qmlEngine = nullptr);
Q_INVOKABLE static int Q_INVOKABLE static int
getDefaultBitrate(int width, int height, int fps); getDefaultBitrate(int width, int height, int fps, bool yuv444);
Q_INVOKABLE void save(); Q_INVOKABLE void save();
@ -125,6 +125,7 @@ public:
Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged) Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged)
Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged) Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged)
Q_PROPERTY(bool enableHdr MEMBER enableHdr NOTIFY enableHdrChanged) Q_PROPERTY(bool enableHdr MEMBER enableHdr NOTIFY enableHdrChanged)
Q_PROPERTY(bool enableYUV444 MEMBER enableYUV444 NOTIFY enableYUV444Changed)
Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged) Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged)
Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged) Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged)
Q_PROPERTY(WindowMode recommendedFullScreenMode MEMBER recommendedFullScreenMode CONSTANT) Q_PROPERTY(WindowMode recommendedFullScreenMode MEMBER recommendedFullScreenMode CONSTANT)
@ -169,6 +170,7 @@ public:
AudioConfig audioConfig; AudioConfig audioConfig;
VideoCodecConfig videoCodecConfig; VideoCodecConfig videoCodecConfig;
bool enableHdr; bool enableHdr;
bool enableYUV444;
VideoDecoderSelection videoDecoderSelection; VideoDecoderSelection videoDecoderSelection;
WindowMode windowMode; WindowMode windowMode;
WindowMode recommendedFullScreenMode; WindowMode recommendedFullScreenMode;
@ -191,6 +193,7 @@ signals:
void audioConfigChanged(); void audioConfigChanged();
void videoCodecConfigChanged(); void videoCodecConfigChanged();
void enableHdrChanged(); void enableHdrChanged();
void enableYUV444Changed();
void videoDecoderSelectionChanged(); void videoDecoderSelectionChanged();
void uiDisplayModeChanged(); void uiDisplayModeChanged();
void windowModeChanged(); void windowModeChanged();

View file

@ -597,15 +597,22 @@ bool Session::initialize()
return false; return false;
} }
LiInitializeStreamConfiguration(&m_StreamConfig);
m_StreamConfig.width = m_Preferences->width;
m_StreamConfig.height = m_Preferences->height;
int x, y, width, height;
getWindowDimensions(x, y, width, height);
// Create a hidden window to use for decoder initialization tests // Create a hidden window to use for decoder initialization tests
SDL_Window* testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_Window* testWindow = SDL_CreateWindow("", x, y, width, height,
SDL_WINDOW_HIDDEN | StreamUtils::getPlatformWindowFlags()); SDL_WINDOW_HIDDEN | StreamUtils::getPlatformWindowFlags());
if (!testWindow) { if (!testWindow) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create test window with platform flags: %s", "Failed to create test window with platform flags: %s",
SDL_GetError()); SDL_GetError());
testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN); testWindow = SDL_CreateWindow("", x, y, width, height, SDL_WINDOW_HIDDEN);
if (!testWindow) { if (!testWindow) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create window for hardware decode test: %s", "Failed to create window for hardware decode test: %s",
@ -621,9 +628,6 @@ bool Session::initialize()
LiInitializeVideoCallbacks(&m_VideoCallbacks); LiInitializeVideoCallbacks(&m_VideoCallbacks);
m_VideoCallbacks.setup = drSetup; m_VideoCallbacks.setup = drSetup;
LiInitializeStreamConfiguration(&m_StreamConfig);
m_StreamConfig.width = m_Preferences->width;
m_StreamConfig.height = m_Preferences->height;
m_StreamConfig.fps = m_Preferences->fps; m_StreamConfig.fps = m_Preferences->fps;
m_StreamConfig.bitrate = m_Preferences->bitrateKbps; m_StreamConfig.bitrate = m_Preferences->bitrateKbps;
@ -677,10 +681,15 @@ bool Session::initialize()
CHANNEL_MASK_FROM_AUDIO_CONFIGURATION(m_StreamConfig.audioConfiguration)); CHANNEL_MASK_FROM_AUDIO_CONFIGURATION(m_StreamConfig.audioConfiguration));
// Start with all codecs and profiles in priority order // Start with all codecs and profiles in priority order
m_SupportedVideoFormats.append(VIDEO_FORMAT_AV1_HIGH10_444);
m_SupportedVideoFormats.append(VIDEO_FORMAT_AV1_MAIN10); m_SupportedVideoFormats.append(VIDEO_FORMAT_AV1_MAIN10);
m_SupportedVideoFormats.append(VIDEO_FORMAT_H265_REXT10_444);
m_SupportedVideoFormats.append(VIDEO_FORMAT_H265_MAIN10); m_SupportedVideoFormats.append(VIDEO_FORMAT_H265_MAIN10);
m_SupportedVideoFormats.append(VIDEO_FORMAT_AV1_HIGH8_444);
m_SupportedVideoFormats.append(VIDEO_FORMAT_AV1_MAIN8); m_SupportedVideoFormats.append(VIDEO_FORMAT_AV1_MAIN8);
m_SupportedVideoFormats.append(VIDEO_FORMAT_H265_REXT8_444);
m_SupportedVideoFormats.append(VIDEO_FORMAT_H265); m_SupportedVideoFormats.append(VIDEO_FORMAT_H265);
m_SupportedVideoFormats.append(VIDEO_FORMAT_H264_HIGH8_444);
m_SupportedVideoFormats.append(VIDEO_FORMAT_H264); m_SupportedVideoFormats.append(VIDEO_FORMAT_H264);
// Mask off 10-bit codecs right away if HDR is not enabled // Mask off 10-bit codecs right away if HDR is not enabled
@ -688,6 +697,11 @@ bool Session::initialize()
m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_10BIT); m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_10BIT);
} }
// Mask off YUV 4:4:4 codecs right away if the option is not enabled
if (!m_Preferences->enableYUV444) {
m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_YUV444);
}
switch (m_Preferences->videoCodecConfig) switch (m_Preferences->videoCodecConfig)
{ {
case StreamingPreferences::VCC_AUTO: case StreamingPreferences::VCC_AUTO:
@ -969,6 +983,37 @@ bool Session::validateLaunch(SDL_Window* testWindow)
} }
} }
if (m_Preferences->enableYUV444) {
if (!(m_Computer->serverCodecModeSupport & SCM_MASK_YUV444)) {
emitLaunchWarning(tr("Your host PC doesn't support YUV 4:4:4 streaming."));
m_SupportedVideoFormats.removeByMask(VIDEO_FORMAT_MASK_YUV444);
}
else if (m_Preferences->videoDecoderSelection != StreamingPreferences::VDS_FORCE_SOFTWARE) {
m_SupportedVideoFormats.removeByMask(~m_SupportedVideoFormats.maskByServerCodecModes(m_Computer->serverCodecModeSupport));
if (!m_SupportedVideoFormats.isEmpty() &&
!(m_SupportedVideoFormats.front() & VIDEO_FORMAT_MASK_YUV444)) {
emitLaunchWarning(tr("Your host PC doesn't support YUV 4:4:4 streaming for selected video codec."));
}
else {
while (!m_SupportedVideoFormats.isEmpty() &&
(m_SupportedVideoFormats.front() & VIDEO_FORMAT_MASK_YUV444) &&
!isHardwareDecodeAvailable(testWindow,
m_Preferences->videoDecoderSelection,
m_SupportedVideoFormats.front(),
m_StreamConfig.width,
m_StreamConfig.height,
m_StreamConfig.fps)) {
m_SupportedVideoFormats.removeFirst();
}
if (!m_SupportedVideoFormats.isEmpty() &&
!(m_SupportedVideoFormats.front() & VIDEO_FORMAT_MASK_YUV444)) {
emitLaunchWarning(tr("This PC's GPU doesn't support YUV 4:4:4 decoding for selected video codec."));
}
}
}
}
if (m_StreamConfig.width >= 3840) { if (m_StreamConfig.width >= 3840) {
// Only allow 4K on GFE 3.x+ // Only allow 4K on GFE 3.x+
if (m_Computer->gfeVersion.isEmpty() || m_Computer->gfeVersion.startsWith("2.")) { if (m_Computer->gfeVersion.isEmpty() || m_Computer->gfeVersion.startsWith("2.")) {

View file

@ -41,36 +41,33 @@ public:
int maskByServerCodecModes(int serverCodecModes) int maskByServerCodecModes(int serverCodecModes)
{ {
int val = *this; int mask = 0;
const QMap<int, int> mapping = {
{SCM_H264, VIDEO_FORMAT_H264},
{SCM_H264_HIGH8_444, VIDEO_FORMAT_H264_HIGH8_444},
{SCM_HEVC, VIDEO_FORMAT_H265},
{SCM_HEVC_MAIN10, VIDEO_FORMAT_H265_MAIN10},
{SCM_HEVC_REXT8_444, VIDEO_FORMAT_H265_REXT8_444},
{SCM_HEVC_REXT10_444, VIDEO_FORMAT_H265_REXT10_444},
{SCM_AV1_MAIN8, VIDEO_FORMAT_AV1_MAIN8},
{SCM_AV1_MAIN10, VIDEO_FORMAT_AV1_MAIN10},
{SCM_AV1_HIGH8_444, VIDEO_FORMAT_AV1_HIGH8_444},
{SCM_AV1_HIGH10_444, VIDEO_FORMAT_AV1_HIGH10_444},
};
for (QMap<int, int>::const_iterator it = mapping.cbegin(); it != mapping.cend(); ++it) {
if (serverCodecModes & it.key()) {
mask |= it.value();
serverCodecModes &= ~it.key();
}
}
// Make sure nobody forgets to update this for new SCM values // Make sure nobody forgets to update this for new SCM values
SDL_assert((serverCodecModes & ~(SCM_MASK_H264 | SCM_MASK_HEVC | SCM_MASK_AV1)) == 0); SDL_assert(serverCodecModes == 0);
// H.264 SCM masks int val = *this;
if (!(serverCodecModes & SCM_H264)) { return val & mask;
val &= ~VIDEO_FORMAT_H264;
}
SDL_assert((serverCodecModes & SCM_MASK_H264 & ~SCM_H264) == 0);
// HEVC SCM masks
if (!(serverCodecModes & SCM_HEVC)) {
val &= ~VIDEO_FORMAT_H265;
}
if (!(serverCodecModes & SCM_HEVC_MAIN10)) {
val &= ~VIDEO_FORMAT_H265_MAIN10;
}
SDL_assert((serverCodecModes & SCM_MASK_HEVC & ~(SCM_HEVC | SCM_HEVC_MAIN10)) == 0);
// AV1 SCM masks
if (!(serverCodecModes & SCM_AV1_MAIN8)) {
val &= ~VIDEO_FORMAT_AV1_MAIN8;
}
if (!(serverCodecModes & SCM_AV1_MAIN10)) {
val &= ~VIDEO_FORMAT_AV1_MAIN10;
}
SDL_assert((serverCodecModes & SCM_MASK_AV1 & ~(SCM_AV1_MAIN8 | SCM_AV1_MAIN10)) == 0);
return val;
} }
}; };

View file

@ -917,9 +917,16 @@ int PlVkRenderer::getRendererAttributes()
return RENDERER_ATTRIBUTE_HDR_SUPPORT; return RENDERER_ATTRIBUTE_HDR_SUPPORT;
} }
int PlVkRenderer::getDecoderColorspace()
{
// We rely on libplacebo for color conversion, pick colorspace with the same primaries as sRGB
return COLORSPACE_REC_709;
}
int PlVkRenderer::getDecoderColorRange() int PlVkRenderer::getDecoderColorRange()
{ {
// Explicitly set the color range to full to fix raised black levels on OLED displays // Explicitly set the color range to full to fix raised black levels on OLED displays,
// should also reduce banding artifacts in all situations
return COLOR_RANGE_FULL; return COLOR_RANGE_FULL;
} }
@ -948,6 +955,15 @@ bool PlVkRenderer::isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFo
// Vulkan frames are always supported // Vulkan frames are always supported
return true; return true;
} }
else if (videoFormat & VIDEO_FORMAT_MASK_YUV444) {
if (videoFormat & VIDEO_FORMAT_MASK_10BIT) {
return pixelFormat == AV_PIX_FMT_YUV444P10;
}
else {
return pixelFormat == AV_PIX_FMT_YUV444P ||
pixelFormat == AV_PIX_FMT_YUVJ444P;
}
}
else if (videoFormat & VIDEO_FORMAT_MASK_10BIT) { else if (videoFormat & VIDEO_FORMAT_MASK_10BIT) {
switch (pixelFormat) { switch (pixelFormat) {
case AV_PIX_FMT_P010: case AV_PIX_FMT_P010:

View file

@ -23,6 +23,7 @@ public:
virtual void notifyOverlayUpdated(Overlay::OverlayType) override; virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) override; virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO) override;
virtual int getRendererAttributes() override; virtual int getRendererAttributes() override;
virtual int getDecoderColorspace() override;
virtual int getDecoderColorRange() override; virtual int getDecoderColorRange() override;
virtual int getDecoderCapabilities() override; virtual int getDecoderCapabilities() override;
virtual bool needsTestFrame() override; virtual bool needsTestFrame() override;

View file

@ -537,6 +537,26 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP
m_Pkt->data = (uint8_t*)k_AV1Main10TestFrame; m_Pkt->data = (uint8_t*)k_AV1Main10TestFrame;
m_Pkt->size = sizeof(k_AV1Main10TestFrame); m_Pkt->size = sizeof(k_AV1Main10TestFrame);
break; break;
case VIDEO_FORMAT_H264_HIGH8_444:
m_Pkt->data = (uint8_t*)k_h264High_444TestFrame;
m_Pkt->size = sizeof(k_h264High_444TestFrame);
break;
case VIDEO_FORMAT_H265_REXT8_444:
m_Pkt->data = (uint8_t*)k_HEVCRExt8_444TestFrame;
m_Pkt->size = sizeof(k_HEVCRExt8_444TestFrame);
break;
case VIDEO_FORMAT_H265_REXT10_444:
m_Pkt->data = (uint8_t*)k_HEVCRExt10_444TestFrame;
m_Pkt->size = sizeof(k_HEVCRExt10_444TestFrame);
break;
case VIDEO_FORMAT_AV1_HIGH8_444:
m_Pkt->data = (uint8_t*)k_AV1High8_444TestFrame;
m_Pkt->size = sizeof(k_AV1High8_444TestFrame);
break;
case VIDEO_FORMAT_AV1_HIGH10_444:
m_Pkt->data = (uint8_t*)k_AV1High10_444TestFrame;
m_Pkt->size = sizeof(k_AV1High10_444TestFrame);
break;
default: default:
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"No test frame for format: %x", "No test frame for format: %x",
@ -692,16 +712,33 @@ void FFmpegVideoDecoder::stringifyVideoStats(VIDEO_STATS& stats, char* output, i
codecString = "H.264"; codecString = "H.264";
break; break;
case VIDEO_FORMAT_H264_HIGH8_444:
codecString = "H.264 4:4:4";
break;
case VIDEO_FORMAT_H265: case VIDEO_FORMAT_H265:
codecString = "HEVC"; codecString = "HEVC";
break; break;
case VIDEO_FORMAT_H265_REXT8_444:
codecString = "HEVC 4:4:4";
break;
case VIDEO_FORMAT_H265_MAIN10: case VIDEO_FORMAT_H265_MAIN10:
if (LiGetCurrentHostDisplayHdrMode()) { if (LiGetCurrentHostDisplayHdrMode()) {
codecString = "HEVC Main 10 HDR"; codecString = "HEVC 10-bit HDR";
} }
else { else {
codecString = "HEVC Main 10 SDR"; codecString = "HEVC 10-bit SDR";
}
break;
case VIDEO_FORMAT_H265_REXT10_444:
if (LiGetCurrentHostDisplayHdrMode()) {
codecString = "HEVC 10-bit HDR 4:4:4";
}
else {
codecString = "HEVC 10-bit SDR 4:4:4";
} }
break; break;
@ -709,6 +746,10 @@ void FFmpegVideoDecoder::stringifyVideoStats(VIDEO_STATS& stats, char* output, i
codecString = "AV1"; codecString = "AV1";
break; break;
case VIDEO_FORMAT_AV1_HIGH8_444:
codecString = "AV1 4:4:4";
break;
case VIDEO_FORMAT_AV1_MAIN10: case VIDEO_FORMAT_AV1_MAIN10:
if (LiGetCurrentHostDisplayHdrMode()) { if (LiGetCurrentHostDisplayHdrMode()) {
codecString = "AV1 10-bit HDR"; codecString = "AV1 10-bit HDR";
@ -718,6 +759,15 @@ void FFmpegVideoDecoder::stringifyVideoStats(VIDEO_STATS& stats, char* output, i
} }
break; break;
case VIDEO_FORMAT_AV1_HIGH10_444:
if (LiGetCurrentHostDisplayHdrMode()) {
codecString = "AV1 10-bit HDR 4:4:4";
}
else {
codecString = "AV1 10-bit SDR 4:4:4";
}
break;
default: default:
SDL_assert(false); SDL_assert(false);
codecString = "UNKNOWN"; codecString = "UNKNOWN";
@ -1254,6 +1304,12 @@ bool FFmpegVideoDecoder::tryInitializeHwAccelDecoder(PDECODER_PARAMETERS params,
break; break;
} }
// TODO: reexamine this
if ((params->videoFormat & VIDEO_FORMAT_MASK_YUV444) && config->device_type != AV_HWDEVICE_TYPE_VULKAN) {
// We only support YUV 4:4:4 decoding on Vulkan through libplacebo
continue;
}
// Initialize the hardware codec and submit a test frame if the renderer needs it // Initialize the hardware codec and submit a test frame if the renderer needs it
IFFmpegRenderer::InitFailureReason failureReason; IFFmpegRenderer::InitFailureReason failureReason;
if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, config, &failureReason, if (tryInitializeRenderer(decoder, AV_PIX_FMT_NONE, params, config, &failureReason,

View file

@ -119,4 +119,10 @@ private:
static const uint8_t k_HEVCMain10TestFrame[]; static const uint8_t k_HEVCMain10TestFrame[];
static const uint8_t k_AV1Main8TestFrame[]; static const uint8_t k_AV1Main8TestFrame[];
static const uint8_t k_AV1Main10TestFrame[]; static const uint8_t k_AV1Main10TestFrame[];
static const uint8_t k_h264High_444TestFrame[];
static const uint8_t k_HEVCRExt8_444TestFrame[];
static const uint8_t k_HEVCRExt10_444TestFrame[];
static const uint8_t k_AV1High8_444TestFrame[];
static const uint8_t k_AV1High10_444TestFrame[];
}; };

View file

@ -41,3 +41,130 @@ const uint8_t FFmpegVideoDecoder::k_AV1Main8TestFrame[] = {
const uint8_t FFmpegVideoDecoder::k_AV1Main10TestFrame[] = { const uint8_t FFmpegVideoDecoder::k_AV1Main10TestFrame[] = {
0x12, 0x00, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x43, 0xFC, 0x13, 0xFC, 0x0B, 0x3C, 0x02, 0x4E, 0xA8, 0x30, 0x30, 0x30, 0xA0, 0x32, 0x8B, 0x81, 0x80, 0x00, 0x10, 0x00, 0x4B, 0x00, 0x10, 0xC2, 0xFB, 0xE1, 0x52, 0x49, 0xFF, 0xE0, 0x00, 0x28, 0xB8, 0xB4, 0x5D, 0x8F, 0xF0, 0x01, 0x33, 0xAC, 0x5D, 0xD3, 0xCB, 0xF0, 0xFB, 0x2F, 0x59, 0xE9, 0xBF, 0x5B, 0x6E, 0x2C, 0x7A, 0x2B, 0xD1, 0xC5, 0x45, 0x24, 0x93, 0xC7, 0x92, 0x89, 0x89, 0x4E, 0x6F, 0x04, 0x58, 0x09, 0xD1, 0x70, 0x67, 0xE9, 0xB6, 0x09, 0x1A, 0x35, 0xB6, 0x37, 0x4E, 0x7D, 0x61, 0xC3, 0xF5, 0xBD, 0x48, 0xA4, 0x23, 0x60, 0x59, 0xA2, 0xA0, 0x21, 0xDA, 0x20, 0x92, 0xDB, 0xB9, 0x31, 0x43, 0xFB, 0x85, 0xD9, 0x3B, 0x4F, 0xF3, 0x96, 0x05, 0x0A, 0x98, 0x6E, 0xCE, 0xC5, 0x3F, 0xCD, 0x18, 0x6D, 0x2C, 0x17, 0x49, 0x68, 0xC3, 0x4A, 0xC0, 0xF5, 0x58, 0x0C, 0xA4, 0xDE, 0xF6, 0x4A, 0x11, 0x24, 0xC2, 0xE0, 0x24, 0xB7, 0x00, 0xCB, 0x71, 0x96, 0xDA, 0x35, 0xFD, 0xBA, 0x3F, 0xD9, 0xB7, 0x58, 0xF2, 0x28, 0x14, 0x2D, 0xB0, 0xE9, 0xE3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x12, 0x00, 0x0A, 0x10, 0x00, 0x00, 0x00, 0x43, 0xFC, 0x13, 0xFC, 0x0B, 0x3C, 0x02, 0x4E, 0xA8, 0x30, 0x30, 0x30, 0xA0, 0x32, 0x8B, 0x81, 0x80, 0x00, 0x10, 0x00, 0x4B, 0x00, 0x10, 0xC2, 0xFB, 0xE1, 0x52, 0x49, 0xFF, 0xE0, 0x00, 0x28, 0xB8, 0xB4, 0x5D, 0x8F, 0xF0, 0x01, 0x33, 0xAC, 0x5D, 0xD3, 0xCB, 0xF0, 0xFB, 0x2F, 0x59, 0xE9, 0xBF, 0x5B, 0x6E, 0x2C, 0x7A, 0x2B, 0xD1, 0xC5, 0x45, 0x24, 0x93, 0xC7, 0x92, 0x89, 0x89, 0x4E, 0x6F, 0x04, 0x58, 0x09, 0xD1, 0x70, 0x67, 0xE9, 0xB6, 0x09, 0x1A, 0x35, 0xB6, 0x37, 0x4E, 0x7D, 0x61, 0xC3, 0xF5, 0xBD, 0x48, 0xA4, 0x23, 0x60, 0x59, 0xA2, 0xA0, 0x21, 0xDA, 0x20, 0x92, 0xDB, 0xB9, 0x31, 0x43, 0xFB, 0x85, 0xD9, 0x3B, 0x4F, 0xF3, 0x96, 0x05, 0x0A, 0x98, 0x6E, 0xCE, 0xC5, 0x3F, 0xCD, 0x18, 0x6D, 0x2C, 0x17, 0x49, 0x68, 0xC3, 0x4A, 0xC0, 0xF5, 0x58, 0x0C, 0xA4, 0xDE, 0xF6, 0x4A, 0x11, 0x24, 0xC2, 0xE0, 0x24, 0xB7, 0x00, 0xCB, 0x71, 0x96, 0xDA, 0x35, 0xFD, 0xBA, 0x3F, 0xD9, 0xB7, 0x58, 0xF2, 0x28, 0x14, 0x2D, 0xB0, 0xE9, 0xE3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
// 720p H.264 High 4:4:4
// ffmpeg -i green128.png -pix_fmt yuv444p -colorspace smpte170m -color_trc smpte170m -color_primaries smpte170m -c:v libx264 -bsf:v filter_units=remove_types=6 test8_444.h264
// xxd -i test8_444.h264
const uint8_t FFmpegVideoDecoder::k_h264High_444TestFrame[] = {
0x00, 0x00, 0x00, 0x01, 0x67, 0xf4, 0x00, 0x1f, 0x91, 0x9b, 0x28, 0x0a,
0x00, 0xb7, 0x60, 0x2d, 0x41, 0x81, 0x81, 0x90, 0x00, 0x00, 0x03, 0x00,
0x10, 0x00, 0x00, 0x03, 0x03, 0x20, 0xf1, 0x83, 0x19, 0x60, 0x00, 0x00,
0x00, 0x01, 0x68, 0xeb, 0xe3, 0xc4, 0x48, 0x44, 0x00, 0x00, 0x01, 0x65,
0x88, 0x84, 0x00, 0x2b, 0xff, 0xfe, 0xf5, 0xdb, 0xf3, 0x2c, 0x93, 0x97,
0x37, 0xc0, 0xa5, 0x7d, 0x51, 0xf0, 0x29, 0x74, 0xec, 0x3f, 0xff, 0x07,
0xb6, 0x53, 0xd1, 0x9d, 0x16, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x59, 0x20, 0x00, 0x00, 0x03, 0x00, 0x69, 0xa0, 0x00,
0x09, 0x84, 0x00, 0x01, 0x59, 0x80, 0x00, 0x44, 0xe0, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x0b, 0x29,
};
// 720p HEVC RExt8 4:4:4
// ffmpeg -i green128.png -pix_fmt yuv444p -colorspace smpte170m -color_trc smpte170m -color_primaries smpte170m -c:v libx265 -x265-params info=0 test8_444.hevc
// xxd -i test8_444.hevc
const uint8_t FFmpegVideoDecoder::k_HEVCRExt8_444TestFrame[] = {
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x04, 0x08,
0x00, 0x00, 0x03, 0x00, 0x9e, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x5d,
0x95, 0x98, 0x09, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x04, 0x08,
0x00, 0x00, 0x03, 0x00, 0x9e, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x5d,
0x90, 0x00, 0x50, 0x10, 0x05, 0xa2, 0xcb, 0x2b, 0x34, 0x92, 0x65, 0x78,
0x0b, 0x50, 0x60, 0x60, 0x60, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00,
0x00, 0x06, 0x42, 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc1, 0x72, 0x86,
0x0c, 0x46, 0x24, 0x00, 0x00, 0x01, 0x28, 0x01, 0xaf, 0x1d, 0x18, 0x69,
0x57, 0x59, 0x55, 0x54, 0x51, 0x34, 0xd2, 0x4a, 0xf7, 0xcf, 0x80, 0xff,
0xf1, 0xcc, 0x1f, 0xc9, 0x84, 0x7d, 0xf8, 0xb6, 0xba, 0xfa, 0xcd, 0x61,
0xb5, 0xe3, 0xc1, 0x02, 0x19, 0x26, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x04, 0xf4, 0xa8, 0x17,
0x96, 0x03, 0x4c, 0x4e, 0x1a, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0xf8, 0x93, 0x0b,
0x93, 0x40, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x48, 0xc0, 0x87, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0xb5, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x0b, 0xd8, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x51, 0xc0, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x01, 0x39, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x02, 0xca, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x74, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x07, 0x6c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x27, 0xa0,
};
// 720p HEVC RExt10 4:4:4
// ffmpeg -i green128.png -pix_fmt yuv444p10 -colorspace bt2020nc -color_trc smpte2084 -color_primaries bt2020 -c:v libx265 -x265-params info=0 test10_444.hevc
// xxd -i test10_444.hevc
const uint8_t FFmpegVideoDecoder::k_HEVCRExt10_444TestFrame[] = {
0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x04, 0x08,
0x00, 0x00, 0x03, 0x00, 0x9c, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x5d,
0x95, 0x98, 0x09, 0x00, 0x00, 0x00, 0x01, 0x42, 0x01, 0x01, 0x04, 0x08,
0x00, 0x00, 0x03, 0x00, 0x9c, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x5d,
0x90, 0x00, 0x50, 0x10, 0x05, 0xa2, 0x6c, 0xb2, 0xb3, 0x49, 0x26, 0x57,
0x80, 0xb5, 0x09, 0x10, 0x09, 0x04, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
0x00, 0x03, 0x00, 0x64, 0x20, 0x00, 0x00, 0x00, 0x01, 0x44, 0x01, 0xc1,
0x72, 0x86, 0x0c, 0x46, 0x24, 0x00, 0x00, 0x01, 0x28, 0x01, 0xaf, 0x1d,
0x18, 0x69, 0x57, 0x59, 0x55, 0x54, 0x51, 0x34, 0xd2, 0x4a, 0xf7, 0xcf,
0x80, 0xff, 0xf1, 0xef, 0x9f, 0xc9, 0x84, 0x7d, 0xf8, 0xb6, 0xba, 0xfa,
0xcd, 0x61, 0xb5, 0xe3, 0xc1, 0x02, 0x19, 0x26, 0x30, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x04, 0xf4,
0xa8, 0x17, 0x96, 0x03, 0x4c, 0x4e, 0x1a, 0x80, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0xf8,
0x93, 0x0b, 0x93, 0x40, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x48, 0xc0, 0x87,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x01, 0xa3, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0xb5, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x0b, 0xd8, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x51,
0xc0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x01, 0x39, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x02, 0xca, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x74,
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x6c, 0x00, 0x00, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
0x27, 0xa0,
};
// 720p AV1 High8 4:4:4
// ffmpeg -i green128.png -pix_fmt yuv444p -colorspace smpte170m -color_trc smpte170m -color_primaries smpte170m -c:v libaom-av1 test8_444.obu
// xxd -i test8_444.obu
const uint8_t FFmpegVideoDecoder::k_AV1High8_444TestFrame[] = {
0x12, 0x00, 0x0a, 0x0e, 0x20, 0x00, 0x00, 0x2d, 0x4c, 0xff, 0xb3, 0xdf,
0xff, 0x9a, 0x0c, 0x0c, 0x0c, 0x20, 0x32, 0x25, 0x10, 0x00, 0x90, 0x00,
0x00, 0x00, 0xa0, 0x00, 0x00, 0x80, 0x0c, 0x80, 0xad, 0xfd, 0xdb, 0x2e,
0x81, 0x37, 0x40, 0xfd, 0x19, 0x97, 0xdc, 0x15, 0x72, 0x1d, 0xe0, 0xff,
0x00, 0x35, 0x9d, 0x2c, 0x10, 0x7d, 0x17, 0x58, 0x60,
};
// 720p AV1 High10 4:4:4
// ffmpeg -i green128.png -pix_fmt yuv444p10 -colorspace bt2020nc -color_trc smpte2084 -color_primaries bt2020 -c:v libaom-av1 test10_444.obu
// xxd -i test10_444.obu
const uint8_t FFmpegVideoDecoder::k_AV1High10_444TestFrame[] = {
0x12, 0x00, 0x0a, 0x0e, 0x20, 0x00, 0x00, 0x2d, 0x4c, 0xff, 0xb3, 0xdf,
0xff, 0x9e, 0x12, 0x20, 0x12, 0x20, 0x32, 0x25, 0x10, 0x00, 0x90, 0x00,
0x00, 0x00, 0xa0, 0x00, 0x00, 0x80, 0x0c, 0x80, 0xad, 0xfe, 0x04, 0x70,
0x81, 0x37, 0x40, 0xfd, 0x19, 0x97, 0xdc, 0x15, 0x72, 0x1d, 0xe0, 0xff,
0x00, 0x35, 0x9d, 0x2c, 0x10, 0x7d, 0x17, 0x58, 0x60,
};

@ -1 +1 @@
Subproject commit c245fe599d932943a50125b903ee325aac2d0d8a Subproject commit 8599b6042a4ba27749b0f94134dd614b4328a9bc