/* * video-xv.c: A plugin for the Video Disk Recorder providing output * capabilities via Xv * * Copyright Stefan Lucke, Roland Praml * * Xv code is taken from libdv http://sourceforge.net/projects/libdv/ * libdv is now LGPL. Let's see/discuss if that will get in trouble * with GPL of this plugin. * * Original copyright of display.c of libdv is: * Copyright (C) Charles 'Buck' Krasic - April 2000 * Copyright (C) Erik Walthinsen - April 2000 * * $Id: video-xv.c,v 1.76 2009-06-14 18:24:11 lucke Exp $ */ #include #include #include #include #include #include #include #include //#include #include "video-xv.h" #include "xscreensaver.h" #include "utils.h" #include "setup-softdevice.h" #define PATCH_VERSION "2007-12-25" #define NO_DIRECT_RENDERING //#define COLOR_KEY 0x00000000 #define COLOR_KEY 0x001a0f00LL int pixFormat[3]={ FOURCC_I420, FOURCC_YV12, FOURCC_YUY2}; static pthread_mutex_t xv_mutex = PTHREAD_MUTEX_INITIALIZER; cSoftRemote *xvRemote = NULL; static cScreensaver *xScreensaver = NULL; static int colorkey; static XErrorHandler old_handler = 0; static Bool got_error = False; static int XvError_Handler(Display *dpy, XErrorEvent *error) { esyslog("got error code: %d \n",error->error_code); got_error=true; if ( error->error_code == BadMatch || error->error_code== BadAlloc ) { return 0; }; if (old_handler) return (*old_handler)(dpy,error); else return 0; }; /* --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- */ cXvPortAttributeStore::cXvPortAttributeStore() { portAttributes = NULL; portAttributeSaveValues = NULL; portAttributeCurrentValues = NULL; portAttributeAtoms = NULL; portAttributeCount = 0; currBrightness = currContrast = currHue = currSaturation = 0; } /* --------------------------------------------------------------------------- */ cXvPortAttributeStore::~cXvPortAttributeStore() { Restore(); portAttributeCount = 0; if (portAttributeSaveValues) { free (portAttributeSaveValues); portAttributeSaveValues = NULL; } if (portAttributeCurrentValues) { free (portAttributeCurrentValues); portAttributeCurrentValues = NULL; } if (portAttributeAtoms) { for (int i = 0; i < portAttributeCount; ++i) { if (portAttributeAtoms[i]) { XFree((void *)portAttributeAtoms[i]); portAttributeAtoms[i] = (Atom) NULL; } } free (portAttributeAtoms); portAttributeAtoms = NULL; } portAttributeCount = 0; } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::SetXInfo(Display *dpy, XvPortID port, cSetupStore *setupStore) { this->dpy = dpy; this->port = port; this->setupStore = setupStore; } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::SetValue(const char *name, int value) { for (int i = 0; i < portAttributeCount; ++i) { if (!strcmp(name,portAttributes[i].name)) { if (value <= portAttributes[i].max_value && value >= portAttributes[i].min_value) { portAttributeCurrentValues[i] = value; XvSetPortAttribute(dpy,port,portAttributeAtoms[i],portAttributeCurrentValues[i]); } return; } } } /* --------------------------------------------------------------------------- */ int cXvPortAttributeStore::GetValuePercent(int index) { int value = portAttributeCurrentValues[index]; value = (int) (((double) value - (double) portAttributes[index].min_value) * 100.0 / ((double) portAttributes[index].max_value - (double) portAttributes[index].min_value)); if (value <= 100 && value >= 0) return value; return 0; } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::SetValuePercent(const char *name, int value) { for (int i = 0; i < portAttributeCount; ++i) { if (!strcmp(name,portAttributes[i].name)) { value = (int) ((double) portAttributes[i].min_value + ((double) portAttributes[i].max_value - (double) portAttributes[i].min_value) * (double) value / 100.0); if (value <= portAttributes[i].max_value && value >= portAttributes[i].min_value) { portAttributeCurrentValues[i] = value; XvSetPortAttribute(dpy,port,portAttributeAtoms[i],portAttributeCurrentValues[i]); } return; } } } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::SetColorkey(int value) { for (int i = 0; i < portAttributeCount; ++i) { if (!strcmp("XV_COLORKEY",portAttributes[i].name)) { portAttributeCurrentValues[i] = value; XvSetPortAttribute(dpy,port,portAttributeAtoms[i],portAttributeCurrentValues[i]); return; } } } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::Increment(const char *name) { for (int i = 0; i < portAttributeCount; ++i) { if (!strcmp(name,portAttributes[i].name)) { if (portAttributes[i].max_value > portAttributeCurrentValues[i]) { portAttributeCurrentValues[i]++; XvSetPortAttribute(dpy,port,portAttributeAtoms[i],portAttributeCurrentValues[i]); } return; } } } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::Decrement(const char *name) { for (int i = 0; i < portAttributeCount; ++i) { if (!strcmp(name,portAttributes[i].name)) { if (portAttributes[i].min_value < portAttributeCurrentValues[i]) { portAttributeCurrentValues[i]--; XvSetPortAttribute(dpy,port,portAttributeAtoms[i],portAttributeCurrentValues[i]); } return; } } } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::Save() { portAttributes = XvQueryPortAttributes(dpy,port,&portAttributeCount); if (portAttributes) { portAttributeAtoms = (Atom *) calloc(sizeof (Atom *),portAttributeCount); portAttributeCurrentValues = (int *) calloc(sizeof(int),portAttributeCount); portAttributeSaveValues = (int *) calloc(sizeof(int),portAttributeCount); for (int i = 0; i < portAttributeCount; i++) { portAttributeAtoms[i] = XInternAtom(dpy,portAttributes[i].name,False); if (portAttributes[i].flags & XvGettable) { XvGetPortAttribute(dpy,port,portAttributeAtoms[i],&portAttributeSaveValues[i]); portAttributeCurrentValues[i] = portAttributeSaveValues[i]; } if (!strcmp(portAttributes[i].name, "XV_BRIGHTNESS")) { setupStore->vidCaps |= CAP_BRIGHTNESS; if ( setupStore->xvUseDefaults || setupStore->vidBrightness<0 ) setupStore->vidBrightness = currBrightness = GetValuePercent(i); } if (!strcmp(portAttributes[i].name, "XV_CONTRAST")) { setupStore->vidCaps |= CAP_CONTRAST; if ( setupStore->xvUseDefaults || setupStore->vidContrast<0 ) setupStore->vidContrast = currContrast = GetValuePercent(i); } if (!strcmp(portAttributes[i].name, "XV_HUE")) { setupStore->vidCaps |= CAP_HUE; if ( setupStore->xvUseDefaults || setupStore->vidHue<0 ) setupStore->vidHue = currHue = GetValuePercent(i); } if (!strcmp(portAttributes[i].name, "XV_SATURATION")) { setupStore->vidCaps |= CAP_SATURATION; if ( setupStore->xvUseDefaults || setupStore->vidSaturation<0 ) setupStore->vidSaturation = currSaturation = GetValuePercent(i); } dsyslog("[XvVideoOut]:" " %-25s %-4sXvGettable %-4sXvSettable " "(%8d [0x%08x] - %8d [0x%08x]) (%8d [0x%08x]", portAttributes[i].name, (portAttributes[i].flags & XvGettable) ? "": "NOT-", (portAttributes[i].flags & XvSettable) ? "": "NOT-", portAttributes[i].min_value, portAttributes[i].min_value, portAttributes[i].max_value, portAttributes[i].max_value, portAttributeCurrentValues[i], portAttributeCurrentValues[i]); } } } /* --------------------------------------------------------------------------- */ bool cXvPortAttributeStore::HasAttribute(char *name) { for (int i = 0; i < portAttributeCount; ++i) { if (!strcmp(name,portAttributes[i].name)) { return true; } } return false; } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::CheckVideoParmChange() { int changed = 0; if (currBrightness != setupStore->vidBrightness) { changed++; currBrightness = setupStore->vidBrightness; SetValuePercent("XV_BRIGHTNESS", currBrightness); } if (currContrast != setupStore->vidContrast) { changed++; currContrast = setupStore->vidContrast; SetValuePercent("XV_CONTRAST", currContrast); } if (currHue != setupStore->vidHue) { changed++; currHue = setupStore->vidHue; SetValuePercent("XV_HUE", currHue); } if (currSaturation != setupStore->vidSaturation) { changed++; currSaturation = setupStore->vidSaturation; SetValuePercent("XV_SATURATION", currSaturation); } if (changed) XSync(dpy, False); } /* --------------------------------------------------------------------------- */ void cXvPortAttributeStore::Restore() { dsyslog("[XvVideoOut]: restoring attribute values"); for (int i = 0; i < portAttributeCount; i++) { if (portAttributes[i].flags & XvSettable) { dsyslog("[XvVideoOut]: %-25s %8d [0x%08x] ", portAttributes[i].name, portAttributeSaveValues[i], portAttributeSaveValues[i]); if (XvSetPortAttribute(dpy,port,portAttributeAtoms[i],portAttributeSaveValues[i]) != Success) { dsyslog("[XvVideoOut]: restore FAILED"); } } } if (portAttributes) XSync(dpy,False); } /* --------------------------------------------------------------------------- */ void cXvVideoOut::toggleFullScreen(void) { XEvent e; XSizeHints wmHints; Atom wmAtom; int x, y, w, h; fullScreen = !fullScreen; if (fullScreen) { // window -> fullscreen XWindowAttributes winAttr; Window dummyWin; if (XGetWindowAttributes(dpy, win, &winAttr)) { XVisualInfo vistemp, *vinfo; int dummy; vinfo = XGetVisualInfo(dpy, VisualIDMask, &vistemp, &dummy); XTranslateCoordinates (dpy, win, winAttr.root, -winAttr.border_width, -winAttr.border_width, &old_x, &old_y, &dummyWin); } else { old_x = dx; old_y = dy; } old_dwidth = dwidth; old_dheight = dheight; #if XINERAMA_SUPPORT if (xin_mode) { int i; i = (xin_screen != -1) ? xin_screen : 0; x = xin_screen_info[i]. x_org; y = xin_screen_info[i]. y_org; w = xin_screen_info[i]. width; h = xin_screen_info[i]. height; } else #endif { x = y = 0; w = DisplayWidth(dpy,DefaultScreen(dpy)); h = DisplayHeight(dpy,DefaultScreen(dpy)); } } else { // fullscreen -> window x = old_x; y = old_y; w = old_dwidth; h = old_dheight; } wmHints.flags = PSize | PPosition | PWinGravity; wmHints.win_gravity = StaticGravity; wmHints.x = x; wmHints.y = y; wmHints.width = w; wmHints.height = h; wmHints.max_width = 0; wmHints.max_height = 0; if ((wmAtom = XInternAtom (dpy, "_MOTIF_WM_HINTS", False))) { long mwmHints [5]; mwmHints [0] = 2; mwmHints [2] = (fullScreen) ? 0 : 1; mwmHints [1] = mwmHints [3] = mwmHints [4] = 0; XChangeProperty (dpy, win, wmAtom, wmAtom, 32, PropModeReplace, (unsigned char *) mwmHints, 5); } XSetWMNormalHints(dpy, win, &wmHints); memset(&e,0,sizeof(e)); e.xclient.type = ClientMessage; e.xclient.message_type = net_wm_STATE; e.xclient.display = dpy; e.xclient.window = win; e.xclient.format = 32; e.xclient.data.l[0] = (fullScreen) ? 1 : 0; if (net_wm_STATE_ABOVE) e.xclient.data.l[1] = net_wm_STATE_ABOVE; else //if (net_wm_STATE_STAYS_ON_TOP) e.xclient.data.l[1] = net_wm_STATE_STAYS_ON_TOP; if (net_wm_STATE_FULLSCREEN) e.xclient.data.l[1] = net_wm_STATE_FULLSCREEN; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureRedirectMask, &e); XReparentWindow (dpy, win, DefaultRootWindow(dpy), x, y); XMoveResizeWindow (dpy, win, x, y, w, h); //XMapRaised (dpy, win); //XRaiseWindow (dpy, win); XFlush (dpy); xScreensaver->DisableScreensaver(fullScreen); // enable of disable based on fullScreen state } /* --------------------------------------------------------------------------- */ void cXvVideoOut::AdjustDisplayRatio() { double displayAspect, displayRatio; /* -------------------------------------------------------------------------- * set PAR values */ displayAspect = (double) DisplayWidthMM(dpy, DefaultScreen(dpy)) / (double) DisplayHeightMM(dpy, DefaultScreen(dpy)); if (xin_mode) displayRatio = (double) GetScreenWidth() / (double) GetScreenHeight(); else displayRatio = (double) DisplayWidth(dpy, DefaultScreen(dpy)) / (double) DisplayHeight(dpy, DefaultScreen(dpy)); SetParValues(displayAspect, displayRatio); } /* --------------------------------------------------------------------------- */ void cXvVideoOut::AdjustXineramaScreen() { #if XINERAMA_SUPPORT XineramaScreenInfo *new_screen_info; int new_num_screens; if (!xin_mode) return; new_screen_info = XineramaQueryScreens (dpy, &new_num_screens); if (new_screen_info) { if (xin_screen_info) XFree(xin_screen_info); xin_screen_info = new_screen_info; xin_num_screens = new_num_screens; } for (int i = 0; i < xin_num_screens; ++i) { if (dx >= xin_screen_info[i]. x_org && dx <= (xin_screen_info[i]. x_org + xin_screen_info[i]. width) && dy >= xin_screen_info[i]. y_org && dy <= (xin_screen_info[i]. y_org + xin_screen_info[i]. height)) { if (i != xin_screen) { fprintf(stderr, "[XvVideoOut]: Xinerama-Screen changed to %d\n", i); xin_screen = i; } break; } } AdjustDisplayRatio(); #endif } /* --------------------------------------------------------------------------- */ int cXvVideoOut::GetScreenWidth() { #if XINERAMA_SUPPORT if (xin_mode) return xin_screen_info[(xin_screen != -1) ? xin_screen : 0]. width; #endif return DisplayWidth(dpy,DefaultScreen(dpy)); } /* --------------------------------------------------------------------------- */ int cXvVideoOut::GetScreenHeight() { #if XINERAMA_SUPPORT if (xin_mode) return xin_screen_info[(xin_screen != -1) ? xin_screen : 0]. height; #endif return DisplayHeight(dpy,DefaultScreen(dpy)); } //#define EVDEB(out...) {printf("EVDEB:");printf(out);} #define EVDEB(out...) /* --------------------------------------------------------------------------- */ void cXvVideoOut::ProcessEvents () { char buffer [80]; int map_count = 0; XComposeStatus compose; KeySym keysym; struct timeval current_time; XEvent event; if (!videoInitialized) return; pthread_mutex_lock(&xv_mutex); while (XCheckMaskEvent (dpy, /* win, */ PointerMotionMask | ButtonPressMask | KeyPressMask | ExposureMask | ConfigureNotify | StructureNotifyMask, &event)) { switch (event.type) { case MotionNotify: case ButtonPress: gettimeofday(¤t_time, NULL); motion_time = current_time.tv_sec; if(event.xbutton.button==Button1) { if(button_time - current_time.tv_sec == 0) { toggleFullScreen(); } button_time = current_time.tv_sec; } if(cursor_visible == False) { XUndefineCursor(dpy, win); cursor_visible = True; } break; case ConfigureNotify: EVDEB("ConfigureNotify\n"); map_count++; dx = event.xconfigure.x; dy = event.xconfigure.y; dwidth = event.xconfigure.width; dheight = event.xconfigure.height; AdjustXineramaScreen(); RecalculateAspect(); if (toggleInProgress && ((fullScreen && dwidth == GetScreenWidth() && dheight == GetScreenHeight()) || (!fullScreen && dwidth == old_dwidth && dheight == old_dheight))) { toggleInProgress = 0; } break; case KeyPress: XLookupString (&event.xkey, buffer, 80, &keysym, &compose); switch (keysym) { case XK_Shift_L: case XK_Shift_R: case XK_Control_L: case XK_Control_R: case XK_Caps_Lock: case XK_Shift_Lock: case XK_Meta_L: case XK_Meta_R: case XK_Alt_L: case XK_Alt_R: break; case 'f': if (!toggleInProgress) { toggleFullScreen(); toggleInProgress++; } break; case 'b': if (xv_initialized) attributeStore.Decrement("XV_BRIGHTNESS"); break; case 'B': if (xv_initialized) attributeStore.Increment("XV_BRIGHTNESS"); break; case 'c': if (xv_initialized) attributeStore.Decrement("XV_CONTRAST"); break; case 'C': if (xv_initialized) attributeStore.Increment("XV_CONTRAST"); break; case 'h': if (xv_initialized) attributeStore.Decrement("XV_HUE"); break; case 'H': if (xv_initialized) attributeStore.Increment("XV_HUE"); break; case 's': if (xv_initialized) attributeStore.Decrement("XV_SATURATION"); break; case 'S': if (xv_initialized) attributeStore.Increment("XV_SATURATION"); break; case 'o': if (xv_initialized) attributeStore.Decrement("XV_OVERLAY_ALPHA"); break; case 'O': if (xv_initialized) attributeStore.Increment("XV_OVERLAY_ALPHA"); break; case 'g': if (xv_initialized) attributeStore.Decrement("XV_GRAPHICS_ALPHA"); break; case 'G': if (xv_initialized) attributeStore.Increment("XV_GRAPHICS_ALPHA"); break; case 'a': if (xv_initialized) attributeStore.Decrement("XV_ALPHA_MODE"); break; case 'A': if (xv_initialized) attributeStore.Increment("XV_ALPHA_MODE"); break; #ifdef SUSPEND_BY_KEY case 'r': case 'R': setupStore->shouldSuspend=!setupStore->shouldSuspend; #endif default: if (xvRemote) { if ( CatchRemoteKey(xvRemote->Name(), keysym, setupStore->cropModeToggleKey) ) { setupStore->CropModeNext(); } else { xvRemote->PutKey(keysym); }; } break; } break; case MapNotify: EVDEB("MapNotify\n"); map_count++; if (videoInitialized) { XSetInputFocus(dpy, win, RevertToParent, CurrentTime); } break; case UnmapNotify: EVDEB("UnmapNotify\n"); if (xv_initialized) XvStopVideo (dpy,port,win); if(cursor_visible == False) { XUndefineCursor(dpy, win); cursor_visible = True; } break; case Expose: EVDEB("Expose\n"); map_count++; break; default: EVDEB("unhandled event: %d\n",event.type); break; } } if (xv_initialized) { if (map_count) { XClearArea (dpy, win, 0, 0, 0, 0, False); ShowOSD(); PutXvImage(xv_image,privBuf.edge_width,privBuf.edge_height); XSync(dpy, False); } attributeStore.CheckVideoParmChange(); } if(cursor_visible == True) { gettimeofday(¤t_time, NULL); if(current_time.tv_sec - motion_time >= 2) { XDefineCursor(dpy, win, hidden_cursor); cursor_visible = False; } } xScreensaver->MaybeSendDeactivate(); xScreensaver->MaybeSendKeyEvent(); pthread_mutex_unlock(&xv_mutex); } /* --------------------------------------------------------------------------- */ cXvVideoOut::cXvVideoOut(cSetupStore *setupStore, cSetupSoftlog *Softlog) : cVideoOut(setupStore, Softlog) { OSDpresent = false; OSDpseudo_alpha = true; needsFullOSDRedraw = false; toggleInProgress = 0; xv_initialized=false; /* ------------------------------------------------------------------------- * could be specified by argv ! TODO */ display_aspect = current_aspect = setupStore->xvAspect; screenPixelAspect = -1; xvWidth = width = XV_SRC_WIDTH; xvHeight = height = XV_SRC_HEIGHT; format = FOURCC_YV12; use_xv_port = 0; w_name = strdup ("vdr"); i_name = strdup ("vdr"); Xres=width; Yres=height; xin_mode = false; xin_screen = -1; #if XINERAMA_SUPPORT xin_screen_info = NULL; #endif /* * default settings: source, destination and logical widht/height * are set to our well known dimensions. */ fwidth = lwidth = old_dwidth = dwidth = swidth = width; fheight = lheight = old_dheight = dheight = sheight = height; if (current_aspect == DV_FORMAT_NORMAL) { lwidth = dwidth = XV_DEST_WIDTH_4_3; lheight = dheight = XV_DEST_HEIGHT; } else { lwidth = dwidth = XV_DEST_WIDTH_16_9; } for (int i=0; i 0; } else { fprintf (stderr, "[XvVideoOut]: NO Xinerama Screens present\n"); } } #endif /* ------------------------------------------------------------------------- * limit widht and height to screen dimensions */ { int screen_width, screen_height; screen_width = DisplayWidth(dpy, scn_id); screen_height = DisplayHeight(dpy, scn_id); if (height > screen_height) old_dheight = lheight = dheight = height = screen_height; if (width > screen_width) old_dwidth = lwidth = dwidth = width = screen_width; } /* ------------------------------------------------------------------------- * default settings which allow arbitraray resizing of the window */ hints.flags = PSize | PMaxSize | PMinSize; hints.min_width = width / 16; hints.min_height = height / 16; /* ------------------------------------------------------------------------- * maximum dimensions for Xv support are about 2048x2048 */ hints.max_width = 2048; hints.max_height = 2048; wmhints.input = True; wmhints.flags = InputHint; XStringListToTextProperty(&w_name, 1 ,&x_wname); XStringListToTextProperty(&i_name, 1 ,&x_iname); AdjustDisplayRatio(); if (flags & XV_FORMAT_MASK) { hints.flags |= PAspect; if (flags & XV_FORMAT_WIDE) { hints.min_aspect.x = hints.max_aspect.x = XV_DEST_WIDTH_16_9; } else { hints.min_aspect.x = hints.max_aspect.x = XV_DEST_WIDTH_4_3; } hints.min_aspect.y = hints.max_aspect.y = XV_DEST_HEIGHT; } win = XCreateSimpleWindow(dpy, rwin, 0, 0, dwidth, dheight, 0, XWhitePixel(dpy, scn_id), XBlackPixel(dpy, scn_id)); XSetWMProperties(dpy, win, &x_wname, &x_iname, NULL, 0, &hints, &wmhints, NULL); XSelectInput(dpy, win, KeyPressMask | ExposureMask | ConfigureNotify | StructureNotifyMask | PointerMotionMask | ButtonPressMask); XMapRaised(dpy, win); //XNextEvent(dpy, &event); gc = XCreateGC(dpy, win, 0, &values); /* * Create transparent cursor */ Pixmap cursor_mask; XColor dummy_col; const char cursor_data[] = { 0x0 }; cursor_mask = XCreateBitmapFromData(dpy, win, cursor_data, 1, 1); hidden_cursor = XCreatePixmapCursor(dpy, cursor_mask, cursor_mask, &dummy_col, &dummy_col, 0, 0); XFreePixmap(dpy, cursor_mask); cursor_visible = True; gettimeofday(¤t_time, NULL); button_time = motion_time = current_time.tv_sec; net_wm_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); net_wm_STATE_STAYS_ON_TOP = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False); net_wm_STATE_ABOVE = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False); net_wm_STATE = XInternAtom(dpy, "_NET_WM_STATE", False); fullScreen = false; /* ----------------------------------------------------------------------- * now let's do some OSD initialisations */ char *dispName=XDisplayName(NULL); bool isLocal=true; dispName=rindex(dispName,':'); if ( dispName && atoi(dispName + 1) > 9 ) isLocal = false; osd_max_width=DisplayWidth(dpy,DefaultScreen(dpy)); osd_max_height=DisplayHeight(dpy,DefaultScreen(dpy)); useShm=XShmQueryExtension(dpy) && isLocal; old_handler = XSetErrorHandler(XvError_Handler); init_osd: if (useShm) { osd_image = XShmCreateImage (dpy, XDefaultVisual (dpy, scn_id), XDefaultDepth (dpy, scn_id), ZPixmap,NULL, &osd_shminfo, osd_max_width,osd_max_height); //width, height); if (osd_image) { dsyslog("[XvVideoOut]: Initialize XShmCreateImage Successful (%p)", osd_image); } else { dsyslog("[XvVideoOut]: Initialize ERROR: XShmCreateImage FAILED !"); } osd_shminfo.shmid = shmget (IPC_PRIVATE, osd_image->bytes_per_line*osd_max_height, //osd_image->bytes_per_line*height, IPC_CREAT | 0777); fprintf(stderr,"[XvVideoOut]: osd_image shmid = %d\n",osd_shminfo.shmid); if (osd_shminfo.shmid == -1) { dsyslog("[XvVideoOut]: Initialize ERROR: shmget FAILED !"); } else { dsyslog("[XvVideoOut]: Initialize shmget Successful (%d bytes)", osd_image->bytes_per_line*height); } osd_shminfo.shmaddr = (char *) shmat(osd_shminfo.shmid, NULL, 0); osd_buffer = (unsigned char *) osd_shminfo.shmaddr; osd_image->data = (char *) osd_buffer; if (osd_image->data == (char *) -1L) { dsyslog("[XvVideoOut]: Initialize ERROR: shmat FAILED !"); } else { dsyslog("[XvVideoOut]: Initialize shmat Successful"); } osd_shminfo.readOnly = False; rc = XShmAttach(dpy, &osd_shminfo); if (osd_shminfo. shmid > 0) shmctl (osd_shminfo. shmid, IPC_RMID, 0); } else { osd_image = XGetImage(dpy, win, 0, 0, osd_max_width, osd_max_height, AllPlanes, ZPixmap); if (osd_image) { dsyslog("[XvVideoOut]: Initialize XGetImage Successful (%p)", osd_image); osd_buffer = (unsigned char *) osd_image->data; } else { dsyslog("[XvVideoOut]: Initialize ERROR: XGetImage FAILED !"); osd_buffer = NULL; } }; InitPicBuffer(&osdBuf); if (osd_image) { Bpp=osd_image->bits_per_pixel; fprintf(stderr, "[XvVideoOut]: got osd_image: width" " %d height %d, bytes per line %d, Bpp %d\n", osd_max_width, osd_max_height, osd_image->bytes_per_line,osd_image->bits_per_pixel); switch (osd_image->bits_per_pixel) { case 32 : osdBuf.format=PIX_FMT_RGBA32; break; case 24 : osdBuf.format=PIX_FMT_RGB24; break; case 16 : default: osdBuf.format=PIX_FMT_RGB555; }; osdBuf.max_width=osd_max_width; osdBuf.max_height=osd_max_height; osdBuf.pixel[0]=(uint8_t*)osd_image->data; osdBuf.stride[0]=osd_image->bytes_per_line; }; rc = XClearArea (dpy, win, 0, 0, 0, 0, True); rc = XSync(dpy, False); if (got_error) { got_error=0;retry++; osd_max_width=720; osd_max_height=536; if (retry<2) { fprintf(stderr,"Error initializing osd image. Retry.\n"); goto init_osd; }; fprintf(stderr,"Error initializing osd image. Exit.\n"); exit(-1); }; if (old_handler) { XSetErrorHandler(old_handler); old_handler = NULL; }; if (!xScreensaver) { xScreensaver = new cScreensaver(dpy); } pthread_mutex_lock(&xv_mutex); /* ------------------------------------------------------------------------- * get up our remote running */ if (!xvRemote) { xvRemote = new cSoftRemote ("softdevice-xv"); } dsyslog("[XvVideoOut]: initialized OK"); if (setupStore->xvFullscreen) { toggleFullScreen(); setupStore->xvFullscreen=0; } pthread_mutex_unlock(&xv_mutex); videoInitialized = true; return true; } /* --------------------------------------------------------------------------- */ bool cXvVideoOut::Reconfigure(int format, int width, int height) { int fmt_cnt, k, rc, got_port, got_fmt; unsigned int ad_cnt, i; XvAdaptorInfo *ad_info; XvImageFormatValues *fmt_info; if (format > 3) { printf("XvVideoOut.Reconfigure format > 3!\n"); return false; }; currentPixelFormat=format; format = pixFormat[currentPixelFormat]; //printf("Reconfigure %d %d %d %d\n",currentPixelFormat,format,width,height);fflush(stdout); pthread_mutex_lock(&xv_mutex); xv_initialized = 0; xvWidth=width; xvHeight=height; // pthread_mutex_unlock(&xv_mutex); // return false; /* * So let's first check for an available adaptor and port */ if(Success == XvQueryAdaptors(dpy, rwin, &ad_cnt, &ad_info)) { for(i = 0, got_port = False; i < ad_cnt; ++i) { dsyslog("[XvVideoOut]: %s: available ports %ld - %ld", ad_info[i].name, ad_info[i].base_id, ad_info[i].base_id + ad_info[i].num_ports - 1); if (use_xv_port != 0 && (use_xv_port < ad_info[i].base_id || use_xv_port >= ad_info[i].base_id+ad_info[i].num_ports)) { dsyslog("[XvVideoOut]: %s: skipping (looking for port %i)", ad_info[i].name, use_xv_port); continue; } if (!(ad_info[i].type & XvImageMask)) { dsyslog("[XvVideoOut]: %s: XvImage NOT in capabilty list (%s%s%s%s%s )", ad_info[i].name, (ad_info[i].type & XvInputMask) ? " XvInput" : "", (ad_info[i]. type & XvOutputMask) ? " XvOutput" : "", (ad_info[i]. type & XvVideoMask) ? " XvVideo" : "", (ad_info[i]. type & XvStillMask) ? " XvStill" : "", (ad_info[i]. type & XvImageMask) ? " XvImage" : ""); continue; } /* if */ fmt_info = XvListImageFormats(dpy, ad_info[i].base_id,&fmt_cnt); if (!fmt_info || fmt_cnt == 0) { dsyslog("[XvVideoOut]: %s: NO supported formats", ad_info[i].name); continue; } /* if */ for(got_fmt = False, k = 0; k < fmt_cnt; ++k) { if (format == fmt_info[k].id) { got_fmt = True; break; } /* if */ } /* for */ if (!got_fmt) { dsyslog("[XvVideoOut]: %s: format %#08x is NOT in format list:", ad_info[i].name, format); for (k = 0; k < fmt_cnt; ++k) { dsyslog("[XvVideoOut]: %#08x[%s] ", fmt_info[k].id, fmt_info[k].guid); } continue; } /* if */ for(port = ad_info[i].base_id, k = 0; (unsigned int) k < ad_info[i].num_ports; ++k, ++(port)) { if (use_xv_port != 0 && use_xv_port != port) continue; if(!XvGrabPort(dpy, port, CurrentTime)) { unsigned int encodingCount, n; XvEncodingInfo *encodingInfo; dsyslog("[XvVideoOut]: grabbed port %ld", port); got_port = True; XvQueryEncodings(dpy,ad_info[i].base_id,&encodingCount,&encodingInfo); for (n = 0; n < encodingCount; ++n) { if (!strcmp(encodingInfo[n].name, "XV_IMAGE")) { fprintf(stderr, "[XvVideoOut]: max area size %lu x %lu\n", encodingInfo[n].width, encodingInfo[n].height); dsyslog("[XvVideoOut]: max area size %lu x %lu", encodingInfo[n].width, encodingInfo[n].height); /* ------------------------------------------------------------ * adjust width to 8 byte boundary and height to an even * number of lines. */ xv_max_width = (encodingInfo[n].width & ~7); xv_max_height = (encodingInfo[n].height & ~1); //FIXME (re)move? fprintf(stderr, "[XvVideoOut]: using area size %d x %d\n", xvWidth, xvHeight); dsyslog("[XvVideoOut]: using area size %d x %d", xvWidth, xvHeight); } } break; } /* if */ } /* for */ if(got_port) break; } /* for */ } else { /* Xv extension probably not present */ esyslog("[XvVideoOut]: (ERROR) no Xv extensions found! No video possible!"); pthread_mutex_unlock(&xv_mutex); return false; } /* else */ if(!ad_cnt) { esyslog("[XvVideoOut]: (ERROR) no adaptor found! No video possible!"); pthread_mutex_unlock(&xv_mutex); return false; } if(!got_port) { esyslog("[XvVideoOut]: (ERROR) could not grab any port! No video possible!"); pthread_mutex_unlock(&xv_mutex); return false; } attributeStore.SetXInfo(dpy,port,setupStore); attributeStore.Save(); switch (osdBuf.format) { case PIX_FMT_RGBA32: ARGB_TO_RGB(RGB32,&colorkey,COLOR_KEY); break; case PIX_FMT_RGB24: ARGB_TO_RGB(RGB24,&colorkey,COLOR_KEY); break; case PIX_FMT_RGB555: default: ARGB_TO_RGB(RGB16,&colorkey,COLOR_KEY); break; }; dsyslog("[XvVideoOut]: using color key 0x%0x",colorkey); FillPicBuffer(&osdBuf,colorkey); attributeStore.SetColorkey(colorkey); //attributeStore.SetColorkey(0x00000000); attributeStore.SetValue("XV_AUTOPAINT_COLORKEY",0); /* * Now we do shared memory allocation etc.. */ int retry=0; old_handler = XSetErrorHandler(XvError_Handler); retry_image: CreateXvImage(dpy,port,xv_image,shminfo, format,xvWidth, xvHeight); switch (format) { case FOURCC_YV12: case FOURCC_I420: pixels[0] = (uint8_t *) (xv_image->data + xv_image->offsets[0]); pixels[1] = (uint8_t *) (xv_image->data + xv_image->offsets[1]); pixels[2] = (uint8_t *) (xv_image->data + xv_image->offsets[2]); privBuf.pixel[0] = (uint8_t *) (xv_image->data + xv_image->offsets[0]); privBuf.stride[0] = xv_image->pitches[0]; if (format == FOURCC_YV12) { privBuf.pixel[1] = (uint8_t *) (xv_image->data + xv_image->offsets[2]); privBuf.pixel[2] = (uint8_t *) (xv_image->data + xv_image->offsets[1]); privBuf.stride[1] = xv_image->pitches[2]; privBuf.stride[2] = xv_image->pitches[1]; } else { privBuf.pixel[1] = (uint8_t *) (xv_image->data + xv_image->offsets[1]); privBuf.pixel[2] = (uint8_t *) (xv_image->data + xv_image->offsets[2]); privBuf.stride[1] = xv_image->pitches[1]; privBuf.stride[2] = xv_image->pitches[2]; }; privBuf.format = PIX_FMT_YUV420P; break; case FOURCC_YUY2: pixels[0] = (uint8_t *) (xv_image->data + xv_image->offsets[0]); privBuf.pixel[0] = (uint8_t *) (xv_image->data + xv_image->offsets[0]); privBuf.pixel[1] = NULL; privBuf.pixel[2] = NULL; privBuf.stride[0] = xv_image->pitches[0]; privBuf.stride[1] = 0; privBuf.stride[2] = 0; privBuf.format = PIX_FMT_YUV422; break; default: break; } privBuf.max_height=xvHeight; privBuf.max_width=xvWidth; privBuf.owner=this; this->format = format; ClearXvArea (0, 128, 128); rc = PutXvImage(xv_image,privBuf.edge_width,privBuf.edge_height); rc = XClearArea (dpy, win, 0, 0, 0, 0, True); ShowOSD(); rc = XSync(dpy, False); if (got_error) { got_error=0;retry++; xv_max_width=xvWidth=XV_SRC_WIDTH; xv_max_height=xvHeight = XV_SRC_HEIGHT; if (retry<2) { fprintf(stderr,"Error initializing Xv. Retry.\n"); goto retry_image; }; fprintf(stderr,"Error intializing Xv. Exit.\n"); exit(-1); }; if (old_handler) { XSetErrorHandler(old_handler); old_handler=NULL; }; needsFullOSDRedraw = true; pthread_mutex_unlock(&xv_mutex); videoInitialized = true; xv_initialized = 1; return true; } void cXvVideoOut::DeInitXv() { //printf("DeinitXv\n");fflush(stdout); pthread_mutex_lock(&xv_mutex); XvStopVideo(dpy, port, win); XvUngrabPort(dpy, port, CurrentTime); if (xv_image->data) { if(useShm && shminfo.shmaddr) { shmdt(shminfo.shmaddr); shminfo.shmaddr = NULL; XShmDetach(dpy, &shminfo); } if (!useShm) { free(xv_image->data); }; xv_image->data = NULL; }; XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); if (xv_image) { free(xv_image); xv_image = NULL; } xv_initialized = 0; }; /* --------------------------------------------------------------------------- */ void cXvVideoOut::ClearXvArea(uint8_t y, uint8_t u, uint8_t v) { uint8_t tu; uint32_t tyuy2, *pyuy2; switch (format) { case FOURCC_I420: tu = u; u = v; v = tu; case FOURCC_YV12: memset (pixels [0], y, xvWidth*xvHeight); memset (pixels [1], u, xvWidth*xvHeight/4); memset (pixels [2], v, xvWidth*xvHeight/4); break; case FOURCC_YUY2: tyuy2 = y + (u << 8) + (y << 16) + (v << 24); pyuy2 = (uint32_t *) pixels[0]; for (int i = 0; i < xvWidth / 2; ++i) *pyuy2++ = tyuy2; for (int i = 1; i < xvHeight; ++i, pyuy2 += xvWidth / 2) fast_memcpy(pyuy2, pixels[0], xvWidth*2); break; default: break; } } /* --------------------------------------------------------------------------- */ void cXvVideoOut::CreateXvImage(Display *dpy,XvPortID port, XvImage *&xv_image, XShmSegmentInfo &shminfo, int format, int &width, int &height) { int len=0; if (useShm) { xv_image = XvShmCreateImage(dpy, port, format, NULL, width, height, &shminfo); if (xv_image) { dsyslog("[XvVideoOut]: XvShmCreateImage Successful (%p)", xv_image); } else { dsyslog("[XvVideoOut]: ERROR: XvShmCreateImage FAILED !"); exit(-1); } shminfo.shmid = shmget(IPC_PRIVATE, xv_image->data_size, IPC_CREAT | 0777); if (shminfo.shmid == -1) { dsyslog("[XvVideoOut]: ERROR: shmget FAILED !"); } else { dsyslog("[XvVideoOut]: shmget Successful (%d bytes)",len); } /* compile fix for gcc 3.4.3 */ shminfo.shmaddr = (char *) shmat(shminfo.shmid, NULL, 0); xv_image->data = (char *) shminfo.shmaddr; if (xv_image->data == (char *) -1L) { dsyslog("[XvVideoOut]: ERROR: shmat FAILED !"); exit(-1); } else { dsyslog("[XvVideoOut]: shmat Successful"); } shminfo.readOnly = False; int rc = XShmAttach(dpy, &shminfo); dsyslog("[XvVideoOut]: XShmAttach rc = %d %s", rc,(rc == 1) ? "(should be OK)":"(thats NOT OK!)"); // request remove after detaching if (shminfo. shmid > 0) shmctl (shminfo. shmid, IPC_RMID, 0); }else { xv_image = XvCreateImage(dpy, port,format, NULL, width, height); if (!xv_image) { dsyslog("[XvVideoOut]: ERROR: XvCreateImage FAILED !"); exit(-1); }; xv_image->data = (char*)malloc(xv_image->data_size); if (!xv_image->data) { dsyslog("[XvVideoOut]: ERROR: malloc xv_image FAILED !"); exit(-1); }; }; }; /*-------------------------------------------------------------------------*/ void cXvVideoOut::DestroyXvImage(Display *dpy,XvPortID port, XvImage *&xv_image, XShmSegmentInfo &shminfo ) { if (!xv_image) return; if (xv_image->data) { if(useShm && shminfo.shmaddr) { shmdt(shminfo.shmaddr); shminfo.shmaddr = NULL; XShmDetach(dpy, &shminfo); shminfo.shmid = -1; } if (!useShm) { free(xv_image->data); }; xv_image->data = NULL; }; free(xv_image); xv_image=NULL; }; /* --------------------------------------------------------------------------- */ bool cXvVideoOut::AllocPicBuffer(int buf_num,PixelFormat pix_fmt, int w, int h) { if ( pix_fmt != PIX_FMT_YUV420P || format != FOURCC_YV12 || !xv_initialized #ifdef NO_DIRECT_RENDERING || 1 #endif ) { // no direct rendering return cVideoOut::AllocPicBuffer(buf_num,pix_fmt,w,h); }; pthread_mutex_lock(&xv_mutex); CreateXvImage(dpy,port,dr_image[buf_num],dr_shminfo[buf_num], format,w, h); XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); XvImage *image=dr_image[buf_num]; sPicBuffer *buf=&PicBuffer[buf_num]; buf->pixel[0] = (uint8_t *) (image->data + image->offsets[0]); buf->pixel[1] = (uint8_t *) (image->data + image->offsets[2]); buf->pixel[2] = (uint8_t *) (image->data + image->offsets[1]); buf->stride[0] = image->pitches[0]; buf->stride[1] = image->pitches[2]; buf->stride[2] = image->pitches[1]; buf->max_height=h; buf->max_width=w; buf->format=pix_fmt; return true; }; void cXvVideoOut::ReleasePicBuffer(int buf_num) { if ( !dr_image[buf_num] ) { // no direct rendering cVideoOut::ReleasePicBuffer(buf_num); return; }; pthread_mutex_lock(&xv_mutex); DestroyXvImage(dpy, port, dr_image[buf_num], dr_shminfo[buf_num] ); pthread_mutex_unlock(&xv_mutex); sPicBuffer *buf=&PicBuffer[buf_num]; for (int i=0; i<4; i++) { buf->pixel[i]=NULL; }; buf->max_height=0; buf->max_width=0; buf->format=PIX_FMT_NB; }; /*---------------------------------------------------------------------------- */ int cXvVideoOut::PutXvImage(XvImage *xv_image, int edge_width, int edge_height) { if (useShm) return XvShmPutImage(dpy, port, win, gc, xv_image, sxoff+edge_width, syoff+edge_height, /* sx, sy */ swidth, sheight, /* sw, sh */ lxoff, lyoff, /* dx, dy */ lwidth, lheight, /* dw, dh */ False); else return XvPutImage(dpy, port, win, gc, xv_image, sxoff+edge_width, syoff+edge_height, /* sx, sy */ swidth, sheight, /* sw, sh */ lxoff, lyoff, /* dx, dy */ lwidth, lheight /* dw, dh */ ); }; /* --------------------------------------------------------------------------- */ void cXvVideoOut::Pause(void) { } /* --------------------------------------------------------------------------- */ void cXvVideoOut::Suspend(void) { if (!xv_initialized) return; DeInitXv(); } /* --------------------------------------------------------------------------- */ bool cXvVideoOut::Resume(void) { return Reconfigure(currentPixelFormat); } /* --------------------------------------------------------------------------- */ void cXvVideoOut::ClearOSD() { cVideoOut::ClearOSD(); if ( videoInitialized ) { pthread_mutex_lock(&xv_mutex); FillPicBuffer(&osdBuf,colorkey); ShowOSD(); XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); }; }; /* --------------------------------------------------------------------------- */ void cXvVideoOut::AdjustOSDMode() { if (xv_initialized) current_osdMode = setupStore->osdMode; else current_osdMode = OSDMODE_SOFTWARE; } /* --------------------------------------------------------------------------- */ int cXvVideoOut::GetOSDColorkey() { return COLOR_KEY; } /* --------------------------------------------------------------------------- */ void cXvVideoOut::GetOSDDimension(int &OsdWidth,int &OsdHeight, int &xPan, int &yPan) { switch (current_osdMode) { case OSDMODE_PSEUDO : OsdWidth=lwidthbits_per_pixel; HasAlpha=false; }; /* --------------------------------------------------------------------------- */ bool cXvVideoOut::OSDNeedsRedraw(void) { bool tmp = needsFullOSDRedraw; needsFullOSDRedraw = false; return tmp; } /* --------------------------------------------------------------------------- */ void cXvVideoOut::GetLockOsdSurface(uint8_t *&osd, int &stride, bool *&dirtyLines) { osd = NULL; if (!videoInitialized) return; osd=osd_buffer; stride=osd_image->bytes_per_line; dirtyLines=NULL; } /* --------------------------------------------------------------------------- */ void cXvVideoOut::CommitUnlockOsdSurface() { if (!videoInitialized) return; cVideoOut::CommitUnlockOsdSurface(); pthread_mutex_lock(&xv_mutex); ShowOSD(); XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); } /* --------------------------------------------------------------------------- */ void cXvVideoOut::ShowOSD () { // if (current_osdMode==OSDMODE_PSEUDO ) { int x= lwidth > osd_max_width ?(lwidth - osd_max_width)/2+lxoff:lxoff; int y= lheight > osd_max_height ? (lheight - osd_max_height) / 2+lyoff:lyoff; //printf(" %d, %d, off %d, %d dim %d, %d \n",1,1,x,y,lwidth-1,lheight-1);fflush(stdout); if (useShm) XShmPutImage (dpy, win, gc, osd_image, 1,1, x,y, lwidth-1,lheight-1, False); else XPutImage (dpy, win, gc, osd_image, 1, 1, x,y, lwidth-1,lheight-1); //} } /* --------------------------------------------------------------------------- */ void cXvVideoOut::YUV(sPicBuffer *buf) { if ( (xvWidth != buf->max_width && xv_max_width >= buf->max_width) || (xvHeight != buf->max_height && xv_max_height >= buf->max_height) || currentPixelFormat != setupStore->pixelFormat) { if (xv_initialized) DeInitXv(); if ( !Reconfigure(setupStore->pixelFormat, buf->max_width,buf->max_height) ) { printf("reconfigure failed\n"); return; }; }; if (!videoInitialized) return; if (!xv_initialized) { // no xv, use software scaler and yuv->rgb conversion pthread_mutex_lock(&xv_mutex); if (aspect_changed || cutTop != setupStore->cropTopLines || cutBottom != setupStore->cropBottomLines || cutLeft != setupStore->cropLeftCols || cutRight != setupStore->cropRightCols) { XClearArea(dpy, win, 0, 0, 0, 0, False); aspect_changed = 0; cutTop = setupStore->cropTopLines; cutBottom = setupStore->cropBottomLines; cutLeft = setupStore->cropLeftCols; cutRight = setupStore->cropRightCols; ClearPicBuffer(&osdBuf); } if ( OSDpresent ) { CopyScalePicBufAlphaBlend(&osdBuf,buf, sxoff, syoff, swidth, sheight, 0, 0, lwidth, lheight, OsdPy,OsdPu,OsdPv, OsdPAlphaY,OsdPAlphaUV,OSD_FULL_WIDTH, cutTop,cutBottom,cutLeft,cutRight); } else { CopyScalePicBuf(&osdBuf, buf, sxoff, syoff, swidth, sheight, 0, 0, lwidth, lheight, 0,0,0,0); }; ShowOSD(); XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); return; }; pthread_mutex_lock(&xv_mutex); if (aspect_changed || cutTop != setupStore->cropTopLines || cutBottom != setupStore->cropBottomLines || cutLeft != setupStore->cropLeftCols || cutRight != setupStore->cropRightCols) { XClearArea (dpy, win, 0, 0, 0, 0, False); ShowOSD(); aspect_changed = 0; cutTop = setupStore->cropTopLines; cutBottom = setupStore->cropBottomLines; cutLeft = setupStore->cropLeftCols; cutRight = setupStore->cropRightCols; needsFullOSDRedraw = true; ClearXvArea (0, 128, 128); } if ( 0 && buf->owner == this ) { int buf_num=0; while ( &PicBuffer[buf_num]!= buf && buf_numedge_width,buf->edge_height); XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); return; }; }; uint8_t *Py=buf->pixel[0] +(buf->edge_height)*buf->stride[0] +buf->edge_width; uint8_t *Pu=buf->pixel[1]+(buf->edge_height/2)*buf->stride[1] +buf->edge_width/2; uint8_t *Pv=buf->pixel[2]+(buf->edge_height/2)*buf->stride[2] +buf->edge_width/2; if ( Py && Pu && Pv ) { /* ----------------------------------------------------------------------- * don't know where those funny stride values (752,376) come from. * therefor we have to copy line by line :-( . * Hmm .. for HDTV they should be larger anyway and for some other * unusual resolutions they should be configurable swidth/sheight ? */ if (OSDpresent && current_osdMode==OSDMODE_SOFTWARE) { CopyPicBufAlphaBlend(&privBuf,buf, OsdPy,OsdPu,OsdPv, OsdPAlphaY,OsdPAlphaUV,OSD_FULL_WIDTH, cutTop,cutBottom,cutLeft,cutRight); } else { CopyPicBuf(&privBuf,buf,cutTop,cutBottom,cutLeft,cutRight); } } PutXvImage(xv_image,privBuf.edge_width,privBuf.edge_height); XSync(dpy, False); pthread_mutex_unlock(&xv_mutex); } cXvVideoOut::~cXvVideoOut() { if (!videoInitialized) return; if (xv_initialized) { pthread_mutex_lock(&xv_mutex); XvStopVideo(dpy, port, win); pthread_mutex_unlock(&xv_mutex); if(shminfo.shmaddr) { shmdt(shminfo.shmaddr); shminfo.shmaddr = NULL; shminfo.shmid = -1; } if (xv_image) { free(xv_image); xv_image = NULL; } } if(osd_shminfo.shmaddr) { shmdt(osd_shminfo.shmaddr); osd_shminfo.shmaddr = NULL; } #if XINERAMA_SUPPORT XFree(xin_screen_info); #endif if (osd_image) { free(osd_image); osd_image = NULL; } videoInitialized = false; if (xScreensaver) { delete xScreensaver; xScreensaver = NULL; } pthread_mutex_unlock(&xv_mutex); } #ifdef USE_SUBPLUGINS /* --------------------------------------------------------------------------- */ extern "C" void * SubPluginCreator(cSetupStore *s, cSetupSoftlog *log) { return new cXvVideoOut(s,log); } #endif