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, ...
This commit is contained in:
Johns 2012-01-18 15:15:37 +01:00
parent 19d4eeed82
commit c6e66e0787
6 changed files with 399 additions and 168 deletions

View File

@ -1,6 +1,11 @@
User johns User johns
Date: 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 software deinterlace with VA-API.
Fix bug: transposed digits 567 should be 576. Fix bug: transposed digits 567 should be 576.
Audio module cleanup: Audio module cleanup:

15
Todo
View File

@ -19,23 +19,20 @@ GNU Affero General Public License for more details.
$Id: $ $Id: $
missing: missing:
software deinterlace software deinterlace (yadif, ...)
software decoder with software deinterlace
auto crop auto crop
zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?) zoom/fit-zoom 4:3 (SetVideoDisplayFormat, SetVideoFormat?)
ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)? ITU BT601, ITU BT709 (HD), RGB studio levels (16-235)?
suspend output / energie saver: stop audio, stop video, configurable suspend output / energie saver: stop audio, stop video, configurable
Option deinterlace off / deinterlace force! Option deinterlace off / deinterlace force!
Make output drivers better moduluar. Make output drivers better modular.
video: video:
subtitle not cleared subtitle not cleared
subtitle could be asyncron subtitle could be asyncron
vdpau: 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 VdpPreemptionCallback handling
hard channel switch hard channel switch
suspendoutput didn't show logo or black picture. suspendoutput didn't show logo or black picture.
@ -43,15 +40,15 @@ vdpau:
libva: libva:
hard channel switch hard channel switch
yaepghd (VaapiSetOutputPosition) support yaepghd (VaapiSetOutputPosition) support
can associate ony displayed part of osd
libva-intel-driver: libva-intel-driver:
intel still has hangups most with 1080i intel still has hangups most with 1080i
1080i does no v-sync (workaround written) 1080i does no v-sync (workaround written)
osd has sometimes wrong size (workaround written) OSD has sometimes wrong size (workaround written)
libva-vdpau-driver: libva-vdpau-driver:
G210 osd update too slow (needs hardware problem workaround) G210/GT520 OSD update too slow (needs hardware problem workaround)
OSD update is too slow
hangup on exit (VaapiDelDecoder -> VaapiCleanup hangup on exit (VaapiDelDecoder -> VaapiCleanup
-> vaDestroyContext -> pthread_rwlock_wrlock) -> vaDestroyContext -> pthread_rwlock_wrlock)

View File

@ -913,22 +913,19 @@ int Flush(int timeout)
void GetOsdSize(int *width, int *height, double *aspect) void GetOsdSize(int *width, int *height, double *aspect)
{ {
#ifdef DEBUG #ifdef DEBUG
static char done; static int done_width;
static int done_height;
#endif #endif
// FIXME: should be configured! VideoGetOsdSize(width, height);
*width = 1920;
*height = 1080;
//*width = 768;
//*height = 576;
*aspect = 16.0 / 9.0 / (double)*width * (double)*height; *aspect = 16.0 / 9.0 / (double)*width * (double)*height;
#ifdef DEBUG #ifdef DEBUG
if (!done) { if (done_width != *width || done_height != *height) {
Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height, Debug(3, "[softhddev]%s: %dx%d %g\n", __FUNCTION__, *width, *height,
*aspect); *aspect);
done = 1; done_width = *width;
done_height = *height;
} }
#endif #endif
} }

View File

@ -53,6 +53,7 @@ static class cSoftHdDevice *MyDevice;
#define RESOLUTIONS 4 ///< number of resolutions #define RESOLUTIONS 4 ///< number of resolutions
/// resolutions names
static const char *const Resolution[RESOLUTIONS] = { static const char *const Resolution[RESOLUTIONS] = {
"576i", "720p", "1080i_fake", "1080i" "576i", "720p", "1080i_fake", "1080i"
}; };
@ -158,8 +159,15 @@ cSoftOsd::~cSoftOsd(void)
SetActive(false); SetActive(false);
#ifdef USE_YAEPG #ifdef USE_YAEPG
if (vidWin.bpp) { // support yaepghd, video window
VideoSetOutputPosition(0, 0, 1920, 1080); 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 #endif
OsdClose(); OsdClose();
@ -175,8 +183,8 @@ void cSoftOsd::Flush(void)
if (!Active()) { if (!Active()) {
return; return;
} }
// support yaepghd, video window
#ifdef USE_YAEPG #ifdef USE_YAEPG
// support yaepghd, video window
if (vidWin.bpp) { if (vidWin.bpp) {
dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(), dsyslog("[softhddev]%s: %dx%d+%d+%d\n", __FUNCTION__, vidWin.Width(),
vidWin.Height(), vidWin.x1, vidWin.y2); vidWin.Height(), vidWin.x1, vidWin.y2);
@ -213,6 +221,7 @@ void cSoftOsd::Flush(void)
if (!bitmap->Dirty(x1, y1, x2, y2)) { if (!bitmap->Dirty(x1, y1, x2, y2)) {
continue; // nothing dirty continue continue; // nothing dirty continue
} }
#if 0
// FIXME: need only to convert and upload dirty areas // FIXME: need only to convert and upload dirty areas
// DrawBitmap(bitmap); // DrawBitmap(bitmap);
@ -225,7 +234,6 @@ void cSoftOsd::Flush(void)
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y); ((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
} }
} }
// check if subtitles // check if subtitles
if (this->Level == OSD_LEVEL_SUBTITLES) { if (this->Level == OSD_LEVEL_SUBTITLES) {
int video_width; int video_width;
@ -238,12 +246,32 @@ void cSoftOsd::Flush(void)
video_width = 1920; video_width = 1920;
video_height = 1080; video_height = 1080;
OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(), OsdDrawARGB((1920 - video_width) / 2 + Left() + bitmap->X0(),
1080 - video_height + Top() + bitmap->Y0(), 1080 - video_height + Top() + bitmap->Y0(), w, h, argb);
bitmap->Width(), bitmap->Height(), argb);
} else { } else {
OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), OsdDrawARGB(Left() + bitmap->X0(), Top() + bitmap->Y0(), w, h,
bitmap->Width(), bitmap->Height(), argb); 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(); bitmap->Clean();
free(argb); free(argb);
@ -475,12 +503,7 @@ class cSoftHdDevice:public cDevice
virtual bool Poll(cPoller &, int = 0); virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0); virtual bool Flush(int = 0);
virtual int64_t GetSTC(void); virtual int64_t GetSTC(void);
virtual void GetVideoSize(int &width, int &height, double &aspect) virtual void GetVideoSize(int &, int &, double &);
{
width = 1920;
height = 1080;
aspect = (double)width / height;
}
virtual void GetOsdSize(int &, int &, double &); virtual void GetOsdSize(int &, int &, double &);
virtual int PlayVideo(const uchar *, int); virtual int PlayVideo(const uchar *, int);
@ -536,18 +559,17 @@ void cSoftHdDevice::MakePrimaryDevice(bool on)
} }
} }
int cSoftHdDevice::ProvidesCa( int cSoftHdDevice::ProvidesCa(
__attribute__ ((unused)) const cChannel * __attribute__ ((unused)) const cChannel * channel) const
channel) const {
{ //dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
//dsyslog("[softhddev]%s: %p\n", __FUNCTION__, channel);
return 0; return 0;
} }
#if 0 #if 0
cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void) cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
{ {
dsyslog("[softhddev]%s:\n", __FUNCTION__); 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)? ** FIXME: Called every second, for nothing (no OSD displayed)?
*/ */

450
video.c
View File

@ -25,7 +25,7 @@
/// ///
/// This module contains all video rendering functions. /// 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 /// Uses Xlib where it is needed for VA-API or vdpau. XCB is used for
/// everything else. /// everything else.
@ -36,16 +36,16 @@
/// - Xrender rendering /// - Xrender rendering
/// ///
#define USE_XLIB_XCB #define USE_XLIB_XCB ///< use xlib/xcb backend
#define noUSE_GRAB #define noUSE_GRAB ///< experimental grab code
#define noUSE_GLX #define noUSE_GLX ///< outdated GLX code
#define noUSE_DOUBLEBUFFER #define noUSE_DOUBLEBUFFER ///< use GLX double buffers
//#define USE_VAAPI ///< enable vaapi support //#define USE_VAAPI ///< enable vaapi support
//#define USE_VDPAU ///< enable vdpau support //#define USE_VDPAU ///< enable vdpau support
#define noUSE_BITMAP ///< use vdpau bitmap surface #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/time.h>
#include <sys/shm.h> #include <sys/shm.h>
@ -275,6 +275,14 @@ static pthread_mutex_t VideoLockMutex; ///< video lock mutex
#endif #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 // Functions
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -863,8 +871,9 @@ static void AutoCropDetect(int width, int height, void *data[3],
{ {
const void *data_y; const void *data_y;
unsigned length_y; unsigned length_y;
int x;
int y; //int x;
//int y;
int x1; int x1;
int x2; int x2;
int y1; int y1;
@ -1009,6 +1018,92 @@ static void VaapiDestroyDeinterlaceImages(VaapiDecoder *);
// Surfaces ------------------------------------------------------------- // Surfaces -------------------------------------------------------------
///
/// Associate OSD with surface.
///
/// @param decoder VA-API decoder
/// @param width surface source/video width
/// @param height surface source/video height
///
static void VaapiAssociate(VaapiDecoder * decoder, int width, int height)
{
int x;
int y;
int w;
int h;
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 (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 (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"));
}
}
}
///
/// Deassociate OSD with surface.
///
/// @param decoder VA-API decoder
///
static void VaapiDeassociate(VaapiDecoder * decoder)
{
if (VaOsdSubpicture != VA_INVALID_ID) {
if (decoder->SurfaceFreeN
&& vaDeassociateSubpicture(VaDisplay, VaOsdSubpicture,
decoder->SurfacesFree, decoder->SurfaceFreeN)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't deassociate %d surfaces\n"),
decoder->SurfaceFreeN);
}
if (decoder->SurfaceUsedN
&& vaDeassociateSubpicture(VaDisplay, VaOsdSubpicture,
decoder->SurfacesUsed, decoder->SurfaceUsedN)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't deassociate %d surfaces\n"),
decoder->SurfaceUsedN);
}
}
}
/// ///
/// Create surfaces for VA-API decoder. /// Create surfaces for VA-API decoder.
/// ///
@ -1039,27 +1134,7 @@ static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height)
// //
// update OSD associate // update OSD associate
// //
if (VaOsdSubpicture == VA_INVALID_ID) { VaapiAssociate(decoder, width, height);
Warning(_("video/vaapi: no osd subpicture yet\n"));
return;
}
// 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)
!= 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)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't associate subpicture\n"));
}
}
} }
/// ///
@ -1074,23 +1149,7 @@ static void VaapiDestroySurfaces(VaapiDecoder * decoder)
// //
// update OSD associate // update OSD associate
// //
if (VaOsdSubpicture != VA_INVALID_ID) { VaapiDeassociate(decoder);
if (decoder->SurfaceFreeN
&& vaDeassociateSubpicture(VaDisplay, VaOsdSubpicture,
decoder->SurfacesFree, decoder->SurfaceFreeN)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't deassociate %d surfaces\n"),
decoder->SurfaceFreeN);
}
if (decoder->SurfaceUsedN
&& vaDeassociateSubpicture(VaDisplay, VaOsdSubpicture,
decoder->SurfacesUsed, decoder->SurfaceUsedN)
!= VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't deassociate %d surfaces\n"),
decoder->SurfaceUsedN);
}
}
if (vaDestroySurfaces(decoder->VaDisplay, decoder->SurfacesFree, if (vaDestroySurfaces(decoder->VaDisplay, decoder->SurfacesFree,
decoder->SurfaceFreeN) decoder->SurfaceFreeN)
@ -1525,23 +1584,6 @@ static void VideoVaapiExit(void)
} }
VaapiDecoderN = 0; 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) { if (!VaDisplay) {
vaTerminate(VaDisplay); vaTerminate(VaDisplay);
VaDisplay = NULL; VaDisplay = NULL;
@ -3384,8 +3426,20 @@ static void VaapiOsdClear(void)
Error(_("video/vaapi: can't map osd image buffer\n")); Error(_("video/vaapi: can't map osd image buffer\n"));
return; return;
} }
// 100% transparent // have dirty area.
memset(image_buffer, 0x00, VaOsdImage.data_size); 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) { if (vaUnmapBuffer(VaDisplay, VaOsdImage.buf) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't unmap osd image buffer\n")); 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, static void VaapiUploadImage(int x, int y, int width, int height,
const uint8_t * argb) const uint8_t * argb)
{ {
uint32_t start;
uint32_t end;
void *image_buffer; void *image_buffer;
int o; int o;
@ -3414,17 +3470,13 @@ static void VaapiUploadImage(int x, int y, int width, int height,
return; return;
} }
Debug(3, "video/vaapi: upload image\n"); start = GetMsTicks();
// map osd surface/image into memory. // map osd surface/image into memory.
if (vaMapBuffer(VaDisplay, VaOsdImage.buf, &image_buffer) if (vaMapBuffer(VaDisplay, VaOsdImage.buf, &image_buffer)
!= VA_STATUS_SUCCESS) { != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't map osd image buffer\n")); Error(_("video/vaapi: can't map osd image buffer\n"));
return; return;
} }
// 100% transparent
//memset(image_buffer, 0x00, VaOsdImage.data_size);
// FIXME: convert image from ARGB to subpicture format, if not argb // FIXME: convert image from ARGB to subpicture format, if not argb
// copy argb to image // 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) { if (vaUnmapBuffer(VaDisplay, VaOsdImage.buf) != VA_STATUS_SUCCESS) {
Error(_("video/vaapi: can't unmap osd image buffer\n")); 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. // FIXME: must store format, to convert ARGB to it.
VaapiOsdClear();
// FIXME: unlock // 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 #endif
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -3629,10 +3707,6 @@ static int VdpauSkipChroma; ///< skip chroma deint. supported
static VdpOutputSurface VdpauSurfacesRb[OUTPUT_SURFACES_MAX]; static VdpOutputSurface VdpauSurfacesRb[OUTPUT_SURFACES_MAX];
static int VdpauSurfaceIndex; ///< current display surface 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 #ifdef USE_BITMAP
/// bitmap surfaces for osd /// bitmap surfaces for osd
static VdpBitmapSurface VdpauOsdBitmapSurface[2] = { static VdpBitmapSurface VdpauOsdBitmapSurface[2] = {
@ -4947,8 +5021,6 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
decoder->InputAspect = video_ctx->sample_aspect_ratio; decoder->InputAspect = video_ctx->sample_aspect_ratio;
VdpauUpdateOutput(decoder); VdpauUpdateOutput(decoder);
VdpauMixerSetup(decoder);
// FIXME: need only to create and destroy surfaces for size changes // FIXME: need only to create and destroy surfaces for size changes
// or when number of needed surfaces changed! // or when number of needed surfaces changed!
decoder->Resolution = decoder->Resolution =
@ -4956,6 +5028,8 @@ static enum PixelFormat Vdpau_get_format(VdpauDecoder * decoder,
decoder->Interlaced); decoder->Interlaced);
VdpauCreateSurfaces(decoder, video_ctx->width, video_ctx->height); 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])); Debug(3, "\t%#010x %s\n", fmt_idx[0], av_get_pix_fmt_name(fmt_idx[0]));
return *fmt_idx; return *fmt_idx;
@ -4983,12 +5057,13 @@ static void VdpauSetup(VdpauDecoder * decoder,
// decoder->Input... already setup by caller // decoder->Input... already setup by caller
VdpauCleanup(decoder); VdpauCleanup(decoder);
VdpauMixerSetup(decoder);
decoder->Resolution = decoder->Resolution =
VideoResolutionGroup(video_ctx->width, video_ctx->height, VideoResolutionGroup(video_ctx->width, video_ctx->height,
decoder->Interlaced); decoder->Interlaced);
VdpauCreateSurfaces(decoder, video_ctx->width, video_ctx->height); VdpauCreateSurfaces(decoder, video_ctx->width, video_ctx->height);
VdpauMixerSetup(decoder);
// get real surface size // get real surface size
status = status =
VdpauVideoSurfaceGetParameters(decoder->SurfacesFree[0], &chroma_type, VdpauVideoSurfaceGetParameters(decoder->SurfacesFree[0], &chroma_type,
@ -5323,15 +5398,30 @@ static void VdpauMixOsd(void)
blend_state.blend_equation_alpha = blend_state.blend_equation_alpha =
VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD; VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
source_rect.x0 = 0; // FIXME: use dirty area
source_rect.y0 = 0; if (OsdDirtyWidth && OsdDirtyHeight) {
source_rect.x1 = VdpauOsdWidth; source_rect.x0 = OsdDirtyX;
source_rect.y1 = VdpauOsdHeight; source_rect.y0 = OsdDirtyY;
source_rect.x1 = source_rect.x0 + OsdDirtyWidth;
source_rect.y1 = source_rect.y0 + OsdDirtyHeight;
output_rect.x0 = 0; output_rect.x0 = (OsdDirtyX * VideoWindowWidth) / OsdWidth;
output_rect.y0 = 0; output_rect.y0 = (OsdDirtyY * VideoWindowHeight) / OsdHeight;
output_rect.x1 = VideoWindowWidth; output_rect.x1 =
output_rect.y1 = VideoWindowHeight; 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;
}
//start = GetMsTicks(); //start = GetMsTicks();
@ -5645,7 +5735,7 @@ static void VdpauDisplayFrame(void)
// //
// add osd to surface // add osd to surface
// //
if (VdpauShowOsd) { // showing costs performance if (OsdShown) { // showing costs performance
VdpauMixOsd(); VdpauMixOsd();
} }
// //
@ -5879,6 +5969,8 @@ static void VdpauSetOutputPosition(VdpauDecoder * decoder, int x, int y,
// VDPAU OSD // VDPAU OSD
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
static const uint8_t OsdZeros[1920 * 1080 * 4]; ///< 0 for clear osd
/// ///
/// Clear subpicture image. /// Clear subpicture image.
/// ///
@ -5887,7 +5979,6 @@ static void VdpauSetOutputPosition(VdpauDecoder * decoder, int x, int y,
static void VdpauOsdClear(void) static void VdpauOsdClear(void)
{ {
VdpStatus status; VdpStatus status;
void *image;
void const *data[1]; void const *data[1];
uint32_t pitches[1]; uint32_t pitches[1];
VdpRect dst_rect; VdpRect dst_rect;
@ -5903,16 +5994,27 @@ static void VdpauOsdClear(void)
} }
#endif #endif
Debug(3, "video/vdpau: clear image\n"); if (OsdWidth * OsdHeight > 1920 * 1080) {
Error(_("video/vdpau: osd too big: unsupported\n"));
image = calloc(4, VdpauOsdWidth * VdpauOsdHeight); return;
}
dst_rect.x0 = 0; // have dirty area.
dst_rect.y0 = 0; if (OsdDirtyWidth && OsdDirtyHeight) {
dst_rect.x1 = dst_rect.x0 + VdpauOsdWidth; Debug(3, "video/vdpau: osd clear dirty %dx%d+%d+%d\n", OsdDirtyWidth,
dst_rect.y1 = dst_rect.y0 + VdpauOsdHeight; OsdDirtyHeight, OsdDirtyX, OsdDirtyY);
data[0] = image; dst_rect.x0 = OsdDirtyX;
pitches[0] = VdpauOsdWidth * 4; 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 #ifdef USE_BITMAP
status = status =
@ -5931,9 +6033,6 @@ static void VdpauOsdClear(void)
VdpauGetErrorString(status)); VdpauGetErrorString(status));
} }
#endif #endif
free(image);
VdpauShowOsd = 0;
} }
/// ///
@ -5954,6 +6053,8 @@ static void VdpauUploadImage(int x, int y, int width, int height,
void const *data[1]; void const *data[1];
uint32_t pitches[1]; uint32_t pitches[1];
VdpRect dst_rect; VdpRect dst_rect;
uint32_t start;
uint32_t end;
// osd image available? // osd image available?
#ifdef USE_BITMAP #ifdef USE_BITMAP
@ -5966,7 +6067,7 @@ static void VdpauUploadImage(int x, int y, int width, int height,
} }
#endif #endif
Debug(3, "video/vdpau: upload image\n"); start = GetMsTicks();
dst_rect.x0 = x; dst_rect.x0 = x;
dst_rect.y0 = y; dst_rect.y0 = y;
@ -5992,7 +6093,10 @@ static void VdpauUploadImage(int x, int y, int width, int height,
VdpauGetErrorString(status)); VdpauGetErrorString(status));
} }
#endif #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"); Debug(3, "video/vdpau: vdpau not setup\n");
return; return;
} }
VdpauOsdWidth = width;
VdpauOsdHeight = height;
// //
// create bitmap/surface for osd // create bitmap/surface for osd
// //
#ifdef USE_BITMAP #ifdef USE_BITMAP
if (VdpauOsdBitmapSurface[0] == VDP_INVALID_HANDLE) { if (VdpauOsdBitmapSurface[0] == VDP_INVALID_HANDLE) {
for (i = 0; i < 2; ++i) { for (i = 0; i < 1; ++i) {
status = status =
VdpauBitmapSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8, VdpauBitmapSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
width, height, VDP_TRUE, VdpauOsdBitmapSurface + i); width, height, VDP_TRUE, VdpauOsdBitmapSurface + i);
@ -6034,7 +6134,7 @@ static void VdpauOsdInit(int width, int height)
} }
#else #else
if (VdpauOsdOutputSurface[0] == VDP_INVALID_HANDLE) { if (VdpauOsdOutputSurface[0] == VDP_INVALID_HANDLE) {
for (i = 0; i < 2; ++i) { for (i = 0; i < 1; ++i) {
status = status =
VdpauOutputSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8, VdpauOutputSurfaceCreate(VdpauDevice, VDP_RGBA_FORMAT_B8G8R8A8,
width, height, VdpauOsdOutputSurface + i); width, height, VdpauOsdOutputSurface + i);
@ -6048,10 +6148,7 @@ static void VdpauOsdInit(int width, int height)
} }
} }
#endif #endif
Debug(3, "video/vdpau: osd surfaces created\n"); Debug(3, "video/vdpau: osd surfaces created\n");
VdpauOsdClear();
} }
/// ///
@ -6059,7 +6156,38 @@ static void VdpauOsdInit(int width, int height)
/// ///
static void VdpauOsdExit(void) 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 #endif
@ -6068,10 +6196,6 @@ static void VdpauOsdExit(void)
// OSD // OSD
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
//static int OsdShow; ///< flag show osd
static int OsdWidth; ///< osd width
static int OsdHeight; ///< osd height
/// ///
/// Clear the OSD. /// Clear the OSD.
/// ///
@ -6080,6 +6204,10 @@ static int OsdHeight; ///< osd height
/// ///
void VideoOsdClear(void) void VideoOsdClear(void)
{ {
if (!VideoThread) { // thread not yet running
return;
}
VideoThreadLock(); VideoThreadLock();
#ifdef USE_GLX #ifdef USE_GLX
if (GlxEnabled) { if (GlxEnabled) {
@ -6100,6 +6228,11 @@ void VideoOsdClear(void)
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoVaapiEnabled) {
VaapiOsdClear(); VaapiOsdClear();
OsdDirtyX = OsdWidth;
OsdDirtyY = OsdHeight;
OsdDirtyWidth = 0;
OsdDirtyHeight = 0;
OsdShown = 0;
VideoThreadUnlock(); VideoThreadUnlock();
return; return;
} }
@ -6107,6 +6240,11 @@ void VideoOsdClear(void)
#ifdef USE_VDPAU #ifdef USE_VDPAU
if (VideoVdpauEnabled) { if (VideoVdpauEnabled) {
VdpauOsdClear(); VdpauOsdClear();
OsdDirtyX = OsdWidth;
OsdDirtyY = OsdHeight;
OsdDirtyWidth = 0;
OsdDirtyHeight = 0;
OsdShown = 0;
VideoThreadUnlock(); VideoThreadUnlock();
return; return;
} }
@ -6123,10 +6261,36 @@ void VideoOsdClear(void)
/// @param height height of image /// @param height height of image
/// @param argb argb 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) const uint8_t * argb)
{ {
if (!VideoThread) { // thread not yet running
return;
}
VideoThreadLock(); 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 #ifdef USE_GLX
if (GlxEnabled) { if (GlxEnabled) {
Debug(3, "video: %p <-> %p\n", glXGetCurrentContext(), GlxContext); Debug(3, "video: %p <-> %p\n", glXGetCurrentContext(), GlxContext);
@ -6137,15 +6301,17 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
#endif #endif
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoVaapiEnabled) {
VaapiUploadImage(x, y, height, width, argb); VaapiUploadImage(x, y, width, height, argb);
VideoThreadUnlock(); VideoThreadUnlock();
OsdShown = 1;
return; return;
} }
#endif #endif
#ifdef USE_VDPAU #ifdef USE_VDPAU
if (VideoVdpauEnabled) { if (VideoVdpauEnabled) {
VdpauUploadImage(x, y, height, width, argb); VdpauUploadImage(x, y, width, height, argb);
VideoThreadUnlock(); VideoThreadUnlock();
OsdShown = 1;
return; return;
} }
#endif #endif
@ -6157,6 +6323,19 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
VideoThreadUnlock(); VideoThreadUnlock();
} }
///
/// Get OSD size.
///
void VideoGetOsdSize(int *width, int *height)
{
*width = 1920;
*height = 1080; // unknown default
if (OsdWidth && OsdHeight) {
*width = OsdWidth;
*height = OsdHeight;
}
}
/// ///
/// Setup osd. /// Setup osd.
/// ///
@ -6165,11 +6344,8 @@ void VideoOsdDrawARGB(int x, int y, int height, int width,
/// ///
void VideoOsdInit(void) void VideoOsdInit(void)
{ {
OsdWidth = 1920 / 1; OsdWidth = VideoWindowWidth; // FIXME: must be configured
OsdHeight = 1080 / 1; // worst-case OsdHeight = VideoWindowHeight;
//OsdWidth = 768;
//OsdHeight = VideoWindowHeight; // FIXME: must be configured
#ifdef USE_GLX #ifdef USE_GLX
// FIXME: make an extra function for this // FIXME: make an extra function for this
@ -6205,12 +6381,14 @@ void VideoOsdInit(void)
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoVaapiEnabled) {
VaapiOsdInit(OsdWidth, OsdHeight); VaapiOsdInit(OsdWidth, OsdHeight);
VideoOsdClear();
return; return;
} }
#endif #endif
#ifdef USE_VDPAU #ifdef USE_VDPAU
if (VideoVdpauEnabled) { if (VideoVdpauEnabled) {
VdpauOsdInit(OsdWidth, OsdHeight); VdpauOsdInit(OsdWidth, OsdHeight);
VideoOsdClear();
return; return;
} }
#endif #endif
@ -6223,7 +6401,7 @@ void VideoOsdExit(void)
{ {
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled) { if (VideoVaapiEnabled) {
// FIXME: VaapiOsdExit(); VaapiOsdExit();
return; return;
} }
#endif #endif
@ -7070,27 +7248,45 @@ void VideoSetVideoMode( __attribute__ ((unused))
int y, int width, int height) int y, int width, int height)
{ {
Debug(3, "video: %s %dx%d%+d%+d\n", __FUNCTION__, width, height, x, y); Debug(3, "video: %s %dx%d%+d%+d\n", __FUNCTION__, width, height, x, y);
if ((unsigned)width == VideoWindowWidth if ((unsigned)width == VideoWindowWidth
&& (unsigned)height == VideoWindowHeight) { && (unsigned)height == VideoWindowHeight) {
return; // same size nothing todo return; // same size nothing todo
} }
if (!VideoThread) { // thread not yet running
return;
}
//VideoThreadLock(); // FIXME: vaapi can crash
VideoWindowWidth = width; VideoWindowWidth = width;
VideoWindowHeight = height; VideoWindowHeight = height;
#ifdef USE_VAAPI #ifdef USE_VAAPI
if (VideoVaapiEnabled && VaapiDecoders[0]) { 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]); VaapiUpdateOutput(VaapiDecoders[0]);
//VideoThreadUnlock();
return; return;
} }
#endif #endif
#ifdef USE_VDPAU #ifdef USE_VDPAU
if (VideoVdpauEnabled && VdpauDecoders[0]) { if (VideoVdpauEnabled && VdpauDecoders[0]) {
VdpauExitOutputQueue(); VdpauExitOutputQueue();
VideoOsdExit();
VideoOsdInit();
VdpauInitOutputQueue(); VdpauInitOutputQueue();
VdpauUpdateOutput(VdpauDecoders[0]); VdpauUpdateOutput(VdpauDecoders[0]);
//VideoThreadUnlock();
return; return;
} }
#endif #endif
//VideoThreadUnlock();
} }
/// ///

View File

@ -103,6 +103,9 @@ extern void VideoOsdClear(void);
/// Draw an OSD ARGB image. /// Draw an OSD ARGB image.
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *); 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 int64_t VideoGetClock(void); ///< Get video clock.
extern void VideoOsdInit(void); ///< Setup osd. extern void VideoOsdInit(void); ///< Setup osd.