From 0776bc5ee472f5013e2507ecb088673e9152caee Mon Sep 17 00:00:00 2001 From: Johns Date: Thu, 5 Jan 2012 17:20:44 +0100 Subject: [PATCH] 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. --- ChangeLog | 9 +- README.txt | 14 +- Todo | 8 + softhddevice.cpp | 75 ++++++--- video.c | 385 +++++++++++++++++++++++++++++++++++------------ video.h | 11 +- 6 files changed, 385 insertions(+), 117 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2923fcb..523d0e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 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 Adds OSS mixer support. diff --git a/README.txt b/README.txt index 7c06269..f50bc17 100644 --- a/README.txt +++ b/README.txt @@ -92,12 +92,22 @@ Setup: /etc/vdr/setup.conf ------ Following is supported: + softhddevice.MakePrimary = 1 + 0 = no change, 1 make softhddevice primary at start + softhddevice.Deinterlace = 0 0 = bob, 1 = weave, 2 = temporal, 3 = temporal_spatial, 4 = software (only 0, 1 supported with vaapi) - softhddevice.MakePrimary = 1 - 0 = no change, 1 make softhddevice primary at start + softhddevice.SkipChromaDeinterlace = 0 + 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 0 = normal, 1 = fast, 2 = HQ, 3 = anamorphic diff --git a/Todo b/Todo index e6570b0..548f00d 100644 --- a/Todo +++ b/Todo @@ -30,11 +30,18 @@ missing: HDMI/SPDIF Passthrough disable screensaver disable window cursor + ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? vdpau: 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 + SkipChromaDeinterlace improves performance + Improve OSD handling, show only what is used. Big OSD costs performance VdpPreemptionCallback handling + hard channel switch + +libva: + hard channel switch libva-intel-driver: intel still has hangups most with 1080i @@ -73,6 +80,7 @@ audio/oss: playback of recording play back is too fast + pause is not reset, when replay exit setup: Setup of decoder type. diff --git a/softhddevice.cpp b/softhddevice.cpp index 97cb12a..a501409 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -49,11 +49,14 @@ static class cSoftHdDevice *MyDevice; ////////////////////////////////////////////////////////////////////////////// -static char ConfigMakePrimary; ///< config primary wanted -static char ConfigVideoDeinterlace; ///< config deinterlace -static char ConfigVideoScaling; ///< config scaling -static int ConfigVideoAudioDelay; ///< config audio delay -static char DoMakePrimary; ///< flag switch primary +static char ConfigMakePrimary; ///< config primary wanted +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 int ConfigVideoAudioDelay; ///< config audio delay +static char DoMakePrimary; ///< flag switch primary ////////////////////////////////////////////////////////////////////////////// @@ -226,7 +229,7 @@ class cSoftOsdProvider:public cOsdProvider cSoftOsdProvider(void); }; -cOsd *cSoftOsdProvider::Osd; ///< single osd +cOsd *cSoftOsdProvider::Osd; ///< single osd /** ** Create a new OSD. @@ -262,6 +265,9 @@ class cMenuSetupSoft:public cMenuSetupPage protected: int MakePrimary; int Deinterlace; + int SkipChromaDeinterlace; + int Denoise; + int Sharpen; int Scaling; int AudioDelay; protected: @@ -275,10 +281,12 @@ class cMenuSetupSoft:public cMenuSetupPage */ cMenuSetupSoft::cMenuSetupSoft(void) { - static const char * const deinterlace[] = { - "Bob", "Weave", "Temporal", "TemporalSpatial", "Software" }; - static const char * const scaling[] = { - "Normal", "Fast", "HQ", "Anamorphic" }; + static const char *const deinterlace[] = { + "Bob", "Weave", "Temporal", "TemporalSpatial", "Software" + }; + static const char *const scaling[] = { + "Normal", "Fast", "HQ", "Anamorphic" + }; // cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem // cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem @@ -286,11 +294,22 @@ cMenuSetupSoft::cMenuSetupSoft(void) Add(new cMenuEditBoolItem(tr("Make primary device"), &MakePrimary, tr("no"), tr("yes"))); 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; Add(new cMenuEditStraItem(tr("Scaling"), &Scaling, 4, scaling)); 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("Deinterlace", ConfigVideoDeinterlace = Deinterlace); VideoSetDeinterlace(ConfigVideoDeinterlace); + SetupStore("SkipChromaDeinterlace", ConfigVideoSkipChromaDeinterlace = + SkipChromaDeinterlace); + VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace); + SetupStore("Denoise", ConfigVideoDenoise = Denoise); + VideoSetDenoise(ConfigVideoDenoise); + SetupStore("Sharpen", ConfigVideoSharpen = Sharpen); + VideoSetSharpen(ConfigVideoSharpen); SetupStore("Scaling", ConfigVideoScaling = Scaling); VideoSetScaling(ConfigVideoScaling); SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay); @@ -333,7 +359,7 @@ class cSoftHdDevice:public cDevice virtual void GetOsdSize(int &, int &, double &); virtual int PlayVideo(const uchar *, int); //virtual int PlayTsVideo(const uchar *, int); -#ifdef USE_OSS // FIXME: testing only oss +#ifdef USE_OSS // FIXME: testing only oss virtual int PlayTsAudio(const uchar *, int); #endif virtual void SetAudioChannelDevice(int); @@ -436,7 +462,7 @@ int64_t cSoftHdDevice::GetSTC(void) { // dsyslog("[softhddev]%s:\n", __FUNCTION__); - return ::VideoGetClock(); + return::VideoGetClock(); } void cSoftHdDevice::TrickSpeed(int Speed) @@ -496,7 +522,7 @@ bool cSoftHdDevice::Poll( { // dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms); - return ::Poll(timeout_ms); + return::Poll(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); - return ::PlayVideo(data, length); + return::PlayVideo(data, length); } #if 0 @@ -573,7 +599,7 @@ int cSoftHdDevice::PlayTsVideo(const uchar * Data, int Length) } #endif -#ifdef USE_OSS // FIXME: testing only oss +#ifdef USE_OSS // FIXME: testing only oss /// /// Play a TS audio packet. /// @@ -583,7 +609,7 @@ int cSoftHdDevice::PlayTsAudio(const uchar * data, int length) { AudioPoller(); - return cDevice::PlayTsAudio(data,length); + return cDevice::PlayTsAudio(data, length); } #endif @@ -786,6 +812,19 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) VideoSetDeinterlace(ConfigVideoDeinterlace = atoi(value)); 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")) { VideoSetScaling(ConfigVideoScaling = atoi(value)); return true; diff --git a/video.c b/video.c index b6d031c..15336b4 100644 --- a/video.c +++ b/video.c @@ -1,7 +1,7 @@ /// /// @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): /// @@ -37,6 +37,7 @@ /// #define USE_XLIB_XCB +#define noUSE_GRAB #define noUSE_GLX #define noUSE_DOUBLEBUFFER @@ -197,6 +198,20 @@ static unsigned VideoWindowHeight; ///< video output window height /// Default deinterlace mode 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 static VideoScalingModes VideoScaling; @@ -3135,6 +3150,7 @@ static int VdpauTemporal; ///< temporal deinterlacer supported static int VdpauTemporalSpatial; ///< temporal spatial deint. supported static int VdpauInverseTelecine; ///< inverse telecine deint. supported static int VdpauNoiseReduction; ///< noise reduction supported +static int VdpauSharpness; ///< sharpness supported static int VdpauSkipChroma; ///< skip chroma deint. supported /// display surface ring buffer @@ -3143,6 +3159,7 @@ static int VdpauSurfaceIndex; ///< current display surface static int VdpauOsdWidth; ///< width of osd surface static int VdpauOsdHeight; ///< height of osd surface +static int VdpauShowOsd; ///< flag show osd #ifdef USE_BITMAP /// bitmap surfaces for osd @@ -3165,13 +3182,12 @@ static VdpGetErrorString *VdpauGetErrorString; static VdpDeviceDestroy *VdpauDeviceDestroy; static VdpGenerateCSCMatrix *VdpauGenerateCSCMatrix; static VdpVideoSurfaceQueryCapabilities *VdpauVideoSurfaceQueryCapabilities; -static VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities - *VdpauVideoSurfaceQueryGetPutBitsYCbCrCapabilities; +static VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities * + VdpauVideoSurfaceQueryGetPutBitsYCbCrCapabilities; static VdpVideoSurfaceCreate *VdpauVideoSurfaceCreate; static VdpVideoSurfaceDestroy *VdpauVideoSurfaceDestroy; static VdpVideoSurfaceGetParameters *VdpauVideoSurfaceGetParameters; - -//static VdpVideoSurfaceGetBitsYCbCr * VdpauVideoSurfaceGetBitsYCbCr; +static VdpVideoSurfaceGetBitsYCbCr *VdpauVideoSurfaceGetBitsYCbCr; static VdpVideoSurfacePutBitsYCbCr *VdpauVideoSurfacePutBitsYCbCr; static VdpOutputSurfaceCreate *VdpauOutputSurfaceCreate; @@ -3185,10 +3201,10 @@ static VdpBitmapSurfaceDestroy *VdpauBitmapSurfaceDestroy; static VdpBitmapSurfacePutBitsNative *VdpauBitmapSurfacePutBitsNative; -static VdpOutputSurfaceRenderOutputSurface * - VdpauOutputSurfaceRenderOutputSurface; -static VdpOutputSurfaceRenderBitmapSurface * - VdpauOutputSurfaceRenderBitmapSurface; +static VdpOutputSurfaceRenderOutputSurface + *VdpauOutputSurfaceRenderOutputSurface; +static VdpOutputSurfaceRenderBitmapSurface + *VdpauOutputSurfaceRenderBitmapSurface; static VdpDecoderQueryCapabilities *VdpauDecoderQueryCapabilities; static VdpDecoderCreate *VdpauDecoderCreate; @@ -3197,6 +3213,9 @@ static VdpDecoderDestroy *VdpauDecoderDestroy; static VdpDecoderRender *VdpauDecoderRender; static VdpVideoMixerQueryFeatureSupport *VdpauVideoMixerQueryFeatureSupport; +static VdpVideoMixerQueryAttributeSupport + *VdpauVideoMixerQueryAttributeSupport; + static VdpVideoMixerCreate *VdpauVideoMixerCreate; static VdpVideoMixerSetFeatureEnables *VdpauVideoMixerSetFeatureEnables; static VdpVideoMixerSetAttributeValues *VdpauVideoMixerSetAttributeValues; @@ -3206,18 +3225,18 @@ static VdpVideoMixerRender *VdpauVideoMixerRender; static VdpPresentationQueueTargetDestroy *VdpauPresentationQueueTargetDestroy; static VdpPresentationQueueCreate *VdpauPresentationQueueCreate; static VdpPresentationQueueDestroy *VdpauPresentationQueueDestroy; -static VdpPresentationQueueSetBackgroundColor - *VdpauPresentationQueueSetBackgroundColor; +static VdpPresentationQueueSetBackgroundColor * + VdpauPresentationQueueSetBackgroundColor; static VdpPresentationQueueGetTime *VdpauPresentationQueueGetTime; static VdpPresentationQueueDisplay *VdpauPresentationQueueDisplay; -static VdpPresentationQueueBlockUntilSurfaceIdle * - VdpauPresentationQueueBlockUntilSurfaceIdle; -static VdpPresentationQueueQuerySurfaceStatus * - VdpauPresentationQueueQuerySurfaceStatus; +static VdpPresentationQueueBlockUntilSurfaceIdle + *VdpauPresentationQueueBlockUntilSurfaceIdle; +static VdpPresentationQueueQuerySurfaceStatus + *VdpauPresentationQueueQuerySurfaceStatus; -static VdpPresentationQueueTargetCreateX11 - *VdpauPresentationQueueTargetCreateX11; +static VdpPresentationQueueTargetCreateX11 * + VdpauPresentationQueueTargetCreateX11; ///@} /// @@ -3374,16 +3393,25 @@ static void VdpauPrintFrames(const VdpauDecoder * 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) { VdpStatus status; int i; - VdpVideoMixerFeature features[14]; - VdpBool enables[14]; + VdpVideoMixerFeature features[15]; + VdpBool enables[15]; int feature_n; - VdpVideoMixerParameter paramaters[10]; - void const *values[10]; + VdpVideoMixerParameter paramaters[4]; + void const *value_ptrs[4]; 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; int layers; @@ -3404,7 +3432,9 @@ static void VdpauMixerSetup(VdpauDecoder * decoder) if (VdpauNoiseReduction) { 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; i <= VdpauHqScalingMax; ++i) { features[feature_n++] = i; @@ -3417,19 +3447,19 @@ static void VdpauMixerSetup(VdpauDecoder * decoder) // Setup parameter/value tables // 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; - values[1] = &decoder->InputHeight; + value_ptrs[1] = &decoder->InputHeight; paramaters[2] = VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE; - values[2] = &chroma_type; + value_ptrs[2] = &chroma_type; layers = 0; paramaters[3] = VDP_VIDEO_MIXER_PARAMETER_LAYERS; - values[3] = &layers; + value_ptrs[3] = &layers; parameter_n = 4; status = VdpauVideoMixerCreate(VdpauDevice, feature_n, features, parameter_n, - paramaters, values, &decoder->VideoMixer); + paramaters, value_ptrs, &decoder->VideoMixer); if (status != VDP_STATUS_OK) { Fatal(_("video/vdpau: can't create video mixer: %s\n"), VdpauGetErrorString(status)); @@ -3441,8 +3471,8 @@ static void VdpauMixerSetup(VdpauDecoder * decoder) feature_n = 0; if (VdpauTemporal) { enables[feature_n] = (VideoDeinterlace == VideoDeinterlaceTemporal - || VideoDeinterlace == - VideoDeinterlaceTemporalSpatial) ? VDP_TRUE : VDP_FALSE; + || (VideoDeinterlace == VideoDeinterlaceTemporalSpatial + && !VdpauTemporalSpatial)) ? VDP_TRUE : VDP_FALSE; features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; Debug(3, "video/vdpau: temporal deinterlace %s\n", enables[feature_n - 1] ? "enabled" : "disabled"); @@ -3463,11 +3493,17 @@ static void VdpauMixerSetup(VdpauDecoder * decoder) enables[feature_n - 1] ? "enabled" : "disabled"); } if (VdpauNoiseReduction) { - enables[feature_n] = VDP_FALSE; - features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; + enables[feature_n] = VideoDenoise ? VDP_TRUE : VDP_FALSE; + features[feature_n++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; Debug(3, "video/vdpau: noise reduction %s\n", 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; i <= VdpauHqScalingMax; ++i) { enables[feature_n] = @@ -3486,10 +3522,34 @@ static void VdpauMixerSetup(VdpauDecoder * decoder) VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_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; //color_standard = VDP_COLOR_STANDARD_ITUR_BT_601; @@ -3711,7 +3771,8 @@ static void VideoVdpauInit(const char *display_name) "VideoSurfaceDestroy"); VdpauGetProc(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS, &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, &VdpauVideoSurfacePutBitsYCbCr, "VideoSurfacePutBitsYCbCr"); #if 0 @@ -3775,7 +3836,11 @@ static void VideoVdpauInit(const char *display_name) &VdpauVideoMixerQueryFeatureSupport, "VideoMixerQueryFeatureSupport"); #if 0 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_ATTRIBUTE_VALUE_RANGE, &, ""); #endif @@ -3921,6 +3986,16 @@ static void VideoVdpauInit(const char *display_name) status = 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); if (status != VDP_STATUS_OK) { 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"), VdpauTemporal ? _("supported") : _("unsupported")); Info(_("video/vdpau: feature deinterlace temporal spatial %s\n"), - VdpauTemporal ? _("supported") : _("unsupported")); + VdpauTemporalSpatial ? _("supported") : _("unsupported")); Info(_("video/vdpau: attribute skip chroma deinterlace %s\n"), - VdpauTemporal ? _("supported") : _("unsupported")); + VdpauSkipChroma ? _("supported") : _("unsupported")); // // 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. /// @@ -4562,8 +4700,9 @@ static void VdpauMixOsd(void) VdpRect source_rect; VdpRect output_rect; VdpStatus status; - uint32_t start; - uint32_t end; + + //uint32_t start; + //uint32_t end; // // blend overlay over output @@ -4592,7 +4731,7 @@ static void VdpauMixOsd(void) output_rect.x1 = VideoWindowWidth; output_rect.y1 = VideoWindowHeight; - start = GetMsTicks(); + //start = GetMsTicks(); VdpauOsdSurfaceIndex = 1; #ifdef USE_BITMAP @@ -4616,7 +4755,7 @@ static void VdpauMixOsd(void) VdpauGetErrorString(status)); } #endif - end = GetMsTicks(); + //end = GetMsTicks(); //Debug(3, "video:/vdpau: osd render %d ms\n", end - start); @@ -4651,56 +4790,99 @@ static void VdpauMixVideo(VdpauDecoder * decoder) dst_video_rect.x1 = decoder->OutputX + decoder->OutputWidth; dst_video_rect.y1 = decoder->OutputY + decoder->OutputHeight; +#ifdef USE_GRAB + VdpauGrabSurface(decoder); +#endif + if (decoder->Interlaced && VideoDeinterlace != VideoDeinterlaceWeave) { // // Build deinterlace structures // VdpVideoMixerPictureStructure cps; - VdpVideoSurface past[2]; - VdpVideoSurface future[2]; + VdpVideoSurface past[3]; + int past_n; + VdpVideoSurface future[3]; + int future_n; #ifdef DEBUG if (atomic_read(&decoder->SurfacesFilled) < 3) { Debug(3, "only %d\n", atomic_read(&decoder->SurfacesFilled)); } #endif + // FIXME: can use VDP_INVALID_HANDLE to support less surface on start - // FIXME: wrong for bottom-field first - // read: past: B0 T0 current T1 future B1 T2 (0 1 2) - // read: past: T1 B0 current B1 future T2 B2 (0 1 2) - if (decoder->TopFieldFirst != decoder->SurfaceField) { - cps = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; + if (VideoDeinterlaceSurfaces == 5) { + past_n = 2; + future_n = 2; + + // FIXME: wrong for bottom-field first + // read: past: B0 T0 current T1 future B1 T2 (0 1 2) + // read: past: T1 B0 current B1 future T2 B2 (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; + future[1] = decoder->SurfacesRb[(decoder->SurfaceRead + 2) + % VIDEO_SURFACES_MAX]; + // FIXME: can support 1 future more + } else { + cps = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; + + // FIXME: can support 1 past more + 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]; + 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]; + } - past[1] = decoder->SurfacesRb[decoder->SurfaceRead]; - past[0] = past[1]; - current = decoder->SurfacesRb[(decoder->SurfaceRead + 1) - % VIDEO_SURFACES_MAX]; - future[0] = current; - future[1] = decoder->SurfacesRb[(decoder->SurfaceRead + 2) - % VIDEO_SURFACES_MAX]; - // FIXME: can support 1 future more } else { - cps = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; - - // FIXME: can support 1 past more - 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]; - future[1] = future[0]; + 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], cps == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD ? 'T' : 'B', current, future[0], future[1]); status = VdpauVideoMixerRender(decoder->VideoMixer, VDP_INVALID_HANDLE, - NULL, cps, 2, past, current, 2, future, &video_src_rect, - VdpauSurfacesRb[VdpauSurfaceIndex], &dst_rect, &dst_video_rect, 0, - NULL); + NULL, cps, past_n, past, current, future_n, future, + &video_src_rect, VdpauSurfacesRb[VdpauSurfaceIndex], &dst_rect, + &dst_video_rect, 0, NULL); } else { current = decoder->SurfacesRb[decoder->SurfaceRead]; @@ -4804,32 +4986,25 @@ static void VdpauAdvanceFrame(void) /// static void VdpauDisplayFrame(void) { - uint32_t now; - uint32_t end; - static uint32_t last_frame_tick; VdpStatus status; VdpTime first_time; static VdpTime last_time; int i; - now = GetMsTicks(); - Debug(4, "video/vdpau: tick %d\n", now - last_frame_tick); - // // wait for surface visible (blocks max ~5ms) // status = VdpauPresentationQueueBlockUntilSurfaceIdle(VdpauQueue, VdpauSurfacesRb[VdpauSurfaceIndex], &first_time); - end = GetMsTicks(); if (status != VDP_STATUS_OK) { Error(_("video/vdpau: can't block queue: %s\n"), VdpauGetErrorString(status)); } // check if surface was displayed for more than 1 frame if (last_time && first_time > last_time + 21 * 1000 * 1000) { - Debug(3, "video/vdpau: %ld display time %ld - %d ms\n", first_time, - (first_time - last_time) / 1000, end - now); + Debug(3, "video/vdpau: %ld display time %ld\n", first_time / 1000, + (first_time - last_time) / 1000); // FIXME: can be more than 1 frame long shown for (i = 0; i < VdpauDecoderN; ++i) { VdpauDecoders[i]->FramesMissed++; @@ -4842,7 +5017,6 @@ static void VdpauDisplayFrame(void) } } last_time = first_time; - last_frame_tick = now; // // Render videos into output @@ -4868,8 +5042,9 @@ static void VdpauDisplayFrame(void) // // add osd to surface // - VdpauMixOsd(); - + if (VdpauShowOsd) { // showing costs performance + VdpauMixOsd(); + } // // place surface in presentation queue // @@ -4906,17 +5081,6 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) VdpauAdvanceFrame(); } 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(); @@ -4944,7 +5108,8 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) decoder->DropNextFrame = 1; } } - +#ifdef DEBUG + // debug audio/video sync if (decoder->DupNextFrame || decoder->DropNextFrame || !(decoder->FramesDisplayed % (50 * 10))) { static int64_t last_video_clock; @@ -4957,6 +5122,7 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) last_video_clock = video_clock; } +#endif } /// @@ -4969,9 +5135,11 @@ static void VdpauSyncDisplayFrame(VdpauDecoder * decoder) static void VdpauSyncRenderFrame(VdpauDecoder * decoder, const AVCodecContext * video_ctx, const AVFrame * frame) { +#ifdef DEBUG if (!atomic_read(&decoder->SurfacesFilled)) { Debug(3, "video: new stream frame %d\n", GetMsTicks() - VideoSwitch); } +#endif if (decoder->DropNextFrame) { // drop frame requested ++decoder->FramesDropped; @@ -5067,7 +5235,8 @@ static void VdpauDisplayHandlerThread(void) clock_gettime(CLOCK_REALTIME, &nowtime); // time for one frame over? - if ((nowtime.tv_sec - decoder->FrameTime.tv_sec) + if ( //filledFrameTime.tv_sec) * 1000 * 1000 * 1000 + (nowtime.tv_nsec - decoder->FrameTime.tv_nsec) < 15 * 1000 * 1000) { return; @@ -5138,6 +5307,7 @@ static void VdpauOsdClear(void) #endif free(image); + VdpauShowOsd = 0; } /// @@ -5196,6 +5366,7 @@ static void VdpauUploadImage(int x, int y, int width, int height, VdpauGetErrorString(status)); } #endif + VdpauShowOsd = 1; } /// @@ -6191,6 +6362,30 @@ void VideoSetDeinterlace(int 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. */ diff --git a/video.h b/video.h index 5a03d4c..9962cf3 100644 --- a/video.h +++ b/video.h @@ -1,7 +1,7 @@ /// /// @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): /// @@ -83,9 +83,18 @@ extern int VideoSetGeometry(const char *); /// set deinterlace extern void VideoSetDeinterlace(int); + /// set skip chroma deinterlace +extern void VideoSetSkipChromaDeinterlace(int); + /// set scaling extern void VideoSetScaling(int); + /// set denoise +extern void VideoSetDenoise(int); + + /// set sharpen +extern void VideoSetSharpen(int); + /// set audio delay extern void VideoSetAudioDelay(int);