summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohns <johns98@gmx.net>2012-01-18 15:15:37 +0100
committerJohns <johns98@gmx.net>2012-01-18 15:15:37 +0100
commitc6e66e0787f62fdf74dde43dcc88818f80b7334e (patch)
tree20cd574eb4c2aa096a9788513b63fe41cdd3b45e
parent19d4eeed8268c88feff69f06218a11e68e548246 (diff)
downloadvdr-plugin-softhddevice-c6e66e0787f62fdf74dde43dcc88818f80b7334e.tar.gz
vdr-plugin-softhddevice-c6e66e0787f62fdf74dde43dcc88818f80b7334e.tar.bz2
OSD improvements:
Use OSD size equal to video window. Update only dirty area(s) of OSD. Show/mix only used area of OSD. Fix bug: vpdau use previous resolution for deint, ...
-rw-r--r--ChangeLog5
-rw-r--r--Todo15
-rw-r--r--softhddev.c15
-rw-r--r--softhddevice.cpp79
-rw-r--r--video.c446
-rw-r--r--video.h3
6 files changed, 397 insertions, 166 deletions
diff --git a/ChangeLog b/ChangeLog
index 2d8e449..bb71fbd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,11 @@
User johns
Date:
+ OSD improvements:
+ Use OSD size equal to video window.
+ Update only dirty area(s) of OSD.
+ Show/mix only used area of OSD.
+ Fix bug: vpdau use previous resolution for deint, ...
Fix software deinterlace with VA-API.
Fix bug: transposed digits 567 should be 576.
Audio module cleanup:
diff --git a/Todo b/Todo
index 4dcef94..57cb97e 100644
--- a/Todo
+++ b/Todo
@@ -19,23 +19,20 @@ GNU Affero General Public License for more details.
$Id: $
missing:
- software deinterlace
+ 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
Option deinterlace off / deinterlace force!
- Make output drivers better moduluar.
+ Make output drivers better modular.
video:
subtitle not cleared
subtitle could be asyncron
vdpau:
- 1080i with temporal spatial and level 1 scaling too slow with my GT 520
- 1080i with temporal spatial too slow with my 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
suspendoutput didn't show logo or black picture.
@@ -43,15 +40,15 @@ vdpau:
libva:
hard channel switch
yaepghd (VaapiSetOutputPosition) support
+ can associate ony displayed part of osd
libva-intel-driver:
intel still has hangups most with 1080i
1080i does no v-sync (workaround written)
- osd has sometimes wrong size (workaround written)
+ OSD has sometimes wrong size (workaround written)
libva-vdpau-driver:
- G210 osd update too slow (needs hardware problem workaround)
- OSD update is too slow
+ G210/GT520 OSD update too slow (needs hardware problem workaround)
hangup on exit (VaapiDelDecoder -> VaapiCleanup
-> vaDestroyContext -> pthread_rwlock_wrlock)
diff --git a/softhddev.c b/softhddev.c
index 6f65ab3..33e5fae 100644
--- a/softhddev.c
+++ b/softhddev.c
@@ -913,22 +913,19 @@ int Flush(int timeout)
void GetOsdSize(int *width, int *height, double *aspect)
{
#ifdef DEBUG
- static char done;
+ static int done_width;
+ static int done_height;
#endif
- // FIXME: should be configured!
- *width = 1920;
- *height = 1080;
- //*width = 768;
- //*height = 576;
-
+ VideoGetOsdSize(width, height);
*aspect = 16.0 / 9.0 / (double)*width * (double)*height;
#ifdef DEBUG
- if (!done) {
+ if (done_width != *width || done_height != *height) {
Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height,
*aspect);
- done = 1;
+ done_width = *width;
+ done_height = *height;
}
#endif
}
diff --git a/softhddevice.cpp b/softhddevice.cpp
index c146db4..b7039ff 100644
--- a/softhddevice.cpp
+++ b/softhddevice.cpp
@@ -53,6 +53,7 @@ static class cSoftHdDevice *MyDevice;
#define RESOLUTIONS 4 ///< number of resolutions
+ /// resolutions names
static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i"
};
@@ -158,8 +159,15 @@ cSoftOsd::~cSoftOsd(void)
SetActive(false);
#ifdef USE_YAEPG
- if (vidWin.bpp) {
- VideoSetOutputPosition(0, 0, 1920, 1080);
+ // support yaepghd, video window
+ if (vidWin.bpp) { // restore fullsized video
+ int width;
+ int height;
+ double video_aspect;
+
+ ::GetOsdSize(&width, &height, &video_aspect);
+ // works osd relative
+ VideoSetOutputPosition(0, 0, width, height);
}
#endif
OsdClose();
@@ -175,8 +183,8 @@ void cSoftOsd::Flush(void)
if (!Active()) {
return;
}
- // support yaepghd, video window
#ifdef USE_YAEPG
+ // support yaepghd, video window
if (vidWin.bpp) {
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
vidWin.Height(), vidWin.x1, vidWin.y2);
@@ -213,6 +221,7 @@ void cSoftOsd::Flush(void)
if (!bitmap->Dirty(x1, y1, x2, y2)) {
continue; // nothing dirty continue
}
+#if 0
// FIXME: need only to convert and upload dirty areas
// DrawBitmap(bitmap);
@@ -225,7 +234,6 @@ void cSoftOsd::Flush(void)
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
}
}
-
// check if subtitles
if (this->Level == OSD_LEVEL_SUBTITLES) {
int video_width;
@@ -238,12 +246,32 @@ void cSoftOsd::Flush(void)
video_width = 1920;
video_height = 1080;
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
- 1080 - video_height + Top() + bitmap->Y0(),
- bitmap->Width(), bitmap->Height(), argb);
+ 1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
} else {
- OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(),
- bitmap->Width(), bitmap->Height(), argb);
+ OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), w, h,
+ argb);
+ }
+#else
+ // convert and upload only dirty areas
+ w = x2 - x1 + 1;
+ h = y2 - y1 + 1;
+#ifdef DEBUG
+ if (w > bitmap->Width() || h > bitmap->Height()) {
+ esyslog(tr("softhdev: dirty area too big\n"));
+ abort();
}
+#endif
+ argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
+ for (y = y1; y <= y2; ++y) {
+ for (x = x1; x <= x2; ++x) {
+ ((uint32_t *) argb)[x - x1 + (y - y1) * w] =
+ bitmap->GetColor(x, y);
+ }
+ }
+ // check if subtitles
+ OsdDrawARGB(Left() + bitmap->X0() + x1, Top() + bitmap->Y0() + y1,
+ w, h, argb);
+#endif
bitmap->Clean();
free(argb);
@@ -475,12 +503,7 @@ class cSoftHdDevice:public cDevice
virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0);
virtual int64_t GetSTC(void);
- virtual void GetVideoSize(int &width, int &height, double &aspect)
- {
- width = 1920;
- height = 1080;
- aspect = (double)width / height;
- }
+ virtual void GetVideoSize(int &, int &, double &);
virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int);
@@ -536,18 +559,17 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
}
}
- int cSoftHdDevice::ProvidesCa(
- __attribute__ ((unused)) const cChannel *
- channel) const
- {
- //dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
+int cSoftHdDevice::ProvidesCa(
+ __attribute__ ((unused)) const cChannel * channel) const
+{
+ //dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
- return 0;
- }
+ return 0;
+}
#if 0
- cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
+cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
@@ -697,7 +719,18 @@ bool cSoftHdDevice::Flush(int timeout_ms)
// ----------------------------------------------------------------------------
/**
-** Returns the With, Height and PixelAspect ratio the OSD.
+** Returns the width, height and video_aspect ratio of the currently
+** displayed video material.
+**
+** @note the size is used to scale the subtitle.
+*/
+void cSoftHdDevice::GetVideoSize(int &width, int &height, double &video_aspect)
+{
+ ::GetOsdSize(&width, &height, &video_aspect);
+}
+
+/**
+** Returns the width, height and pixel_aspect ratio the OSD.
**
** FIXME: Called every second, for nothing (no OSD displayed)?
*/
diff --git a/video.c b/video.c
index 85b7beb..41351d9 100644
--- a/video.c
+++ b/video.c
@@ -25,7 +25,7 @@
///
/// This module contains all video rendering functions.
///
-/// @todo hide mouse cursor support
+/// @todo disable screen saver support
///
/// Uses Xlib where it is needed for VA-API or vdpau. XCB is used for
/// everything else.
@@ -36,16 +36,16 @@
/// - Xrender rendering
///
-#define USE_XLIB_XCB
-#define noUSE_GRAB
-#define noUSE_GLX
-#define noUSE_DOUBLEBUFFER
+#define USE_XLIB_XCB ///< use xlib/xcb backend
+#define noUSE_GRAB ///< experimental grab code
+#define noUSE_GLX ///< outdated GLX code
+#define noUSE_DOUBLEBUFFER ///< use GLX double buffers
//#define USE_VAAPI ///< enable vaapi support
//#define USE_VDPAU ///< enable vdpau support
#define noUSE_BITMAP ///< use vdpau bitmap surface
-#define USE_VIDEO_THREAD
+#define USE_VIDEO_THREAD ///< run decoder in an own thread
#include <sys/time.h>
#include <sys/shm.h>
@@ -275,6 +275,14 @@ static pthread_mutex_t VideoLockMutex; ///< video lock mutex
#endif
+static char OsdShown; ///< flag show osd
+static int OsdWidth; ///< osd width
+static int OsdHeight; ///< osd height
+static int OsdDirtyX; ///< osd dirty area x
+static int OsdDirtyY; ///< osd dirty area y
+static int OsdDirtyWidth; ///< osd dirty area width
+static int OsdDirtyHeight; ///< osd dirty area height
+
//----------------------------------------------------------------------------
// Functions
//----------------------------------------------------------------------------
@@ -863,8 +871,9 @@ static void AutoCropDetect(int width, int height, void *data[3],
{
const void *data_y;
unsigned length_y;
- int x;
- int y;
+
+ //int x;
+ //int y;
int x1;
int x2;
int y1;
@@ -1010,52 +1019,59 @@ static void VaapiDestroyDeinterlaceImages(VaapiDecoder *);
// Surfaces -------------------------------------------------------------
///
-/// Create surfaces for VA-API decoder.
+/// Associate OSD with surface.
///
/// @param decoder VA-API decoder
/// @param width surface source/video width
/// @param height surface source/video height
///
-static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
+static void VaapiAssociate(VaapiDecoder * decoder, int width, int height)
{
-#ifdef DEBUG
- if (!decoder->SurfacesNeeded) {
- Error(_("video/vaapi: surface needed not set\n"));
- decoder->SurfacesNeeded = 3 + VIDEO_SURFACES_MAX;
- }
-#endif
- Debug(3, "video/vaapi: %s: %dx%d * %d\n", __FUNCTION__, width, height,
- decoder->SurfacesNeeded);
+ int x;
+ int y;
+ int w;
+ int h;
- decoder->SurfaceFreeN = decoder->SurfacesNeeded;
- // VA_RT_FORMAT_YUV420 VA_RT_FORMAT_YUV422 VA_RT_FORMAT_YUV444
- if (vaCreateSurfaces(decoder->VaDisplay, width, height,
- VA_RT_FORMAT_YUV420, decoder->SurfaceFreeN,
- decoder->SurfacesFree) != VA_STATUS_SUCCESS) {
- Fatal(_("video/vaapi: can't create %d surfaces\n"),
- decoder->SurfaceFreeN);
- // FIXME: write error handler / fallback
- }
- //
- // update OSD associate
- //
if (VaOsdSubpicture == VA_INVALID_ID) {
Warning(_("video/vaapi: no osd subpicture yet\n"));
return;
}
+
+ x = 0;
+ y = 0;
+ w = VaOsdImage.width;
+ h = VaOsdImage.height;
+
// FIXME: associate only if osd is displayed
if (VaapiUnscaledOsd) {
- if (vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
- decoder->SurfacesFree, decoder->SurfaceFreeN, 0, 0,
- VaOsdImage.width, VaOsdImage.height, 0, 0, VideoWindowWidth,
- VideoWindowHeight, VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD)
+ if (decoder->SurfaceFreeN
+ && vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
+ decoder->SurfacesFree, decoder->SurfaceFreeN, x, y, w, h, 0, 0,
+ VideoWindowWidth, VideoWindowHeight,
+ VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD)
+ != VA_STATUS_SUCCESS) {
+ Error(_("video/vaapi: can't associate subpicture\n"));
+ }
+ if (decoder->SurfaceUsedN
+ && vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
+ decoder->SurfacesUsed, decoder->SurfaceUsedN, x, y, w, h, 0, 0,
+ VideoWindowWidth, VideoWindowHeight,
+ VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't associate subpicture\n"));
}
} else {
- if (vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
- decoder->SurfacesFree, decoder->SurfaceFreeN, 0, 0,
- VaOsdImage.width, VaOsdImage.height, 0, 0, width, height, 0)
+ if (decoder->SurfaceFreeN
+ && vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
+ decoder->SurfacesFree, decoder->SurfaceFreeN, x, y, w, h, 0, 0,
+ width, height, 0)
+ != VA_STATUS_SUCCESS) {
+ Error(_("video/vaapi: can't associate subpicture\n"));
+ }
+ if (decoder->SurfaceUsedN
+ && vaAssociateSubpicture(VaDisplay, VaOsdSubpicture,
+ decoder->SurfacesUsed, decoder->SurfaceUsedN, x, y, w, h, 0, 0,
+ width, height, 0)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't associate subpicture\n"));
}
@@ -1063,17 +1079,12 @@ static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
}
///
-/// Destroy surfaces of VA-API decoder.
+/// Deassociate OSD with surface.
///
/// @param decoder VA-API decoder
///
-static void VaapiDestroySurfaces(VaapiDecoder * decoder)
+static void VaapiDeassociate(VaapiDecoder * decoder)
{
- Debug(3, "video/vaapi: %s:\n", __FUNCTION__);
-
- //
- // update OSD associate
- //
if (VaOsdSubpicture != VA_INVALID_ID) {
if (decoder->SurfaceFreeN
&& vaDeassociateSubpicture(VaDisplay, VaOsdSubpicture,
@@ -1091,6 +1102,54 @@ static void VaapiDestroySurfaces(VaapiDecoder * decoder)
decoder->SurfaceUsedN);
}
}
+}
+
+///
+/// Create surfaces for VA-API decoder.
+///
+/// @param decoder VA-API decoder
+/// @param width surface source/video width
+/// @param height surface source/video height
+///
+static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
+{
+#ifdef DEBUG
+ if (!decoder->SurfacesNeeded) {
+ Error(_("video/vaapi: surface needed not set\n"));
+ decoder->SurfacesNeeded = 3 + VIDEO_SURFACES_MAX;
+ }
+#endif
+ Debug(3, "video/vaapi: %s: %dx%d * %d\n", __FUNCTION__, width, height,
+ decoder->SurfacesNeeded);
+
+ decoder->SurfaceFreeN = decoder->SurfacesNeeded;
+ // VA_RT_FORMAT_YUV420 VA_RT_FORMAT_YUV422 VA_RT_FORMAT_YUV444
+ if (vaCreateSurfaces(decoder->VaDisplay, width, height,
+ VA_RT_FORMAT_YUV420, decoder->SurfaceFreeN,
+ decoder->SurfacesFree) != VA_STATUS_SUCCESS) {
+ Fatal(_("video/vaapi: can't create %d surfaces\n"),
+ decoder->SurfaceFreeN);
+ // FIXME: write error handler / fallback
+ }
+ //
+ // update OSD associate
+ //
+ VaapiAssociate(decoder, width, height);
+}
+
+///
+/// Destroy surfaces of VA-API decoder.
+///
+/// @param decoder VA-API decoder
+///
+static void VaapiDestroySurfaces(VaapiDecoder * decoder)
+{
+ Debug(3, "video/vaapi: %s:\n", __FUNCTION__);
+
+ //
+ // update OSD associate
+ //
+ VaapiDeassociate(decoder);
if (vaDestroySurfaces(decoder->VaDisplay, decoder->SurfacesFree,
decoder->SurfaceFreeN)
@@ -1525,23 +1584,6 @@ static void VideoVaapiExit(void)
}
VaapiDecoderN = 0;
- if (VaOsdImage.image_id != VA_INVALID_ID) {
- if (vaDestroyImage(VaDisplay,
- VaOsdImage.image_id) != VA_STATUS_SUCCESS) {
- Error(_("video/vaapi: can't destroy image!\n"));
- }
- VaOsdImage.image_id = VA_INVALID_ID;
- }
-
- if (VaOsdSubpicture != VA_INVALID_ID) {
- // still has 35 surfaces associated to it
- if (vaDestroySubpicture(VaDisplay, VaOsdSubpicture)
- != VA_STATUS_SUCCESS) {
- Error(_("video/vaapi: can't destroy subpicture\n"));
- }
- VaOsdSubpicture = VA_INVALID_ID;
- }
-
if (!VaDisplay) {
vaTerminate(VaDisplay);
VaDisplay = NULL;
@@ -3384,8 +3426,20 @@ static void VaapiOsdClear(void)
Error(_("video/vaapi: can't map osd image buffer\n"));
return;
}
- // 100% transparent
- memset(image_buffer, 0x00, VaOsdImage.data_size);
+ // have dirty area.
+ if (OsdDirtyWidth && OsdDirtyHeight) {
+ int o;
+
+ Debug(3, "video/vaapi: handle osd dirty area\n");
+ for (o = 0; o < OsdDirtyHeight; ++o) {
+ memset(image_buffer + (OsdDirtyX + (o +
+ OsdDirtyY) * VaOsdImage.width) * 4, 0,
+ OsdDirtyWidth * 4);
+ }
+ } else {
+ // 100% transparent
+ memset(image_buffer, 0x00, VaOsdImage.data_size);
+ }
if (vaUnmapBuffer(VaDisplay, VaOsdImage.buf) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't unmap osd image buffer\n"));
@@ -3406,6 +3460,8 @@ static void VaapiOsdClear(void)
static void VaapiUploadImage(int x, int y, int width, int height,
const uint8_t * argb)
{
+ uint32_t start;
+ uint32_t end;
void *image_buffer;
int o;
@@ -3414,17 +3470,13 @@ static void VaapiUploadImage(int x, int y, int width, int height,
return;
}
- Debug(3, "video/vaapi: upload image\n");
-
+ start = GetMsTicks();
// map osd surface/image into memory.
if (vaMapBuffer(VaDisplay, VaOsdImage.buf, &image_buffer)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't map osd image buffer\n"));
return;
}
- // 100% transparent
- //memset(image_buffer, 0x00, VaOsdImage.data_size);
-
// FIXME: convert image from ARGB to subpicture format, if not argb
// copy argb to image
@@ -3436,6 +3488,10 @@ static void VaapiUploadImage(int x, int y, int width, int height,
if (vaUnmapBuffer(VaDisplay, VaOsdImage.buf) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't unmap osd image buffer\n"));
}
+ end = GetMsTicks();
+
+ Debug(3, "video/vaapi: osd upload %dx%d+%d+%d %d ms %d\n", width, height,
+ x, y, end - start, width * height * 4);
}
///
@@ -3528,10 +3584,32 @@ static void VaapiOsdInit(int width, int height)
}
// FIXME: must store format, to convert ARGB to it.
- VaapiOsdClear();
// FIXME: unlock
}
+///
+/// VA-API cleanup osd.
+///
+static void VaapiOsdExit(void)
+{
+ if (VaOsdImage.image_id != VA_INVALID_ID) {
+ if (vaDestroyImage(VaDisplay,
+ VaOsdImage.image_id) != VA_STATUS_SUCCESS) {
+ Error(_("video/vaapi: can't destroy image!\n"));
+ }
+ VaOsdImage.image_id = VA_INVALID_ID;
+ }
+
+ if (VaOsdSubpicture != VA_INVALID_ID) {
+ // FIXME: still has 35 surfaces associated to it
+ if (vaDestroySubpicture(VaDisplay, VaOsdSubpicture)
+ != VA_STATUS_SUCCESS) {
+ Error(_("video/vaapi: can't destroy subpicture\n"));
+ }
+ VaOsdSubpicture = VA_INVALID_ID;
+ }
+}
+
#endif
//----------------------------------------------------------------------------
@@ -3629,10 +3707,6 @@ static int VdpauSkipChroma; ///< skip chroma deint. supported
static VdpOutputSurface VdpauSurfacesRb[OUTPUT_SURFACES_MAX];
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
static VdpBitmapSurface VdpauOsdBitmapSurface[2] = {
@@ -4947,8 +5021,6 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
decoder->InputAspect = video_ctx->sample_aspect_ratio;
VdpauUpdateOutput(decoder);
- VdpauMixerSetup(decoder);
-
// FIXME: need only to create and destroy surfaces for size changes
// or when number of needed surfaces changed!
decoder->Resolution =
@@ -4956,6 +5028,8 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
decoder->Interlaced);
VdpauCreateSurfaces(decoder, video_ctx->width, video_ctx->height);
+ VdpauMixerSetup(decoder);
+
Debug(3, "\t%#010x %s\n", fmt_idx[0], av_get_pix_fmt_name(fmt_idx[0]));
return *fmt_idx;
@@ -4983,12 +5057,13 @@ static void VdpauSetup(VdpauDecoder * decoder,
// decoder->Input... already setup by caller
VdpauCleanup(decoder);
- VdpauMixerSetup(decoder);
decoder->Resolution =
VideoResolutionGroup(video_ctx->width, video_ctx->height,
decoder->Interlaced);
VdpauCreateSurfaces(decoder, video_ctx->width, video_ctx->height);
+ VdpauMixerSetup(decoder);
+
// get real surface size
status =
VdpauVideoSurfaceGetParameters(decoder->SurfacesFree[0], &chroma_type,
@@ -5323,15 +5398,30 @@ static void VdpauMixOsd(void)
blend_state.blend_equation_alpha =
VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
- source_rect.x0 = 0;
- source_rect.y0 = 0;
- source_rect.x1 = VdpauOsdWidth;
- source_rect.y1 = VdpauOsdHeight;
+ // FIXME: use dirty area
+ if (OsdDirtyWidth && OsdDirtyHeight) {
+ source_rect.x0 = OsdDirtyX;
+ source_rect.y0 = OsdDirtyY;
+ source_rect.x1 = source_rect.x0 + OsdDirtyWidth;
+ source_rect.y1 = source_rect.y0 + OsdDirtyHeight;
+
+ output_rect.x0 = (OsdDirtyX * VideoWindowWidth) / OsdWidth;
+ output_rect.y0 = (OsdDirtyY * VideoWindowHeight) / OsdHeight;
+ output_rect.x1 =
+ output_rect.x0 + (OsdDirtyWidth * VideoWindowWidth) / OsdWidth;
+ output_rect.y1 =
+ output_rect.y0 + (OsdDirtyHeight * VideoWindowHeight) / OsdHeight;
+ } else {
+ source_rect.x0 = 0;
+ source_rect.y0 = 0;
+ source_rect.x1 = OsdWidth;
+ source_rect.y1 = OsdHeight;
- output_rect.x0 = 0;
- output_rect.y0 = 0;
- output_rect.x1 = VideoWindowWidth;
- output_rect.y1 = VideoWindowHeight;
+ output_rect.x0 = 0;
+ output_rect.y0 = 0;
+ output_rect.x1 = VideoWindowWidth;
+ output_rect.y1 = VideoWindowHeight;
+ }
//start = GetMsTicks();
@@ -5645,7 +5735,7 @@ static void VdpauDisplayFrame(void)
//
// add osd to surface
//
- if (VdpauShowOsd) { // showing costs performance
+ if (OsdShown) { // showing costs performance
VdpauMixOsd();
}
//
@@ -5879,6 +5969,8 @@ static void VdpauSetOutputPosition(VdpauDecoder * decoder, int x, int y,
// VDPAU OSD
//----------------------------------------------------------------------------
+static const uint8_t OsdZeros[1920 * 1080 * 4]; ///< 0 for clear osd
+
///
/// Clear subpicture image.
///
@@ -5887,7 +5979,6 @@ static void VdpauSetOutputPosition(VdpauDecoder * decoder, int x, int y,
static void VdpauOsdClear(void)
{
VdpStatus status;
- void *image;
void const *data[1];
uint32_t pitches[1];
VdpRect dst_rect;
@@ -5903,16 +5994,27 @@ static void VdpauOsdClear(void)
}
#endif
- Debug(3, "video/vdpau: clear image\n");
-
- image = calloc(4, VdpauOsdWidth * VdpauOsdHeight);
-
- dst_rect.x0 = 0;
- dst_rect.y0 = 0;
- dst_rect.x1 = dst_rect.x0 + VdpauOsdWidth;
- dst_rect.y1 = dst_rect.y0 + VdpauOsdHeight;
- data[0] = image;
- pitches[0] = VdpauOsdWidth * 4;
+ if (OsdWidth * OsdHeight > 1920 * 1080) {
+ Error(_("video/vdpau: osd too big: unsupported\n"));
+ return;
+ }
+ // have dirty area.
+ if (OsdDirtyWidth && OsdDirtyHeight) {
+ Debug(3, "video/vdpau: osd clear dirty %dx%d+%d+%d\n", OsdDirtyWidth,
+ OsdDirtyHeight, OsdDirtyX, OsdDirtyY);
+ dst_rect.x0 = OsdDirtyX;
+ dst_rect.y0 = OsdDirtyY;
+ dst_rect.x1 = dst_rect.x0 + OsdDirtyWidth;
+ dst_rect.y1 = dst_rect.y0 + OsdDirtyHeight;
+ } else {
+ Debug(3, "video/vdpau: osd clear image\n");
+ dst_rect.x0 = 0;
+ dst_rect.y0 = 0;
+ dst_rect.x1 = dst_rect.x0 + OsdWidth;
+ dst_rect.y1 = dst_rect.y0 + OsdHeight;
+ }
+ data[0] = OsdZeros;
+ pitches[0] = OsdWidth * 4;
#ifdef USE_BITMAP
status =
@@ -5931,9 +6033,6 @@ static void VdpauOsdClear(void)
VdpauGetErrorString(status));
}
#endif
-
- free(image);
- VdpauShowOsd = 0;
}
///
@@ -5954,6 +6053,8 @@ static void VdpauUploadImage(int x, int y, int width, int height,
void const *data[1];
uint32_t pitches[1];
VdpRect dst_rect;
+ uint32_t start;
+ uint32_t end;
// osd image available?
#ifdef USE_BITMAP
@@ -5966,7 +6067,7 @@ static void VdpauUploadImage(int x, int y, int width, int height,
}
#endif
- Debug(3, "video/vdpau: upload image\n");
+ start = GetMsTicks();
dst_rect.x0 = x;
dst_rect.y0 = y;
@@ -5992,7 +6093,10 @@ static void VdpauUploadImage(int x, int y, int width, int height,
VdpauGetErrorString(status));
}
#endif
- VdpauShowOsd = 1;
+ end = GetMsTicks();
+
+ Debug(3, "video/vdpau: osd upload %dx%d+%d+%d %d ms %d\n", width, height,
+ x, y, end - start, width * height * 4);
}
///
@@ -6010,16 +6114,12 @@ static void VdpauOsdInit(int width, int height)
Debug(3, "video/vdpau: vdpau not setup\n");
return;
}
-
- VdpauOsdWidth = width;
- VdpauOsdHeight = height;
-
//
// create bitmap/surface for osd
//
#ifdef USE_BITMAP
if (VdpauOsdBitmapSurface[0] == VDP_INVALID_HANDLE) {
- for (i = 0; i < 2; ++i) {
+ for (i = 0; i < 1; ++i) {
status =
VdpauBitmapSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
width, height, VDP_TRUE, VdpauOsdBitmapSurface + i);
@@ -6034,7 +6134,7 @@ static void VdpauOsdInit(int width, int height)
}
#else
if (VdpauOsdOutputSurface[0] == VDP_INVALID_HANDLE) {
- for (i = 0; i < 2; ++i) {
+ for (i = 0; i < 1; ++i) {
status =
VdpauOutputSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
width, height, VdpauOsdOutputSurface + i);
@@ -6048,10 +6148,7 @@ static void VdpauOsdInit(int width, int height)
}
}
#endif
-
Debug(3, "video/vdpau: osd surfaces created\n");
-
- VdpauOsdClear();
}
///
@@ -6059,7 +6156,38 @@ static void VdpauOsdInit(int width, int height)
///
static void VdpauOsdExit(void)
{
- Debug(3, "FIXME: %s\n", __FUNCTION__);
+ int i;
+
+ //
+ // destroy osd bitmap/output surfaces
+ //
+#ifdef USE_BITMAP
+ for (i = 0; i < 1; ++i) {
+ VdpStatus status;
+
+ if (VdpauOsdBitmapSurface[i] != VDP_INVALID_HANDLE) {
+ status = VdpauBitmapSurfaceDestroy(VdpauOsdBitmapSurface[i]);
+ if (status != VDP_STATUS_OK) {
+ Error(_("video/vdpau: can't destroy bitmap surface: %s\n"),
+ VdpauGetErrorString(status));
+ }
+ VdpauOsdBitmapSurface[i] = VDP_INVALID_HANDLE;
+ }
+ }
+#else
+ for (i = 0; i < 1; ++i) {
+ VdpStatus status;
+
+ if (VdpauOsdOutputSurface[i] != VDP_INVALID_HANDLE) {
+ status = VdpauOutputSurfaceDestroy(VdpauOsdOutputSurface[i]);
+ if (status != VDP_STATUS_OK) {
+ Error(_("video/vdpau: can't destroy output surface: %s\n"),
+ VdpauGetErrorString(status));
+ }
+ VdpauOsdOutputSurface[i] = VDP_INVALID_HANDLE;
+ }
+ }
+#endif
}
#endif
@@ -6068,10 +6196,6 @@ static void VdpauOsdExit(void)
// OSD
//----------------------------------------------------------------------------
-//static int OsdShow; ///< flag show osd
-static int OsdWidth; ///< osd width
-static int OsdHeight; ///< osd height
-
///
/// Clear the OSD.
///
@@ -6080,6 +6204,10 @@ static int OsdHeight; ///< osd height
///
void VideoOsdClear(void)
{
+ if (!VideoThread) { // thread not yet running
+ return;
+ }
+
VideoThreadLock();
#ifdef USE_GLX
if (GlxEnabled) {
@@ -6100,6 +6228,11 @@ void VideoOsdClear(void)
#ifdef USE_VAAPI
if (VideoVaapiEnabled) {
VaapiOsdClear();
+ OsdDirtyX = OsdWidth;
+ OsdDirtyY = OsdHeight;
+ OsdDirtyWidth = 0;
+ OsdDirtyHeight = 0;
+ OsdShown = 0;
VideoThreadUnlock();
return;
}
@@ -6107,6 +6240,11 @@ void VideoOsdClear(void)
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
VdpauOsdClear();
+ OsdDirtyX = OsdWidth;
+ OsdDirtyY = OsdHeight;
+ OsdDirtyWidth = 0;
+ OsdDirtyHeight = 0;
+ OsdShown = 0;
VideoThreadUnlock();
return;
}
@@ -6123,10 +6261,36 @@ void VideoOsdClear(void)
/// @param height height of image
/// @param argb argb image
///
-void VideoOsdDrawARGB(int x, int y, int height, int width,
+void VideoOsdDrawARGB(int x, int y, int width, int height,
const uint8_t * argb)
{
+ if (!VideoThread) { // thread not yet running
+ return;
+ }
VideoThreadLock();
+
+ // update dirty area
+ if (x < OsdDirtyX) {
+ if (OsdDirtyWidth) {
+ OsdDirtyWidth += OsdDirtyX - x;
+ }
+ OsdDirtyX = x;
+ }
+ if (y < OsdDirtyY) {
+ if (OsdDirtyHeight) {
+ OsdDirtyHeight += OsdDirtyY - y;
+ }
+ OsdDirtyY = y;
+ }
+ if (x + width > OsdDirtyX + OsdDirtyWidth) {
+ OsdDirtyWidth = x + width - OsdDirtyX;
+ }
+ if (y + height > OsdDirtyY + OsdDirtyHeight) {
+ OsdDirtyHeight = y + height - OsdDirtyY;
+ }
+ Debug(3, "video: osd dirty %dx%d+%d+%d -> %dx%d+%d+%d\n", width, height, x,
+ y, OsdDirtyWidth, OsdDirtyHeight, OsdDirtyX, OsdDirtyY);
+
#ifdef USE_GLX
if (GlxEnabled) {
Debug(3, "video: %p <-> %p\n", glXGetCurrentContext(), GlxContext);
@@ -6137,15 +6301,17 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
#endif
#ifdef USE_VAAPI
if (VideoVaapiEnabled) {
- VaapiUploadImage(x, y, height, width, argb);
+ VaapiUploadImage(x, y, width, height, argb);
VideoThreadUnlock();
+ OsdShown = 1;
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
- VdpauUploadImage(x, y, height, width, argb);
+ VdpauUploadImage(x, y, width, height, argb);
VideoThreadUnlock();
+ OsdShown = 1;
return;
}
#endif
@@ -6158,6 +6324,19 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
}
///
+/// Get OSD size.
+///
+void VideoGetOsdSize(int *width, int *height)
+{
+ *width = 1920;
+ *height = 1080; // unknown default
+ if (OsdWidth && OsdHeight) {
+ *width = OsdWidth;
+ *height = OsdHeight;
+ }
+}
+
+///
/// Setup osd.
///
/// FIXME: looking for BGRA, but this fourcc isn't supported by the
@@ -6165,11 +6344,8 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
///
void VideoOsdInit(void)
{
- OsdWidth = 1920 / 1;
- OsdHeight = 1080 / 1; // worst-case
-
- //OsdWidth = 768;
- //OsdHeight = VideoWindowHeight; // FIXME: must be configured
+ OsdWidth = VideoWindowWidth; // FIXME: must be configured
+ OsdHeight = VideoWindowHeight;
#ifdef USE_GLX
// FIXME: make an extra function for this
@@ -6205,12 +6381,14 @@ void VideoOsdInit(void)
#ifdef USE_VAAPI
if (VideoVaapiEnabled) {
VaapiOsdInit(OsdWidth, OsdHeight);
+ VideoOsdClear();
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled) {
VdpauOsdInit(OsdWidth, OsdHeight);
+ VideoOsdClear();
return;
}
#endif
@@ -6223,7 +6401,7 @@ void VideoOsdExit(void)
{
#ifdef USE_VAAPI
if (VideoVaapiEnabled) {
- // FIXME: VaapiOsdExit();
+ VaapiOsdExit();
return;
}
#endif
@@ -7070,27 +7248,45 @@ void VideoSetVideoMode( __attribute__ ((unused))
int y, int width, int height)
{
Debug(3, "video: %s %dx%d%+d%+d\n", __FUNCTION__, width, height, x, y);
+
if ((unsigned)width == VideoWindowWidth
&& (unsigned)height == VideoWindowHeight) {
return; // same size nothing todo
}
+
+ if (!VideoThread) { // thread not yet running
+ return;
+ }
+ //VideoThreadLock(); // FIXME: vaapi can crash
+
VideoWindowWidth = width;
VideoWindowHeight = height;
#ifdef USE_VAAPI
if (VideoVaapiEnabled && VaapiDecoders[0]) {
- // FIXME: must update osd surfaces?
+ VaapiDeassociate(VaapiDecoders[0]);
+ VideoOsdExit();
+ VideoOsdInit();
+ if (VaapiDecoders[0]->InputWidth && VaapiDecoders[0]->InputHeight) {
+ VaapiAssociate(VaapiDecoders[0], VaapiDecoders[0]->InputWidth,
+ VaapiDecoders[0]->InputHeight);
+ }
VaapiUpdateOutput(VaapiDecoders[0]);
+ //VideoThreadUnlock();
return;
}
#endif
#ifdef USE_VDPAU
if (VideoVdpauEnabled && VdpauDecoders[0]) {
VdpauExitOutputQueue();
+ VideoOsdExit();
+ VideoOsdInit();
VdpauInitOutputQueue();
VdpauUpdateOutput(VdpauDecoders[0]);
+ //VideoThreadUnlock();
return;
}
#endif
+ //VideoThreadUnlock();
}
///
diff --git a/video.h b/video.h
index b76dc5c..f26cbd2 100644
--- a/video.h
+++ b/video.h
@@ -103,6 +103,9 @@ extern void VideoOsdClear(void);
/// Draw an OSD ARGB image.
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
+ /// Get OSD size.
+extern void VideoGetOsdSize(int *, int *);
+
extern int64_t VideoGetClock(void); ///< Get video clock.
extern void VideoOsdInit(void); ///< Setup osd.