diff options
Diffstat (limited to 'libvo')
-rw-r--r-- | libvo/gl_common.c | 19 | ||||
-rw-r--r-- | libvo/gl_common.h | 2 | ||||
-rw-r--r-- | libvo/vdpau_template.c | 1 | ||||
-rw-r--r-- | libvo/video_out.h | 19 | ||||
-rw-r--r-- | libvo/vo_gl.c | 59 | ||||
-rw-r--r-- | libvo/vo_vdpau.c | 100 | ||||
-rw-r--r-- | libvo/vo_xv.c | 51 |
7 files changed, 240 insertions, 11 deletions
diff --git a/libvo/gl_common.c b/libvo/gl_common.c index bbcbeb2f3b..f433f5642d 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -71,6 +71,7 @@ void glAdjustAlignment(GL *gl, int stride) else gl_alignment = 1; gl->PixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment); + gl->PixelStorei(GL_PACK_ALIGNMENT, gl_alignment); } struct gl_name_map_struct { @@ -635,6 +636,24 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, } /** + * \brief download a texture, handling things like stride and slices + * \param target texture target, usually GL_TEXTURE_2D + * \param format OpenGL format of data + * \param type OpenGL type of data + * \param dataptr destination memory for download + * \param stride data stride (must be positive) + * \ingroup gltexture + */ +void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type, + void *dataptr, int stride) +{ + // this is not always correct, but should work for MPlayer + glAdjustAlignment(gl, stride); + gl->PixelStorei(GL_PACK_ROW_LENGTH, stride / glFmt2bpp(format, type)); + gl->GetTexImage(target, 0, format, type, dataptr); +} + +/** * \brief Setup ATI version of register combiners for YUV to RGB conversion. * \param csp_params parameters used for colorspace conversion * \param text if set use the GL_ATI_text_fragment_shader API as diff --git a/libvo/gl_common.h b/libvo/gl_common.h index a56248403a..d1d034b99a 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -256,6 +256,8 @@ int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter, void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, const void *dataptr, int stride, int x, int y, int w, int h, int slice); +void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type, + void *dataptr, int stride); void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, int sx, int sy, int rect_tex, int is_yv12, int flip); diff --git a/libvo/vdpau_template.c b/libvo/vdpau_template.c index 3f9b26c5d8..14e5e7d211 100644 --- a/libvo/vdpau_template.c +++ b/libvo/vdpau_template.c @@ -18,6 +18,7 @@ VDP_FUNCTION(VdpDeviceDestroy, VDP_FUNC_ID_DEVICE_DESTROY, device_destroy) VDP_FUNCTION(VdpGenerateCSCMatrix, VDP_FUNC_ID_GENERATE_CSC_MATRIX, generate_csc_matrix) VDP_FUNCTION(VdpOutputSurfaceCreate, VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, output_surface_create) VDP_FUNCTION(VdpOutputSurfaceDestroy, VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY, output_surface_destroy) +VDP_FUNCTION(VdpOutputSurfaceGetBitsNative, VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE, output_surface_get_bits_native) VDP_FUNCTION(VdpOutputSurfacePutBitsIndexed, VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED, output_surface_put_bits_indexed) VDP_FUNCTION(VdpOutputSurfacePutBitsNative, VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE, output_surface_put_bits_native) VDP_FUNCTION(VdpOutputSurfaceRenderBitmapSurface, VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE, output_surface_render_bitmap_surface) diff --git a/libvo/video_out.h b/libvo/video_out.h index d1a2a7f65a..bd7b2e8fa5 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -78,6 +78,8 @@ enum mp_voctrl { VOCTRL_SET_YUV_COLORSPACE, // struct mp_csp_details VOCTRL_GET_YUV_COLORSPACE, // struct mp_csp_details + + VOCTRL_SCREENSHOT, // struct voctrl_screenshot_args }; // VOCTRL_SET_EQUALIZER @@ -104,6 +106,23 @@ typedef struct mp_eosd_res { int mt, mb, ml, mr; // borders (top, bottom, left, right) } mp_eosd_res_t; +// VOCTRL_SCREENSHOT +struct voctrl_screenshot_args { + // 0: Save image of the currently displayed video frame, in original + // resolution. + // 1: Save full screenshot of the window. Should contain OSD, EOSD, and the + // scaled video. + // The value of this variable can be ignored if only a single method is + // implemented. + int full_window; + // Will be set to a newly allocated image, that contains the screenshot. + // The caller has to free the pointer with free_mp_image(). + // It is not specified whether the image data is a copy or references the + // image data directly. + // Is never NULL. (Failure has to be indicated by returning VO_FALSE.) + struct mp_image *out_image; +}; + typedef struct { int x,y; int w,h; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 5f06cf7148..e99ff4432f 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -1134,6 +1134,57 @@ skip_upload: return VO_TRUE; } +static mp_image_t *get_screenshot(struct vo *vo) +{ + struct gl_priv *p = vo->priv; + GL *gl = p->gl; + + mp_image_t *image = alloc_mpi(p->texture_width, p->texture_height, + p->image_format); + + glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[0], + image->stride[0]); + + if (p->is_yuv) { + gl->ActiveTexture(GL_TEXTURE1); + glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[1], + image->stride[1]); + gl->ActiveTexture(GL_TEXTURE2); + glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[2], + image->stride[2]); + gl->ActiveTexture(GL_TEXTURE0); + } + + image->width = p->image_width; + image->height = p->image_height; + + image->w = p->image_d_width; + image->h = p->image_d_height; + + return image; +} + +static mp_image_t *get_window_screenshot(struct vo *vo) +{ + struct gl_priv *p = vo->priv; + GL *gl = p->gl; + + GLint vp[4]; //x, y, w, h + gl->GetIntegerv(GL_VIEWPORT, vp); + mp_image_t *image = alloc_mpi(vp[2], vp[3], IMGFMT_RGB24); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + gl->PixelStorei(GL_PACK_ALIGNMENT, 0); + gl->PixelStorei(GL_PACK_ROW_LENGTH, 0); + gl->ReadBuffer(GL_FRONT); + //flip image while reading + for (int y = 0; y < vp[3]; y++) { + gl->ReadPixels(vp[0], vp[1] + vp[3] - y - 1, vp[2], 1, + GL_RGB, GL_UNSIGNED_BYTE, + image->planes[0] + y * image->stride[0]); + } + return image; +} + static int query_format(struct vo *vo, uint32_t format) { struct gl_priv *p = vo->priv; @@ -1460,6 +1511,14 @@ static int control(struct vo *vo, uint32_t request, void *data) do_render_osd(vo, 2); flip_page(vo); return VO_TRUE; + case VOCTRL_SCREENSHOT: { + struct voctrl_screenshot_args *args = data; + if (args->full_window) + args->out_image = get_window_screenshot(vo); + else + args->out_image = get_screenshot(vo); + return true; + } } return VO_NOTIMPL; } diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 322645ebd3..be4540002b 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -88,6 +88,9 @@ /* Initial size of EOSD surface in pixels (x*x) */ #define EOSD_SURFACE_INITIAL_SIZE 256 +/* Pixelformat used for output surfaces */ +#define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8 + /* * Global variable declaration - VDPAU specific */ @@ -113,7 +116,7 @@ struct vdpctx { uint64_t last_vdp_time; unsigned int last_sync_update; - /* an extra last output surface is misused for OSD. */ + /* an extra last output surface is used for OSD and screenshots */ VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES + 1]; int num_output_surfaces; struct buffered_video_surface { @@ -158,6 +161,7 @@ struct vdpctx { bool dropped_frame; uint64_t dropped_time; uint32_t vid_width, vid_height; + uint32_t vid_d_width, vid_d_height; uint32_t image_format; VdpChromaType vdp_chroma_type; VdpYCbCrFormat vdp_pixel_format; @@ -242,7 +246,9 @@ static uint64_t convert_to_vdptime(struct vo *vo, unsigned int t) static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration); -static int video_to_output_surface(struct vo *vo) +static int render_video_to_output_surface(struct vo *vo, + VdpOutputSurface output_surface, + VdpRect *output_rect) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; @@ -265,7 +271,6 @@ static int video_to_output_surface(struct vo *vo) bv[(dp+1)/2].surface, bv[(dp+2)/2].surface}; const VdpVideoSurface *future_fields = (const VdpVideoSurface []){ dp >= 1 ? bv[(dp-1)/2].surface : VDP_INVALID_HANDLE}; - VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue, output_surface, &dummy); @@ -276,11 +281,20 @@ static int video_to_output_surface(struct vo *vo) 0, field, 2, past_fields, bv[dp/2].surface, 1, future_fields, &vc->src_rect_vid, output_surface, - NULL, &vc->out_rect_vid, 0, NULL); + NULL, output_rect, 0, NULL); CHECK_ST_WARNING("Error when calling vdp_video_mixer_render"); return 0; } +static int video_to_output_surface(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + + return render_video_to_output_surface(vo, + vc->output_surfaces[vc->surface_num], + &vc->out_rect_vid); +} + static void get_buffered_frame(struct vo *vo, bool eof) { struct vdpctx *vc = vo->priv; @@ -393,18 +407,21 @@ static void resize(struct vo *vo) int flip_offset_ms = vo_fs ? vc->flip_offset_fs : vc->flip_offset_window; vo->flip_queue_offset = flip_offset_ms / 1000.; + int min_output_width = FFMAX(vo->dwidth, vc->vid_width); + int min_output_height = FFMAX(vo->dheight, vc->vid_height); + bool had_frames = vc->num_shown_frames; - if (vc->output_surface_width < vo->dwidth - || vc->output_surface_height < vo->dheight) { - if (vc->output_surface_width < vo->dwidth) { + if (vc->output_surface_width < min_output_width + || vc->output_surface_height < min_output_height) { + if (vc->output_surface_width < min_output_width) { vc->output_surface_width += vc->output_surface_width >> 1; vc->output_surface_width = FFMAX(vc->output_surface_width, - vo->dwidth); + min_output_width); } - if (vc->output_surface_height < vo->dheight) { + if (vc->output_surface_height < min_output_height) { vc->output_surface_height += vc->output_surface_height >> 1; vc->output_surface_height = FFMAX(vc->output_surface_height, - vo->dheight); + min_output_height); } // Creation of output_surfaces for (i = 0; i <= vc->num_output_surfaces; i++) { @@ -414,7 +431,7 @@ static void resize(struct vo *vo) "vdp_output_surface_destroy"); } vdp_st = vdp->output_surface_create(vc->vdp_device, - VDP_RGBA_FORMAT_B8G8R8A8, + OUTPUT_RGBA_FORMAT, vc->output_surface_width, vc->output_surface_height, &vc->output_surfaces[i]); @@ -868,6 +885,9 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, vc->image_format = format; vc->vid_width = width; vc->vid_height = height; + vc->vid_d_width = d_width; + vc->vid_d_height = d_height; + free_video_specific(vo); if (IMGFMT_IS_VDPAU(vc->image_format) && !create_vdp_decoder(vo, 2)) return -1; @@ -1475,6 +1495,56 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) return; } +// warning: the size and pixel format of surface must match that of the +// surfaces in vc->output_surfaces +static struct mp_image *read_output_surface(struct vdpctx *vc, + VdpOutputSurface surface) +{ + VdpStatus vdp_st; + struct vdp_functions *vdp = vc->vdp; + struct mp_image *image = alloc_mpi(vc->output_surface_width, + vc->output_surface_height, IMGFMT_BGR32); + + void *dst_planes[] = { image->planes[0] }; + uint32_t dst_pitches[] = { image->stride[0] }; + vdp_st = vdp->output_surface_get_bits_native(surface, NULL, dst_planes, + dst_pitches); + CHECK_ST_WARNING("Error when calling vdp_output_surface_get_bits_native"); + + return image; +} + +static struct mp_image *get_screenshot(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + + VdpOutputSurface screenshot_surface = + vc->output_surfaces[vc->num_output_surfaces]; + + VdpRect rc = { .x1 = vc->vid_width, .y1 = vc->vid_height }; + render_video_to_output_surface(vo, screenshot_surface, &rc); + + struct mp_image *image = read_output_surface(vc, screenshot_surface); + + image->width = vc->vid_width; + image->height = vc->vid_height; + image->w = vc->vid_d_width; + image->h = vc->vid_d_height; + + return image; +} + +static struct mp_image *get_window_screenshot(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + int last_surface = WRAP_ADD(vc->surface_num, -1, vc->num_output_surfaces); + VdpOutputSurface screen = vc->output_surfaces[last_surface]; + struct mp_image *image = read_output_surface(vo->priv, screen); + image->width = image->w = vo->dwidth; + image->height = image->h = vo->dheight; + return image; +} + static uint32_t get_image(struct vo *vo, mp_image_t *mpi) { struct vdpctx *vc = vo->priv; @@ -1797,6 +1867,14 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_RESET: forget_frames(vo); return true; + case VOCTRL_SCREENSHOT: { + struct voctrl_screenshot_args *args = data; + if (args->full_window) + args->out_image = get_window_screenshot(vo); + else + args->out_image = get_screenshot(vo); + return true; + } } return VO_NOTIMPL; } diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 3c8b040195..694dbc048a 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -98,6 +98,8 @@ struct xvctx { uint32_t image_width; uint32_t image_height; uint32_t image_format; + uint32_t image_d_width; + uint32_t image_d_height; int is_paused; struct vo_rect src_rect; struct vo_rect dst_rect; @@ -212,6 +214,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, ctx->image_height = height; ctx->image_width = width; ctx->image_format = format; + ctx->image_d_width = d_width; + ctx->image_d_height = d_height; if ((ctx->max_width != 0 && ctx->max_height != 0) && (ctx->image_width > ctx->max_width @@ -521,6 +525,48 @@ static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w, return 0; } +static mp_image_t *get_screenshot(struct vo *vo) { + struct xvctx *ctx = vo->priv; + + // try to get an image without OSD + if (ctx->have_visible_image_copy) + copy_backup_image(vo, ctx->visible_buf, ctx->num_buffers); + + XvImage *xv_image = ctx->xvimage[ctx->visible_buf]; + + int w = xv_image->width; + int h = xv_image->height; + + mp_image_t *image = alloc_mpi(w, h, ctx->image_format); + + int bytes = 1; + if (!(image->flags & MP_IMGFLAG_PLANAR) && (image->flags & MP_IMGFLAG_YUV)) + // packed YUV + bytes = image->bpp / 8; + + memcpy_pic(image->planes[0], xv_image->data + xv_image->offsets[0], + bytes * w, h, image->stride[0], xv_image->pitches[0]); + + if (image->flags & MP_IMGFLAG_PLANAR) { + int swap = ctx->image_format == IMGFMT_YV12; + int p1 = swap ? 2 : 1; + int p2 = swap ? 1 : 2; + + w /= 2; + h /= 2; + + memcpy_pic(image->planes[p1], xv_image->data + xv_image->offsets[1], + w, h, image->stride[p1], xv_image->pitches[1]); + memcpy_pic(image->planes[p2], xv_image->data + xv_image->offsets[2], + w, h, image->stride[p2], xv_image->pitches[2]); + } + + image->w = ctx->image_d_width; + image->h = ctx->image_d_height; + + return image; +} + static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) { struct xvctx *ctx = vo->priv; @@ -829,6 +875,11 @@ static int control(struct vo *vo, uint32_t request, void *data) return VO_TRUE; case VOCTRL_REDRAW_OSD: return redraw_osd(vo, data); + case VOCTRL_SCREENSHOT: { + struct voctrl_screenshot_args *args = data; + args->out_image = get_screenshot(vo); + return true; + } } return VO_NOTIMPL; } |