static void put_updated_rectangle(rfbClient *client, int x, int y, int width, int height, int f_width, int f_height, int first_for_frame) { if (curr_surface == VA_INVALID_ID) { rfbClientErr("%s: called, but current surface is invalid\n", __FUNCTION__); return; } VAStatus va_status; if (client->outputWindow) { /* use efficient vaPutSurface() method of putting the framebuffer on the screen */ if (first_for_frame) { /* vaPutSurface() clears window contents outside the given destination rectangle => always update full screen. */ va_status = vaPutSurface(va_dpy, curr_surface, client->outputWindow, 0, 0, f_width, f_height, 0, 0, f_width, f_height, NULL, 0, VA_FRAME_PICTURE); CHECK_VASTATUS(va_status, "vaPutSurface"); } } else if (client->frameBuffer) { /* ... or copy the changed framebuffer region manually as a fallback */ VAImage decoded_image; decoded_image.image_id = VA_INVALID_ID; decoded_image.buf = VA_INVALID_ID; va_status = vaDeriveImage(va_dpy, curr_surface, &decoded_image); CHECK_VASTATUS(va_status, "vaDeriveImage"); if ((decoded_image.image_id == VA_INVALID_ID) || (decoded_image.buf == VA_INVALID_ID)) { rfbClientErr("%s: vaDeriveImage() returned success but VA image is invalid (id: %d, buf: %d)\n", __FUNCTION__, decoded_image.image_id, decoded_image.buf); } nv12_to_rgba(decoded_image, client, x, y, width, height); va_status = vaDestroyImage(va_dpy, decoded_image.image_id); CHECK_VASTATUS(va_status, "vaDestroyImage"); } }
static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image, GLuint *out_textures) { struct priv *p = hw->priv; VAStatus status; if (!p->pixmap) return -1; va_lock(p->ctx); status = vaPutSurface(p->display, va_surface_id(hw_image), p->pixmap, 0, 0, hw_image->w, hw_image->h, 0, 0, hw_image->w, hw_image->h, NULL, 0, va_get_colorspace_flag(hw_image->params.colorspace)); CHECK_VA_STATUS(p, "vaPutSurface()"); va_unlock(p->ctx); out_textures[0] = p->gl_texture; return 0; }
Decode_Status VaapiDecoderBase::getOutput(unsigned long draw, int64_t *timeStamp , int drawX, int drawY, int drawWidth, int drawHeight, bool draining , int frameX, int frameY, int frameWidth, int frameHeight) { VAStatus vaStatus = VA_STATUS_SUCCESS; const VideoRenderBuffer *renderBuffer = getOutput(draining); if (!renderBuffer) return RENDER_NO_AVAILABLE_FRAME; if (frameX == -1 && frameY == -1 && frameWidth == -1 && frameHeight == -1) { frameX = 0; frameY = 0; frameWidth = m_videoFormatInfo.width; frameHeight = m_videoFormatInfo.height; } if (!draw || drawX < 0 || drawY < 0 || drawWidth <=0 || drawHeight <=0 || frameX < 0 || frameY < 0 || frameWidth <= 0 || frameHeight <= 0) return RENDER_INVALID_PARAMETER; #if __ENABLE_X11__ vaStatus = vaPutSurface(m_display->getID(), renderBuffer->surface, draw, drawX, drawY, drawWidth, drawHeight, frameX, frameY, frameWidth, frameHeight, NULL,0,0); #else vaStatus = VA_STATUS_ERROR_OPERATION_FAILED; ERROR("vaPutSurface is not supported when libva-x11 backend is disable during build (--disable-x11)"); #endif if (vaStatus != VA_STATUS_SUCCESS) return RENDER_FAIL; *timeStamp = renderBuffer->timeStamp; renderDone(renderBuffer); return RENDER_SUCCESS; }
void GtkAggVaapiGlue::render() { VaapiGlobalContext * const gvactx = VaapiGlobalContext::get(); if (!gvactx) return; if (!_window_is_setup) return; if (!_vaapi_image.get() || !_vaapi_surface.get()) return; if (!_vaapi_image->unmap()) { printf("ERROR: failed to unmap VA-API image\n"); return; } VAStatus status; status = vaPutSurface(gvactx->display(), _vaapi_surface->get(), GDK_DRAWABLE_XID(_drawing_area->window), 0, 0, _vaapi_surface->width(), _vaapi_surface->height(), 0, 0, _window_width, _window_height, NULL, 0, VA_FRAME_PICTURE); if (!vaapi_check_status(status, "vaPutSurface() canvas")) return; Renderer_agg_base::RenderImages::const_iterator img, first_img, last_img; first_img = _agg_renderer->getFirstRenderImage(); last_img = _agg_renderer->getLastRenderImage(); if (first_img != last_img) { for (img = first_img; img != last_img; ++img) { boost::shared_ptr<VaapiSurface> surface = (*img)->surface(); VaapiRectangle src_rect; src_rect.x = (*img)->x(); src_rect.y = (*img)->y(); src_rect.width = (*img)->width(); src_rect.height = (*img)->height(); VaapiRectangle dst_rect; const float xscale = _window_width / (float)_vaapi_image_width; const float yscale = _window_height / (float)_vaapi_image_height; dst_rect.x = src_rect.x * xscale; dst_rect.y = src_rect.y * yscale; dst_rect.width = src_rect.width * xscale; dst_rect.height = src_rect.height * yscale; VaapiVideoWindow *videoWindow; videoWindow = getVideoWindow(surface, _drawing_area->window, dst_rect); if (!videoWindow) { log_debug(_("ERROR: failed to setup video window for surface 0x%08x."), surface->get()); continue; } videoWindow->moveResize(dst_rect); VaapiRectangle pic_rect(surface->width(), surface->height()); if (!surface->associateSubpicture(_vaapi_subpicture, src_rect, pic_rect)) { log_debug(_("ERROR: failed to associate subpicture to surface 0x%08x."), surface->get()); continue; } status = vaPutSurface(gvactx->display(), surface->get(), videoWindow->xid(), 0, 0, surface->width(), surface->height(), 0, 0, dst_rect.width, dst_rect.height, NULL, 0, VA_FRAME_PICTURE); if (!vaapi_check_status(status, "vaPutSurface() video")) continue; surface->deassociateSubpicture(_vaapi_subpicture); } for (img = first_img; img != last_img; ++img) { boost::shared_ptr<VaapiSurface> surface = (*img)->surface(); status = vaSyncSurface(gvactx->display(), surface->get()); if (!vaapi_check_status(status, "vaSyncSurface() video")) continue; } } }
static void* putsurface_thread(void *data) { int width=win_width, height=win_height; void *drawable = data; int quit = 0; VAStatus vaStatus; int row_shift = 0; int index = 0; unsigned int frame_num=0, start_time, putsurface_time; VARectangle cliprects[2]; /* client supplied clip list */ int continue_display = 0; if (drawable == drawable_thread0) printf("Enter into thread0\n\n"); if (drawable == drawable_thread1) printf("Enter into thread1\n\n"); putsurface_time = 0; while (!quit) { VASurfaceID surface_id = VA_INVALID_SURFACE; while (surface_id == VA_INVALID_SURFACE) surface_id = get_next_free_surface(&index); if (verbose) printf("Thread: %p Display surface 0x%x,\n", drawable, surface_id); if (multi_thread) upload_surface(va_dpy, surface_id, box_width, row_shift, display_field); if (check_event) pthread_mutex_lock(&gmutex); start_time = get_tick_count(); if ((continue_display == 0) && getenv("FRAME_STOP")) { char c; printf("Press any key to display frame %d...(c/C to continue)\n", frame_num); c = getchar(); if (c == 'c' || c == 'C') continue_display = 1; } if (test_color_conversion) { static int _put_surface_count = 0; if (_put_surface_count++ %50 == 0) { printf("do additional colorcoversion from %s to %s\n", map_vafourcc_to_str(csc_src_fourcc), map_vafourcc_to_str(csc_dst_fourcc)); } // get image from surface, csc_src_fourcc to csc_dst_fourcc conversion happens vaStatus = vaGetImage(va_dpy, surface_id, 0, 0, surface_width, surface_height, csc_dst_fourcc_image.image_id); CHECK_VASTATUS(vaStatus,"vaGetImage"); // render csc_dst_fourcc image to temp surface vaStatus = vaPutImage(va_dpy, csc_render_surface, csc_dst_fourcc_image.image_id, 0, 0, surface_width, surface_height, 0, 0, surface_width, surface_height); CHECK_VASTATUS(vaStatus,"vaPutImage"); // render the temp surface, it should be same with original surface without color conversion test vaStatus = vaPutSurface(va_dpy, csc_render_surface, CAST_DRAWABLE(drawable), 0,0,surface_width,surface_height, 0,0,width,height, (test_clip==0)?NULL:&cliprects[0], (test_clip==0)?0:2, display_field); CHECK_VASTATUS(vaStatus,"vaPutSurface"); } else { vaStatus = vaPutSurface(va_dpy, surface_id, CAST_DRAWABLE(drawable), 0,0,surface_width,surface_height, 0,0,width,height, (test_clip==0)?NULL:&cliprects[0], (test_clip==0)?0:2, display_field); CHECK_VASTATUS(vaStatus,"vaPutSurface"); } putsurface_time += (get_tick_count() - start_time); if (check_event) pthread_mutex_unlock(&gmutex); pthread_mutex_unlock(&surface_mutex[index]); /* locked in get_next_free_surface */ if ((frame_num % 0xff) == 0) { fprintf(stderr, "%.2f FPS \r", 256000.0 / (float)putsurface_time); putsurface_time = 0; update_clipbox(cliprects, width, height); } if (check_event) check_window_event(win_display, drawable, &width, &height, &quit); if (multi_thread) { /* reload surface content */ row_shift++; if (row_shift==(2*box_width)) row_shift= 0; } if (frame_rate != 0) /* rough framerate control */ usleep(1000/frame_rate*1000); frame_num++; if (frame_num >= frame_num_total) quit = 1; } if (drawable == drawable_thread1) pthread_exit(NULL); return 0; }
/** * gst_vaapi_texture_put_surface: * @texture: a #GstVaapiTexture * @surface: a #GstVaapiSurface * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags * * Renders the @surface into the àtexture. The @flags specify how * de-interlacing (if needed), color space conversion, scaling and * other postprocessing transformations are performed. * * Return value: %TRUE on success */ static gboolean gst_vaapi_texture_glx_put_surface_unlocked (GstVaapiTexture * base_texture, GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags) { GstVaapiTextureGLX *const texture = GST_VAAPI_TEXTURE_GLX (base_texture); VAStatus status; GLContextState old_cs; gboolean success = FALSE; const GLfloat *txc, *tyc; static const GLfloat g_texcoords[2][2] = { {0.0f, 1.0f}, {1.0f, 0.0f}, }; status = vaPutSurface (GST_VAAPI_OBJECT_VADISPLAY (texture), GST_VAAPI_OBJECT_ID (surface), texture->pixo->pixmap, crop_rect->x, crop_rect->y, crop_rect->width, crop_rect->height, 0, 0, base_texture->width, base_texture->height, NULL, 0, from_GstVaapiSurfaceRenderFlags (flags)); if (!vaapi_check_status (status, "vaPutSurface() [TFP]")) return FALSE; if (texture->gl_context && !gl_set_current_context (texture->gl_context, &old_cs)) return FALSE; if (!gl_bind_framebuffer_object (texture->fbo)) { GST_ERROR ("failed to bind FBO"); goto out_reset_context; } if (!gst_vaapi_surface_sync (surface)) { GST_ERROR ("failed to render surface to pixmap"); goto out_unbind_fbo; } if (!gl_bind_pixmap_object (texture->pixo)) { GST_ERROR ("could not bind GLX pixmap"); goto out_unbind_fbo; } flags = GST_VAAPI_TEXTURE_FLAGS (texture); txc = g_texcoords[! !(flags & GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED)]; tyc = g_texcoords[! !(flags & GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED)]; glColor4f (1.0f, 1.0f, 1.0f, 1.0f); glBegin (GL_QUADS); { glTexCoord2f (txc[0], tyc[0]); glVertex2i (0, 0); glTexCoord2f (txc[0], tyc[1]); glVertex2i (0, base_texture->height); glTexCoord2f (txc[1], tyc[1]); glVertex2i (base_texture->width, base_texture->height); glTexCoord2f (txc[1], tyc[0]); glVertex2i (base_texture->width, 0); } glEnd (); if (!gl_unbind_pixmap_object (texture->pixo)) { GST_ERROR ("failed to release GLX pixmap"); goto out_unbind_fbo; } success = TRUE; out_unbind_fbo: if (!gl_unbind_framebuffer_object (texture->fbo)) success = FALSE; out_reset_context: if (texture->gl_context && !gl_set_current_context (&old_cs, NULL)) success = FALSE; return success; }
static void request_buffers(struct pp_video_decoder_s *vd) { const PP_Instance instance = vd->instance->id; const struct PP_Size dimensions = { .width = vd->avctx->width, .height = vd->avctx->height }; pp_resource_release(vd->self_id); // TODO: how many surfaces do we need? vd->ppp_video_decoder_dev->ProvidePictureBuffers(instance, vd->self_id, 21, &dimensions, GL_TEXTURE_2D); pp_resource_acquire(vd->self_id, PP_RESOURCE_VIDEO_DECODER); } static uint32_t find_free_buffer(struct pp_video_decoder_s *vd) { for (uint32_t idx = 0; idx < vd->buffer_count; idx ++) { if (!vd->buffers[idx].used) { vd->buffers[idx].used = 1; return idx; } } return (uint32_t)-1; } static void issue_frame(struct pp_video_decoder_s *vd) { AVFrame *frame = vd->avframe; uint32_t idx = find_free_buffer(vd); int32_t bitstream_buffer_id = (int32_t)frame->pkt_pts; if (idx == (uint32_t)-1) { trace_warning("%s, no free buffer available\n", __func__); return; } struct pp_graphics3d_s *g3d = pp_resource_acquire(vd->graphics3d, PP_RESOURCE_GRAPHICS3D); if (!g3d) { trace_error("%s, bad resource\n", __func__); return; } VASurfaceID va_surf = GPOINTER_TO_SIZE(frame->data[3]); pthread_mutex_lock(&display.lock); glXMakeCurrent(display.x, g3d->glx_pixmap, g3d->glc); glBindTexture(GL_TEXTURE_2D, vd->buffers[idx].texture_id); display.glXBindTexImageEXT(display.x, vd->buffers[idx].glx_pixmap, GLX_FRONT_EXT, NULL); XFlush(display.x); vaPutSurface(display.va, va_surf, vd->buffers[idx].pixmap, 0, 0, frame->width, frame->height, 0, 0, frame->width, frame->height, NULL, 0, VA_FRAME_PICTURE); XFlush(display.x); glXMakeCurrent(display.x, None, NULL); pthread_mutex_unlock(&display.lock); pp_resource_release(vd->graphics3d); const PP_Instance instance = vd->instance->id; const struct PP_Picture_Dev picture = { .picture_buffer_id = vd->buffers[idx].id, .bitstream_buffer_id = bitstream_buffer_id, }; pp_resource_release(vd->self_id); vd->ppp_video_decoder_dev->PictureReady(instance, vd->self_id, &picture); pp_resource_acquire(vd->self_id, PP_RESOURCE_VIDEO_DECODER); } static void decode_frame(struct pp_video_decoder_s *vd, uint8_t *data, size_t data_len, int32_t bitstream_buffer_id) { AVPacket packet; av_init_packet(&packet); packet.data = data; packet.size = data_len; packet.pts = bitstream_buffer_id; // libavcodec can call hw functions, which in turn can call Xlib functions, // therefore we need to lock pthread_mutex_lock(&display.lock); int got_frame = 0; int len = avcodec_decode_video2(vd->avctx, vd->avframe, &got_frame, &packet); pthread_mutex_unlock(&display.lock); if (len < 0) { trace_error("%s, error %d while decoding frame\n", __func__, len); return; } if (got_frame) { if (!vd->buffers_were_requested) { request_buffers(vd); vd->buffers_were_requested = 1; } issue_frame(vd); } }
static void* putsurface_thread(void *data) { int width=win_width, height=win_height; void *drawable = data; int quit = 0; VAStatus vaStatus; int row_shift = 0; int index = 0; unsigned int frame_num=0, start_time, putsurface_time; VARectangle cliprects[2]; /* client supplied clip list */ int continue_display = 0; if (drawable == drawable_thread0) printf("Enter into thread0\n\n"); if (drawable == drawable_thread1) printf("Enter into thread1\n\n"); putsurface_time = 0; while (!quit) { VASurfaceID surface_id = VA_INVALID_SURFACE; while (surface_id == VA_INVALID_SURFACE) surface_id = get_next_free_surface(&index); if (verbose) printf("Thread %x Display surface 0x%p,\n", (unsigned int)drawable, (void *)surface_id); if (multi_thread) upload_surface(va_dpy, surface_id, box_width, row_shift, display_field); if (check_event) pthread_mutex_lock(&gmutex); start_time = get_tick_count(); if ((continue_display == 0) && getenv("FRAME_STOP")) { char c; printf("Press any key to display frame %d...(c/C to continue)\n", frame_num); c = getchar(); if (c == 'c' || c == 'C') continue_display = 1; } vaStatus = vaPutSurface(va_dpy, surface_id, CAST_DRAWABLE(drawable), 0,0,surface_width,surface_height, 0,0,width,height, (test_clip==0)?NULL:&cliprects[0], (test_clip==0)?0:2, display_field); CHECK_VASTATUS(vaStatus,"vaPutSurface"); putsurface_time += (get_tick_count() - start_time); if (check_event) pthread_mutex_unlock(&gmutex); pthread_mutex_unlock(&surface_mutex[index]); /* locked in get_next_free_surface */ if ((frame_num % 0xff) == 0) { fprintf(stderr, "%.2f FPS \r", 256000.0 / (float)putsurface_time); putsurface_time = 0; update_clipbox(cliprects, width, height); } if (check_event) check_window_event(win_display, drawable, &width, &height, &quit); if (multi_thread) { /* reload surface content */ row_shift++; if (row_shift==(2*box_width)) row_shift= 0; } if (frame_rate != 0) /* rough framerate control */ usleep(1000/frame_rate*1000); frame_num++; if (frame_num >= frame_num_total) quit = 1; } if (drawable == drawable_thread1) pthread_exit(NULL); return 0; }