VDPAU improvements.

Add denoise, sharpness, skip chroma deinterlace support.
Show OSD only if something is to display, improves performance.
Add deinterlace mode with only 4 surfaces.
This commit is contained in:
Johns 2012-01-05 17:20:44 +01:00
parent aba14813c0
commit 0776bc5ee4
6 changed files with 385 additions and 117 deletions

View File

@ -1,5 +1,12 @@
User johns User johns
Date: Data:
VDPAU: Add denoise and sharpness support.
VDPAU: Add skip chroma deinterlace support.
VDPAU: Show OSD only if something is to display, improves performance.
VDPAU: Add deinterlace with only 4 surfaces.
Date: Thu Jan 4 17:00:00 CET 2012
Release Version 0.1.5 Release Version 0.1.5
Adds OSS mixer support. Adds OSS mixer support.

View File

@ -92,12 +92,22 @@ Setup: /etc/vdr/setup.conf
------ ------
Following is supported: Following is supported:
softhddevice.MakePrimary = 1
0 = no change, 1 make softhddevice primary at start
softhddevice.Deinterlace = 0 softhddevice.Deinterlace = 0
0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software 0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software
(only 0, 1 supported with vaapi) (only 0, 1 supported with vaapi)
softhddevice.MakePrimary = 1 softhddevice.SkipChromaDeinterlace = 0
0 = no change, 1 make softhddevice primary at start 0 = disabled, 1 = enabled (for slower cards, poor qualität)
softhddevice.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max)
softhddevice.Sharpness = 0
-1000 .. 1000 noise reduction level (0 off, -1000 max blur,
1000 max sharp)
softhddevice.Scaling = 0 softhddevice.Scaling = 0
0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic 0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic

8
Todo
View File

@ -30,11 +30,18 @@ missing:
HDMI/SPDIF Passthrough HDMI/SPDIF Passthrough
disable screensaver disable screensaver
disable window cursor disable window cursor
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
vdpau: vdpau:
1080i with temporal spatial and level 1 scaling too slow with GT 520 1080i with temporal spatial and level 1 scaling too slow with GT 520
1080i with temporal spatial too slow with GT 520 on some channels 1080i with temporal spatial too slow with GT 520 on some channels
SkipChromaDeinterlace improves performance
Improve OSD handling, show only what is used. Big OSD costs performance
VdpPreemptionCallback handling VdpPreemptionCallback handling
hard channel switch
libva:
hard channel switch
libva-intel-driver: libva-intel-driver:
intel still has hangups most with 1080i intel still has hangups most with 1080i
@ -73,6 +80,7 @@ audio/oss:
playback of recording playback of recording
play back is too fast play back is too fast
pause is not reset, when replay exit
setup: setup:
Setup of decoder type. Setup of decoder type.

View File

@ -51,6 +51,9 @@ static class cSoftHdDevice *MyDevice;
static char ConfigMakePrimary; ///< config primary wanted static char ConfigMakePrimary; ///< config primary wanted
static char ConfigVideoDeinterlace; ///< config deinterlace static char ConfigVideoDeinterlace; ///< config deinterlace
static char ConfigVideoSkipChromaDeinterlace; ///< config skip chroma
static int ConfigVideoDenoise; ///< config denoise
static int ConfigVideoSharpen; ///< config sharpen
static char ConfigVideoScaling; ///< config scaling static char ConfigVideoScaling; ///< config scaling
static int ConfigVideoAudioDelay; ///< config audio delay static int ConfigVideoAudioDelay; ///< config audio delay
static char DoMakePrimary; ///< flag switch primary static char DoMakePrimary; ///< flag switch primary
@ -262,6 +265,9 @@ class cMenuSetupSoft:public cMenuSetupPage
protected: protected:
int MakePrimary; int MakePrimary;
int Deinterlace; int Deinterlace;
int SkipChromaDeinterlace;
int Denoise;
int Sharpen;
int Scaling; int Scaling;
int AudioDelay; int AudioDelay;
protected: protected:
@ -275,10 +281,12 @@ class cMenuSetupSoft:public cMenuSetupPage
*/ */
cMenuSetupSoft::cMenuSetupSoft(void) cMenuSetupSoft::cMenuSetupSoft(void)
{ {
static const char * const deinterlace[] = { static const char *const deinterlace[] = {
"Bob", "Weave", "Temporal", "TemporalSpatial", "Software" }; "Bob", "Weave", "Temporal", "TemporalSpatial", "Software"
static const char * const scaling[] = { };
"Normal", "Fast", "HQ", "Anamorphic" }; static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic"
};
// cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem // cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem // cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
@ -286,11 +294,22 @@ cMenuSetupSoft::cMenuSetupSoft(void)
Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary, Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary,
tr("no"), tr("yes"))); tr("no"), tr("yes")));
Deinterlace = ConfigVideoDeinterlace; Deinterlace = ConfigVideoDeinterlace;
Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5, deinterlace)); Add(new cMenuEditStraItem(tr("Deinterlace"), &Deinterlace, 5,
deinterlace));
SkipChromaDeinterlace = ConfigVideoSkipChromaDeinterlace;
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace, tr("no"), tr("yes")));
Denoise = ConfigVideoDenoise;
Add(new cMenuEditIntItem(tr("Denoise (vdpau 0..1000)"), &Denoise, 0,
1000));
Sharpen = ConfigVideoSharpen;
Add(new cMenuEditIntItem(tr("Sharpen (vdpau -1000..1000)"), &Sharpen,
-1000, 1000));
Scaling = ConfigVideoScaling; Scaling = ConfigVideoScaling;
Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling)); Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling));
AudioDelay = ConfigVideoAudioDelay; AudioDelay = ConfigVideoAudioDelay;
Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000, 1000)); Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000,
1000));
} }
/** /**
@ -301,6 +320,13 @@ void cMenuSetupSoft::Store(void)
SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary); SetupStore("MakePrimary", ConfigMakePrimary = MakePrimary);
SetupStore("Deinterlace", ConfigVideoDeinterlace = Deinterlace); SetupStore("Deinterlace", ConfigVideoDeinterlace = Deinterlace);
VideoSetDeinterlace(ConfigVideoDeinterlace); VideoSetDeinterlace(ConfigVideoDeinterlace);
SetupStore("SkipChromaDeinterlace", ConfigVideoSkipChromaDeinterlace =
SkipChromaDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
SetupStore("Denoise", ConfigVideoDenoise = Denoise);
VideoSetDenoise(ConfigVideoDenoise);
SetupStore("Sharpen", ConfigVideoSharpen = Sharpen);
VideoSetSharpen(ConfigVideoSharpen);
SetupStore("Scaling", ConfigVideoScaling = Scaling); SetupStore("Scaling", ConfigVideoScaling = Scaling);
VideoSetScaling(ConfigVideoScaling); VideoSetScaling(ConfigVideoScaling);
SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay); SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay);
@ -436,7 +462,7 @@ int64_t cSoftHdDevice::GetSTC(void)
{ {
// dsyslog("[softhddev]%s:\n", __FUNCTION__); // dsyslog("[softhddev]%s:\n", __FUNCTION__);
return ::VideoGetClock(); return::VideoGetClock();
} }
void cSoftHdDevice::TrickSpeed(int Speed) void cSoftHdDevice::TrickSpeed(int Speed)
@ -496,7 +522,7 @@ bool cSoftHdDevice::Poll(
{ {
// dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms); // dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
return ::Poll(timeout_ms); return::Poll(timeout_ms);
} }
bool cSoftHdDevice::Flush(int timeout_ms) bool cSoftHdDevice::Flush(int timeout_ms)
@ -560,7 +586,7 @@ int cSoftHdDevice::PlayVideo(const uchar * data, int length)
{ {
//dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length); //dsyslog("[softhddev]%s: %p %d\n", __FUNCTION__, data, length);
return ::PlayVideo(data, length); return::PlayVideo(data, length);
} }
#if 0 #if 0
@ -583,7 +609,7 @@ int cSoftHdDevice::PlayTsAudio(const uchar * data, int length)
{ {
AudioPoller(); AudioPoller();
return cDevice::PlayTsAudio(data,length); return cDevice::PlayTsAudio(data, length);
} }
#endif #endif
@ -786,6 +812,19 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetDeinterlace(ConfigVideoDeinterlace = atoi(value)); VideoSetDeinterlace(ConfigVideoDeinterlace = atoi(value));
return true; return true;
} }
if (!strcmp(name, "SkipChromaDeinterlace")) {
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace =
atoi(value));
return true;
}
if (!strcmp(name, "Denoise")) {
VideoSetDenoise(ConfigVideoDenoise = atoi(value));
return true;
}
if (!strcmp(name, "Sharpen")) {
VideoSetSharpen(ConfigVideoSharpen = atoi(value));
return true;
}
if (!strcmp(name, "Scaling")) { if (!strcmp(name, "Scaling")) {
VideoSetScaling(ConfigVideoScaling = atoi(value)); VideoSetScaling(ConfigVideoScaling = atoi(value));
return true; return true;

337
video.c
View File

@ -1,7 +1,7 @@
/// ///
/// @file video.c @brief Video module /// @file video.c @brief Video module
/// ///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@ -37,6 +37,7 @@
/// ///
#define USE_XLIB_XCB #define USE_XLIB_XCB
#define noUSE_GRAB
#define noUSE_GLX #define noUSE_GLX
#define noUSE_DOUBLEBUFFER #define noUSE_DOUBLEBUFFER
@ -197,6 +198,20 @@ static unsigned VideoWindowHeight; ///< video output window height
/// Default deinterlace mode /// Default deinterlace mode
static VideoDeinterlaceModes VideoDeinterlace; static VideoDeinterlaceModes VideoDeinterlace;
/// Default number of deinterlace surfaces
static const int VideoDeinterlaceSurfaces = 4;
/// Default skip chroma deinterlace flag (VDPAU only)
static int VideoSkipChromaDeinterlace = 1;
/// Default amount of noise reduction algorithm to apply (0 .. 1000).
static int VideoDenoise;
/// Default amount of of sharpening, or blurring, to apply (-1000 .. 1000).
static int VideoSharpen;
// FIXME: color space
/// Default scaling mode /// Default scaling mode
static VideoScalingModes VideoScaling; static VideoScalingModes VideoScaling;
@ -3135,6 +3150,7 @@ static int VdpauTemporal; ///< temporal deinterlacer supported
static int VdpauTemporalSpatial; ///< temporal spatial deint. supported static int VdpauTemporalSpatial; ///< temporal spatial deint. supported
static int VdpauInverseTelecine; ///< inverse telecine deint. supported static int VdpauInverseTelecine; ///< inverse telecine deint. supported
static int VdpauNoiseReduction; ///< noise reduction supported static int VdpauNoiseReduction; ///< noise reduction supported
static int VdpauSharpness; ///< sharpness supported
static int VdpauSkipChroma; ///< skip chroma deint. supported static int VdpauSkipChroma; ///< skip chroma deint. supported
/// display surface ring buffer /// display surface ring buffer
@ -3143,6 +3159,7 @@ static int VdpauSurfaceIndex; ///< current display surface
static int VdpauOsdWidth; ///< width of osd surface static int VdpauOsdWidth; ///< width of osd surface
static int VdpauOsdHeight; ///< height of osd surface static int VdpauOsdHeight; ///< height of osd surface
static int VdpauShowOsd; ///< flag show osd
#ifdef USE_BITMAP #ifdef USE_BITMAP
/// bitmap surfaces for osd /// bitmap surfaces for osd
@ -3165,13 +3182,12 @@ static VdpGetErrorString *VdpauGetErrorString;
static VdpDeviceDestroy *VdpauDeviceDestroy; static VdpDeviceDestroy *VdpauDeviceDestroy;
static VdpGenerateCSCMatrix *VdpauGenerateCSCMatrix; static VdpGenerateCSCMatrix *VdpauGenerateCSCMatrix;
static VdpVideoSurfaceQueryCapabilities *VdpauVideoSurfaceQueryCapabilities; static VdpVideoSurfaceQueryCapabilities *VdpauVideoSurfaceQueryCapabilities;
static VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities static VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *
*VdpauVideoSurfaceQueryGetPutBitsYCbCrCapabilities; VdpauVideoSurfaceQueryGetPutBitsYCbCrCapabilities;
static VdpVideoSurfaceCreate *VdpauVideoSurfaceCreate; static VdpVideoSurfaceCreate *VdpauVideoSurfaceCreate;
static VdpVideoSurfaceDestroy *VdpauVideoSurfaceDestroy; static VdpVideoSurfaceDestroy *VdpauVideoSurfaceDestroy;
static VdpVideoSurfaceGetParameters *VdpauVideoSurfaceGetParameters; static VdpVideoSurfaceGetParameters *VdpauVideoSurfaceGetParameters;
static VdpVideoSurfaceGetBitsYCbCr *VdpauVideoSurfaceGetBitsYCbCr;
//static VdpVideoSurfaceGetBitsYCbCr * VdpauVideoSurfaceGetBitsYCbCr;
static VdpVideoSurfacePutBitsYCbCr *VdpauVideoSurfacePutBitsYCbCr; static VdpVideoSurfacePutBitsYCbCr *VdpauVideoSurfacePutBitsYCbCr;
static VdpOutputSurfaceCreate *VdpauOutputSurfaceCreate; static VdpOutputSurfaceCreate *VdpauOutputSurfaceCreate;
@ -3185,10 +3201,10 @@ static VdpBitmapSurfaceDestroy *VdpauBitmapSurfaceDestroy;
static VdpBitmapSurfacePutBitsNative *VdpauBitmapSurfacePutBitsNative; static VdpBitmapSurfacePutBitsNative *VdpauBitmapSurfacePutBitsNative;
static VdpOutputSurfaceRenderOutputSurface * static VdpOutputSurfaceRenderOutputSurface
VdpauOutputSurfaceRenderOutputSurface; *VdpauOutputSurfaceRenderOutputSurface;
static VdpOutputSurfaceRenderBitmapSurface * static VdpOutputSurfaceRenderBitmapSurface
VdpauOutputSurfaceRenderBitmapSurface; *VdpauOutputSurfaceRenderBitmapSurface;
static VdpDecoderQueryCapabilities *VdpauDecoderQueryCapabilities; static VdpDecoderQueryCapabilities *VdpauDecoderQueryCapabilities;
static VdpDecoderCreate *VdpauDecoderCreate; static VdpDecoderCreate *VdpauDecoderCreate;
@ -3197,6 +3213,9 @@ static VdpDecoderDestroy *VdpauDecoderDestroy;
static VdpDecoderRender *VdpauDecoderRender; static VdpDecoderRender *VdpauDecoderRender;
static VdpVideoMixerQueryFeatureSupport *VdpauVideoMixerQueryFeatureSupport; static VdpVideoMixerQueryFeatureSupport *VdpauVideoMixerQueryFeatureSupport;
static VdpVideoMixerQueryAttributeSupport
*VdpauVideoMixerQueryAttributeSupport;
static VdpVideoMixerCreate *VdpauVideoMixerCreate; static VdpVideoMixerCreate *VdpauVideoMixerCreate;
static VdpVideoMixerSetFeatureEnables *VdpauVideoMixerSetFeatureEnables; static VdpVideoMixerSetFeatureEnables *VdpauVideoMixerSetFeatureEnables;
static VdpVideoMixerSetAttributeValues *VdpauVideoMixerSetAttributeValues; static VdpVideoMixerSetAttributeValues *VdpauVideoMixerSetAttributeValues;
@ -3206,18 +3225,18 @@ static VdpVideoMixerRender *VdpauVideoMixerRender;
static VdpPresentationQueueTargetDestroy *VdpauPresentationQueueTargetDestroy; static VdpPresentationQueueTargetDestroy *VdpauPresentationQueueTargetDestroy;
static VdpPresentationQueueCreate *VdpauPresentationQueueCreate; static VdpPresentationQueueCreate *VdpauPresentationQueueCreate;
static VdpPresentationQueueDestroy *VdpauPresentationQueueDestroy; static VdpPresentationQueueDestroy *VdpauPresentationQueueDestroy;
static VdpPresentationQueueSetBackgroundColor static VdpPresentationQueueSetBackgroundColor *
*VdpauPresentationQueueSetBackgroundColor; VdpauPresentationQueueSetBackgroundColor;
static VdpPresentationQueueGetTime *VdpauPresentationQueueGetTime; static VdpPresentationQueueGetTime *VdpauPresentationQueueGetTime;
static VdpPresentationQueueDisplay *VdpauPresentationQueueDisplay; static VdpPresentationQueueDisplay *VdpauPresentationQueueDisplay;
static VdpPresentationQueueBlockUntilSurfaceIdle * static VdpPresentationQueueBlockUntilSurfaceIdle
VdpauPresentationQueueBlockUntilSurfaceIdle; *VdpauPresentationQueueBlockUntilSurfaceIdle;
static VdpPresentationQueueQuerySurfaceStatus * static VdpPresentationQueueQuerySurfaceStatus
VdpauPresentationQueueQuerySurfaceStatus; *VdpauPresentationQueueQuerySurfaceStatus;
static VdpPresentationQueueTargetCreateX11 static VdpPresentationQueueTargetCreateX11 *
*VdpauPresentationQueueTargetCreateX11; VdpauPresentationQueueTargetCreateX11;
///@} ///@}
/// ///
@ -3374,16 +3393,25 @@ static void VdpauPrintFrames(const VdpauDecoder * decoder)
/// ///
/// @param decoder VDPAU hw decoder /// @param decoder VDPAU hw decoder
/// ///
/// @note don't forget to update features, paramaters, attributes table
/// size, if more is add.
///
static void VdpauMixerSetup(VdpauDecoder * decoder) static void VdpauMixerSetup(VdpauDecoder * decoder)
{ {
VdpStatus status; VdpStatus status;
int i; int i;
VdpVideoMixerFeature features[14]; VdpVideoMixerFeature features[15];
VdpBool enables[14]; VdpBool enables[15];
int feature_n; int feature_n;
VdpVideoMixerParameter paramaters[10]; VdpVideoMixerParameter paramaters[4];
void const *values[10]; void const *value_ptrs[4];
int parameter_n; int parameter_n;
VdpVideoMixerAttribute attributes[3];
void const *attribute_value_ptrs[3];
int attribute_n;
uint8_t skip_chroma_value;
float noise_reduction_level;
float sharpness_level;
VdpChromaType chroma_type; VdpChromaType chroma_type;
int layers; int layers;
@ -3404,7 +3432,9 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
if (VdpauNoiseReduction) { if (VdpauNoiseReduction) {
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION;
} }
// VDP_VIDEO_MIXER_FEATURE_SHARPNESS if (VdpauSharpness) {
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS;
}
for (i = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1; for (i = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1;
i <= VdpauHqScalingMax; ++i) { i <= VdpauHqScalingMax; ++i) {
features[feature_n++] = i; features[feature_n++] = i;
@ -3417,19 +3447,19 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
// Setup parameter/value tables // Setup parameter/value tables
// //
paramaters[0] = VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH; paramaters[0] = VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH;
values[0] = &decoder->InputWidth; value_ptrs[0] = &decoder->InputWidth;
paramaters[1] = VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT; paramaters[1] = VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT;
values[1] = &decoder->InputHeight; value_ptrs[1] = &decoder->InputHeight;
paramaters[2] = VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE; paramaters[2] = VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE;
values[2] = &chroma_type; value_ptrs[2] = &chroma_type;
layers = 0; layers = 0;
paramaters[3] = VDP_VIDEO_MIXER_PARAMETER_LAYERS; paramaters[3] = VDP_VIDEO_MIXER_PARAMETER_LAYERS;
values[3] = &layers; value_ptrs[3] = &layers;
parameter_n = 4; parameter_n = 4;
status = status =
VdpauVideoMixerCreate(VdpauDevice, feature_n, features, parameter_n, VdpauVideoMixerCreate(VdpauDevice, feature_n, features, parameter_n,
paramaters, values, &decoder->VideoMixer); paramaters, value_ptrs, &decoder->VideoMixer);
if (status != VDP_STATUS_OK) { if (status != VDP_STATUS_OK) {
Fatal(_("video/vdpau: can't create video mixer: %s\n"), Fatal(_("video/vdpau: can't create video mixer: %s\n"),
VdpauGetErrorString(status)); VdpauGetErrorString(status));
@ -3441,8 +3471,8 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
feature_n = 0; feature_n = 0;
if (VdpauTemporal) { if (VdpauTemporal) {
enables[feature_n] = (VideoDeinterlace == VideoDeinterlaceTemporal enables[feature_n] = (VideoDeinterlace == VideoDeinterlaceTemporal
|| VideoDeinterlace == || (VideoDeinterlace == VideoDeinterlaceTemporalSpatial
VideoDeinterlaceTemporalSpatial) ? VDP_TRUE : VDP_FALSE; && !VdpauTemporalSpatial)) ? VDP_TRUE : VDP_FALSE;
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL;
Debug(3, "video/vdpau: temporal deinterlace %s\n", Debug(3, "video/vdpau: temporal deinterlace %s\n",
enables[feature_n - 1] ? "enabled" : "disabled"); enables[feature_n - 1] ? "enabled" : "disabled");
@ -3463,11 +3493,17 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
enables[feature_n - 1] ? "enabled" : "disabled"); enables[feature_n - 1] ? "enabled" : "disabled");
} }
if (VdpauNoiseReduction) { if (VdpauNoiseReduction) {
enables[feature_n] = VDP_FALSE; enables[feature_n] = VideoDenoise ? VDP_TRUE : VDP_FALSE;
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION;
Debug(3, "video/vdpau: noise reduction %s\n", Debug(3, "video/vdpau: noise reduction %s\n",
enables[feature_n - 1] ? "enabled" : "disabled"); enables[feature_n - 1] ? "enabled" : "disabled");
} }
if (VdpauSharpness) {
enables[feature_n] = VideoSharpen ? VDP_TRUE : VDP_FALSE;
features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS;
Debug(3, "video/vdpau: sharpness %s\n",
enables[feature_n - 1] ? "enabled" : "disabled");
}
for (i = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1; for (i = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1;
i <= VdpauHqScalingMax; ++i) { i <= VdpauHqScalingMax; ++i) {
enables[feature_n] = enables[feature_n] =
@ -3486,10 +3522,34 @@ static void VdpauMixerSetup(VdpauDecoder * decoder)
VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA
VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA
VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
VdpVideoMixerSetAttributeValues(decoder->Mixer, attribute_n,
attributes, values);
*/ */
attribute_n = 0;
if (VdpauSkipChroma) {
skip_chroma_value = VideoSkipChromaDeinterlace;
attributes[attribute_n]
= VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE;
attribute_value_ptrs[attribute_n++] = &skip_chroma_value;
Debug(3, "video/vdpau: skip chroma deinterlace %s\n",
skip_chroma_value ? "enabled" : "disabled");
}
if (VdpauNoiseReduction) {
noise_reduction_level = VideoDenoise / 1000.0;
attributes[attribute_n]
= VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL;
attribute_value_ptrs[attribute_n++] = &noise_reduction_level;
Debug(3, "video/vdpau: noise reduction level %1.3f\n",
noise_reduction_level);
}
if (VdpauSharpness) {
sharpness_level = VideoSharpen / 1000.0;
attributes[attribute_n]
= VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL;
attribute_value_ptrs[attribute_n++] = &sharpness_level;
Debug(3, "video/vdpau: sharpness level %+1.3f\n", sharpness_level);
}
VdpauVideoMixerSetAttributeValues(decoder->VideoMixer, attribute_n,
attributes, attribute_value_ptrs);
//VdpColorStandard color_standard; //VdpColorStandard color_standard;
//color_standard = VDP_COLOR_STANDARD_ITUR_BT_601; //color_standard = VDP_COLOR_STANDARD_ITUR_BT_601;
@ -3711,7 +3771,8 @@ static void VideoVdpauInit(const char *display_name)
"VideoSurfaceDestroy"); "VideoSurfaceDestroy");
VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS,
&VdpauVideoSurfaceGetParameters, "VideoSurfaceGetParameters"); &VdpauVideoSurfaceGetParameters, "VideoSurfaceGetParameters");
// VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, &VdpauVideoSurfaceGetBitsYCbCr, "VideoSurfaceGetBitsYCbCr"); VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR,
&VdpauVideoSurfaceGetBitsYCbCr, "VideoSurfaceGetBitsYCbCr");
VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR, VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR,
&VdpauVideoSurfacePutBitsYCbCr, "VideoSurfacePutBitsYCbCr"); &VdpauVideoSurfacePutBitsYCbCr, "VideoSurfacePutBitsYCbCr");
#if 0 #if 0
@ -3775,7 +3836,11 @@ static void VideoVdpauInit(const char *display_name)
&VdpauVideoMixerQueryFeatureSupport, "VideoMixerQueryFeatureSupport"); &VdpauVideoMixerQueryFeatureSupport, "VideoMixerQueryFeatureSupport");
#if 0 #if 0
VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT, &, ""); VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT, &, "");
VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT, &, ""); #endif
VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT,
&VdpauVideoMixerQueryAttributeSupport,
"VideoMixerQueryAttributeSupport");
#if 0
VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE, &, ""); VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE, &, "");
VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE, &, ""); VdpauGetProc(VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE, &, "");
#endif #endif
@ -3921,6 +3986,16 @@ static void VideoVdpauInit(const char *display_name)
status = status =
VdpauVideoMixerQueryFeatureSupport(VdpauDevice, VdpauVideoMixerQueryFeatureSupport(VdpauDevice,
VDP_VIDEO_MIXER_FEATURE_SHARPNESS, &flag);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't query feature '%s': %s\n"), "sharpness",
VdpauGetErrorString(status));
} else {
VdpauSharpness = flag;
}
status =
VdpauVideoMixerQueryAttributeSupport(VdpauDevice,
VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE, &flag); VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE, &flag);
if (status != VDP_STATUS_OK) { if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't query feature '%s': %s\n"), Error(_("video/vdpau: can't query feature '%s': %s\n"),
@ -3937,9 +4012,9 @@ static void VideoVdpauInit(const char *display_name)
Info(_("video/vdpau: feature deinterlace temporal %s\n"), Info(_("video/vdpau: feature deinterlace temporal %s\n"),
VdpauTemporal ? _("supported") : _("unsupported")); VdpauTemporal ? _("supported") : _("unsupported"));
Info(_("video/vdpau: feature deinterlace temporal spatial %s\n"), Info(_("video/vdpau: feature deinterlace temporal spatial %s\n"),
VdpauTemporal ? _("supported") : _("unsupported")); VdpauTemporalSpatial ? _("supported") : _("unsupported"));
Info(_("video/vdpau: attribute skip chroma deinterlace %s\n"), Info(_("video/vdpau: attribute skip chroma deinterlace %s\n"),
VdpauTemporal ? _("supported") : _("unsupported")); VdpauSkipChroma ? _("supported") : _("unsupported"));
// //
// video formats // video formats
@ -4337,6 +4412,69 @@ static void VdpauSetup(VdpauDecoder * decoder,
// //
} }
///
/// Grab video surface.
///
/// @param decoder VDPAU hw decoder
///
static void VdpauGrabSurface(VdpauDecoder * decoder)
{
VdpVideoSurface surface;
VdpStatus status;
VdpChromaType chroma_type;
uint32_t size;
uint32_t width;
uint32_t height;
void *base;
void *data[3];
uint32_t pitches[3];
VdpYCbCrFormat format;
// FIXME: test function to grab output surface content
// for screen shots, atom light and auto crop.
surface = decoder->SurfacesRb[(decoder->SurfaceRead + 1)
% VIDEO_SURFACES_MAX];
// get real surface size
status =
VdpauVideoSurfaceGetParameters(surface, &chroma_type, &width, &height);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't get video surface parameters: %s\n"),
VdpauGetErrorString(status));
return;
}
switch (chroma_type) {
case VDP_CHROMA_TYPE_420:
case VDP_CHROMA_TYPE_422:
case VDP_CHROMA_TYPE_444:
size = width * height + ((width + 1) / 2) * ((height + 1) / 2)
+ ((width + 1) / 2) * ((height + 1) / 2);
base = malloc(size);
if (!base) {
Error(_("video/vdpau: out of memory\n"));
return;
}
pitches[0] = width;
pitches[1] = width / 2;
pitches[2] = width / 2;
data[0] = base;
data[1] = base + width * height;
data[2] = base + width * height + width * height / 4;
format = VDP_YCBCR_FORMAT_YV12;
break;
}
status = VdpauVideoSurfaceGetBitsYCbCr(surface, format, data, pitches);
if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't get video surface bits: %s\n"),
VdpauGetErrorString(status));
return;
}
// 0x10 0x80 0x80 black
free(base);
}
/// ///
/// Queue output surface. /// Queue output surface.
/// ///
@ -4562,8 +4700,9 @@ static void VdpauMixOsd(void)
VdpRect source_rect; VdpRect source_rect;
VdpRect output_rect; VdpRect output_rect;
VdpStatus status; VdpStatus status;
uint32_t start;
uint32_t end; //uint32_t start;
//uint32_t end;
// //
// blend overlay over output // blend overlay over output
@ -4592,7 +4731,7 @@ static void VdpauMixOsd(void)
output_rect.x1 = VideoWindowWidth; output_rect.x1 = VideoWindowWidth;
output_rect.y1 = VideoWindowHeight; output_rect.y1 = VideoWindowHeight;
start = GetMsTicks(); //start = GetMsTicks();
VdpauOsdSurfaceIndex = 1; VdpauOsdSurfaceIndex = 1;
#ifdef USE_BITMAP #ifdef USE_BITMAP
@ -4616,7 +4755,7 @@ static void VdpauMixOsd(void)
VdpauGetErrorString(status)); VdpauGetErrorString(status));
} }
#endif #endif
end = GetMsTicks(); //end = GetMsTicks();
//Debug(3, "video:/vdpau: osd render %d ms\n", end - start); //Debug(3, "video:/vdpau: osd render %d ms\n", end - start);
@ -4651,19 +4790,30 @@ static void VdpauMixVideo(VdpauDecoder * decoder)
dst_video_rect.x1 = decoder->OutputX + decoder->OutputWidth; dst_video_rect.x1 = decoder->OutputX + decoder->OutputWidth;
dst_video_rect.y1 = decoder->OutputY + decoder->OutputHeight; dst_video_rect.y1 = decoder->OutputY + decoder->OutputHeight;
#ifdef USE_GRAB
VdpauGrabSurface(decoder);
#endif
if (decoder->Interlaced && VideoDeinterlace != VideoDeinterlaceWeave) { if (decoder->Interlaced && VideoDeinterlace != VideoDeinterlaceWeave) {
// //
// Build deinterlace structures // Build deinterlace structures
// //
VdpVideoMixerPictureStructure cps; VdpVideoMixerPictureStructure cps;
VdpVideoSurface past[2]; VdpVideoSurface past[3];
VdpVideoSurface future[2]; int past_n;
VdpVideoSurface future[3];
int future_n;
#ifdef DEBUG #ifdef DEBUG
if (atomic_read(&decoder->SurfacesFilled) < 3) { if (atomic_read(&decoder->SurfacesFilled) < 3) {
Debug(3, "only %d\n", atomic_read(&decoder->SurfacesFilled)); Debug(3, "only %d\n", atomic_read(&decoder->SurfacesFilled));
} }
#endif #endif
// FIXME: can use VDP_INVALID_HANDLE to support less surface on start
if (VideoDeinterlaceSurfaces == 5) {
past_n = 2;
future_n = 2;
// FIXME: wrong for bottom-field first // FIXME: wrong for bottom-field first
// read: past: B0 T0 current T1 future B1 T2 (0 1 2) // read: past: B0 T0 current T1 future B1 T2 (0 1 2)
@ -4692,15 +4842,47 @@ static void VdpauMixVideo(VdpauDecoder * decoder)
future[1] = future[0]; future[1] = future[0];
} }
} else if (VideoDeinterlaceSurfaces == 4) {
past_n = 2;
future_n = 1;
// FIXME: wrong for bottom-field first
// read: past: B0 T0 current T1 future B1 (0 1 2)
// read: past: T1 B0 current B1 future T2 (0 1 2)
if (decoder->TopFieldFirst != decoder->SurfaceField) {
cps = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
past[1] = decoder->SurfacesRb[decoder->SurfaceRead];
past[0] = past[1];
current = decoder->SurfacesRb[(decoder->SurfaceRead + 1)
% VIDEO_SURFACES_MAX];
future[0] = current;
} else {
cps = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
past[1] = decoder->SurfacesRb[decoder->SurfaceRead];
past[0] = decoder->SurfacesRb[(decoder->SurfaceRead + 1)
% VIDEO_SURFACES_MAX];
current = past[0];
future[0] = decoder->SurfacesRb[(decoder->SurfaceRead + 2)
% VIDEO_SURFACES_MAX];
}
} else {
Error(_("video/vdpau: %d surface deinterlace unsupported\n"),
VideoDeinterlaceSurfaces);
}
// FIXME: past_n, future_n here:
Debug(4, " %02d %02d(%c%02d) %02d %02d\n", past[1], past[0], Debug(4, " %02d %02d(%c%02d) %02d %02d\n", past[1], past[0],
cps == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD ? 'T' : 'B', cps == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD ? 'T' : 'B',
current, future[0], future[1]); current, future[0], future[1]);
status = status =
VdpauVideoMixerRender(decoder->VideoMixer, VDP_INVALID_HANDLE, VdpauVideoMixerRender(decoder->VideoMixer, VDP_INVALID_HANDLE,
NULL, cps, 2, past, current, 2, future, &video_src_rect, NULL, cps, past_n, past, current, future_n, future,
VdpauSurfacesRb[VdpauSurfaceIndex], &dst_rect, &dst_video_rect, 0, &video_src_rect, VdpauSurfacesRb[VdpauSurfaceIndex], &dst_rect,
NULL); &dst_video_rect, 0, NULL);
} else { } else {
current = decoder->SurfacesRb[decoder->SurfaceRead]; current = decoder->SurfacesRb[decoder->SurfaceRead];
@ -4804,32 +4986,25 @@ static void VdpauAdvanceFrame(void)
/// ///
static void VdpauDisplayFrame(void) static void VdpauDisplayFrame(void)
{ {
uint32_t now;
uint32_t end;
static uint32_t last_frame_tick;
VdpStatus status; VdpStatus status;
VdpTime first_time; VdpTime first_time;
static VdpTime last_time; static VdpTime last_time;
int i; int i;
now = GetMsTicks();
Debug(4, "video/vdpau: tick %d\n", now - last_frame_tick);
// //
// wait for surface visible (blocks max ~5ms) // wait for surface visible (blocks max ~5ms)
// //
status = status =
VdpauPresentationQueueBlockUntilSurfaceIdle(VdpauQueue, VdpauPresentationQueueBlockUntilSurfaceIdle(VdpauQueue,
VdpauSurfacesRb[VdpauSurfaceIndex], &first_time); VdpauSurfacesRb[VdpauSurfaceIndex], &first_time);
end = GetMsTicks();
if (status != VDP_STATUS_OK) { if (status != VDP_STATUS_OK) {
Error(_("video/vdpau: can't block queue: %s\n"), Error(_("video/vdpau: can't block queue: %s\n"),
VdpauGetErrorString(status)); VdpauGetErrorString(status));
} }
// check if surface was displayed for more than 1 frame // check if surface was displayed for more than 1 frame
if (last_time && first_time > last_time + 21 * 1000 * 1000) { if (last_time && first_time > last_time + 21 * 1000 * 1000) {
Debug(3, "video/vdpau: %ld display time %ld - %d ms\n", first_time, Debug(3, "video/vdpau: %ld display time %ld\n", first_time / 1000,
(first_time - last_time) / 1000, end - now); (first_time - last_time) / 1000);
// FIXME: can be more than 1 frame long shown // FIXME: can be more than 1 frame long shown
for (i = 0; i < VdpauDecoderN; ++i) { for (i = 0; i < VdpauDecoderN; ++i) {
VdpauDecoders[i]->FramesMissed++; VdpauDecoders[i]->FramesMissed++;
@ -4842,7 +5017,6 @@ static void VdpauDisplayFrame(void)
} }
} }
last_time = first_time; last_time = first_time;
last_frame_tick = now;
// //
// Render videos into output // Render videos into output
@ -4868,8 +5042,9 @@ static void VdpauDisplayFrame(void)
// //
// add osd to surface // add osd to surface
// //
if (VdpauShowOsd) { // showing costs performance
VdpauMixOsd(); VdpauMixOsd();
}
// //
// place surface in presentation queue // place surface in presentation queue
// //
@ -4906,17 +5081,6 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
VdpauAdvanceFrame(); VdpauAdvanceFrame();
} }
filled = atomic_read(&decoder->SurfacesFilled); filled = atomic_read(&decoder->SurfacesFilled);
#if 0
// debug duplicate frames (done by VdpauAdvanceFrame)
if (filled == 1) {
decoder->FramesDuped++;
Warning(_("video: display buffer empty, duping frame (%d/%d)\n"),
decoder->FramesDuped, decoder->FrameCounter);
if (!(decoder->FramesDisplayed % 300)) {
VdpauPrintFrames(decoder);
}
}
#endif
VdpauDisplayFrame(); VdpauDisplayFrame();
@ -4944,7 +5108,8 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
decoder->DropNextFrame = 1; decoder->DropNextFrame = 1;
} }
} }
#ifdef DEBUG
// debug audio/video sync
if (decoder->DupNextFrame || decoder->DropNextFrame if (decoder->DupNextFrame || decoder->DropNextFrame
|| !(decoder->FramesDisplayed % (50 * 10))) { || !(decoder->FramesDisplayed % (50 * 10))) {
static int64_t last_video_clock; static int64_t last_video_clock;
@ -4957,6 +5122,7 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
last_video_clock = video_clock; last_video_clock = video_clock;
} }
#endif
} }
/// ///
@ -4969,9 +5135,11 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder)
static void VdpauSyncRenderFrame(VdpauDecoder * decoder, static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
const AVCodecContext * video_ctx, const AVFrame * frame) const AVCodecContext * video_ctx, const AVFrame * frame)
{ {
#ifdef DEBUG
if (!atomic_read(&decoder->SurfacesFilled)) { if (!atomic_read(&decoder->SurfacesFilled)) {
Debug(3, "video: new stream frame %d\n", GetMsTicks() - VideoSwitch); Debug(3, "video: new stream frame %d\n", GetMsTicks() - VideoSwitch);
} }
#endif
if (decoder->DropNextFrame) { // drop frame requested if (decoder->DropNextFrame) { // drop frame requested
++decoder->FramesDropped; ++decoder->FramesDropped;
@ -5067,7 +5235,8 @@ static void VdpauDisplayHandlerThread(void)
clock_gettime(CLOCK_REALTIME, &nowtime); clock_gettime(CLOCK_REALTIME, &nowtime);
// time for one frame over? // time for one frame over?
if ((nowtime.tv_sec - decoder->FrameTime.tv_sec) if ( //filled<VIDEO_SURFACES_MAX &&
(nowtime.tv_sec - decoder->FrameTime.tv_sec)
* 1000 * 1000 * 1000 + (nowtime.tv_nsec - decoder->FrameTime.tv_nsec) < * 1000 * 1000 * 1000 + (nowtime.tv_nsec - decoder->FrameTime.tv_nsec) <
15 * 1000 * 1000) { 15 * 1000 * 1000) {
return; return;
@ -5138,6 +5307,7 @@ static void VdpauOsdClear(void)
#endif #endif
free(image); free(image);
VdpauShowOsd = 0;
} }
/// ///
@ -5196,6 +5366,7 @@ static void VdpauUploadImage(int x, int y, int width, int height,
VdpauGetErrorString(status)); VdpauGetErrorString(status));
} }
#endif #endif
VdpauShowOsd = 1;
} }
/// ///
@ -6191,6 +6362,30 @@ void VideoSetDeinterlace(int mode)
VideoDeinterlace = mode; VideoDeinterlace = mode;
} }
/**
** Set skip chroma deinterlace on/off.
*/
void VideoSetSkipChromaDeinterlace(int onoff)
{
VideoSkipChromaDeinterlace = onoff;
}
/**
** Set denoise level (0 .. 1000).
*/
void VideoSetDenoise(int level)
{
VideoDenoise = level;
}
/**
** Set sharpness level (-1000 .. 1000).
*/
void VideoSetSharpen(int level)
{
VideoSharpen = level;
}
/** /**
** Set scaling mode. ** Set scaling mode.
*/ */

11
video.h
View File

@ -1,7 +1,7 @@
/// ///
/// @file video.h @brief Video module header file /// @file video.h @brief Video module header file
/// ///
/// Copyright (c) 2009 - 2011 by Johns. All Rights Reserved. /// Copyright (c) 2009 - 2012 by Johns. All Rights Reserved.
/// ///
/// Contributor(s): /// Contributor(s):
/// ///
@ -83,9 +83,18 @@ extern int VideoSetGeometry(const char *);
/// set deinterlace /// set deinterlace
extern void VideoSetDeinterlace(int); extern void VideoSetDeinterlace(int);
/// set skip chroma deinterlace
extern void VideoSetSkipChromaDeinterlace(int);
/// set scaling /// set scaling
extern void VideoSetScaling(int); extern void VideoSetScaling(int);
/// set denoise
extern void VideoSetDenoise(int);
/// set sharpen
extern void VideoSetSharpen(int);
/// set audio delay /// set audio delay
extern void VideoSetAudioDelay(int); extern void VideoSetAudioDelay(int);