From aca508114b4e34a9317f8d62ce24f8d52cbe416c Mon Sep 17 00:00:00 2001 From: durchflieger <> Date: Mon, 30 Apr 2012 14:47:08 +0200 Subject: [PATCH] Adds VDR DFAtmo Plugin support. --- ChangeLog | 9 +++ Todo | 1 - softhddevice.cpp | 50 ++++++++++--- softhddevice_service.h | 44 +++++++++++ video.c | 162 ++++++++++++++++++++++++++++++++++++----- video.h | 3 + 6 files changed, 242 insertions(+), 27 deletions(-) create mode 100644 softhddevice_service.h diff --git a/ChangeLog b/ChangeLog index cd14662..b2abb88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,15 @@ User johns Date: Release Version 0.5.1 + +User durchflieger +Date: Mon Apr 30 14:46:51 CEST 2012 + + Adds VDR DFAtmo Plugin support. + +User johns +Date: Mon Apr 30 13:56:26 CEST 2012 + Fix bug: don't normalize or compress pass-through samples. Make audio ring buffer size a multiple of 3,5,7,8. Add reset ring buffer support. diff --git a/Todo b/Todo index a36b976..e8de19f 100644 --- a/Todo +++ b/Todo @@ -121,7 +121,6 @@ future features (not planed for 1.0 - 1.5) video out with opengl video out with xvba software decoder for xv / opengl - atmolight support multistream handling pip support save and use auto-crop with channel zapping diff --git a/softhddevice.cpp b/softhddevice.cpp index 7a07e53..e2ab45f 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -33,6 +33,7 @@ #include "softhddev.h" #include "softhddevice.h" +#include "softhddevice_service.h" extern "C" { #include "audio.h" @@ -693,8 +694,8 @@ void cMenuSetupSoft::Create(void) if (Audio) { Add(new cMenuEditIntItem(tr("Audio/Video delay (ms)"), &AudioDelay, -1000, 1000)); - Add(new cMenuEditStraItem(tr("Audio drift correction"), - &AudioDrift, 4, audiodrift)); + Add(new cMenuEditStraItem(tr("Audio drift correction"), &AudioDrift, 4, + audiodrift)); Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2, passthrough)); Add(new cMenuEditBoolItem(tr("Enable AC-3 downmix"), &AudioDownmix, @@ -1720,7 +1721,7 @@ class cPluginSoftHdDevice:public cPlugin virtual cOsdObject *MainMenuAction(void); virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *, const char *); -// virtual bool Service(const char *, void * = NULL); + virtual bool Service(const char *, void * = NULL); virtual const char **SVDRPHelpPages(void); virtual cString SVDRPCommand(const char *, const char *, int &); }; @@ -2074,17 +2075,48 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value) return false; } -#if 0 - -bool cPluginSoftHdDevice::Service(const char *Id, void *Data) +/** +** Receive requests or messages. +** +** @param id unique identification string that identifies the +** service protocol +** @param data custom data structure +*/ +bool cPluginSoftHdDevice::Service(const char *id, void *data) { - dsyslog("[softhddev]%s:\n", __FUNCTION__); + dsyslog("[softhddev]%s: id %s\n", __FUNCTION__, id); + if (strcmp(id, ATMO_GRAB_SERVICE) == 0) { + int width; + int height; + + if (data == NULL) { + return true; + } + + SoftHDDevice_AtmoGrabService_v1_0_t *r = + (SoftHDDevice_AtmoGrabService_v1_0_t *) data; + if (r->structSize != sizeof(SoftHDDevice_AtmoGrabService_v1_0_t) + || r->analyseSize < 64 || r->analyseSize > 256 + || r->clippedOverscan < 0 || r->clippedOverscan > 200) { + return false; + } + + width = r->analyseSize * -1; // Internal marker for Atmo grab service + height = r->clippedOverscan; + + r->img = VideoGrabService(&r->imgSize, &width, &height); + if (r->img == NULL) { + return false; + } + r->imgType = GRAB_IMG_RGBA_FORMAT_B8G8R8A8; + r->width = width; + r->height = height; + return true; + } return false; } -#endif - //---------------------------------------------------------------------------- // cPlugin SVDRP //---------------------------------------------------------------------------- diff --git a/softhddevice_service.h b/softhddevice_service.h new file mode 100644 index 0000000..737f8b0 --- /dev/null +++ b/softhddevice_service.h @@ -0,0 +1,44 @@ +/// +/// @file softhddev_service.h @brief software HD device service header file. +/// +/// Copyright (c) 2012 by durchflieger. All Rights Reserved. +/// +/// Contributor(s): +/// +/// License: AGPLv3 +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU Affero General Public License as +/// published by the Free Software Foundation, either version 3 of the +/// License. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU Affero General Public License for more details. +/// +/// $Id$ +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#define ATMO_GRAB_SERVICE "SoftHDDevice-AtmoGrabService-v1.0" + +enum +{ GRAB_IMG_RGBA_FORMAT_B8G8R8A8 }; + +typedef struct +{ + int structSize; + + // request data + int analyseSize; + int clippedOverscan; + + // reply data + int imgType; + int imgSize; + int width; + int height; + void *img; +} SoftHDDevice_AtmoGrabService_v1_0_t; diff --git a/video.c b/video.c index 7e3003d..75aca6c 100644 --- a/video.c +++ b/video.c @@ -5079,6 +5079,10 @@ static VdpOutputSurface VdpauOsdOutputSurface[2] = { #endif static int VdpauOsdSurfaceIndex; ///< index into double buffered osd + /// grab render output surface +static VdpOutputSurface VdpauGrabRenderSurface = VDP_INVALID_HANDLE; +static pthread_mutex_t VdpauGrabMutex; + /// /// Function pointer of the VDPAU device. /// @@ -5807,6 +5811,7 @@ static inline void VdpauGetProc(const VdpFuncId id, void *addr, static void VdpauInitOutputQueue(void) { VdpStatus status; + VdpRGBAFormat format; int i; status = @@ -5839,12 +5844,10 @@ static void VdpauInitOutputQueue(void) // // Create display output surfaces // + format = VDP_RGBA_FORMAT_B8G8R8A8; + // FIXME: does a 10bit rgba produce a better output? + // format = VDP_RGBA_FORMAT_R10G10B10A2; for (i = 0; i < OUTPUT_SURFACES_MAX; ++i) { - VdpRGBAFormat format; - - format = VDP_RGBA_FORMAT_B8G8R8A8; - // FIXME: does a 10bit rgba produce a better output? - // format = VDP_RGBA_FORMAT_R10G10B10A2; status = VdpauOutputSurfaceCreate(VdpauDevice, format, VideoWindowWidth, VideoWindowHeight, VdpauSurfacesRb + i); @@ -5855,6 +5858,20 @@ static void VdpauInitOutputQueue(void) Debug(3, "video/vdpau: created output surface %dx%d with id 0x%08x\n", VideoWindowWidth, VideoWindowHeight, VdpauSurfacesRb[i]); } + + // + // Create render output surface for grabbing + // + status = + VdpauOutputSurfaceCreate(VdpauDevice, format, VideoWindowWidth, + VideoWindowHeight, &VdpauGrabRenderSurface); + if (status != VDP_STATUS_OK) { + Fatal(_("video/vdpau: can't create grab render output surface: %s\n"), + VdpauGetErrorString(status)); + } + Debug(3, + "video/vdpau: created grab render output surface %dx%d with id 0x%08x\n", + VideoWindowWidth, VideoWindowHeight, VdpauGrabRenderSurface); } /// @@ -5863,13 +5880,12 @@ static void VdpauInitOutputQueue(void) static void VdpauExitOutputQueue(void) { int i; + VdpStatus status; // // destroy display output surfaces // for (i = 0; i < OUTPUT_SURFACES_MAX; ++i) { - VdpStatus status; - Debug(4, "video/vdpau: destroy output surface with id 0x%08x\n", VdpauSurfacesRb[i]); if (VdpauSurfacesRb[i] != VDP_INVALID_HANDLE) { @@ -5881,6 +5897,15 @@ static void VdpauExitOutputQueue(void) VdpauSurfacesRb[i] = VDP_INVALID_HANDLE; } } + if (VdpauGrabRenderSurface != VDP_INVALID_HANDLE) { + status = VdpauOutputSurfaceDestroy(VdpauGrabRenderSurface); + if (status != VDP_STATUS_OK) { + Error(_ + ("video/vdpau: can't destroy grab render output surface: %s\n"), + VdpauGetErrorString(status)); + } + VdpauGrabRenderSurface = VDP_INVALID_HANDLE; + } if (VdpauQueue) { VdpauPresentationQueueDestroy(VdpauQueue); VdpauQueue = 0; @@ -5927,6 +5952,8 @@ static int VdpauInit(const char *display_name) uint32_t max_width; uint32_t max_height; + pthread_mutex_init(&VdpauGrabMutex, NULL); + status = vdp_device_create_x11(XlibDisplay, DefaultScreen(XlibDisplay), &VdpauDevice, &VdpauGetProcAddress); @@ -6358,6 +6385,8 @@ static void VdpauExit(void) } VdpauDevice = 0; } + + pthread_mutex_destroy(&VdpauGrabMutex); } /// @@ -6684,13 +6713,13 @@ static void VdpauGrabVideoSurface(VdpauDecoder * decoder) #endif /// -/// Grab output surface. +/// Grab output surface already locked. /// /// @param ret_size[out] size of allocated surface copy /// @param ret_width[in,out] width of output /// @param ret_height[in,out] height of output /// -static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, +static uint8_t *VdpauGrabOutputSurfaceLocked(int *ret_size, int *ret_width, int *ret_height) { VdpOutputSurface surface; @@ -6703,8 +6732,7 @@ static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, void *data[1]; uint32_t pitches[1]; VdpRect source_rect; - - // FIXME: test function to grab output surface content + VdpRect output_rect; surface = VdpauSurfacesRb[VdpauSurfaceIndex]; @@ -6721,8 +6749,62 @@ static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, Debug(3, "video/vdpau: grab %dx%d format %d\n", width, height, rgba_format); - // FIXME: scale surface to requested size with - // VdpauOutputSurfaceRenderOutputSurface + source_rect.x0 = 0; + source_rect.y0 = 0; + source_rect.x1 = width; + source_rect.y1 = height; + + if (ret_width && ret_height) { + if (*ret_width <= -64) { // this is a Atmo grab service request + int overscan; + + // calculate aspect correct size of analyze image + width = *ret_width * -1; + height = (width * source_rect.y1) / source_rect.x1; + + // calculate size of grab (sub) window + overscan = *ret_height; + + if (overscan > 0 && overscan <= 200) { + source_rect.x0 = source_rect.x1 * overscan / 1000; + source_rect.x1 -= source_rect.x0; + source_rect.y0 = source_rect.y1 * overscan / 1000; + source_rect.y1 -= source_rect.y0; + } + } else { + if (*ret_width > 0 && (unsigned)*ret_width < width) { + width = *ret_width; + } + if (*ret_height > 0 && (unsigned)*ret_height < height) { + height = *ret_height; + } + } + + Debug(3, "video/vdpau: grab source rect %d,%d:%d,%d dest dim %dx%d\n", + source_rect.x0, source_rect.y0, source_rect.x1, source_rect.y1, + width, height); + + if ((source_rect.x1 - source_rect.x0) != width + || (source_rect.y1 - source_rect.y0) != height) { + output_rect.x0 = 0; + output_rect.y0 = 0; + output_rect.x1 = width; + output_rect.y1 = height; + + status = + VdpauOutputSurfaceRenderOutputSurface(VdpauGrabRenderSurface, + &output_rect, surface, &source_rect, NULL, NULL, + VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); + if (status != VDP_STATUS_OK) { + Error(_("video/vdpau: can't render output surface: %s\n"), + VdpauGetErrorString(status)); + return NULL; + } + + surface = VdpauGrabRenderSurface; + source_rect = output_rect; + } + } switch (rgba_format) { case VDP_RGBA_FORMAT_B8G8R8A8: @@ -6744,10 +6826,6 @@ static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, return NULL; } - source_rect.x0 = 0; - source_rect.y0 = 0; - source_rect.x1 = source_rect.x0 + width; - source_rect.y1 = source_rect.y0 + height; status = VdpauOutputSurfaceGetBitsNative(surface, &source_rect, data, pitches); if (status != VDP_STATUS_OK) { @@ -6770,6 +6848,28 @@ static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, return base; } +/// +/// Grab output surface. +/// +/// @param ret_size[out] size of allocated surface copy +/// @param ret_width[in,out] width of output +/// @param ret_height[in,out] height of output +/// +static uint8_t *VdpauGrabOutputSurface(int *ret_size, int *ret_width, + int *ret_height) +{ + uint8_t *img; + + if (VdpauGrabRenderSurface == VDP_INVALID_HANDLE) { + return NULL; // vdpau video module not yet initialized + } + + pthread_mutex_lock(&VdpauGrabMutex); + img = VdpauGrabOutputSurfaceLocked(ret_size, ret_width, ret_height); + pthread_mutex_unlock(&VdpauGrabMutex); + return img; +} + #endif #ifdef USE_AUTOCROP @@ -9264,6 +9364,8 @@ uint8_t *VideoGrab(int *size, int *width, int *height, int write_header) scale_height = *height; n = 0; data = VideoUsedModule->GrabOutput(size, width, height); + if (data == NULL) + return NULL; if (scale_width <= 0) { scale_width = *width; @@ -9350,6 +9452,32 @@ uint8_t *VideoGrab(int *size, int *width, int *height, int write_header) return NULL; } +/// +/// Grab image service. +/// +/// @param size[out] size of allocated image +/// @param width[in,out] width of image +/// @param height[in,out] height of image +/// +uint8_t *VideoGrabService(int *size, int *width, int *height) +{ + Debug(3, "video: grab service\n"); + +#ifdef USE_GRAB + if (VideoUsedModule->GrabOutput) { + return VideoUsedModule->GrabOutput(size, width, height); + } else +#endif + { + Warning(_("softhddev: grab unsupported\n")); + } + + (void)size; + (void)width; + (void)height; + return NULL; +} + #ifdef USE_SCREENSAVER //---------------------------------------------------------------------------- diff --git a/video.h b/video.h index 2be1e5d..1793e29 100644 --- a/video.h +++ b/video.h @@ -168,6 +168,9 @@ extern void VideoSetTrickSpeed(VideoHwDecoder *, int); /// Grab screen. extern uint8_t *VideoGrab(int *, int *, int *, int); + /// Grab screen raw. +extern uint8_t *VideoGrabService(int *, int *, int *); + extern void VideoOsdInit(void); ///< Setup osd. extern void VideoOsdExit(void); ///< Cleanup osd.