From c6e66e0787f62fdf74dde43dcc88818f80b7334e Mon Sep 17 00:00:00 2001 From: Johns Date: Wed, 18 Jan 2012 15:15:37 +0100 Subject: [PATCH] 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, ... --- ChangeLog | 5 + Todo | 15 +- softhddev.c | 15 +- softhddevice.cpp | 79 ++++++--- video.c | 450 ++++++++++++++++++++++++++++++++++------------- video.h | 3 + 6 files changed, 399 insertions(+), 168 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 #include @@ -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; @@ -1009,6 +1018,92 @@ static void VaapiDestroyDeinterlaceImages(VaapiDecoder *); // 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. /// @@ -1039,27 +1134,7 @@ static void VaapiCreateSurfaces(VaapiDecoder * decoder, int width, int height) // // update OSD associate // - if (VaOsdSubpicture == VA_INVALID_ID) { - 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")); - } - } + VaapiAssociate(decoder, width, height); } /// @@ -1074,23 +1149,7 @@ static void VaapiDestroySurfaces(VaapiDecoder * decoder) // // update OSD associate // - 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); - } - } + 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 = 0; - output_rect.y0 = 0; - output_rect.x1 = VideoWindowWidth; - output_rect.y1 = VideoWindowHeight; + 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; + } //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 @@ -6157,6 +6323,19 @@ void VideoOsdDrawARGB(int x, int y, int height, int width, 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. /// @@ -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.