summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/out/vo_vdpau.c168
1 files changed, 154 insertions, 14 deletions
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index 973ca235da..2b4198ebfb 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -87,16 +87,22 @@ struct vdpctx {
VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES];
VdpOutputSurface screenshot_surface;
int num_output_surfaces;
+ VdpOutputSurface rgb_surfaces[NUM_BUFFERED_VIDEO];
+ VdpOutputSurface black_pixel;
struct buffered_video_surface {
+ // Either surface or rgb_surface is used (never both)
VdpVideoSurface surface;
+ VdpOutputSurface rgb_surface;
double pts;
mp_image_t *mpi;
} buffered_video[NUM_BUFFERED_VIDEO];
int deint_queue_pos;
int output_surface_width, output_surface_height;
+ int force_yuv;
VdpVideoMixer video_mixer;
struct mp_csp_details colorspace;
+ int user_deint;
int deint;
int deint_type;
int pullup;
@@ -136,6 +142,7 @@ struct vdpctx {
uint32_t image_format;
VdpChromaType vdp_chroma_type;
VdpYCbCrFormat vdp_pixel_format;
+ bool rgb_mode;
// OSD
struct osd_bitmap_surface {
@@ -218,8 +225,32 @@ static int render_video_to_output_surface(struct vo *vo,
return -1;
struct buffered_video_surface *bv = vc->buffered_video;
- int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
unsigned int dp = vc->deint_queue_pos;
+
+ vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue,
+ output_surface,
+ &dummy);
+ CHECK_ST_WARNING("Error when calling "
+ "vdp_presentation_queue_block_until_surface_idle");
+
+ if (vc->rgb_mode) {
+ int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0;
+ vdp_st = vdp->output_surface_render_output_surface(output_surface,
+ NULL, vc->black_pixel,
+ NULL, NULL, NULL,
+ flags);
+ CHECK_ST_WARNING("Error clearing screen");
+ vdp_st = vdp->output_surface_render_output_surface(output_surface,
+ output_rect,
+ bv[dp/2].rgb_surface,
+ video_rect,
+ NULL, NULL, flags);
+ CHECK_ST_WARNING("Error when calling "
+ "vdp_output_surface_render_output_surface");
+ return 0;
+ }
+
+ int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
// dp==0 means last field of latest frame, 1 earlier field of latest frame,
// 2 last field of previous frame and so on
if (vc->deint) {
@@ -231,11 +262,6 @@ static int render_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};
- vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue,
- output_surface,
- &dummy);
- CHECK_ST_WARNING("Error when calling "
- "vdp_presentation_queue_block_until_surface_idle");
vdp_st = vdp->video_mixer_render(vc->video_mixer, VDP_INVALID_HANDLE,
0, field, 2, past_fields,
@@ -306,6 +332,7 @@ static void set_next_frame_info(struct vo *vo, bool eof)
}
static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface,
+ VdpOutputSurface rgb_surface,
struct mp_image *reserved_mpi, double pts)
{
struct vdpctx *vc = vo->priv;
@@ -318,6 +345,7 @@ static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface,
bv[0] = (struct buffered_video_surface){
.mpi = reserved_mpi,
.surface = surface,
+ .rgb_surface = rgb_surface,
.pts = pts,
};
@@ -337,6 +365,7 @@ static void forget_frames(struct vo *vo)
mp_image_unrefp(&p->mpi);
*p = (struct buffered_video_surface){
.surface = VDP_INVALID_HANDLE,
+ .rgb_surface = VDP_INVALID_HANDLE,
};
}
}
@@ -549,6 +578,9 @@ static int set_video_attribute(struct vdpctx *vc, VdpVideoMixerAttribute attr,
struct vdp_functions *vdp = vc->vdp;
VdpStatus vdp_st;
+ if (vc->rgb_mode)
+ return -1;
+
vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, &attr,
&value);
if (vdp_st != VDP_STATUS_OK) {
@@ -680,11 +712,35 @@ static void free_video_specific(struct vo *vo)
CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
}
vc->screenshot_surface = VDP_INVALID_HANDLE;
+
+ for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) {
+ if (vc->rgb_surfaces[n] != VDP_INVALID_HANDLE) {
+ vdp_st = vdp->output_surface_destroy(vc->rgb_surfaces[n]);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
+ }
+ vc->rgb_surfaces[n] = VDP_INVALID_HANDLE;
+ }
+
+ if (vc->black_pixel != VDP_INVALID_HANDLE) {
+ vdp_st = vdp->output_surface_destroy(vc->black_pixel);
+ CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
+ }
+ vc->black_pixel = VDP_INVALID_HANDLE;
+}
+
+static int get_rgb_format(int imgfmt)
+{
+ switch (imgfmt) {
+ case IMGFMT_BGR32: return VDP_RGBA_FORMAT_B8G8R8A8;
+ default: return -1;
+ }
}
static int initialize_vdpau_objects(struct vo *vo)
{
struct vdpctx *vc = vo->priv;
+ struct vdp_functions *vdp = vc->vdp;
+ VdpStatus vdp_st;
mp_vdpau_get_format(vc->image_format, &vc->vdp_chroma_type,
&vc->vdp_pixel_format);
@@ -692,8 +748,27 @@ static int initialize_vdpau_objects(struct vo *vo)
if (win_x11_init_vdpau_flip_queue(vo) < 0)
return -1;
- if (create_vdp_mixer(vo, vc->vdp_chroma_type) < 0)
- return -1;
+ if (vc->rgb_mode) {
+ int format = get_rgb_format(vc->image_format);
+ for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) {
+ vdp_st = vdp->output_surface_create(vc->vdp_device,
+ format,
+ vc->vid_width, vc->vid_height,
+ &vc->rgb_surfaces[n]);
+ CHECK_ST_ERROR("Allocating RGB surface");
+ }
+ vdp_st = vdp->output_surface_create(vc->vdp_device, OUTPUT_RGBA_FORMAT,
+ 1, 1, &vc->black_pixel);
+ CHECK_ST_ERROR("Allocating clearing surface");
+ const char data[4] = {0};
+ vdp_st = vdp->output_surface_put_bits_native(vc->black_pixel,
+ (const void*[]){data},
+ (uint32_t[]){4}, NULL);
+ CHECK_ST_ERROR("Initializing clearing surface");
+ } else {
+ if (create_vdp_mixer(vo, vc->vdp_chroma_type) < 0)
+ return -1;
+ }
forget_frames(vo);
resize(vo);
@@ -706,7 +781,10 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
for (int i = 0; i < MAX_VIDEO_SURFACES; i++)
vc->video_surfaces[i].surface = VDP_INVALID_HANDLE;
+ for (int i = 0; i < NUM_BUFFERED_VIDEO; i++)
+ vc->rgb_surfaces[i] = VDP_INVALID_HANDLE;
forget_frames(vo);
+ vc->black_pixel = VDP_INVALID_HANDLE;
vc->video_mixer = VDP_INVALID_HANDLE;
vc->flip_queue = VDP_INVALID_HANDLE;
vc->flip_target = VDP_INVALID_HANDLE;
@@ -787,6 +865,10 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
vc->vid_width = width;
vc->vid_height = height;
+ vc->rgb_mode = get_rgb_format(format) >= 0;
+
+ vc->deint = vc->rgb_mode ? 0 : vc->user_deint;
+
free_video_specific(vo);
vo_x11_config_vo_window(vo, NULL, vo->dx, vo->dy, d_width, d_height,
@@ -1200,16 +1282,53 @@ static struct mp_image *get_video_surface(struct mp_vdpau_ctx *ctx, int fmt,
return NULL;
}
+static VdpOutputSurface get_rgb_surface(struct vo *vo)
+{
+ struct vdpctx *vc = vo->priv;
+
+ assert(vc->rgb_mode);
+
+ for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) {
+ VdpOutputSurface surface = vc->rgb_surfaces[n];
+ // Note: we expect to be called before add_new_video_surface(), which
+ // will lead to vc->buffered_video[NUM_BUFFERED_VIDEO - 1] to be
+ // marked unused. So this entries rgb_surface can be reused
+ // freely.
+ for (int i = 0; i < NUM_BUFFERED_VIDEO - 1; i++) {
+ if (vc->buffered_video[i].rgb_surface == surface)
+ goto in_use;
+ }
+ return surface;
+ in_use:;
+ }
+
+ mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] no surfaces available in "
+ "get_rgb_surface\n");
+ return VDP_INVALID_HANDLE;
+}
+
static void draw_image(struct vo *vo, mp_image_t *mpi)
{
struct vdpctx *vc = vo->priv;
struct vdp_functions *vdp = vc->vdp;
struct mp_image *reserved_mpi = NULL;
VdpVideoSurface surface = VDP_INVALID_HANDLE;
+ VdpOutputSurface rgb_surface = VDP_INVALID_HANDLE;
+ VdpStatus vdp_st;
if (IMGFMT_IS_VDPAU(vc->image_format)) {
surface = (VdpVideoSurface)(intptr_t)mpi->planes[3];
reserved_mpi = mp_image_new_ref(mpi);
+ } else if (vc->rgb_mode) {
+ rgb_surface = get_rgb_surface(vo);
+ if (rgb_surface != VDP_INVALID_HANDLE) {
+ vdp_st = vdp->output_surface_put_bits_native(rgb_surface,
+ &(const void *){mpi->planes[0]},
+ &(uint32_t){mpi->stride[0]},
+ NULL);
+ CHECK_ST_WARNING("Error when calling "
+ "output_surface_put_bits_native");
+ }
} else {
reserved_mpi = get_video_surface(&vc->mpvdp, IMGFMT_VDPAU,
vc->vdp_chroma_type, mpi->w, mpi->h);
@@ -1233,7 +1352,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
else
vc->top_field_first = 1;
- add_new_video_surface(vo, surface, reserved_mpi, mpi->pts);
+ add_new_video_surface(vo, surface, rgb_surface, reserved_mpi, mpi->pts);
return;
}
@@ -1296,12 +1415,17 @@ static struct mp_image *get_window_screenshot(struct vo *vo)
return image;
}
-
static int query_format(struct vo *vo, uint32_t format)
{
- if (!mp_vdpau_get_format(format, NULL, NULL))
- return 0;
- return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP;
+ struct vdpctx *vc = vo->priv;
+
+ int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP;
+ if (mp_vdpau_get_format(format, NULL, NULL))
+ return flags;
+ int rgb_format = get_rgb_format(format);
+ if (!vc->force_yuv && rgb_format >= 0)
+ return flags;
+ return 0;
}
static void destroy_vdpau_objects(struct vo *vo)
@@ -1399,6 +1523,10 @@ static int preinit(struct vo *vo)
static int get_equalizer(struct vo *vo, const char *name, int *value)
{
struct vdpctx *vc = vo->priv;
+
+ if (vc->rgb_mode)
+ return false;
+
return mp_csp_equalizer_get(&vc->video_eq, name, value) >= 0 ?
VO_TRUE : VO_NOTIMPL;
}
@@ -1407,6 +1535,9 @@ static int set_equalizer(struct vo *vo, const char *name, int value)
{
struct vdpctx *vc = vo->priv;
+ if (vc->rgb_mode)
+ return false;
+
if (mp_csp_equalizer_set(&vc->video_eq, name, value) < 0)
return VO_NOTIMPL;
@@ -1431,10 +1562,14 @@ static int control(struct vo *vo, uint32_t request, void *data)
switch (request) {
case VOCTRL_GET_DEINTERLACE:
+ if (vc->rgb_mode)
+ break;
*(int *)data = vc->deint;
return VO_TRUE;
case VOCTRL_SET_DEINTERLACE:
- vc->deint = *(int *)data;
+ if (vc->rgb_mode)
+ break;
+ vc->deint = vc->user_deint = *(int *)data;
if (vc->deint)
vc->deint = vc->deint_type;
if (vc->deint_type > 2 && status_ok(vo)) {
@@ -1475,12 +1610,16 @@ static int control(struct vo *vo, uint32_t request, void *data)
return get_equalizer(vo, args->name, args->valueptr);
}
case VOCTRL_SET_YUV_COLORSPACE:
+ if (vc->rgb_mode)
+ break;
vc->colorspace = *(struct mp_csp_details *)data;
if (status_ok(vo))
update_csc_matrix(vo);
vo->want_redraw = true;
return true;
case VOCTRL_GET_YUV_COLORSPACE:
+ if (vc->rgb_mode)
+ break;
*(struct mp_csp_details *)data = vc->colorspace;
return true;
case VOCTRL_NEWFRAME:
@@ -1559,6 +1698,7 @@ const struct vo_driver video_out_vdpau = {
.defval = &(const struct m_color) {
.r = 2, .g = 5, .b = 7, .a = 255,
}),
+ OPT_FLAG("force-yuv", force_yuv, 0),
{NULL},
}
};