summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohns <johns98@gmx.net>2012-01-20 15:33:37 +0100
committerJohns <johns98@gmx.net>2012-01-20 15:33:37 +0100
commit0422b6aa5aad384dac6eea345219a5bec32e9d78 (patch)
tree73428935c0956c8e739c804fb8cc134bd0fdf146
parenteb024558dece3d93b44f329da8626c358b7f4ace (diff)
downloadvdr-plugin-softhddevice-0422b6aa5aad384dac6eea345219a5bec32e9d78.tar.gz
vdr-plugin-softhddevice-0422b6aa5aad384dac6eea345219a5bec32e9d78.tar.bz2
VDPAU: Add auto-crop support.
-rw-r--r--ChangeLog3
-rw-r--r--README.txt23
-rw-r--r--Todo2
-rw-r--r--audio.c2
-rw-r--r--softhddevice.cpp44
-rw-r--r--video.c265
-rw-r--r--video.h3
7 files changed, 317 insertions, 25 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ff8c00..576fc6a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,8 @@
User johns
Date:
- Release Version 0.3.6
+ Release Version 0.4.0
+ VDPAU: Add auto-crop support.
VDPAU: Changed OSD alpha calculation.
Fix bug: Used VideoSharpen for denoise settings.
Instant update deinterlace/... configuration changes.
diff --git a/README.txt b/README.txt
index 0bd67d5..d4cfb5e 100644
--- a/README.txt
+++ b/README.txt
@@ -24,17 +24,20 @@ A software and GPU emulated HD output device plugin for VDR.
o Video CPU/VA-API
o Video VDPAU/VDPAU
o Video CPU/VDPAU
+ o Audio FFMpeg/Alsa/Analog
+ o Audio FFMpeg/Alsa/Digital
+ o Audio FFMpeg/OSS/Analog
+ o HDMI/SPDIF Passthrough
+ o VA-API bob software deinterlace
+ o Auto-crop
+
o planned: Video VA-API/Opengl
o planned: Video VDPAU/Opengl
o planned: Video CPU/Xv
o planned: Video CPU/Opengl
- o planned: Software Deinterlacer
+ o planned: Improved Software Deinterlacer (yadif or/and ffmpeg filters)
o planned: Video XvBA/XvBA
- o Audio FFMpeg/Alsa/Analog
- o Audio FFMpeg/Alsa/Digital
- o Audio FFMpeg/OSS/Analog
- o Alsa HDMI/SPDIF Passthrough
- o planned: OSS HDMI/SPDIF Passthrough
+ o planned: atmo light support
To compile you must have the 'requires' installed.
@@ -125,6 +128,14 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
+ softhddevice.AutoCrop.Interval = 0
+ 0 disables auto-crop
+ n each 'n' frames auto-crop is checked.
+
+ softhddevice.AutoCrop.Delay = 0
+ if auto-crop is over after 'n' intervals the same, the cropping is
+ used.
+
Setup: /etc/vdr/remote.conf
------
diff --git a/Todo b/Todo
index 57cb97e..6ba8992 100644
--- a/Todo
+++ b/Todo
@@ -21,7 +21,6 @@ $Id: $
missing:
software deinterlace (yadif, ...)
software decoder with software deinterlace
- auto crop
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop audio, stop video, configurable
@@ -41,6 +40,7 @@ libva:
hard channel switch
yaepghd (VaapiSetOutputPosition) support
can associate ony displayed part of osd
+ auto crop for va-api
libva-intel-driver:
intel still has hangups most with 1080i
diff --git a/audio.c b/audio.c
index 4eced8e..7a8e643 100644
--- a/audio.c
+++ b/audio.c
@@ -2125,7 +2125,7 @@ void AudioExit(void)
#ifdef USE_AUDIO_THREAD
AudioExitThread();
#endif
- if ( UsedAudioModule ) {
+ if (UsedAudioModule) {
UsedAudioModule->Exit();
}
#ifdef USE_AUDIORING
diff --git a/softhddevice.cpp b/softhddevice.cpp
index 764595b..2e5ef41 100644
--- a/softhddevice.cpp
+++ b/softhddevice.cpp
@@ -42,7 +42,7 @@ extern "C"
//////////////////////////////////////////////////////////////////////////////
-static const char *const VERSION = "0.3.5";
+static const char *const VERSION = "0.4.0";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
@@ -79,6 +79,9 @@ static int ConfigVideoScaling[RESOLUTIONS];
static int ConfigVideoAudioDelay; ///< config audio delay
static int ConfigAudioPassthrough; ///< config audio pass-through
+static int ConfigAutoCropInterval; ///< auto crop detection interval
+static int ConfigAutoCropDelay; ///< auto crop detection delay
+
static volatile char DoMakePrimary; ///< flag switch primary
//////////////////////////////////////////////////////////////////////////////
@@ -362,6 +365,8 @@ class cMenuSetupSoft:public cMenuSetupPage
int Sharpen[RESOLUTIONS];
int AudioDelay;
int AudioPassthrough;
+ int AutoCropInterval;
+ int AutoCropDelay;
protected:
virtual void Store(void);
public:
@@ -370,6 +375,8 @@ class cMenuSetupSoft:public cMenuSetupPage
/**
** Create a seperator item.
+**
+** @param label text inside separator
*/
static inline cOsdItem *SeparatorItem(const char *label)
{
@@ -439,6 +446,16 @@ cMenuSetupSoft::cMenuSetupSoft(void)
AudioPassthrough = ConfigAudioPassthrough;
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
passthrough));
+ //
+ // auto-crop
+ //
+ Add(SeparatorItem(tr("Auto-crop")));
+ AutoCropInterval = ConfigAutoCropInterval;
+ Add(new cMenuEditIntItem(tr("autocrop interval (frames)"),
+ &AutoCropInterval, 0, 200));
+ AutoCropDelay = ConfigAutoCropDelay;
+ Add(new cMenuEditIntItem(tr("autocrop delay (n * interval)"),
+ &AutoCropDelay, 0, 200));
}
/**
@@ -478,6 +495,11 @@ void cMenuSetupSoft::Store(void)
VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
CodecSetAudioPassthrough(ConfigAudioPassthrough);
+
+ SetupStore("AutoCrop.Interval", ConfigAutoCropInterval = AutoCropInterval);
+ SetupStore("AutoCrop.Delay", ConfigAutoCropDelay = AutoCropDelay);
+
+ VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay);
}
//////////////////////////////////////////////////////////////////////////////
@@ -1001,11 +1023,15 @@ cMenuSetupPage *cPluginSoftHdDevice::SetupMenu(void)
/**
** Parse setup parameters
+**
+** @param name paramter name (case sensetive)
+** @param value value as string
+**
+** @returns true if the parameter is supported.
*/
bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
{
int i;
- char buf[128];
//dsyslog("[softhddev]%s: '%s' = '%s'\n", __FUNCTION__, name, value);
@@ -1018,6 +1044,8 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
for (i = 0; i < RESOLUTIONS; ++i) {
+ char buf[128];
+
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Scaling");
if (!strcmp(name, buf)) {
ConfigVideoScaling[i] = atoi(value);
@@ -1050,6 +1078,7 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
}
+
if (!strcmp(name, "AudioDelay")) {
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true;
@@ -1059,6 +1088,17 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
return true;
}
+ if (!strcmp(name, "AutoCrop.Interval")) {
+ VideoSetAutoCrop(ConfigAutoCropInterval =
+ atoi(value), ConfigAutoCropDelay);
+ return true;
+ }
+ if (!strcmp(name, "AutoCrop.Delay")) {
+ VideoSetAutoCrop(ConfigAutoCropInterval, ConfigAutoCropDelay =
+ atoi(value));
+ return true;
+ }
+
return false;
}
diff --git a/video.c b/video.c
index fba4048..6fb1fb2 100644
--- a/video.c
+++ b/video.c
@@ -37,6 +37,7 @@
///
#define USE_XLIB_XCB ///< use xlib/xcb backend
+#define USE_AUTOCROP ///< compile autocrop support
#define noUSE_GRAB ///< experimental grab code
#define noUSE_GLX ///< outdated GLX code
#define noUSE_DOUBLEBUFFER ///< use GLX double buffers
@@ -820,20 +821,31 @@ static VideoResolutions VideoResolutionGroup(int width, int height,
//----------------------------------------------------------------------------
///
-/// avfilter_vf_cropdetect
+/// Autocrop context structure and typedef.
///
-typedef struct _video_auto_crop_ctx_
+typedef struct _auto_crop_ctx_
{
- int x1; ///< detected left border
- int x2; ///< detected right border
- int y1; ///< detected top border
- int y2; ///< detected bottom border
-} VideoAutoCropCtx;
+ int X1; ///< detected left border
+ int X2; ///< detected right border
+ int Y1; ///< detected top border
+ int Y2; ///< detected bottom border
+
+ int Count; ///< counter to delay switch
+ int State; ///< autocrop state (0, 14, 16)
+
+} AutoCropCtx;
+
+#ifdef USE_AUTOCROP
#define YBLACK 0x20 ///< below is black
#define UVBLACK 0x80 ///< around is black
#define M64 UINT64_C(0x0101010101010101) ///< 64bit multiplicator
+ /// percent of width to ignore logos
+static const int AutoCropLogoIgnore = 24;
+static int AutoCropInterval; ///< check interval
+static int AutoCropDelay; ///< switch delay
+
///
/// Detect black line Y.
///
@@ -872,8 +884,19 @@ static int AutoCropIsBlackLineY(const uint8_t * data, int length, int stride)
///
/// Auto detect black borders and crop them.
///
-static void AutoCropDetect(int width, int height, void *data[3],
- uint32_t pitches[3])
+/// @param autocrop autocrop variables
+/// @param width frame width in pixel
+/// @param height frame height in pixel
+/// @param data frame planes data (Y, U, V)
+/// @param pitches frame planes pitches (Y, U, V)
+///
+/// @note FIXME: can reduce the checked range, left, right crop isn't
+/// used yet.
+///
+/// @note FIXME: only Y is checked, for black.
+///
+static void AutoCropDetect(AutoCropCtx * autocrop, int width, int height,
+ void *data[3], uint32_t pitches[3])
{
const void *data_y;
unsigned length_y;
@@ -886,15 +909,15 @@ static void AutoCropDetect(int width, int height, void *data[3],
int logo_skip;
//
- // ignore top+bottom 4 lines and left+right 8 pixels
+ // ignore top+bottom 6 lines and left+right 8 pixels
//
#define SKIP_X 8
-#define SKIP_Y 4
+#define SKIP_Y 6
x1 = width - 1;
x2 = 0;
y1 = height - 1;
y2 = 0;
- logo_skip = SKIP_X;
+ logo_skip = SKIP_X + (((width * AutoCropLogoIgnore) / 100 + 8) / 8) * 8;
data_y = data[0];
length_y = pitches[0];
@@ -957,12 +980,21 @@ static void AutoCropDetect(int width, int height, void *data[3],
Debug(3, "video/autocrop: top=%d bottom=%d left=%d right=%d\n", y1, y2,
x1, x2);
}
+
+ autocrop->X1 = x1;
+ autocrop->X2 = x2;
+ autocrop->Y1 = y1;
+ autocrop->Y2 = y2;
}
+#endif
+
//----------------------------------------------------------------------------
// software - deinterlace
//----------------------------------------------------------------------------
+// FIXME: move general software deinterlace functions to here.
+
//----------------------------------------------------------------------------
// VA-API
//----------------------------------------------------------------------------
@@ -1703,6 +1735,9 @@ static void VaapiUpdateOutput(VaapiDecoder * decoder)
}
Debug(3, "video: aspect output %dx%d+%d+%d\n", decoder->OutputWidth,
decoder->OutputHeight, decoder->OutputX, decoder->OutputY);
+
+ //decoder->AutoCrop->State = 0;
+ //decoder->AutoCrop->Count = 0;
}
///
@@ -3698,6 +3733,8 @@ typedef struct _vdpau_decoder_
int CropWidth; ///< video crop width
int CropHeight; ///< video crop height
+ AutoCropCtx AutoCrop[1]; ///< autocrop variables
+
#ifdef noyetUSE_GLX
GLuint GlTexture[2]; ///< gl texture for VDPAU
void *GlxSurface[2]; ///< VDPAU/GLX surface
@@ -4906,6 +4943,7 @@ static void VdpauUpdateOutput(VdpauDecoder * decoder)
case VideoStretch:
case VideoZoom:
case VideoAnamorphic:
+ // AutoCrop
break;
}
}
@@ -4925,6 +4963,9 @@ static void VdpauUpdateOutput(VdpauDecoder * decoder)
}
Debug(3, "video: aspect output %dx%d+%d+%d\n", decoder->OutputWidth,
decoder->OutputHeight, decoder->OutputX, decoder->OutputY);
+
+ decoder->AutoCrop->State = 0;
+ decoder->AutoCrop->Count = 0;
}
///
@@ -5162,6 +5203,8 @@ static void VdpauSetup(VdpauDecoder * decoder,
//
}
+#ifdef USE_GRAB
+
///
/// Grab video surface.
///
@@ -5213,6 +5256,9 @@ static void VdpauGrabSurface(VdpauDecoder * decoder)
data[2] = base + width * height + width * height / 4;
format = VDP_YCBCR_FORMAT_YV12;
break;
+ default:
+ Error(_("video/vdpau: unsupported chroma type %d\n"), chroma_type);
+ return;
}
status = VdpauVideoSurfaceGetBitsYCbCr(surface, format, data, pitches);
if (status != VDP_STATUS_OK) {
@@ -5221,11 +5267,165 @@ static void VdpauGrabSurface(VdpauDecoder * decoder)
return;
}
- AutoCropDetect(width, height, data, pitches);
+ free(base);
+}
+
+#endif
+
+#ifdef USE_AUTOCROP
+
+///
+/// VDPAU Auto crop support.
+///
+/// @param decoder VDPAU hw decoder
+///
+static void VdpauAutoCrop(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];
+ int crop14;
+ int crop16;
+ int next_state;
+ VdpYCbCrFormat format;
+
+ 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;
+ default:
+ Error(_("video/vdpau: unsupported chroma type %d\n"), chroma_type);
+ return;
+ }
+ 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;
+ }
+ AutoCropDetect(decoder->AutoCrop, width, height, data, pitches);
free(base);
+
+ // ignore black frames
+ if (decoder->AutoCrop->Y1 >= decoder->AutoCrop->Y2) {
+ return;
+ }
+
+ crop14 =
+ (decoder->InputWidth * decoder->InputAspect.num * 9) /
+ (decoder->InputAspect.den * 14);
+ crop14 = (decoder->InputHeight - crop14) / 2;
+ crop16 =
+ (decoder->InputWidth * decoder->InputAspect.num * 9) /
+ (decoder->InputAspect.den * 16);
+ crop16 = (decoder->InputHeight - crop16) / 2;
+
+ // -2 for rounding errors
+ if (decoder->AutoCrop->Y1 >= crop16 - 2
+ && decoder->InputHeight - decoder->AutoCrop->Y2 >= crop16 - 2) {
+ next_state = 16;
+ } else if (decoder->AutoCrop->Y1 >= crop14 - 2
+ && decoder->InputHeight - decoder->AutoCrop->Y2 >= crop14 - 2) {
+ next_state = 14;
+ } else {
+ next_state = 0;
+ }
+
+ if (decoder->AutoCrop->State == next_state) {
+ return;
+ }
+
+ Debug(3, "video: crop aspect %d:%d %d/%d %d+%d\n",
+ decoder->InputAspect.num, decoder->InputAspect.den, crop14, crop16,
+ decoder->AutoCrop->Y1, decoder->InputHeight - decoder->AutoCrop->Y2);
+
+ Debug(3, "video: crop aspect %d -> %d\n", decoder->AutoCrop->State,
+ next_state);
+
+ switch (decoder->AutoCrop->State) {
+ case 16:
+ case 14:
+ if (decoder->AutoCrop->Count++ < AutoCropDelay / 2) {
+ return;
+ }
+ break;
+ case 0:
+ if (decoder->AutoCrop->Count++ < AutoCropDelay) {
+ return;
+ }
+ break;
+ }
+
+ decoder->AutoCrop->Count = 0;
+ decoder->AutoCrop->State = next_state;
+
+ if (next_state) {
+ decoder->CropX = 0;
+ decoder->CropY = next_state == 16 ? crop16 : crop14;
+ decoder->CropWidth = decoder->InputWidth;
+ decoder->CropHeight = decoder->InputHeight - decoder->CropY * 2;
+
+ // FIXME: this overwrites user choosen output position
+ // FIXME: resize kills the auto crop values
+ decoder->OutputX = 0;
+ decoder->OutputY = 0;
+ decoder->OutputWidth = (VideoWindowHeight * next_state) / 9;
+ decoder->OutputHeight = (VideoWindowWidth * 9) / next_state;
+ if ((unsigned)decoder->OutputWidth > VideoWindowWidth) {
+ decoder->OutputWidth = VideoWindowWidth;
+ decoder->OutputY = (VideoWindowHeight - decoder->OutputHeight) / 2;
+ } else if ((unsigned)decoder->OutputHeight > VideoWindowHeight) {
+ decoder->OutputHeight = VideoWindowHeight;
+ decoder->OutputX = (VideoWindowWidth - decoder->OutputWidth) / 2;
+ }
+ Debug(3, "video: aspect output %dx%d %dx%d+%d+%d\n",
+ decoder->InputWidth, decoder->InputHeight, decoder->OutputWidth,
+ decoder->OutputHeight, decoder->OutputX, decoder->OutputY);
+ } else {
+ decoder->CropX = 0;
+ decoder->CropY = 0;
+ decoder->CropWidth = decoder->InputWidth;
+ decoder->CropHeight = decoder->InputHeight;
+
+ VdpauUpdateOutput(decoder);
+ }
}
+#endif
+
///
/// Queue output surface.
///
@@ -5568,6 +5768,24 @@ static void VdpauMixVideo(VdpauDecoder * decoder)
#ifdef USE_GRAB
VdpauGrabSurface(decoder);
#endif
+#ifdef USE_AUTOCROP
+ // reduce load, check only n frames
+ if (AutoCropInterval && !(decoder->FrameCounter % AutoCropInterval)) {
+ AVRational display_aspect_ratio;
+
+ av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
+ decoder->InputWidth * decoder->InputAspect.num,
+ decoder->InputHeight * decoder->InputAspect.den, 1024 * 1024);
+
+ // only 4:3 with 16:9/14:9 inside supported
+ if (display_aspect_ratio.num == 4 && display_aspect_ratio.den == 3) {
+ VdpauAutoCrop(decoder);
+ } else {
+ decoder->AutoCrop->Count = 0;
+ decoder->AutoCrop->State = 0;
+ }
+ }
+#endif
if (decoder->Interlaced
&& VideoDeinterlace[decoder->Resolution] != VideoDeinterlaceWeave) {
@@ -7482,6 +7700,25 @@ void VideoSetAudioDelay(int ms)
}
///
+/// Set auto-crop parameters.
+///
+void VideoSetAutoCrop(int interval, int delay)
+{
+#ifdef USE_AUTOCROP
+ int i;
+
+ AutoCropInterval = interval;
+ AutoCropDelay = delay;
+#ifdef USE_VDPAU
+ for (i = 0; i < VdpauDecoderN; ++i) {
+ VdpauDecoders[i]->AutoCrop->State = 0;
+ VdpauDecoders[i]->AutoCrop->Count = 0;
+ }
+#endif
+#endif
+}
+
+///
/// Initialize video output module.
///
/// @param display_name X11 display name
@@ -7659,7 +7896,7 @@ static void PrintVersion(void)
#ifdef GIT_REV
"(GIT-" GIT_REV ")"
#endif
- ",\n\t(c) 2009 - 2011 by Johns\n"
+ ",\n\t(c) 2009 - 2012 by Johns\n"
"\tLicense AGPLv3: GNU Affero General Public License version 3\n");
}
diff --git a/video.h b/video.h
index 15ba976..f3ff6ad 100644
--- a/video.h
+++ b/video.h
@@ -100,6 +100,9 @@ extern void VideoSetSharpen(int[]);
/// Set audio delay.
extern void VideoSetAudioDelay(int);
+ /// Set auto-crop parameters.
+extern void VideoSetAutoCrop(int, int);
+
/// Clear OSD.
extern void VideoOsdClear(void);