Пример #1
0
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");
    }
}
Пример #2
0
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;
}
Пример #3
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;
}
Пример #4
0
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;
         }
     }
}
Пример #5
0
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);
    }
}
Пример #8
0
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;
}