BC_XvShmImage::BC_XvShmImage(BC_Bitmap *bitmap, int index, int w, int h, int color_model) : BC_BitmapImage(bitmap, index) { Display *display = top_level->get_display(); int id = BC_CModels::bc_to_x(color_model); // Create the XvImage xv_image = XvShmCreateImage(display, bitmap->xv_portid, id, 0, w, h, &shm_info); dataSize = xv_image->data_size; // Create the shared memory shm_info.shmid = shmget(IPC_PRIVATE, dataSize + 8, IPC_CREAT | 0777); if(shm_info.shmid < 0) perror("BC_XvShmImage::BC_XvShmImage shmget"); data = (unsigned char *)shmat(shm_info.shmid, NULL, 0); // This causes it to automatically delete when the program exits. shmctl(shm_info.shmid, IPC_RMID, 0); // setting ximage->data stops BadValue xv_image->data = shm_info.shmaddr = (char*)data; shm_info.readOnly = 0; // Get the real parameters w = xv_image->width; h = xv_image->height; if(!XShmAttach(top_level->display, &shm_info)) perror("BC_XvShmImage::BC_XvShmImage XShmAttach"); if( color_model == BC_YUV422 ) { bytesPerLine = w*2; bitsPerPixel = 12; row_data = new unsigned char*[h]; for( int i=0; i<h; ++i ) row_data[i] = &data[i*bytesPerLine]; } }
static int xv_alloc_frame( void ) { int size; uint8_t *alloc; size = input_width * input_height * 2; if( use_shm ) { alloc = create_shm( size ); } else { alloc = malloc( input_width * input_height * 2 ); } if( alloc ) { /* Initialize the input image to black. */ blit_colour_packed422_scanline( alloc, input_width * input_height, 16, 128, 128 ); if( use_shm ) { image = XvShmCreateImage( display, xv_port, FOURCC_YUY2, (char *) alloc, input_width, input_height, &shminfo ); } else { image = XvCreateImage( display, xv_port, FOURCC_YUY2, (char *) alloc, input_width, input_height ); } image_data = alloc; return 1; } return 0; }
bool prepareImage(int w, int h) { if (xv_image_width == w && xv_image_height == h && xv_image) return true; xv_image_width = w; xv_image_height = h; #ifdef _XSHM_H_ if (use_shm) { xv_image = XvShmCreateImage(display, xv_port, format_id, 0, xv_image_width, xv_image_height, &shm); shm.shmid = shmget(IPC_PRIVATE, xv_image->data_size, IPC_CREAT | 0777); if (shm.shmid < 0) { qCritical("get shm failed. try to use none shm"); use_shm = false; } else { shm.shmaddr = (char *)shmat(shm.shmid, 0, 0); xv_image->data = shm.shmaddr; shm.readOnly = 0; if (XShmAttach(display, &shm)) { XSync(display, false); shmctl(shm.shmid, IPC_RMID, 0); } else { qCritical("Attach to shm failed! try to use none shm"); use_shm = false; } } } #endif //_XSHM_H_ if (!use_shm) { xv_image = XvCreateImage(display, xv_port, format_id, 0, xv_image_width, xv_image_height); // malloc if use copy (e.g. shm) xv_image->data = (char*)malloc(xv_image->data_size); } return true; }
XvImage* create_yuv_image(Display* display, XvPortID port, fourcc_t format, int width, int height, XShmSegmentInfo* shminfo) { XvImage* image; if (shminfo) { if (!(image = XvShmCreateImage(display, port, format.id, NULL, width, height, shminfo))) { printf("Unable to create shm XvImage\n"); return NULL; } if ((shminfo->shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777)) == -1) { printf("Unable to allocate shared memory\n"); XFree(image); return NULL; } if (!(shminfo->shmaddr = shmat(shminfo->shmid, 0, 0))) { printf("Unable to attach shared memory\n"); XFree(image); shmctl(shminfo->shmid, IPC_RMID, 0); return NULL; } shminfo->readOnly = False; image->data = shminfo->shmaddr; if (!XShmAttach(display, shminfo)) { printf("XShmAttach failed\n"); XFree(image); shmctl(shminfo->shmid, IPC_RMID, 0); shmdt(shminfo->shmaddr); return NULL; } /* Send image to X server. This instruction is required, since having * built a Shm XImage and not using it causes an error on XCloseDisplay. */ XSync(display, False); /* Mark the segment to be automatically removed when the last attachment is broken (i.e. on shmdt or process exit). */ shmctl(shminfo->shmid, IPC_RMID, 0); } else { if (!(image = XvCreateImage(display, port, format.id, NULL, width, height))) { printf("Unable to create XvImage\n"); return NULL; } image->data = malloc(image->data_size); } return image; }
static bool allocate_xvimage(struct vo *vo, int foo) { struct xvctx *ctx = vo->priv; struct vo_x11_state *x11 = vo->x11; // align it for faster OSD rendering (draw_bmp.c swscale usage) int aligned_w = FFALIGN(ctx->image_width, 32); #if HAVE_SHM if (x11->display_is_local && XShmQueryExtension(x11->display)) { ctx->Shmem_Flag = 1; x11->ShmCompletionEvent = XShmGetEventBase(x11->display) + ShmCompletion; } else { ctx->Shmem_Flag = 0; MP_INFO(vo, "Shared memory not supported\nReverting to normal Xv.\n"); } if (ctx->Shmem_Flag) { ctx->xvimage[foo] = (XvImage *) XvShmCreateImage(x11->display, ctx->xv_port, ctx->xv_format, NULL, aligned_w, ctx->image_height, &ctx->Shminfo[foo]); if (!ctx->xvimage[foo]) return false; ctx->Shminfo[foo].shmid = shmget(IPC_PRIVATE, ctx->xvimage[foo]->data_size, IPC_CREAT | 0777); ctx->Shminfo[foo].shmaddr = (char *) shmat(ctx->Shminfo[foo].shmid, 0, 0); if (ctx->Shminfo[foo].shmaddr == (void *)-1) return false; ctx->Shminfo[foo].readOnly = False; ctx->xvimage[foo]->data = ctx->Shminfo[foo].shmaddr; XShmAttach(x11->display, &ctx->Shminfo[foo]); XSync(x11->display, False); shmctl(ctx->Shminfo[foo].shmid, IPC_RMID, 0); } else #endif { ctx->xvimage[foo] = (XvImage *) XvCreateImage(x11->display, ctx->xv_port, ctx->xv_format, NULL, aligned_w, ctx->image_height); if (!ctx->xvimage[foo]) return false; ctx->xvimage[foo]->data = av_malloc(ctx->xvimage[foo]->data_size); if (!ctx->xvimage[foo]->data) return false; XSync(x11->display, False); } struct mp_image img = get_xv_buffer(vo, foo); img.w = aligned_w; mp_image_clear(&img, 0, 0, img.w, img.h); return true; }
void QGstXvImageBufferPool::doAlloc() { //should be always called from the main thread with m_poolMutex locked //Q_ASSERT(QThread::currentThread() == thread()); XSync(QX11Info::display(), false); QGstXvImageBuffer *xvBuffer = (QGstXvImageBuffer *)gst_mini_object_new(QGstXvImageBuffer::get_type()); quint64 portId = m_format.property("portId").toULongLong(); int xvFormatId = m_format.property("xvFormatId").toInt(); xvBuffer->xvImage = XvShmCreateImage( QX11Info::display(), portId, xvFormatId, 0, m_format.frameWidth(), m_format.frameHeight(), &xvBuffer->shmInfo ); if (!xvBuffer->xvImage) { qWarning() << "QGstXvImageBufferPool: XvShmCreateImage failed"; return; } XSync(QX11Info::display(), false); xvBuffer->shmInfo.shmid = shmget(IPC_PRIVATE, xvBuffer->xvImage->data_size, IPC_CREAT | 0777); xvBuffer->shmInfo.shmaddr = xvBuffer->xvImage->data = (char*)shmat(xvBuffer->shmInfo.shmid, 0, 0); xvBuffer->shmInfo.readOnly = False; if (!XShmAttach(QX11Info::display(), &xvBuffer->shmInfo)) { qWarning() << "QGstXvImageBufferPool: XShmAttach failed"; return; } XSync(QX11Info::display(), false); shmctl (xvBuffer->shmInfo.shmid, IPC_RMID, NULL); xvBuffer->pool = this; GST_MINI_OBJECT_CAST(xvBuffer)->flags = 0; gst_buffer_set_caps(GST_BUFFER_CAST(xvBuffer), m_caps); GST_BUFFER_DATA(xvBuffer) = (uchar*)xvBuffer->xvImage->data; GST_BUFFER_SIZE(xvBuffer) = xvBuffer->xvImage->data_size; m_allBuffers.append(xvBuffer); m_pool.append(xvBuffer); XSync(QX11Info::display(), false); }
void S9xXVDisplayDriver::update_image_size (int width, int height) { if (desired_width != width || desired_height != height) { XShmDetach (display, &shm); XSync (display, 0); shmctl (shm.shmid, IPC_RMID, 0); shmdt (shm.shmaddr); xv_image = XvShmCreateImage (display, xv_portid, format, 0, width, height, &shm); shm.shmid = shmget (IPC_PRIVATE, xv_image->data_size, IPC_CREAT | 0777); for (int tries = 0; tries <= 10; tries++) { shm.shmaddr = (char *) shmat (shm.shmid, 0, 0); if (shm.shmaddr == (void *) -1 && tries >= 10) { /* Can't recover, send exit. */ fprintf (stderr, "Couldn't reallocate shared memory.\n"); S9xExit (); } else if (shm.shmaddr != (void *) -1) { break; } } shm.readOnly = FALSE; xv_image->data = shm.shmaddr; XShmAttach (display, &shm); desired_width = width; desired_height = height; } return; }
int XVWindow::init(Display* dp, Window rootWindow, int x, int y, int windowWidth, int windowHeight, int imageWidth, int imageHeight) { // local variables needed for creation of window and initialization of XV extension unsigned int i; unsigned int ver, rel, req, ev, err, adapt; XSetWindowAttributes xswattributes; XWindowAttributes xwattributes; XVisualInfo xvinfo; XvAdaptorInfo *xvainfo; unsigned int candidateXVPort=0; unsigned int busyPorts=0; _display=dp; _rootWindow=rootWindow; _state.origLayer=0; // initialize atoms WM_DELETE_WINDOW = XInternAtom(_display, "WM_DELETE_WINDOW", False); XA_WIN_PROTOCOLS = XInternAtom(_display, "_WIN_PROTOCOLS", False); XA_NET_SUPPORTED = XInternAtom(_display, "_NET_SUPPORTED", False); XA_NET_WM_STATE = XInternAtom(_display, "_NET_WM_STATE", False); XA_NET_WM_STATE_FULLSCREEN = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", False); XA_NET_WM_STATE_ABOVE = XInternAtom(_display, "_NET_WM_STATE_ABOVE", False); XA_NET_WM_STATE_STAYS_ON_TOP = XInternAtom(_display, "_NET_WM_STATE_STAYS_ON_TOP", False); XA_NET_WM_STATE_BELOW = XInternAtom(_display, "_NET_WM_STATE_BELOW", False); XGetWindowAttributes(_display, _rootWindow, &xwattributes); XMatchVisualInfo(_display, DefaultScreen(_display), xwattributes.depth, TrueColor, &xvinfo); // define window properties and create the window xswattributes.colormap = XCreateColormap(_display, _rootWindow, xvinfo.visual, AllocNone); xswattributes.event_mask = StructureNotifyMask | ExposureMask; xswattributes.background_pixel = 0; xswattributes.border_pixel = 0; _XVWindow = XCreateWindow(_display, _rootWindow, x, y, windowWidth, windowHeight, 0, xvinfo.depth, InputOutput, xvinfo.visual, CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &xswattributes); // define inputs events XSelectInput(_display, _XVWindow, StructureNotifyMask | KeyPressMask | ButtonPressMask); setSizeHints(DEFAULT_X,DEFAULT_Y, imageWidth, imageHeight, windowWidth, windowHeight); // map the window XMapWindow(_display, _XVWindow); XSetWMProtocols(_display, _XVWindow, &WM_DELETE_WINDOW,1); // check if SHM XV window is possible if (Success != XvQueryExtension(_display, &ver, &rel, &req, &ev, &err)) { LOG_DEBUG("[x11] XQueryExtension failed"); return 0; } if (!XShmQueryExtension(_display)) { LOG_DEBUG("[x11] XQueryShmExtension failed"); return 0; } if (Success != XvQueryAdaptors(_display, _rootWindow, &adapt, &xvainfo)) { LOG_DEBUG("[x11] XQueryAdaptor failed"); XFree(xvainfo); return 0; } // look for a usable XV port for (i = 0; i < adapt && _XVPort == 0; i++) { if ((xvainfo[i].type & XvInputMask) && (xvainfo[i].type & XvImageMask)) { for (candidateXVPort = xvainfo[i].base_id; candidateXVPort < xvainfo[i].base_id + xvainfo[i].num_ports; ++candidateXVPort) if (!XvGrabPort(_display, candidateXVPort, CurrentTime)) { _XVPort = candidateXVPort; break; } else { LOG_DEBUG("[x11] Could not grab port: " + String::fromNumber(candidateXVPort)); ++busyPorts; } } } XvFreeAdaptorInfo(xvainfo); if (!_XVPort) { if (busyPorts) { LOG_WARN("[x11] Could not find free Xvideo port - maybe another process is already using it."); } else { LOG_WARN("[x11] It seems there is no Xvideo support for your video card available."); } return 0; } else { LOG_WARN("[x11] Use XVideo port: " + String::fromNumber(_XVPort)); } _gc = XCreateGC(_display, _XVWindow, 0, 0); // create the shared memory portion _XVImage = XvShmCreateImage(_display, _XVPort, GUID_I420_PLANAR, 0, imageWidth, imageHeight, &_XShmInfo); _XShmInfo.shmid = shmget(IPC_PRIVATE, _XVImage->data_size, IPC_CREAT | 0777); _XShmInfo.shmaddr = (char *) shmat(_XShmInfo.shmid, 0, 0); _XVImage->data = _XShmInfo.shmaddr; _XShmInfo.readOnly = False; if (!XShmAttach(_display, &_XShmInfo)) { LOG_WARN("[x11] XShmAttach failed"); return 0; } else { _isInitialized = true; } // detect the window manager type _wmType=getWMType(); return 1; }
static void x11video_prepare(MSFilter *f){ X11Video *s=(X11Video*)f->data; unsigned int n; unsigned int nadaptors; int i; XvAdaptorInfo *xai=NULL; XvPortID port=-1; int imgfmt_id=0; XShmSegmentInfo *shminfo=&s->shminfo; XWindowAttributes wa = {0}; if (s->display==NULL) return; if (s->window_id==0){ if(s->auto_window) { s->window_id=createX11Window(s); } if (s->window_id==0) return; s->own_window=TRUE; } /* Make sure X11 window is ready to use*/ XSync(s->display, False); if (s->own_window==FALSE){ /*we need to register for resize events*/ XSelectInput(s->display,s->window_id,StructureNotifyMask); } XGetWindowAttributes(s->display,s->window_id,&wa); XClearWindow(s->display,s->window_id); ms_message("x11video_prepare(): Window has size %ix%i, received video is %ix%i",wa.width,wa.height,s->vsize.width,s->vsize.height); if (wa.width<MS_LAYOUT_MIN_SIZE || wa.height<MS_LAYOUT_MIN_SIZE){ return; } s->wsize.width=wa.width; s->wsize.height=wa.height; s->fbuf.w=s->vsize.width; s->fbuf.h=s->vsize.height; s->port=-1; if (XvQueryExtension(s->display, &n, &n, &n, &n, &n)!=0){ ms_error("Fail to query xv extension"); return; } if (XShmQueryExtension(s->display)==0){ ms_error("Fail to query xshm extension"); return; } if (XvQueryAdaptors(s->display,DefaultRootWindow(s->display), &nadaptors, &xai)!=0){ ms_error("XvQueryAdaptors failed."); return; } for (n=0;n<nadaptors && port==-1;++n){ XvAdaptorInfo *ai=&xai[n]; XvImageFormatValues *imgfmt; int nimgfmt=0; ms_message("Found output adaptor; name=%s num_ports=%i, with %i formats:", ai->name,(int)ai->num_ports,(int)ai->num_formats); imgfmt=XvListImageFormats(s->display,ai->base_id,&nimgfmt); for(i=0;i<nimgfmt;++i){ char fcc[5]={0}; memcpy(fcc,&imgfmt[i].id,4); ms_message("type=%s/%s id=%s", imgfmt[i].type == XvYUV ? "YUV" : "RGB", imgfmt[i].format==XvPlanar ? "Planar" : "Packed",fcc); if (port==-1 && imgfmt[i].format==XvPlanar && strcasecmp(fcc,"YV12")==0){ int k; /*we found a format interesting to us*/ for(k=0;k<ai->num_ports;++k){ if (XvGrabPort(s->display,ai->base_id+k,CurrentTime)==0){ ms_message("Grabbed port %i",(int)ai->base_id+k); port=ai->base_id+k; imgfmt_id=imgfmt[i].id; break; } } } } if (imgfmt) XFree(imgfmt); } XvFreeAdaptorInfo(xai); if (port==-1){ ms_error("Could not find suitable format or Xv port to work with."); return; } s->port=port; /*create the shared memory XvImage*/ memset(shminfo,0,sizeof(*shminfo)); s->xv_image=XvShmCreateImage(s->display,s->port,imgfmt_id,NULL,s->fbuf.w,s->fbuf.h,shminfo); if (s->xv_image==NULL){ ms_error("XvShmCreateImage failed."); x11video_unprepare(f); return; } /*allocate some shared memory to receive the pixel data */ shminfo->shmid=shmget(IPC_PRIVATE, s->xv_image->data_size,IPC_CREAT | 0777); if (shminfo->shmid==-1){ ms_error("Could not allocate %i bytes of shared memory: %s", s->xv_image->data_size, strerror(errno)); x11video_unprepare(f); return; } shminfo->shmaddr=shmat(shminfo->shmid,NULL,0); if (shminfo->shmaddr==(void*)-1){ ms_error("shmat() failed: %s",strerror(errno)); shminfo->shmaddr=NULL; x11video_unprepare(f); return; } /*ask the x-server to attach this shared memory segment*/ x11_error=FALSE; if (!XShmAttach(s->display,shminfo)){ ms_error("XShmAttach failed !"); x11video_unprepare(f); return ; } s->xv_image->data=s->shminfo.shmaddr; s->fbuf.planes[0]=(void*)s->xv_image->data; s->fbuf.planes[2]=s->fbuf.planes[0]+(s->xv_image->height*s->xv_image->pitches[0]); s->fbuf.planes[1]=s->fbuf.planes[2]+((s->xv_image->height/2)*s->xv_image->pitches[1]); s->fbuf.strides[0]=s->xv_image->pitches[0]; s->fbuf.strides[2]=s->xv_image->pitches[1]; s->fbuf.strides[1]=s->xv_image->pitches[2]; /* set picture black */ x11video_fill_background(f); /*Create a GC*/ s->gc=XCreateGC(s->display,s->window_id,0,NULL); if (s->gc==NULL){ ms_error("XCreateGC() failed."); x11video_unprepare(f); return ; } s->ready=TRUE; }
static GstXvImageMeta * gst_buffer_add_xvimage_meta (GstBuffer * buffer, GstXvImageBufferPool * xvpool) { GstXvImageSink *xvimagesink; int (*handler) (Display *, XErrorEvent *); gboolean success = FALSE; GstXContext *xcontext; GstXvImageMeta *meta; gint width, height, im_format, align = 15, offset; GstXvImageBufferPoolPrivate *priv; priv = xvpool->priv; xvimagesink = xvpool->sink; xcontext = xvimagesink->xcontext; width = priv->padded_width; height = priv->padded_height; im_format = priv->im_format; meta = (GstXvImageMeta *) gst_buffer_add_meta (buffer, GST_XVIMAGE_META_INFO, NULL); #ifdef HAVE_XSHM meta->SHMInfo.shmaddr = ((void *) -1); meta->SHMInfo.shmid = -1; #endif meta->x = priv->align.padding_left; meta->y = priv->align.padding_top; meta->width = priv->info.width; meta->height = priv->info.height; meta->sink = gst_object_ref (xvimagesink); meta->im_format = im_format; GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", buffer, width, height); g_mutex_lock (&xvimagesink->x_lock); /* Setting an error handler to catch failure */ error_caught = FALSE; handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); #ifdef HAVE_XSHM if (xcontext->use_xshm) { int expected_size; meta->xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id, im_format, NULL, width, height, &meta->SHMInfo); if (!meta->xvimage || error_caught) { g_mutex_unlock (&xvimagesink->x_lock); /* Reset error flag */ error_caught = FALSE; /* Push a warning */ GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", width, height), ("could not XShmCreateImage a %dx%d image", width, height)); /* Retry without XShm */ xvimagesink->xcontext->use_xshm = FALSE; /* Hold X mutex again to try without XShm */ g_mutex_lock (&xvimagesink->x_lock); goto no_xshm; } /* we have to use the returned data_size for our shm size */ meta->size = meta->xvimage->data_size; GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT, meta->size); /* calculate the expected size. This is only for sanity checking the * number we get from X. */ switch (im_format) { case GST_MAKE_FOURCC ('I', '4', '2', '0'): case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): { gint pitches[3]; gint offsets[3]; guint plane; offsets[0] = 0; pitches[0] = GST_ROUND_UP_4 (width); offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (height); pitches[1] = GST_ROUND_UP_8 (width) / 2; offsets[2] = offsets[1] + pitches[1] * GST_ROUND_UP_2 (height) / 2; pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2; expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (height) / 2; for (plane = 0; plane < meta->xvimage->num_planes; plane++) { GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a expected pitch of %d bytes, " "offset of %d", plane, pitches[plane], offsets[plane]); } break; } case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): expected_size = height * GST_ROUND_UP_4 (width * 2); break; default: expected_size = 0; break; } if (expected_size != 0 && meta->size != expected_size) { GST_WARNING_OBJECT (xvimagesink, "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", meta->size, expected_size); } /* Be verbose about our XvImage stride */ { guint plane; for (plane = 0; plane < meta->xvimage->num_planes; plane++) { GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, " "offset of %d", plane, meta->xvimage->pitches[plane], meta->xvimage->offsets[plane]); } } /* get shared memory */ meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size + align, IPC_CREAT | 0777); if (meta->SHMInfo.shmid == -1) goto shmget_failed; /* attach */ meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0); if (meta->SHMInfo.shmaddr == ((void *) -1)) goto shmat_failed; /* now we can set up the image data */ meta->xvimage->data = meta->SHMInfo.shmaddr; meta->SHMInfo.readOnly = FALSE; if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0) goto xattach_failed; XSync (xcontext->disp, FALSE); /* Delete the shared memory segment as soon as we everyone is attached. * This way, it will be deleted as soon as we detach later, and not * leaked if we crash. */ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx", meta->SHMInfo.shmid, meta->SHMInfo.shmseg); } else no_xshm: #endif /* HAVE_XSHM */ { meta->xvimage = XvCreateImage (xcontext->disp, xcontext->xv_port_id, im_format, NULL, width, height); if (!meta->xvimage || error_caught) goto create_failed; /* we have to use the returned data_size for our image size */ meta->size = meta->xvimage->data_size; meta->xvimage->data = g_malloc (meta->size + align); XSync (xcontext->disp, FALSE); } if ((offset = ((guintptr) meta->xvimage->data & align))) offset = (align + 1) - offset; GST_DEBUG_OBJECT (xvimagesink, "memory %p, align %d, offset %d", meta->xvimage->data, align, offset); /* Reset error handler */ error_caught = FALSE; XSetErrorHandler (handler); gst_buffer_append_memory (buffer, gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->xvimage->data, meta->size + align, offset, meta->size, NULL, NULL)); g_mutex_unlock (&xvimagesink->x_lock); success = TRUE; beach: if (!success) meta = NULL; return meta; /* ERRORS */ create_failed: { g_mutex_unlock (&xvimagesink->x_lock); /* Reset error handler */ error_caught = FALSE; XSetErrorHandler (handler); /* Push an error */ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", width, height), ("could not XvShmCreateImage a %dx%d image", width, height)); goto beach; } #ifdef HAVE_XSHM shmget_failed: { g_mutex_unlock (&xvimagesink->x_lock); GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", width, height), ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", meta->size)); goto beach; } shmat_failed: { g_mutex_unlock (&xvimagesink->x_lock); GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", width, height), ("Failed to shmat: %s", g_strerror (errno))); /* Clean up the shared memory segment */ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); goto beach; } xattach_failed: { /* Clean up the shared memory segment */ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL); g_mutex_unlock (&xvimagesink->x_lock); GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, ("Failed to create output image buffer of %dx%d pixels", width, height), ("Failed to XShmAttach")); goto beach; } #endif }
int xv_init( xv_handle_t handle, Display *dpy, __u32 fourcc, int width, int height, int bpp ) { unsigned int version, release; unsigned int request_base, event_base, error_base; int i; if( XvQueryExtension( dpy, &version, &release, &request_base, &event_base, &error_base ) != Success ) { #ifdef DEBUG fprintf( stderr, "XvQueryExtension failed\n" ); #endif return -1; } if( XvQueryAdaptors( dpy, DefaultRootWindow( dpy ), &handle->num_adaptors, &handle->p_adaptor_info ) != Success ) { #ifdef DEBUG fprintf( stderr, "XvQueryAdaptors failed\n" ); #endif return -1; } /* printf( "%d adaptors found\n", handle->num_adaptors ); */ if( handle->num_adaptors == 0 ) { return -2; } for( i = 0; i < handle->num_adaptors; i++ ) { /* int format; */ unsigned int num_encodings; XvEncodingInfo *p_encoding_info; int encoding; XvAttribute *at; unsigned int num_attributes; int attribute; XvImageFormatValues *xvimage_formats; unsigned int num_xvimage_formats; int format; #ifdef DEBUG printf( "Adaptor: %d\n", i ); printf( "Name: %s\n", handle->p_adaptor_info[i].name ); printf( "Ports: %lu\n", handle->p_adaptor_info[i].num_ports ); printf( "Formats: %lu\n", handle->p_adaptor_info[i].num_formats ); for( format = 0; format < handle->p_adaptor_info[i].num_formats; format++ ) { printf( "+Format: %d\n", format ); printf( " +Depth: %d\n", handle->p_adaptor_info[i].formats[format].depth ); printf( " +VisualID: %lu\n", handle->p_adaptor_info[i].formats[format].visual_id ); } if( XvQueryEncodings( dpy, handle->p_adaptor_info[i].base_id, &num_encodings, &p_encoding_info ) != Success ) { fprintf( stderr, "XvQueryEncodings failed\n" ); } printf( " +num_encodings: %d\n", num_encodings ); for( encoding = 0; encoding < num_encodings; encoding++ ) { printf( " +Encoding: %d\n", encoding ); printf( " +Name: %s\n", p_encoding_info[encoding].name ); printf( " +Resolution: %lu x %lu\n", p_encoding_info[encoding].width, p_encoding_info[encoding].height ); } #endif //DEBUG at = XvQueryPortAttributes( dpy, handle->p_adaptor_info[i].base_id, &num_attributes ); #ifdef DEBUG printf( "num_attributes: %d\n", num_attributes ); #endif for( attribute = 0; attribute < num_attributes; attribute++ ) { int val; Atom atom; if( !strcmp( at[attribute].name, "XV_COLORKEY" ) ) { #ifdef DEBUG printf( "attribute: %d\n", attribute ); printf( "name: %s\n", at[attribute].name ); #endif atom = (Atom)XInternAtom( dpy, at[attribute].name, 0 ); #ifdef DEBUG printf( "atom: %p\n", atom ); #endif XvGetPortAttribute( dpy, handle->p_adaptor_info[i].base_id, atom, &val ); #ifdef DEBUG printf( "Attribute: %d\n", attribute ); printf( "Name: %s\n", at[attribute].name ); printf( "min: %x\n", at[attribute].min_value ); printf( "max: %x\n", at[attribute].max_value ); printf( "value: %x\n", val ); #endif handle->atom_colorkey = XInternAtom( dpy, at[attribute].name, 0 ); } if( !strcmp( at[attribute].name, "XV_BRIGHTNESS" ) ) { handle->atom_brightness = XInternAtom( dpy, at[attribute].name, 0 ); handle->brightness_min = at[attribute].min_value; handle->brightness_max = at[attribute].max_value; } if( !strcmp( at[attribute].name, "XV_HUE" ) ) { handle->atom_hue = XInternAtom( dpy, at[attribute].name, 0 ); handle->hue_min = at[attribute].min_value; handle->hue_max = at[attribute].max_value; } if( !strcmp( at[attribute].name, "XV_CONTRAST" ) ) { handle->atom_contrast = XInternAtom( dpy, at[attribute].name, 0 ); handle->contrast_min = at[attribute].min_value; handle->contrast_max = at[attribute].max_value; } if( !strcmp( at[attribute].name, "XV_DOUBLE_BUFFER" ) ) { Atom _atom; _atom = XInternAtom( dpy, at[attribute].name, 0 ); XvSetPortAttribute( dpy, handle->p_adaptor_info[i].base_id, _atom, 1 ); #ifdef DEBUG printf( "Xv: DOUBLE_BUFFER available\n" ); #endif } } xvimage_formats = XvListImageFormats( dpy, handle->p_adaptor_info[i].base_id, &num_xvimage_formats ); /* printf( "num_xvimage_formats: %d\n", num_xvimage_formats ); */ for( format = 0; format < num_xvimage_formats; format++ ) { char imageName[5] = {0, 0, 0, 0, 0}; memcpy(imageName, &(xvimage_formats[format].id), 4); #ifdef DEBUG fprintf(stdout, " id: 0x%x", xvimage_formats[format].id); #endif if( isprint( imageName[0]) && isprint(imageName[1]) && isprint( imageName[2]) && isprint(imageName[3])) { #ifdef DEBUG fprintf(stdout, " (%s)\n", imageName); #endif if( xvimage_formats[format].id == fourcc ) { handle->xv_mode_id = fourcc; break; } } else { #ifdef DEBUG fprintf(stdout, "\n"); #endif } } if( handle->xv_mode_id != fourcc ) { return -3; } if( XvGrabPort( dpy, handle->p_adaptor_info[i].base_id, CurrentTime ) != Success ) { /* fprintf( stderr, "Failed to grab port!\n" ); */ return -1; } } handle->use_shm = 1; if( handle->use_shm ) { memset( &handle->shminfo, 0, sizeof( XShmSegmentInfo ) ); handle->image = XvShmCreateImage( dpy, handle->p_adaptor_info[0].base_id, handle->xv_mode_id, (char*)NULL, width, height, &handle->shminfo ); if( handle->image ) { handle->shminfo.shmid = shmget( IPC_PRIVATE, handle->image->data_size, IPC_CREAT | 0777 ); if( handle->shminfo.shmid == -1 ) { /* fprintf( stderr, "shmget failed\n" ); */ return -1; } handle->shminfo.shmaddr = handle->image->data = shmat( handle->shminfo.shmid, 0, 0 ); shmctl(handle->shminfo.shmid, IPC_RMID, 0); /* destroy when we terminate, now if shmat failed */ if( handle->shminfo.shmaddr == ( void * ) -1 ) { /* fprintf( stderr, "shmat failed\n" ); */ return -1; } handle->shminfo.readOnly = False; if( !XShmAttach( dpy, &handle->shminfo ) ) { /* fprintf( stderr, "XShmAttach failed\n" ); */ shmdt( handle->shminfo.shmaddr ); XFree( handle->image ); return -1; } } else { /* fprintf( stderr, "XvShmCreateImage failed\n" ); */ return -1; } } else { char * data = (char*) malloc( width*height*(bpp/8)); handle->image = XvCreateImage( dpy, handle->p_adaptor_info[0].base_id, handle->xv_mode_id, data, width, height ); } handle->display = dpy; return 0; }
int svlWindowManagerX11::DoModal(bool show, bool fullscreen) { Destroy(); DestroyFlag = false; unsigned int i, atom_count; int x, y, prevright, prevbottom; unsigned int lastimage = 0; unsigned long black, white; XSizeHints wsh; #if CISST_SVL_HAS_XV Atom atoms[3]; unsigned int xvadaptorcount; XvAdaptorInfo *xvai; XVisualInfo xvvinfo; bool xvupdateimage = true; #else // CISST_SVL_HAS_XV Atom atoms[2]; #endif // CISST_SVL_HAS_XV // setting decoration hints for borderless mode struct { unsigned long flags; unsigned long functions; unsigned long decorations; signed long input_mode; unsigned long status; } mwm; mwm.flags = MWM_HINTS_DECORATIONS; mwm.decorations = 0; mwm.functions = 0; mwm.input_mode = 0; mwm.status = 0; // resetting DestroyedSignal event if (DestroyedSignal) delete(DestroyedSignal); DestroyedSignal = new osaThreadSignal(); if (DestroyedSignal == 0) goto labError; // initialize display and pick default screen xDisplay = XOpenDisplay(reinterpret_cast<char*>(0)); xScreen = DefaultScreen(xDisplay); #if CISST_SVL_HAS_XV // check if 24bpp is suppoted by the display if (XMatchVisualInfo(xDisplay, xScreen, 24, TrueColor, &xvvinfo) == 0) goto labError; #endif // CISST_SVL_HAS_XV // pick colors black = BlackPixel(xDisplay, xScreen); white = WhitePixel(xDisplay, xScreen); // create windows xWindows = new Window[NumOfWins]; memset(xWindows, 0, NumOfWins * sizeof(Window)); xGCs = new GC[NumOfWins]; memset(xGCs, 0, NumOfWins * sizeof(GC)); // create atoms for overriding default window behaviours atoms[0] = XInternAtom(xDisplay, "WM_DELETE_WINDOW", False); atoms[1] = XInternAtom(xDisplay, "_MOTIF_WM_HINTS", False); #if CISST_SVL_HAS_XV atoms[2] = XInternAtom(xDisplay, "XV_SYNC_TO_VBLANK", False); #endif // CISST_SVL_HAS_XV // create title strings Titles = new std::string[NumOfWins]; CustomTitles = new std::string[NumOfWins]; CustomTitleEnabled = new int[NumOfWins]; #if CISST_SVL_HAS_XV xvImg = new XvImage*[NumOfWins]; xvShmInfo = new XShmSegmentInfo[NumOfWins]; xvPort = new XvPortID[NumOfWins]; if (xvImg == 0 || xvShmInfo == 0 || xvPort == 0) goto labError; memset(xvImg, 0, NumOfWins * sizeof(XvImage*)); memset(xvShmInfo, 0, NumOfWins * sizeof(XShmSegmentInfo)); memset(xvPort, 0, NumOfWins * sizeof(XvPortID)); #else // CISST_SVL_HAS_XV // create images xImageBuffers = new unsigned char*[NumOfWins]; for (i = 0; i < NumOfWins; i ++) { xImageBuffers[i] = new unsigned char[Width[i] * Height[i] * 4]; } xImg = new XImage*[NumOfWins]; memset(xImg, 0, NumOfWins * sizeof(XImage*)); if (xImg == 0) goto labError; for (i = 0; i < NumOfWins; i ++) { xImg[i] = XCreateImage(xDisplay, DefaultVisual(xDisplay, xScreen), 24, ZPixmap, 0, reinterpret_cast<char*>(xImageBuffers[i]), Width[i], Height[i], 32, 0); } #endif // CISST_SVL_HAS_XV prevright = prevbottom = 0; for (i = 0; i < NumOfWins; i ++) { if (PosX == 0 || PosY == 0) { if (fullscreen) { x = prevright; y = 0; prevright += Width[i]; } else { x = prevright; y = prevbottom; prevright += 50; prevbottom += 50; } } else { x = PosX[i]; y = PosY[i]; } xWindows[i] = XCreateSimpleWindow(xDisplay, DefaultRootWindow(xDisplay), x, y, Width[i], Height[i], 0, black, white); if (xWindows[i] == 0) goto labError; // overriding default behaviours: // - borderless mode // - closing window if (fullscreen) { XChangeProperty(xDisplay, xWindows[i], atoms[1], atoms[1], 32, PropModeReplace, reinterpret_cast<unsigned char*>(&mwm), 5); atom_count = 2; } else { atom_count = 1; } XSetWMProtocols(xDisplay, xWindows[i], atoms, atom_count); wsh.flags = PPosition|PSize; wsh.x = x; wsh.y = y; wsh.width = Width[i]; wsh.height = Height[i]; XSetNormalHints(xDisplay, xWindows[i], &wsh); // set window title CustomTitleEnabled[i] = 0; std::ostringstream ostring; if (Title.length() > 0) { if (NumOfWins > 0) ostring << Title << " #" << i; else ostring << Title; } else { if (NumOfWins > 0) ostring << Title << "svlImageWindow #" << i; else ostring << "svlImageWindow"; } Titles[i] = ostring.str(); XSetStandardProperties(xDisplay, xWindows[i], Titles[i].c_str(), Titles[i].c_str(), None, NULL, 0, NULL); // set even mask XSelectInput(xDisplay, xWindows[i], ExposureMask|PointerMotionMask|ButtonPressMask|KeyPressMask); // set window colormap XSetWindowColormap(xDisplay, xWindows[i], DefaultColormapOfScreen(DefaultScreenOfDisplay(xDisplay))); #if CISST_SVL_HAS_XV // query shared memory extension if (!XShmQueryExtension(xDisplay)) goto labError; // query video adaptors if (XvQueryAdaptors(xDisplay, DefaultRootWindow(xDisplay), &xvadaptorcount, &xvai) != Success) goto labError; xvPort[i] = xvai->base_id + i; XvFreeAdaptorInfo(xvai); // overriding default Xvideo vertical sync behavior XvSetPortAttribute (xDisplay, xvPort[i], atoms[2], 1); #endif // CISST_SVL_HAS_XV // create graphics context xGCs[i] = XCreateGC(xDisplay, xWindows[i], 0, 0); // set default colors XSetBackground(xDisplay, xGCs[i], white); XSetForeground(xDisplay, xGCs[i], black); #if CISST_SVL_HAS_XV // create image in shared memory xvImg[i] = XvShmCreateImage(xDisplay, xvPort[i], 0x32595559/*YUV2*/, 0, Width[i], Height[i], &(xvShmInfo[i])); if (xvImg[i]->width < static_cast<int>(Width[i]) || xvImg[i]->height < static_cast<int>(Height[i])) { CMN_LOG_INIT_ERROR << "DoModal - image too large for XV to display (requested=" << Width[i] << "x" << Height[i] << "; allowed=" << xvImg[i]->width << "x" << xvImg[i]->height << ")" << std::endl; goto labError; } xvShmInfo[i].shmid = shmget(IPC_PRIVATE, xvImg[i]->data_size, IPC_CREAT | 0777); xvShmInfo[i].shmaddr = xvImg[i]->data = reinterpret_cast<char*>(shmat(xvShmInfo[i].shmid, 0, 0)); xvShmInfo[i].readOnly = False; if (!XShmAttach(xDisplay, &(xvShmInfo[i]))) goto labError; #endif // CISST_SVL_HAS_XV // clear window XClearWindow(xDisplay, xWindows[i]); // show window if requested if (show) XMapRaised(xDisplay, xWindows[i]); } // signal that initialization is done if (InitReadySignal) InitReadySignal->Raise(); // main message loop XEvent event; KeySym code; unsigned int winid; while (1) { osaSleep(0.001); #if CISST_SVL_HAS_XV if (!xvupdateimage) { for (int events = XPending(xDisplay); events > 0; events --) { #else // CISST_SVL_HAS_XV if (XPending(xDisplay)) { #endif // CISST_SVL_HAS_XV XNextEvent(xDisplay, &event); // find recipient for (winid = 0; winid < NumOfWins; winid ++) { if (event.xany.window == xWindows[winid]) break; } if (winid == NumOfWins) continue; // override default window behaviour if (event.type == ClientMessage) { if (static_cast<unsigned long>(event.xclient.data.l[0]) == atoms[0]) { // X11 server wants to close window // Do nothing.... we will destroy it ourselves later } continue; } // window should be closed if (event.type == UnmapNotify) { printf("destroy\n"); if (xGCs[winid]) { XFreeGC(xDisplay, xGCs[winid]); xGCs[winid] = 0; } xWindows[winid] = 0; continue; } // window should be updated if (event.type == Expose && event.xexpose.count == 0) { XClearWindow(xDisplay, xWindows[winid]); continue; } if (event.type == KeyPress) { code = XLookupKeysym(&event.xkey, 0); if (code >= 48 && code <= 57) { // ascii numbers OnUserEvent(winid, true, code); continue; } if (code >= 97 && code <= 122) { // ascii letters OnUserEvent(winid, true, code); continue; } if (code == 13 || code == 32) { // special characters with correct ascii code OnUserEvent(winid, true, code); continue; } if (code >= 0xffbe && code <= 0xffc9) { // F1-F12 OnUserEvent(winid, false, winInput_KEY_F1 + (code - 0xffbe)); continue; } switch (code) { case 0xFF55: OnUserEvent(winid, false, winInput_KEY_PAGEUP); break; case 0xFF56: OnUserEvent(winid, false, winInput_KEY_PAGEDOWN); break; case 0xFF50: OnUserEvent(winid, false, winInput_KEY_HOME); break; case 0xFF57: OnUserEvent(winid, false, winInput_KEY_END); break; case 0xFF63: OnUserEvent(winid, false, winInput_KEY_INSERT); break; case 0xFFFF: OnUserEvent(winid, false, winInput_KEY_DELETE); break; case 0xFF51: OnUserEvent(winid, false, winInput_KEY_LEFT); break; case 0xFF53: OnUserEvent(winid, false, winInput_KEY_RIGHT); break; case 0xFF52: OnUserEvent(winid, false, winInput_KEY_UP); break; case 0xFF54: OnUserEvent(winid, false, winInput_KEY_DOWN); break; } continue; } if (event.type == ButtonPress) { if (event.xbutton.button == Button1) { if (!LButtonDown && !RButtonDown) { LButtonDown = true; XGrabPointer(xDisplay, xWindows[winid], false, PointerMotionMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } OnUserEvent(winid, false, winInput_LBUTTONDOWN); } else if (event.xbutton.button == Button3) { if (!LButtonDown && !RButtonDown) { RButtonDown = true; XGrabPointer(xDisplay, xWindows[winid], false, PointerMotionMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } OnUserEvent(winid, false, winInput_RBUTTONDOWN); } } if (event.type == ButtonRelease) { if (event.xbutton.button == Button1) { OnUserEvent(winid, false, winInput_LBUTTONUP); if (LButtonDown && !RButtonDown) { LButtonDown = false; XUngrabPointer(xDisplay, CurrentTime); } } else if (event.xbutton.button == Button3) { OnUserEvent(winid, false, winInput_RBUTTONUP); if (!LButtonDown && RButtonDown) { RButtonDown = false; XUngrabPointer(xDisplay, CurrentTime); } } } if (event.type == MotionNotify) { SetMousePos(static_cast<short>(event.xmotion.x), static_cast<short>(event.xmotion.y)); OnUserEvent(winid, false, winInput_MOUSEMOVE); } #if CISST_SVL_HAS_XV // image update complete if (event.type == XShmGetEventBase(xDisplay) + ShmCompletion) { xvupdateimage = true; continue; } } if (!xvupdateimage) signalImage.Wait(0.01); #endif // CISST_SVL_HAS_XV } else { if (DestroyFlag) break; if (ImageCounter > lastimage) { csImage.Enter(); lastimage = ImageCounter; #if CISST_SVL_HAS_XV for (i = 0; i < NumOfWins; i ++) { XvShmPutImage(xDisplay, xvPort[i], xWindows[i], xGCs[i], xvImg[i], 0, 0, Width[i], Height[i], 0, 0, Width[i], Height[i], True); } xvupdateimage = false; #else // CISST_SVL_HAS_XV for (i = 0; i < NumOfWins; i ++) { xImg[i]->data = reinterpret_cast<char*>(xImageBuffers[i]); XPutImage(xDisplay, xWindows[i], xGCs[i], xImg[i], 0, 0, 0, 0, Width[i], Height[i]); } #endif // CISST_SVL_HAS_XV /* for (i = 0; i < NumOfWins; i ++) { if (CustomTitleEnabled[i] < 0) { // Restore original timestamp XSetStandardProperties(xDisplay, xWindows[i], Titles[i].c_str(), Titles[i].c_str(), None, NULL, 0, NULL); } else if (CustomTitleEnabled[i] > 0) { // Set custom timestamp XSetStandardProperties(xDisplay, xWindows[i], CustomTitles[i].c_str(), CustomTitles[i].c_str(), None, NULL, 0, NULL); } } */ csImage.Leave(); } } } labError: #if CISST_SVL_HAS_XV if (xvShmInfo) { for (i = 0; i < NumOfWins; i ++) { XShmDetach(xDisplay, &(xvShmInfo[i])); shmdt(xvShmInfo[i].shmaddr); } delete [] xvShmInfo; xvShmInfo = 0; } #endif // CISST_SVL_HAS_XV XSync(xDisplay, 0); for (i = 0; i < NumOfWins; i ++) { if (xGCs[i]) XFreeGC(xDisplay, xGCs[i]); if (xWindows[i]) XDestroyWindow(xDisplay, xWindows[i]); } XCloseDisplay(xDisplay); #if CISST_SVL_HAS_XV if (xvImg) { for (i = 0; i < NumOfWins; i ++) { if (xvImg[i]) XFree(xvImg[i]); } delete [] xvImg; xvImg = 0; } if (xvPort) { delete [] xvPort; xvPort = 0; } #else // CISST_SVL_HAS_XV if (xImg) { for (i = 0; i < NumOfWins; i ++) { if (xImg[i]) XDestroyImage(xImg[i]); } delete [] xImg; xImg = 0; } if (xImageBuffers) { delete [] xImageBuffers; xImageBuffers = 0; } #endif // CISST_SVL_HAS_XV if (xGCs) { delete [] xGCs; xGCs = 0; } if (xWindows) { delete [] xWindows; xWindows = 0; } if (Titles) { delete [] Titles; Titles = 0; } if (CustomTitles) { delete [] CustomTitles; CustomTitles = 0; } if (CustomTitleEnabled) { delete [] CustomTitleEnabled; CustomTitleEnabled = 0; } xScreen = 0; xDisplay = 0; if (DestroyedSignal) DestroyedSignal->Raise(); return 0; }
void XVWindow::ShmAttach(int imageWidth, int imageHeight) { unsigned int i = 0; for (i = 0; i < NUM_BUFFERS; i++) { if (_useShm) { // create the shared memory portion _XVImage[i] = XvShmCreateImage (_display, _XVPort, GUID_YV12_PLANAR, 0, imageWidth, imageHeight, &_XShmInfo[i]); if (_XVImage[i] == NULL) { PTRACE(1, "XVideo\tXShmCreateImage failed"); _useShm = false; } if ((_XVImage[i]) && (_XVImage[i]->id != GUID_YV12_PLANAR)) { PTRACE(1, "XVideo\t XvShmCreateImage returned a different colorspace than YV12"); XFree (_XVImage[i]); _useShm = false; } } #if PTRACING if (_useShm) { int j = 0; PTRACE(4, "XVideo\tCreated XvImage (" << _XVImage[i]->width << "x" << _XVImage[i]->height << ", data size: " << _XVImage[i]->data_size << ", num_planes: " << _XVImage[i]->num_planes); for (j = 0 ; j < _XVImage[i]->num_planes ; j++) PTRACE(4, "XVideo\t Plane " << j << ": pitch=" << _XVImage[i]->pitches [j] << ", offset=" << _XVImage[i]->offsets [j]); } #endif if (_useShm) { _XShmInfo[i].shmid = shmget (IPC_PRIVATE, _XVImage[i]->data_size, IPC_CREAT | 0777); if (_XShmInfo[i].shmid < 0) { XFree (_XVImage[i]); PTRACE(1, "XVideo\tshmget failed"); //strerror(errno) _useShm = FALSE; } } if (_useShm) { _XShmInfo[i].shmaddr = (char *) shmat(_XShmInfo[i].shmid, 0, 0); if (_XShmInfo[i].shmaddr == ((char *) -1)) { XFree (_XVImage[i]); _XVImage[i] = NULL; PTRACE(1, "XVideo\tshmat failed"); //strerror(errno) _useShm = FALSE; } } if (_useShm) { _XVImage[i]->data = _XShmInfo[i].shmaddr; _XShmInfo[i].readOnly = False; // Attaching the shared memory to the display XErrorHandler oldHandler = XSetErrorHandler((XErrorHandler) catchXShmError); Status status = XShmAttach (_display, &_XShmInfo[i]); XSync(_display, False); XSetErrorHandler((XErrorHandler) oldHandler); if ( (status != True) || (_shmError) ) { XFree (_XVImage[i]); _XVImage[i] = NULL; if (_XShmInfo[i].shmaddr != ((char *) -1)) { shmdt(_XShmInfo[i].shmaddr); } PTRACE(1, "XVideo\t XShmAttach failed"); if ( (status == True) && (_shmError) ) { PTRACE(1, "XVideo\t X server supports SHM but apparently we are remotely connected..."); } _useShm = false; } } if (_useShm) { shmctl(_XShmInfo[i].shmid, IPC_RMID, 0); } } }
void XvMCOSD::CreateBuffer(XvMCContext &xvmc_ctx, int width, int height) { if (NO_SUBPICTURE == osd_subpict_mode) { VERBOSE(VB_IMPORTANT, "XvMCOSD::CreateBuffer() failed because " "no subpicture is available"); osd_subpict_alloc = false; return; } XJ_width = width; XJ_height = height; osd_subpict_clear_color = 0; int ret = Success; X11S(ret = XvMCCreateSubpicture(XJ_disp, &xvmc_ctx, &osd_subpict, XJ_width, XJ_height, osd_subpict_info.id)); if (ret != Success) { VERBOSE(VB_IMPORTANT, "XvMCOSD::CreateBuffer() failed on XvMCCreateSubpicture"); osd_subpict_mode = NO_SUBPICTURE; osd_subpict_alloc = false; return; } X11L; XvMCClearSubpicture(XJ_disp, &osd_subpict, 0, 0, XJ_width, XJ_height, osd_subpict_clear_color); osd_xv_image = XvShmCreateImage(XJ_disp, xv_port, osd_subpict_info.id, NULL, XJ_width, XJ_height, &XJ_osd_shm_info); X11U; if (!osd_xv_image) { VERBOSE(VB_IMPORTANT, "XvMCOSD::CreateBuffer() failed on XvShmCreateImage"); osd_subpict_mode = NO_SUBPICTURE; osd_subpict_alloc = false; return; } XJ_osd_shm_info.shmid = shmget(IPC_PRIVATE, osd_xv_image->data_size, IPC_CREAT | 0777); XJ_osd_shm_info.shmaddr = (char *)shmat(XJ_osd_shm_info.shmid, 0, 0); XJ_osd_shm_info.readOnly = False; osd_xv_image->data = XJ_osd_shm_info.shmaddr; X11S(XShmAttach(XJ_disp, &XJ_osd_shm_info)); shmctl(XJ_osd_shm_info.shmid, IPC_RMID, 0); if (osd_subpict.num_palette_entries > 0) { int snum = osd_subpict.num_palette_entries; int seb = osd_subpict.entry_bytes; osd_palette = new unsigned char[snum * seb]; for (int i = 0; i < snum; i++) { int Y = i * (1 << osd_subpict_info.y_sample_bits) / snum; int U = 1 << (osd_subpict_info.u_sample_bits - 1); int V = 1 << (osd_subpict_info.v_sample_bits - 1); for (int j = 0; j < seb; j++) { switch (osd_subpict.component_order[j]) { case 'U': osd_palette[i * seb + j] = U; break; case 'V': osd_palette[i * seb + j] = V; break; case 'Y': default: osd_palette[i * seb + j] = Y; break; } } } X11S(XvMCSetSubpicturePalette(XJ_disp, &osd_subpict, osd_palette)); } osd_subpict_alloc = true; }
int xf_video_process_frame(xfInfo * xfi, RD_VIDEO_FRAME_EVENT * vevent) { XShmSegmentInfo shminfo; XvImage * image; int colorkey = 0; int i; uint32 pixfmt; uint8 * data1; uint8 * data2; if (xfi->xv_port == -1) return 1; /* In case the player is minimized */ if (vevent->x < -2048 || vevent->y < -2048 || vevent->num_visible_rects <= 0) return 0; if (xfi->xv_colorkey_atom != None) { XvGetPortAttribute(xfi->display, xfi->xv_port, xfi->xv_colorkey_atom, &colorkey); XSetFunction(xfi->display, xfi->gc, GXcopy); XSetFillStyle(xfi->display, xfi->gc, FillSolid); XSetForeground(xfi->display, xfi->gc, colorkey); for (i = 0; i < vevent->num_visible_rects; i++) { XFillRectangle(xfi->display, xfi->wnd, xfi->gc, vevent->x + vevent->visible_rects[i].x, vevent->y + vevent->visible_rects[i].y, vevent->visible_rects[i].width, vevent->visible_rects[i].height); } } pixfmt = vevent->frame_pixfmt; image = XvShmCreateImage(xfi->display, xfi->xv_port, pixfmt, 0, vevent->frame_width, vevent->frame_height, &shminfo); if (xfi->xv_image_size != image->data_size) { if (xfi->xv_image_size > 0) { shmdt(xfi->xv_shmaddr); shmctl(xfi->xv_shmid, IPC_RMID, NULL); } xfi->xv_image_size = image->data_size; xfi->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777); xfi->xv_shmaddr = shmat(xfi->xv_shmid, 0, 0); } shminfo.shmid = xfi->xv_shmid; shminfo.shmaddr = image->data = xfi->xv_shmaddr; shminfo.readOnly = False; if (!XShmAttach(xfi->display, &shminfo)) { XFree(image); printf("xf_video_process_frame: XShmAttach failed.\n"); return 1; } /* The video driver may align each line to a different size and we need to convert our original image data. */ switch (pixfmt) { case RD_PIXFMT_I420: case RD_PIXFMT_YV12: if (!xf_video_is_format_supported(xfi, RD_PIXFMT_I420) && !xf_video_is_format_supported(xfi, RD_PIXFMT_YV12)) { printf("xf_video_process_frame: pixel format 0x%X not supported by hardware.\n", pixfmt); break; } /* Y */ if (image->pitches[0] == vevent->frame_width) { memcpy(image->data + image->offsets[0], vevent->frame_data, vevent->frame_width * vevent->frame_height); } else { for (i = 0; i < vevent->frame_height; i++) { memcpy(image->data + image->offsets[0] + i * image->pitches[0], vevent->frame_data + i * vevent->frame_width, vevent->frame_width); } } /* UV */ /* Conversion between I420 and YV12 is to simply swap U and V */ if (xf_video_is_format_supported(xfi, pixfmt)) { data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height; data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height + vevent->frame_width * vevent->frame_height / 4; } else { data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height; data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height + vevent->frame_width * vevent->frame_height / 4; image->id = pixfmt == RD_PIXFMT_I420 ? RD_PIXFMT_YV12 : RD_PIXFMT_I420; } if (image->pitches[1] * 2 == vevent->frame_width) { memcpy(image->data + image->offsets[1], data1, vevent->frame_width * vevent->frame_height / 4); memcpy(image->data + image->offsets[2], data2, vevent->frame_width * vevent->frame_height / 4); } else { for (i = 0; i < vevent->frame_height / 2; i++) { memcpy(image->data + image->offsets[1] + i * image->pitches[1], data1 + i * vevent->frame_width / 2, vevent->frame_width / 2); memcpy(image->data + image->offsets[2] + i * image->pitches[2], data2 + i * vevent->frame_width / 2, vevent->frame_width / 2); } } break; default: memcpy(image->data, vevent->frame_data, image->data_size <= vevent->frame_size ? image->data_size : vevent->frame_size); break; } XvShmPutImage(xfi->display, xfi->xv_port, xfi->wnd, xfi->gc_default, image, 0, 0, image->width, image->height, vevent->x, vevent->y, vevent->width, vevent->height, False); XSync(xfi->display, False); XShmDetach(xfi->display, &shminfo); XFree(image); return 0; }
//------------------------------------ // //------------------------------------ uint8_t GUI_XvInit(GUI_WindowInfo * window, uint32_t w, uint32_t h) { unsigned int ver, rel, req, ev, err; unsigned int port, adaptors; static XvAdaptorInfo *ai; static XvAdaptorInfo *curai; #if 0 win = gtk_widget_get_parent_window(window); xv_display = GDK_WINDOW_XDISPLAY(win); // xv_win= RootWindow(xv_display,0); xv_win = GDK_WINDOW_XWINDOW(GTK_WIDGET(window)->window); #endif xv_display=(Display *)window->display; xv_win=window->window; #define WDN xv_display xv_port = 0; if (Success != XvQueryExtension(WDN, &ver, &rel, &req, &ev, &err)) { printf("\n Query Extension failed\n"); goto failed; } /* check for Xvideo support */ if (Success != XvQueryAdaptors(WDN, DefaultRootWindow(WDN), &adaptors, &ai)) { printf("\n Query Adaptor failed\n"); goto failed; } curai = ai; XvFormat *formats; // Dump infos port = 0; for (uint16_t i = 0; (!port) && (i < adaptors); i++) { /* XvPortID base_id; unsigned long num_ports; char type; char *name; unsigned long num_formats; XvFormat *formats; unsigned long num_adaptors; */ #ifdef VERBOSE_XV printf("\n_______________________________\n"); printf("\n Adaptor : %d", i); printf("\n Base ID : %ld", curai->base_id); printf("\n Nb Port : %lu", curai->num_ports); printf("\n Type : %d,", curai->type); #define CHECK(x) if(curai->type & x) printf("|"#x); CHECK(XvInputMask); CHECK(XvOutputMask); CHECK(XvVideoMask); CHECK(XvStillMask); CHECK(XvImageMask); printf("\n Name : %s", curai->name); printf("\n Num Adap : %lu", curai->num_adaptors); printf("\n Num fmt : %lu", curai->num_formats); #endif formats = curai->formats; // uint16_t k; for (k = 0; (k < curai->num_ports) && !port; k++) { if (GUI_XvList(WDN, k + curai->base_id, &xv_format)) port = k + curai->base_id; } curai++; } // if (!port) { printf("\n no port found"); goto failed; } #ifdef COLORSPACE_YV12 printf("\n Xv YV12 found at port :%d, format : %ld", port, xv_format); #else printf("\n Xv YUY2 found at port :%d, format : %ld", port, xv_format); #endif if (Success != XvGrabPort(WDN, port, 0)) goto failed; { xv_port = port; /* Display *display, XvPortID port, int id, char* data, int width, int height, XShmSegmentInfo *shminfo */ XSetWindowAttributes xswa; XWindowAttributes attribs; static Atom xv_atom; unsigned long xswamask; int erCode; /* check if colorkeying is needed */ xv_atom = getAtom( "XV_AUTOPAINT_COLORKEY" ); if(xv_atom!=None) { XvSetPortAttribute( xv_display, xv_port, xv_atom, 1 ); } else printf("No autopaint \n"); /* if we have to deal with colorkeying ... */ xvimage = XvShmCreateImage(WDN, xv_port, xv_format, 0, w, h, &Shminfo); Shminfo.shmid = shmget(IPC_PRIVATE, xvimage->data_size, IPC_CREAT | 0777); if(Shminfo.shmid<=0) { printf("shmget failed\n"); } Shminfo.shmaddr = (char *) shmat(Shminfo.shmid, 0, 0); Shminfo.readOnly = False; if(Shminfo.shmaddr==(char *)-1) { printf("Shmat failed\n"); } xvimage->data = Shminfo.shmaddr; XShmAttach(WDN, &Shminfo); XSync(WDN, False); erCode=shmctl(Shminfo.shmid, IPC_RMID, 0); if(erCode) { printf("Shmctl failed :%d\n",erCode); } memset(xvimage->data, 0, xvimage->data_size); xv_xgc.graphics_exposures = False; xv_gc = XCreateGC(xv_display, xv_win, 0L, &xv_xgc); //ADM_assert(BadWindow!=XSelectInput(xv_display, xv_win, ExposureMask | VisibilityChangeMask)); } printf("\n Xv init succeedeed\n"); return 1; failed: printf("\n Xv init failed..\n"); return 0; }
static int X11_xshm_xv_blit(struct DriverInstance* sh, const uint8_t* fb, int width, int height, struct blit_params* params, int needs_adjust, char* error_text, int text_len) { // wait until last blit has completed if (sh->event_pending) { int max_wait = 15; XEvent event; sh->event_pending = 0; while (max_wait--) { XNextEvent(sh->display, &event); if (event.type == sh->completion_type) break; } } if (sh->xv_image == 0 || width != sh->image_width || height != sh->image_height) { if (sh->xv_image) XFree(sh->xv_image); sh->xv_image = XvShmCreateImage(sh->display, sh->xv_port, sh->xv_format_id, sh->shminfo.shmaddr, width, height, &sh->shminfo); sh->image_width = width; sh->image_height = height; } //TODO: this is a hack for big-endian machines if (big_endian()) convert_endianness((uint8_t*) fb, sh->width, sh->height); if (sh->vis.depth == 24) { #if defined(OPT_INCLUDE_MMX) if (sh->mmx_supported) cvt_rgb32_to_i420_mmx((uint8_t*) sh->xv_image->data, (uint32_t*) fb, width, height, sh->xv_image->pitches, sh->xv_image->offsets); else #endif cvt_rgb32_to_i420((uint8_t*) sh->xv_image->data, (uint32_t*) fb, width, height, sh->xv_image->pitches, sh->xv_image->offsets); } else if (sh->vis.depth == 16) cvt_rgb16_to_i420((uint8_t*) sh->xv_image->data, (uint16_t*) fb, width, height, sh->xv_image->pitches, sh->xv_image->offsets); // blit shared mem image XvShmPutImage(sh->display, sh->xv_port, sh->win, sh->gc, sh->xv_image, 0, 0, width, height, 0, 0, sh->width, sh->height, True); sh->event_pending = 1; XFlush(sh->display); //XSync(sh->display, False); return 1; }
/** The initialization function * This function opens the frame buffer device and allocates memory for display * also it finds the frame buffer supported display formats */ OMX_ERRORTYPE omx_xvideo_sink_component_Init(OMX_COMPONENTTYPE *openmaxStandComp) { omx_xvideo_sink_component_PrivateType* omx_xvideo_sink_component_Private = openmaxStandComp->pComponentPrivate; omx_xvideo_sink_component_PortType* pPort = (omx_xvideo_sink_component_PortType *) omx_xvideo_sink_component_Private->ports[OMX_BASE_SINK_INPUTPORT_INDEX]; int yuv_width = pPort->sPortParam.format.video.nFrameWidth; int yuv_height = pPort->sPortParam.format.video.nFrameHeight; unsigned int err,i; omx_xvideo_sink_component_Private->dpy = XOpenDisplay(NULL); omx_xvideo_sink_component_Private->screen = DefaultScreen(omx_xvideo_sink_component_Private->dpy); XGetWindowAttributes(omx_xvideo_sink_component_Private->dpy, DefaultRootWindow(omx_xvideo_sink_component_Private->dpy), &omx_xvideo_sink_component_Private->attribs); XMatchVisualInfo(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->screen, omx_xvideo_sink_component_Private->attribs.depth, TrueColor, & omx_xvideo_sink_component_Private->vinfo); omx_xvideo_sink_component_Private->wmDeleteWindow = XInternAtom(omx_xvideo_sink_component_Private->dpy, "WM_DELETE_WINDOW", False); omx_xvideo_sink_component_Private->hint.x = 1; omx_xvideo_sink_component_Private->hint.y = 1; omx_xvideo_sink_component_Private->hint.width = yuv_width; omx_xvideo_sink_component_Private->hint.height = yuv_height; omx_xvideo_sink_component_Private->hint.flags = PPosition | PSize; omx_xvideo_sink_component_Private->xswa.colormap = XCreateColormap(omx_xvideo_sink_component_Private->dpy, DefaultRootWindow(omx_xvideo_sink_component_Private->dpy), omx_xvideo_sink_component_Private->vinfo.visual, AllocNone); omx_xvideo_sink_component_Private->xswa.event_mask = StructureNotifyMask | ExposureMask; omx_xvideo_sink_component_Private->xswa.background_pixel = 0; omx_xvideo_sink_component_Private->xswa.border_pixel = 0; omx_xvideo_sink_component_Private->window = XCreateWindow(omx_xvideo_sink_component_Private->dpy, DefaultRootWindow(omx_xvideo_sink_component_Private->dpy), 0, 0, yuv_width, yuv_height, 0, omx_xvideo_sink_component_Private->vinfo.depth, InputOutput, omx_xvideo_sink_component_Private->vinfo.visual, CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &omx_xvideo_sink_component_Private->xswa); XSelectInput(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->window, StructureNotifyMask); XSetStandardProperties(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->window, "xvcam", "xvcam", None, NULL, 0, &omx_xvideo_sink_component_Private->hint); XSetWMProtocols(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->window, &omx_xvideo_sink_component_Private->wmDeleteWindow, 1); XMapWindow(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->window); if (XShmQueryExtension(omx_xvideo_sink_component_Private->dpy)) omx_xvideo_sink_component_Private->CompletionType = XShmGetEventBase(omx_xvideo_sink_component_Private->dpy) + ShmCompletion; else return OMX_ErrorUndefined; if (Success != XvQueryExtension(omx_xvideo_sink_component_Private->dpy, &omx_xvideo_sink_component_Private->ver, &omx_xvideo_sink_component_Private->rel, &omx_xvideo_sink_component_Private->req, &omx_xvideo_sink_component_Private->ev, &err)) fprintf(stderr, "Couldn't do Xv stuff\n"); if (Success != XvQueryAdaptors(omx_xvideo_sink_component_Private->dpy, DefaultRootWindow(omx_xvideo_sink_component_Private->dpy), &omx_xvideo_sink_component_Private->adapt, &omx_xvideo_sink_component_Private->ai)) fprintf(stderr, "Couldn't do Xv stuff\n"); for (i = 0; i < (int) omx_xvideo_sink_component_Private->adapt; i++) { omx_xvideo_sink_component_Private->xv_port = omx_xvideo_sink_component_Private->ai[i].base_id; } if (omx_xvideo_sink_component_Private->adapt > 0) XvFreeAdaptorInfo(omx_xvideo_sink_component_Private->ai); omx_xvideo_sink_component_Private->gc = XCreateGC(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->window, 0, 0); omx_xvideo_sink_component_Private->yuv_image = XvShmCreateImage(omx_xvideo_sink_component_Private->dpy, omx_xvideo_sink_component_Private->xv_port, GUID_I420_PLANAR, 0, yuv_width, yuv_height, &omx_xvideo_sink_component_Private->yuv_shminfo); omx_xvideo_sink_component_Private->yuv_shminfo.shmid = shmget(IPC_PRIVATE, omx_xvideo_sink_component_Private->yuv_image->data_size, IPC_CREAT | 0777); omx_xvideo_sink_component_Private->yuv_shminfo.shmaddr = (char *) shmat(omx_xvideo_sink_component_Private->yuv_shminfo.shmid, 0, 0); omx_xvideo_sink_component_Private->yuv_image->data = omx_xvideo_sink_component_Private->yuv_shminfo.shmaddr; omx_xvideo_sink_component_Private->yuv_shminfo.readOnly = False; if (!XShmAttach(omx_xvideo_sink_component_Private->dpy, &omx_xvideo_sink_component_Private->yuv_shminfo)) { printf("XShmAttach go boom boom!\n"); return OMX_ErrorUndefined; } omx_xvideo_sink_component_Private->old_time = 0; omx_xvideo_sink_component_Private->new_time = 0; omx_xvideo_sink_component_Private->bIsXVideoInit = OMX_TRUE; /*Signal XVideo Initialized*/ tsem_up(omx_xvideo_sink_component_Private->xvideoSyncSem); return OMX_ErrorNone; }
static void xf_process_tsmf_video_frame_event(xfInfo* xfi, RDP_VIDEO_FRAME_EVENT* vevent) { int i; BYTE* data1; BYTE* data2; UINT32 pixfmt; UINT32 xvpixfmt; BOOL converti420yv12 = FALSE; XvImage * image; int colorkey = 0; XShmSegmentInfo shminfo; xfXvContext* xv = (xfXvContext*) xfi->xv_context; if (xv->xv_port == 0) return; /* In case the player is minimized */ if (vevent->x < -2048 || vevent->y < -2048 || vevent->num_visible_rects <= 0) return; if (xv->xv_colorkey_atom != None) { XvGetPortAttribute(xfi->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey); XSetFunction(xfi->display, xfi->gc, GXcopy); XSetFillStyle(xfi->display, xfi->gc, FillSolid); XSetForeground(xfi->display, xfi->gc, colorkey); for (i = 0; i < vevent->num_visible_rects; i++) { XFillRectangle(xfi->display, xfi->window->handle, xfi->gc, vevent->x + vevent->visible_rects[i].x, vevent->y + vevent->visible_rects[i].y, vevent->visible_rects[i].width, vevent->visible_rects[i].height); } } else { XSetClipRectangles(xfi->display, xfi->gc, vevent->x, vevent->y, (XRectangle*) vevent->visible_rects, vevent->num_visible_rects, YXBanded); } pixfmt = vevent->frame_pixfmt; if (xf_tsmf_is_format_supported(xv, pixfmt)) { xvpixfmt = pixfmt; } else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12)) { xvpixfmt = RDP_PIXFMT_YV12; converti420yv12 = TRUE; } else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420)) { xvpixfmt = RDP_PIXFMT_I420; converti420yv12 = TRUE; } else { DEBUG_XV("pixel format 0x%X not supported by hardware.", pixfmt); return; } image = XvShmCreateImage(xfi->display, xv->xv_port, xvpixfmt, 0, vevent->frame_width, vevent->frame_height, &shminfo); if (xv->xv_image_size != image->data_size) { if (xv->xv_image_size > 0) { shmdt(xv->xv_shmaddr); shmctl(xv->xv_shmid, IPC_RMID, NULL); } xv->xv_image_size = image->data_size; xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777); xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0); } shminfo.shmid = xv->xv_shmid; shminfo.shmaddr = image->data = xv->xv_shmaddr; shminfo.readOnly = FALSE; if (!XShmAttach(xfi->display, &shminfo)) { XFree(image); DEBUG_XV("XShmAttach failed."); return; } /* The video driver may align each line to a different size and we need to convert our original image data. */ switch (pixfmt) { case RDP_PIXFMT_I420: case RDP_PIXFMT_YV12: /* Y */ if (image->pitches[0] == vevent->frame_width) { memcpy(image->data + image->offsets[0], vevent->frame_data, vevent->frame_width * vevent->frame_height); } else { for (i = 0; i < vevent->frame_height; i++) { memcpy(image->data + image->offsets[0] + i * image->pitches[0], vevent->frame_data + i * vevent->frame_width, vevent->frame_width); } } /* UV */ /* Conversion between I420 and YV12 is to simply swap U and V */ if (converti420yv12 == FALSE) { data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height; data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height + vevent->frame_width * vevent->frame_height / 4; } else { data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height; data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height + vevent->frame_width * vevent->frame_height / 4; image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420; } if (image->pitches[1] * 2 == vevent->frame_width) { memcpy(image->data + image->offsets[1], data1, vevent->frame_width * vevent->frame_height / 4); memcpy(image->data + image->offsets[2], data2, vevent->frame_width * vevent->frame_height / 4); } else { for (i = 0; i < vevent->frame_height / 2; i++) { memcpy(image->data + image->offsets[1] + i * image->pitches[1], data1 + i * vevent->frame_width / 2, vevent->frame_width / 2); memcpy(image->data + image->offsets[2] + i * image->pitches[2], data2 + i * vevent->frame_width / 2, vevent->frame_width / 2); } } break; default: memcpy(image->data, vevent->frame_data, image->data_size <= vevent->frame_size ? image->data_size : vevent->frame_size); break; } XvShmPutImage(xfi->display, xv->xv_port, xfi->window->handle, xfi->gc, image, 0, 0, image->width, image->height, vevent->x, vevent->y, vevent->width, vevent->height, FALSE); if (xv->xv_colorkey_atom == None) XSetClipMask(xfi->display, xfi->gc, None); XSync(xfi->display, FALSE); XShmDetach(xfi->display, &shminfo); XFree(image); }
int main (int argc, char* argv[]) { int yuv_width = 1024; int yuv_height = 768; int xv_port = -1; int adaptor, encodings, attributes, formats; int i, j, ret, p, _d, _w, _h; long secsb, secsa, frames; XvAdaptorInfo *ai; XvEncodingInfo *ei; XvAttribute *at; XvImageFormatValues *fo; XvImage *yuv_image; #define GUID_YUV12_PLANAR 0x32315659 unsigned int p_version, p_release, p_request_base, p_event_base, p_error_base; int p_num_adaptors; Display *dpy; Window window, _dw; XSizeHints hint; XSetWindowAttributes xswa; XVisualInfo vinfo; int screen; unsigned long mask; XEvent event; GC gc; /** for shm */ int shmem_flag = 0; XShmSegmentInfo yuv_shminfo; int CompletionType; printf("starting up video testapp...\n\n"); adaptor = -1; dpy = XOpenDisplay(NULL); if (dpy == NULL) { printf("Cannot open Display.\n"); exit (-1); } screen = DefaultScreen(dpy); /** find best display */ if (XMatchVisualInfo(dpy, screen, 24, TrueColor, &vinfo)) { printf(" found 24bit TrueColor\n"); } else if (XMatchVisualInfo(dpy, screen, 16, TrueColor, &vinfo)) { printf(" found 16bit TrueColor\n"); } else if (XMatchVisualInfo(dpy, screen, 15, TrueColor, &vinfo)) { printf(" found 15bit TrueColor\n"); } else if (XMatchVisualInfo(dpy, screen, 8, PseudoColor, &vinfo)) { printf(" found 8bit PseudoColor\n"); } else if (XMatchVisualInfo(dpy, screen, 8, GrayScale, &vinfo)) { printf(" found 8bit GrayScale\n"); } else if (XMatchVisualInfo(dpy, screen, 8, StaticGray, &vinfo)) { printf(" found 8bit StaticGray\n"); } else if (XMatchVisualInfo(dpy, screen, 1, StaticGray, &vinfo)) { printf(" found 1bit StaticGray\n"); } else { printf("requires 16 bit display\n"); exit (-1); } CompletionType = -1; hint.x = 1; hint.y = 1; hint.width = yuv_width; hint.height = yuv_height; hint.flags = PPosition | PSize; xswa.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy), vinfo.visual, AllocNone); xswa.event_mask = StructureNotifyMask | ExposureMask; xswa.background_pixel = 0; xswa.border_pixel = 0; mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; window = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, yuv_width, yuv_height, 0, vinfo.depth, InputOutput, vinfo.visual, mask, &xswa); XStoreName(dpy, window, "XV"); XSetIconName(dpy, window, "XV"); XSelectInput(dpy, window, StructureNotifyMask); /** Map window */ XMapWindow(dpy, window); /** Wait for map. */ do { XNextEvent(dpy, &event); } while (event.type != MapNotify || event.xmap.event != window); if (XShmQueryExtension(dpy)) shmem_flag = 1; if (!shmem_flag) { printf("no shmem available.\n"); exit (-1); } if (shmem_flag==1) CompletionType = XShmGetEventBase(dpy) + ShmCompletion; /**--------------------------------- XV ------------------------------------*/ printf("beginning to parse the Xvideo extension...\n\n"); /** query and print Xvideo properties */ ret = XvQueryExtension(dpy, &p_version, &p_release, &p_request_base, &p_event_base, &p_error_base); if (ret != Success) { if (ret == XvBadExtension) printf("XvBadExtension returned at XvQueryExtension.\n"); else if (ret == XvBadAlloc) printf("XvBadAlloc returned at XvQueryExtension.\n"); else printf("other error happened at XvQueryExtension.\n"); } printf("========================================\n"); printf("XvQueryExtension returned the following:\n"); printf("p_version : %u\n", p_version); printf("p_release : %u\n", p_release); printf("p_request_base : %u\n", p_request_base); printf("p_event_base : %u\n", p_event_base); printf("p_error_base : %u\n", p_error_base); printf("========================================\n"); ret = XvQueryAdaptors(dpy, DefaultRootWindow(dpy), &p_num_adaptors, &ai); if (ret != Success) { if (ret == XvBadExtension) printf("XvBadExtension returned at XvQueryExtension.\n"); else if (ret == XvBadAlloc) printf("XvBadAlloc returned at XvQueryExtension.\n"); else printf("other error happaned at XvQueryAdaptors.\n"); } printf("=======================================\n"); printf("XvQueryAdaptors returned the following:\n"); printf("%d adaptors available.\n", p_num_adaptors); for (i = 0; i < p_num_adaptors; i++) { printf(" name: %s\n" " type: %s%s%s%s%s\n" " ports: %ld\n" " first port: %ld\n", ai[i].name, (ai[i].type & XvInputMask) ? "input | " : "", (ai[i].type & XvOutputMask) ? "output | " : "", (ai[i].type & XvVideoMask) ? "video | " : "", (ai[i].type & XvStillMask) ? "still | " : "", (ai[i].type & XvImageMask) ? "image | " : "", ai[i].num_ports, ai[i].base_id); xv_port = ai[i].base_id; printf("adaptor %d ; format list:\n", i); for (j = 0; j < ai[i].num_formats; j++) { printf(" depth=%d, visual=%ld\n", ai[i].formats[j].depth, ai[i].formats[j].visual_id); } for (p = ai[i].base_id; p < ai[i].base_id+ai[i].num_ports; p++) { printf(" encoding list for port %d\n", p); if (XvQueryEncodings(dpy, p, &encodings, &ei) != Success) { printf("XvQueryEncodings failed.\n"); continue; } for (j = 0; j < encodings; j++) { printf(" id=%ld, name=%s, size=%ldx%ld, numerator=%d, denominator=%d\n", ei[j].encoding_id, ei[j].name, ei[j].width, ei[j].height, ei[j].rate.numerator, ei[j].rate.denominator); } XvFreeEncodingInfo(ei); printf(" attribute list for port %d\n", p); at = XvQueryPortAttributes(dpy, p, &attributes); for (j = 0; j < attributes; j++) { printf(" name: %s\n" " flags: %s%s\n" " min_color: %i\n" " max_color: %i\n", at[j].name, (at[j].flags & XvGettable) ? " get" : "", (at[j].flags & XvSettable) ? " set" : "", at[j].min_value, at[j].max_value); } if (at) XFree(at); printf(" image format list for port %d\n", p); fo = XvListImageFormats(dpy, p, &formats); for (j = 0; j < formats; j++) { printf(" 0x%x (%4.4s) %s\n", fo[j].id, (char *)&fo[j].id, (fo[j].format == XvPacked) ? "packed" : "planar"); } if (fo) XFree(fo); } printf("\n"); } if (p_num_adaptors > 0) XvFreeAdaptorInfo(ai); if (xv_port == -1) exit (0); gc = XCreateGC(dpy, window, 0, 0); yuv_image = XvShmCreateImage(dpy, xv_port, GUID_YUV12_PLANAR, 0, yuv_width, yuv_height, &yuv_shminfo); yuv_shminfo.shmid = shmget(IPC_PRIVATE, yuv_image->data_size, IPC_CREAT | 0777); yuv_shminfo.shmaddr = yuv_image->data = shmat(yuv_shminfo.shmid, 0, 0); yuv_shminfo.readOnly = False; if (!XShmAttach(dpy, &yuv_shminfo)) { printf("XShmAttach failed !\n"); exit (-1); } for (i = 0; i < yuv_image->height; i++) { for (j = 0; j < yuv_image->width; j++) { yuv_image->data[yuv_image->width*i + j] = i*j; } } printf("%d\n", yuv_image->data_size); int joe = 0; while (1) { frames = secsa = secsb = 0; time(&secsa); while (frames < 200) { XGetGeometry(dpy, window, &_dw, &_d, &_d, &_w, &_h, &_d, &_d); for (i = 0; i < yuv_image->height * 1.5; i++) { for (j = 0; j < yuv_image->width; j++) { yuv_image->data[yuv_image->width*i + j] = (i + j + joe / 5); } } XvShmPutImage(dpy, xv_port, window, gc, yuv_image, 0, 0, yuv_image->width, yuv_image->height, 0, 0, _w, _h, True); /* XFlush(dpy); */ joe++; frames++; } time(&secsb); printf("%ld frames in %ld seconds; %.4f fps\n", frames, secsb-secsa, (double) frames/(secsb-secsa)); } return 0; }
/* This function checks that it is actually really possible to create an image using XShm */ gboolean gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink, GstXContext * xcontext) { XvImage *xvimage; XShmSegmentInfo SHMInfo; size_t size; int (*handler) (Display *, XErrorEvent *); gboolean result = FALSE; gboolean did_attach = FALSE; g_return_val_if_fail (xcontext != NULL, FALSE); /* Sync to ensure any older errors are already processed */ XSync (xcontext->disp, FALSE); /* Set defaults so we don't free these later unnecessarily */ SHMInfo.shmaddr = ((void *) -1); SHMInfo.shmid = -1; /* Setting an error handler to catch failure */ error_caught = FALSE; handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); /* Trying to create a 1x1 picture */ GST_DEBUG ("XvShmCreateImage of 1x1"); xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id, xcontext->im_format, NULL, 1, 1, &SHMInfo); /* Might cause an error, sync to ensure it is noticed */ XSync (xcontext->disp, FALSE); if (!xvimage || error_caught) { GST_WARNING ("could not XvShmCreateImage a 1x1 image"); goto beach; } size = xvimage->data_size; SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); if (SHMInfo.shmid == -1) { GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", size); goto beach; } SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); if (SHMInfo.shmaddr == ((void *) -1)) { GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); /* Clean up the shared memory segment */ shmctl (SHMInfo.shmid, IPC_RMID, NULL); goto beach; } xvimage->data = SHMInfo.shmaddr; SHMInfo.readOnly = FALSE; if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { GST_WARNING ("Failed to XShmAttach"); /* Clean up the shared memory segment */ shmctl (SHMInfo.shmid, IPC_RMID, NULL); goto beach; } /* Sync to ensure we see any errors we caused */ XSync (xcontext->disp, FALSE); /* Delete the shared memory segment as soon as everyone is attached. * This way, it will be deleted as soon as we detach later, and not * leaked if we crash. */ shmctl (SHMInfo.shmid, IPC_RMID, NULL); if (!error_caught) { GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid, SHMInfo.shmseg); did_attach = TRUE; /* store whether we succeeded in result */ result = TRUE; } else { GST_WARNING ("MIT-SHM extension check failed at XShmAttach. " "Not using shared memory."); } beach: /* Sync to ensure we swallow any errors we caused and reset error_caught */ XSync (xcontext->disp, FALSE); error_caught = FALSE; XSetErrorHandler (handler); if (did_attach) { GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx", SHMInfo.shmid, SHMInfo.shmseg); XShmDetach (xcontext->disp, &SHMInfo); XSync (xcontext->disp, FALSE); } if (SHMInfo.shmaddr != ((void *) -1)) shmdt (SHMInfo.shmaddr); if (xvimage) XFree (xvimage); return result; }
int BC_Bitmap::allocate_data() { int want_row_pointers = 1; // Shared memory available if(use_shm) { switch(color_model) { // Planar YUV. Must use BC_WindowBase::accel_available before calling this. case BC_YUV420P: case BC_YUV422P: // Packed YUV case BC_YUV422: ring_buffers = BITMAP_RING; xv_portid = top_level->xvideo_port_id; // Create the X Image xv_image[0] = XvShmCreateImage(top_level->display, xv_portid, cmodel_bc_to_x(color_model), 0, w, h, &shm_info); // Create the shared memory shm_info.shmid = shmget(IPC_PRIVATE, xv_image[0]->data_size * ring_buffers + 4, IPC_CREAT | 0600); if(shm_info.shmid == -1) perror("BC_Bitmap::allocate_data shmget"); data[0] = (unsigned char *)shmat(shm_info.shmid, NULL, 0); // setting ximage->data stops BadValue xv_image[0]->data = shm_info.shmaddr = (char*)data[0]; shm_info.readOnly = 0; // Get the real parameters w = xv_image[0]->width; h = xv_image[0]->height; // Create remaining X Images for(int i = 1; i < ring_buffers; i++) { data[i] = data[0] + xv_image[0]->data_size * i; xv_image[i] = XvShmCreateImage(top_level->display, xv_portid, cmodel_bc_to_x(color_model), (char*)data[i], w, h, &shm_info); xv_image[i]->data = (char*)data[i]; } if(color_model == BC_YUV422) { bytes_per_line = w * 2; bits_per_pixel = 2; want_row_pointers = 1; } else { bytes_per_line = 0; bits_per_pixel = 0; want_row_pointers = 0; } break; default: // RGB ring_buffers = BITMAP_RING; // Create first X Image ximage[0] = XShmCreateImage(top_level->display, top_level->vis, get_default_depth(), get_default_depth() == 1 ? XYBitmap : ZPixmap, (char*)NULL, &shm_info, w, h); // Create shared memory shm_info.shmid = shmget(IPC_PRIVATE, h * ximage[0]->bytes_per_line * ring_buffers + 4, IPC_CREAT | 0600); if(shm_info.shmid == -1) perror("BC_Bitmap::allocate_data shmget"); data[0] = (unsigned char *)shmat(shm_info.shmid, NULL, 0); ximage[0]->data = shm_info.shmaddr = (char*)data[0]; // setting ximage->data stops BadValue shm_info.readOnly = 0; // Get the real parameters bits_per_pixel = ximage[0]->bits_per_pixel; bytes_per_line = ximage[0]->bytes_per_line; // Create remaining X Images for(int i = 1; i < ring_buffers; i++) { data[i] = data[0] + h * ximage[0]->bytes_per_line * i; ximage[i] = XShmCreateImage(top_level->display, top_level->vis, get_default_depth(), get_default_depth() == 1 ? XYBitmap : ZPixmap, (char*)data[i], &shm_info, w, h); ximage[i]->data = (char*)data[i]; //printf("BC_Bitmap::allocate_data %p\n", ximage[i]); } break; } if(!XShmAttach(top_level->display, &shm_info)) { perror("BC_Bitmap::allocate_data XShmAttach"); } // This causes it to automatically delete when the program exits. shmctl(shm_info.shmid, IPC_RMID, 0); } else // Use unshared memory. { ring_buffers = 1; // need to use bytes_per_line for some X servers data[0] = 0; // Use RGB frame //printf("BCBitmap::allocate_data 1\n"); ximage[0] = XCreateImage(top_level->display, top_level->vis, get_default_depth(), get_default_depth() == 1 ? XYBitmap : ZPixmap, 0, (char*)data[0], w, h, 8, 0); //printf("BCBitmap::allocate_data 1 %d\n", h * ximage[0]->bytes_per_line + 4); data[0] = (unsigned char*)malloc(h * ximage[0]->bytes_per_line + 4); //printf("BCBitmap::allocate_data 2\n"); XDestroyImage(ximage[0]); //printf("BCBitmap::allocate_data 1\n"); ximage[0] = XCreateImage(top_level->display, top_level->vis, get_default_depth(), get_default_depth() == 1 ? XYBitmap : ZPixmap, 0, (char*)data[0], w, h, 8, 0); //printf("BCBitmap::allocate_data 1\n"); // This differs from the depth parameter of the top_level. bits_per_pixel = ximage[0]->bits_per_pixel; bytes_per_line = ximage[0]->bytes_per_line; //printf("BCBitmap::allocate_data 2\n"); } // Create row pointers if(want_row_pointers) { //printf("BC_Bitmap::allocate 1 %d %d %d %d\n", w, h, get_default_depth(), bytes_per_line); for(int j = 0; j < ring_buffers; j++) { row_data[j] = new unsigned char*[h]; for(int i = 0; i < h; i++) { row_data[j][i] = &data[j][i * bytes_per_line]; } } } return 0; }
SDL_Overlay *X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) { SDL_Overlay *overlay; struct private_yuvhwdata *hwdata; int xv_port; int i, j; int adaptors; XvAdaptorInfo *ainfo; XShmSegmentInfo *yuvshm; xv_port = -1; if ( (Success == XvQueryExtension(GFX_Display, &j, &j, &j, &j, &j)) && (Success == XvQueryAdaptors(GFX_Display, RootWindow(GFX_Display, SDL_Screen), &adaptors, &ainfo)) ) { for ( i=0; (i<adaptors) && (xv_port == -1); ++i ) { if ( (ainfo[i].type & XvInputMask) && (ainfo[i].type & XvImageMask) ) { int num_formats; XvImageFormatValues *formats; formats = XvListImageFormats(GFX_Display, ainfo[i].base_id, &num_formats); for ( j=0; j<num_formats; ++j ) { if ( (Uint32)formats[j].id == format ) { xv_port = ainfo[i].base_id; break; } } } } } if ( xv_port == -1 ) { SDL_SetError("No available video ports for requested format"); return(NULL); } /* Create the overlay structure */ overlay = (SDL_Overlay *)malloc(sizeof *overlay); if ( overlay == NULL ) { SDL_OutOfMemory(); return(NULL); } memset(overlay, 0, (sizeof *overlay)); /* Fill in the basic members */ overlay->format = format; overlay->w = width; overlay->h = height; /* Set up the YUV surface function structure */ overlay->hwfuncs = &x11_yuvfuncs; /* Create the pixel data and lookup tables */ hwdata = (struct private_yuvhwdata *)malloc(sizeof *hwdata); overlay->hwdata = hwdata; if ( hwdata == NULL ) { SDL_OutOfMemory(); SDL_FreeYUVOverlay(overlay); return(NULL); } yuvshm = &hwdata->yuvshm; memset(yuvshm, 0, sizeof(*yuvshm)); hwdata->port = xv_port; hwdata->image = XvShmCreateImage(GFX_Display, xv_port, format, 0, width, height, yuvshm); if ( hwdata->image == NULL ) { SDL_OutOfMemory(); SDL_FreeYUVOverlay(overlay); return(NULL); } yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size, IPC_CREAT | 0777); if ( yuvshm->shmid < 0 ) { SDL_SetError("Unable to get %d bytes shared memory", hwdata->image->data_size); SDL_FreeYUVOverlay(overlay); return(NULL); } yuvshm->shmaddr = (caddr_t) shmat(yuvshm->shmid, 0, 0); yuvshm->readOnly = False; hwdata->image->data = yuvshm->shmaddr; XShmAttach(GFX_Display, yuvshm); XSync(GFX_Display, False); shmctl(yuvshm->shmid, IPC_RMID, 0); /* We're all done.. */ return(overlay); }