static inline void put_xvimage(struct vo *vo, XvImage *xvi) { struct xvctx *ctx = vo->priv; struct vo_x11_state *x11 = vo->x11; struct mp_rect *src = &ctx->src_rect; struct mp_rect *dst = &ctx->dst_rect; int dw = dst->x1 - dst->x0, dh = dst->y1 - dst->y0; int sw = src->x1 - src->x0, sh = src->y1 - src->y0; #if HAVE_SHM if (ctx->Shmem_Flag) { XvShmPutImage(x11->display, ctx->xv_port, x11->window, x11->vo_gc, xvi, src->x0, src->y0, sw, sh, dst->x0, dst->y0, dw, dh, True); x11->ShmCompletionWaitCount++; } else #endif { XvPutImage(x11->display, ctx->xv_port, x11->window, x11->vo_gc, xvi, src->x0, src->y0, sw, sh, dst->x0, dst->y0, dw, dh); } }
void display_yuv_image(Display* display, XvPortID port, Drawable d, GC gc, XvImage* image, XShmSegmentInfo* shminfo, int src_x, int src_y, unsigned int src_w, unsigned int src_h, struct xywh_s *dest, double aspect_ratio) { int dest_x = 0, dest_y = 0; int dest_w = dest->w; int dest_h = dest->h; /* Maybe keep aspect ratio of src image. */ if (aspect_ratio == 0.0) { /* * Don't bother correcting any aspect ratio, just scale * to size as given. */ } else if (dest_w * src_h < src_w * aspect_ratio * dest_h) { dest_y = dest_h; dest_h = dest_w * src_h / (src_w * aspect_ratio); dest_y = (dest_y - dest_h) / 2; } else { dest_x = dest_w; dest_w = dest_h * src_w * aspect_ratio / src_h; dest_x = (dest_x - dest_w) / 2; } /* Record (for the lightpen code) where the scaled screen ended up */ dest->x = dest_x; dest->y = dest_y; dest->w = dest_w; dest->h = dest_h; if (shminfo) { XvShmPutImage(display, port, d, gc, image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w, dest_h, False); } else { XvPutImage(display, port, d, gc, image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w, dest_h); } }
int BC_Bitmap::write_drawable(Drawable &pixmap, GC &gc, int source_x, int source_y, int source_w, int source_h, int dest_x, int dest_y, int dest_w, int dest_h, int dont_wait) { //printf("BC_Bitmap::write_drawable 1 %p %d\n", this, current_ringbuffer);fflush(stdout); if(use_shm) { if(dont_wait) XSync(top_level->display, False); if(hardware_scaling()) { // printf("BC_Bitmap::write_drawable %d %d %d %d -> %d %d %d %d\n", source_x, // source_y, // source_w, // source_h, // dest_x, // dest_y, // dest_w, // dest_h); //for(int i = 0; i < 1000; i++) xv_image[current_ringbuffer]->data[i] = 255; //printf("BC_Bitmap::write_drawable 2 %d %d %p %p\n", xv_portid, // pixmap, // gc, // xv_image[current_ringbuffer]); XvShmPutImage(top_level->display, xv_portid, pixmap, gc, xv_image[current_ringbuffer], source_x, source_y, source_w, source_h, dest_x, dest_y, dest_w, dest_h, False); // Need to pass these to the XvStopVideo last_pixmap = pixmap; last_pixmap_used = 1; } else { // printf("BC_Bitmap::write_drawable %d %d %d %d -> %d %d %d %d\n", source_x, // source_y, // source_w, // source_h, // dest_x, // dest_y, // dest_w, // dest_h); XShmPutImage(top_level->display, pixmap, gc, ximage[current_ringbuffer], source_x, source_y, dest_x, dest_y, dest_w, dest_h, False); } // Force the X server into processing all requests. // This allows the shared memory to be written to again. if(!dont_wait) XSync(top_level->display, False); //TRACE("BC_Bitmap::write_drawable 5"); } else { XPutImage(top_level->display, pixmap, gc, ximage[current_ringbuffer], source_x, source_y, dest_x, dest_y, dest_w, dest_h); } //printf("BC_Bitmap %d\n", current_ringbuffer); current_ringbuffer++; if(current_ringbuffer >= ring_buffers) current_ringbuffer = 0; //printf("BC_Bitmap::write_drawable 2\n");fflush(stdout); return 0; }
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; }
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; }
void XVWindow::putFrame(uint8_t* frame, uint16_t width, uint16_t height) { XEvent event; if ((width!= _XVImage->width) || (height!=_XVImage->height)) { printf ("[x11] dynamic switching of resolution not supported\n"); return; } // event handling while (XPending(_display)) { XNextEvent(_display, &event); if (event.type == ClientMessage) { // if "closeWindow" is clicked do nothing right now (window is closed from the Qt Gui // if (event.xclient.format == 32 && event.xclient.data.l[0] == (signed) WM_DELETE_WINDOW) exit(0); } // the window size has changed if (event.type == ConfigureNotify) { XConfigureEvent* xce = (XConfigureEvent*) &event; // if a slave window exists it has to be resized as well if (_slave) { _slave->resize( xce->width - (int)(xce->width / DEFAULT_SLAVE_RATIO), xce->height - (int)(_slave->getYUVHeight() * xce->width / DEFAULT_SLAVE_RATIO / _slave->getYUVWidth()), (int)(xce->width / DEFAULT_SLAVE_RATIO), (int)(_slave->getYUVHeight() * xce->width / DEFAULT_SLAVE_RATIO / _slave->getYUVWidth())); } // if we are a slave window the master window takes care of aspect ration if (_master) { _state.curX=0; _state.curY=0; _state.curWidth=xce->width; _state.curHeight=xce->height; // if we are a master window we have to recalculate the window size (important for non 4:3 screens) } else { if ((xce->width*_XVImage->height/_XVImage->width)>xce->height) { _state.curX=(int)((xce->width-(xce->height*_XVImage->width/_XVImage->height))/2); _state.curY=0; _state.curWidth=(int)(xce->height*_XVImage->width/_XVImage->height); _state.curHeight=xce->height; } else if ((xce->height*_XVImage->width/_XVImage->height)>xce->width) { _state.curX=0; _state.curY=(int)((xce->height-(xce->width*_XVImage->height/_XVImage->width))/2); _state.curWidth=xce->width; _state.curHeight=(int)(xce->width*_XVImage->height/_XVImage->width); } else { _state.curX=0; _state.curY=0; _state.curWidth=xce->width; _state.curHeight=xce->height; } } } // a key is pressed if (event.type == KeyPress) { XKeyEvent* xke = (XKeyEvent*) &event; switch (xke->keycode) { case 41: toggleFullscreen(); // "f" break; case 40: setDecoration(!_state.decoration); // "d" break; case 32: toggleOntop(); // "o" break; case 9: if (_state.fullscreen) { toggleFullscreen(); } // esc break; } } // a mouse button is clicked if (event.type == ButtonPress) { if (_master) { _master->toggleFullscreen(); } else { toggleFullscreen(); } } } // copy image to shared memory memcpy(_XVImage->data, frame, (int) (_XVImage->width * _XVImage->height * 3 /2)); XvShmPutImage(_display, _XVPort, _XVWindow, _gc, _XVImage, 0, 0, _XVImage->width, _XVImage->height, _state.curX, _state.curY, _state.curWidth, _state.curHeight, True); XFlush(_display); }
static void x11video_process(MSFilter *f){ X11Video *obj=(X11Video*)f->data; mblk_t *inm; int update=0; MSPicture lsrc={0}; MSPicture src={0}; MSRect mainrect,localrect; bool_t precious=FALSE; bool_t local_precious=FALSE; XWindowAttributes wa; MSTickerLateEvent late_info; ms_filter_lock(f); if ((obj->window_id == 0) || (x11_error == TRUE)) goto end; XGetWindowAttributes(obj->display,obj->window_id,&wa); if (x11_error == TRUE) { ms_error("Could not get window attributes for window %lu", obj->window_id); goto end; } if (wa.width!=obj->wsize.width || wa.height!=obj->wsize.height){ ms_warning("Resized to %ix%i", wa.width,wa.height); obj->wsize.width=wa.width; obj->wsize.height=wa.height; XClearWindow(obj->display,obj->window_id); } ms_ticker_get_last_late_tick(f->ticker, &late_info); if(late_info.current_late_ms > 100) { ms_warning("Dropping frames because we're late"); goto end; } if (!obj->show) { goto end; } if (!obj->ready){ goto end; } if (f->inputs[0]!=NULL && (inm=ms_queue_peek_last(f->inputs[0]))!=0) { if (ms_yuv_buf_init_from_mblk(&src,inm)==0){ MSVideoSize newsize; newsize.width=src.w; newsize.height=src.h; precious=mblk_get_precious_flag(inm); if (!ms_video_size_equal(newsize,obj->vsize) ) { ms_message("received size is %ix%i",newsize.width,newsize.height); obj->vsize=newsize; if (obj->autofit){ MSVideoSize new_window_size; static const MSVideoSize min_size=MS_VIDEO_SIZE_QVGA; /*don't resize less than QVGA, it is too small*/ if (min_size.width*min_size.height>newsize.width*newsize.height){ new_window_size.width=newsize.width*2; new_window_size.height=newsize.height*2; }else new_window_size=newsize; obj->wsize=new_window_size; ms_message("autofit: new window size should be %ix%i",new_window_size.width,new_window_size.height); XResizeWindow(obj->display,obj->window_id,new_window_size.width,new_window_size.height); XSync(obj->display,FALSE); } x11video_unprepare(f); x11video_prepare(f); if (!obj->ready) goto end; } } update=1; } /*process last video message for local preview*/ if (obj->corner!=-1 && f->inputs[1]!=NULL && (inm=ms_queue_peek_last(f->inputs[1]))!=0) { if (ms_yuv_buf_init_from_mblk(&lsrc,inm)==0){ obj->lsize.width=lsrc.w; obj->lsize.height=lsrc.h; local_precious=mblk_get_precious_flag(inm); update=1; } } ms_layout_compute(obj->vsize, obj->vsize,obj->lsize,obj->corner,obj->scale_factor,&mainrect,&localrect); if (lsrc.w!=0 && obj->corner!=-1){ /* first reduce the local preview image into a temporary image*/ if (obj->local_msg==NULL){ obj->local_msg=ms_yuv_buf_alloc(&obj->local_pic,localrect.w,localrect.h); } if (obj->sws2==NULL){ obj->sws2=ms_scaler_create_context(lsrc.w,lsrc.h,MS_YUV420P,localrect.w,localrect.h,MS_YUV420P, MS_SCALER_METHOD_BILINEAR); } ms_scaler_process(obj->sws2,lsrc.planes,lsrc.strides,obj->local_pic.planes,obj->local_pic.strides); if (!local_precious) ms_yuv_buf_mirror(&obj->local_pic); } if (update && src.w!=0){ ms_yuv_buf_copy(src.planes,src.strides,obj->fbuf.planes,obj->fbuf.strides,obj->vsize); if (obj->mirror && !precious) ms_yuv_buf_mirror(&obj->fbuf); } /*copy resized local view into a corner:*/ if (update && obj->local_msg!=NULL && obj->corner!=-1){ MSPicture corner=obj->fbuf; MSVideoSize roi; roi.width=obj->local_pic.w; roi.height=obj->local_pic.h; corner.w=obj->local_pic.w; corner.h=obj->local_pic.h; corner.planes[0]+=localrect.x+(localrect.y*corner.strides[0]); corner.planes[1]+=(localrect.x/2)+((localrect.y/2)*corner.strides[1]); corner.planes[2]+=(localrect.x/2)+((localrect.y/2)*corner.strides[2]); corner.planes[3]=0; ms_yuv_buf_copy(obj->local_pic.planes,obj->local_pic.strides, corner.planes,corner.strides,roi); } if (update){ MSRect rect; ms_layout_center_rectangle(obj->wsize,obj->vsize,&rect); //ms_message("XvShmPutImage() %ix%i --> %ix%i",obj->fbuf.w,obj->fbuf.h,obj->wsize.width,obj->wsize.height); XvShmPutImage(obj->display,obj->port,obj->window_id,obj->gc, obj->xv_image, 0,0,obj->fbuf.w,obj->fbuf.h, rect.x,rect.y,rect.w,rect.h,TRUE); XSync(obj->display,FALSE); } end: ms_filter_unlock(f); if (f->inputs[0]!=NULL) ms_queue_flush(f->inputs[0]); if (f->inputs[1]!=NULL) ms_queue_flush(f->inputs[1]); }
bool QX11VideoSurface::present(const QVideoFrame &frame) { if (!m_image) { setError(StoppedError); return false; } else if (m_image->width != frame.width() || m_image->height != frame.height()) { setError(IncorrectFormatError); return false; } else { QVideoFrame frameCopy(frame); if (!frameCopy.map(QAbstractVideoBuffer::ReadOnly)) { setError(IncorrectFormatError); return false; } else { bool presented = false; if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle && m_image->data_size > frame.mappedBytes()) { qWarning("Insufficient frame buffer size"); setError(IncorrectFormatError); } else if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle && m_image->num_planes > 0 && m_image->pitches[0] != frame.bytesPerLine()) { qWarning("Incompatible frame pitches"); setError(IncorrectFormatError); } else { if (frame.handleType() != QAbstractVideoBuffer::XvShmImageHandle) { m_image->data = reinterpret_cast<char *>(frameCopy.bits()); //qDebug() << "copy frame"; XvPutImage( QX11Info::display(), m_portId, m_winId, m_gc, m_image, m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height(), m_displayRect.x(), m_displayRect.y(), m_displayRect.width(), m_displayRect.height()); m_image->data = 0; } else { XvImage *img = frame.handle().value<XvImage*>(); //qDebug() << "render directly"; if (img) XvShmPutImage( QX11Info::display(), m_portId, m_winId, m_gc, img, m_viewport.x(), m_viewport.y(), m_viewport.width(), m_viewport.height(), m_displayRect.x(), m_displayRect.y(), m_displayRect.width(), m_displayRect.height(), false); } presented = true; } frameCopy.unmap(); return presented; } } }
void S9xXVDisplayDriver::update (int width, int height) { int current_width, current_height, final_pitch; uint8 *final_buffer; int dst_x, dst_y, dst_width, dst_height; GtkAllocation allocation; gtk_widget_get_allocation (drawing_area, &allocation); current_width = allocation.width; current_height = allocation.height; if (width <= 0) { gdk_window_hide (gdk_window); return; } if (output_window_width != current_width || output_window_height != current_height) { resize_window (current_width, current_height); } if (config->scale_method > 0) { uint8 *src_buffer = (uint8 *) padded_buffer[0]; uint8 *dst_buffer = (uint8 *) padded_buffer[1]; int src_pitch = image_width * image_bpp; int dst_pitch = scaled_max_width * image_bpp; S9xFilter (src_buffer, src_pitch, dst_buffer, dst_pitch, width, height); final_buffer = (uint8 *) padded_buffer[1]; final_pitch = dst_pitch; } else { final_buffer = (uint8 *) padded_buffer[0]; final_pitch = image_width * image_bpp; } update_image_size (width, height); if (format == FOURCC_YUY2) { S9xConvertYUV (final_buffer, (uint8 *) xv_image->data, final_pitch, 2 * xv_image->width, width + (width < xv_image->width ? (width % 2) + 4 : 0), height + (height < xv_image->height ? 4 : 0)); } else { S9xConvertMask (final_buffer, (uint8 *) xv_image->data, final_pitch, bytes_per_pixel * xv_image->width, width + (width < xv_image->width ? (width % 2) + 4 : 0), height + (height < xv_image->height ? 4 : 0), rshift, gshift, bshift, bpp); } dst_x = width; dst_y = height; dst_width = current_width; dst_height = current_height; S9xApplyAspect (dst_x, dst_y, dst_width, dst_height); if (last_known_width != dst_width || last_known_height != dst_height) { last_known_width = dst_width; last_known_height = dst_height; clear (); } XvShmPutImage (display, xv_portid, xwindow, XDefaultGC (display, XDefaultScreen (display)), xv_image, 0, 0, width, height, dst_x, dst_y, dst_width, dst_height, False); top_level->set_mouseable_area (dst_x, dst_y, dst_width, dst_height); XSync (display, False); return; }
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); }
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; }
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::PutFrame (uint8_t* frame, uint16_t width, uint16_t height) { if (!_XVImage[_curBuffer]) return; if (width != _XVImage[_curBuffer]->width || height != _XVImage[_curBuffer]->height) { PTRACE (1, "XVideo\tDynamic switching of resolution not supported\n"); return; } XLockDisplay (_display); if (_XVImage[_curBuffer]->pitches [0] ==_XVImage[_curBuffer]->width && _XVImage[_curBuffer]->pitches [2] == (int) (_XVImage[_curBuffer]->width / 2) && _XVImage[_curBuffer]->pitches [1] == (int) (_XVImage[_curBuffer]->width / 2)) { memcpy (_XVImage[_curBuffer]->data, frame, (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height)); memcpy (_XVImage[_curBuffer]->data + (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height), frame + _XVImage[_curBuffer]->offsets [2], (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height / 4)); memcpy (_XVImage[_curBuffer]->data + (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height * 5 / 4), frame + _XVImage[_curBuffer]->offsets [1], (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height / 4)); } else { unsigned int i = 0; int width2 = (int) (_XVImage[_curBuffer]->width / 2); uint8_t* dstY = (uint8_t*) _XVImage[_curBuffer]->data; uint8_t* dstV = (uint8_t*) _XVImage[_curBuffer]->data + (_XVImage[_curBuffer]->pitches [0] * _XVImage[_curBuffer]->height); uint8_t* dstU = (uint8_t*) _XVImage[_curBuffer]->data + (_XVImage[_curBuffer]->pitches [0] * _XVImage[_curBuffer]->height) + (_XVImage[_curBuffer]->pitches [1] * (_XVImage[_curBuffer]->height/2)); uint8_t* srcY = frame; uint8_t* srcV = frame + (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height * 5 / 4); uint8_t* srcU = frame + (int) (_XVImage[_curBuffer]->width * _XVImage[_curBuffer]->height); for (i = 0 ; i < (unsigned int)_XVImage[_curBuffer]->height ; i+=2) { memcpy (dstY, srcY, _XVImage[_curBuffer]->width); dstY +=_XVImage[_curBuffer]->pitches [0]; srcY +=_XVImage[_curBuffer]->width; memcpy (dstY, srcY, _XVImage[_curBuffer]->width); dstY +=_XVImage[_curBuffer]->pitches [0]; srcY +=_XVImage[_curBuffer]->width; memcpy (dstV, srcV, width2); dstV +=_XVImage[_curBuffer]->pitches [1]; srcV += width2; memcpy(dstU, srcU, width2); dstU+=_XVImage[_curBuffer]->pitches [2]; srcU += width2; } } #ifdef HAVE_SHM if (_useShm) { XvShmPutImage (_display, _XVPort, _XWindow, _gc, _XVImage[_curBuffer], 0, 0, _XVImage[_curBuffer]->width, _XVImage[_curBuffer]->height, _state.curX, _state.curY, _state.curWidth, _state.curHeight, false); } else #endif { XvPutImage (_display, _XVPort, _XWindow, _gc, _XVImage[_curBuffer], 0, 0, _XVImage[_curBuffer]->width, _XVImage[_curBuffer]->height, _state.curX, _state.curY, _state.curWidth, _state.curHeight); } _curBuffer = (_curBuffer + 1) % NUM_BUFFERS; XUnlockDisplay (_display); }
static int display_frame(X11XVDisplaySink* sink, X11DisplayFrame* frame, const FrameInfo* frameInfo) { struct timeval timeNow; long requiredUsec; long durationSlept; unsigned int windowWidth; unsigned int windowHeight; float scaleFactorX; float scaleFactorY; float scaleFactor; YUV_frame inputFrame; YUV_frame outputFrame; unsigned char* activeBuffer; int frameDurationMsec; int frameSlippage; frameDurationMsec = (int)(1000 * frameInfo->frameRate.den / (double)(frameInfo->frameRate.num)); frameSlippage = frameDurationMsec * 1000 / 2; /* half a frame */ if (frame->videoIsPresent) { /* convert if required */ if (sink->inputVideoFormat == UYVY_10BIT_FORMAT) { if (sink->swScale != 1) { /* scale required afterwards */ activeBuffer = frame->scaleInputBuffer; } else { /* no scale afterwards */ activeBuffer = (unsigned char*)frame->yuv_image->data; } ConvertFrameV210to8(activeBuffer, frame->inputBuffer, sink->inputWidth * 2, (sink->inputWidth + 47) / 48 * 128, sink->inputWidth, sink->inputHeight); } else if (sink->inputVideoFormat == YUV444_FORMAT) { if (sink->swScale != 1) { /* scale required afterwards */ activeBuffer = frame->scaleInputBuffer; } else { /* no scale afterwards */ activeBuffer = (unsigned char*)frame->yuv_image->data; } yuv444_to_uyvy(sink->inputWidth, sink->inputHeight, frame->inputBuffer, activeBuffer); } else if (sink->inputVideoFormat == YUV422_FORMAT) { if (sink->swScale != 1) { /* scale required afterwards */ activeBuffer = frame->scaleInputBuffer; } else { /* no scale afterwards */ activeBuffer = (unsigned char*)frame->yuv_image->data; } yuv422_to_uyvy_2(sink->inputWidth, sink->inputHeight, 0, frame->inputBuffer, activeBuffer); } else if (sink->inputVideoFormat == YUV422_10BIT_FORMAT) { if (sink->swScale != 1) { /* scale required afterwards */ activeBuffer = frame->scaleInputBuffer; } else { /* no scale afterwards */ activeBuffer = (unsigned char*)frame->yuv_image->data; } ConvertFrameYUV10to8_2(frame->ditherOutputBuffer, (const uint16_t*)frame->inputBuffer, sink->inputWidth, sink->inputHeight, 2, 1); yuv422_to_uyvy_2(sink->inputWidth, sink->inputHeight, 0, frame->ditherOutputBuffer, activeBuffer); } else if (sink->inputVideoFormat == YUV420_10BIT_FORMAT) { if (sink->swScale != 1) { /* scale required afterwards */ activeBuffer = frame->scaleInputBuffer; } else { /* no scale afterwards */ activeBuffer = (unsigned char*)frame->yuv_image->data; } ConvertFrameYUV10to8_2(activeBuffer, (const uint16_t*)frame->inputBuffer, sink->inputWidth, sink->inputHeight, 2, 2); } else { /* no conversion - scale input frame->input buffer != frame->yuv_image->data */ activeBuffer = frame->inputBuffer; } /* scale image and output to frame->yuv_image */ if (sink->swScale != 1) { YUV_frame_from_buffer(&inputFrame, (void*)activeBuffer, sink->inputWidth, sink->inputHeight, sink->outputYUVFormat); YUV_frame_from_buffer(&outputFrame, (void*)(unsigned char*)frame->yuv_image->data, sink->width, sink->height, sink->outputYUVFormat); small_pic(&inputFrame, &outputFrame, 0, 0, sink->swScale, sink->swScale, 1, sink->applyScaleFilter, sink->applyScaleFilter, frame->scaleWorkspace); } /* add OSD to frame */ if (sink->osd != NULL && sink->osdInitialised) { if (!osd_add_to_image(sink->osd, frameInfo, (unsigned char*)frame->yuv_image->data, frame->yuv_image->width, frame->yuv_image->height)) { ml_log_error("Failed to add OSD to frame\n"); /* continue anyway */ } } /* wait until it is time to display this frame */ gettimeofday(&timeNow, NULL); durationSlept = 0; if (frameInfo->rateControl) { durationSlept = sleep_diff(frameDurationMsec * 1000, &timeNow, &sink->lastFrameTime); } /* adjust the display width/height if the window has been resized */ windowWidth = sink->x11Common.windowWidth; windowHeight = sink->x11Common.windowHeight; scaleFactorX = windowWidth / (float)(sink->initialDisplayWidth); scaleFactorY = windowHeight / (float)(sink->initialDisplayHeight); scaleFactor = (scaleFactorX < scaleFactorY) ? scaleFactorX : scaleFactorY; sink->x11Common.displayWidth = sink->initialDisplayWidth * scaleFactor; sink->x11Common.displayHeight = sink->initialDisplayHeight * scaleFactor; XLockDisplay(sink->x11Common.windowInfo.display); if (sink->useSharedMemory) { XvShmPutImage(sink->x11Common.windowInfo.display, sink->xvport, sink->x11Common.windowInfo.window, sink->x11Common.windowInfo.gc, frame->yuv_image, 0, 0, frame->yuv_image->width, frame->yuv_image->height, 0, 0, sink->x11Common.displayWidth, sink->x11Common.displayHeight, False); } else { XvPutImage(sink->x11Common.windowInfo.display, sink->xvport, sink->x11Common.windowInfo.window, sink->x11Common.windowInfo.gc, frame->yuv_image, 0, 0, frame->yuv_image->width, frame->yuv_image->height, 0, 0, sink->x11Common.displayWidth, sink->x11Common.displayHeight); } XSync(sink->x11Common.windowInfo.display, False); XUnlockDisplay(sink->x11Common.windowInfo.display); x11c_process_events(&sink->x11Common); /* report that a new frame has been displayed */ msl_frame_displayed(sink->listener, frameInfo); /* set the time that this frame was displayed */ if (frameInfo->rateControl) { if (durationSlept < - frameSlippage) { /* reset rate control when slipped by more than frameSlippage */ sink->lastFrameTime = timeNow; } else { /* set what the frame's display time should have been */ requiredUsec = sink->lastFrameTime.tv_sec * 1000000 + sink->lastFrameTime.tv_usec + frameDurationMsec * 1000; sink->lastFrameTime.tv_usec = requiredUsec % 1000000; sink->lastFrameTime.tv_sec = requiredUsec / 1000000; } } else { gettimeofday(&sink->lastFrameTime, NULL); } } else { gettimeofday(&sink->lastFrameTime, NULL); } reset_streams(frame); return 1; }