summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-22 20:55:17 +0200
committerwm4 <wm4@nowhere>2014-05-22 20:59:31 +0200
commit7b7e15a460f2a24ba8c42f6caa71f1ca0ad25499 (patch)
tree3ed0a651606f334ec17a69b049689a0d2005659e /video
parentdbed21cde451aed60e7e06b3c700234dcffd8012 (diff)
downloadmpv-7b7e15a460f2a24ba8c42f6caa71f1ca0ad25499.tar.bz2
mpv-7b7e15a460f2a24ba8c42f6caa71f1ca0ad25499.tar.xz
vdpau: move RGB surface management out of the VO
Integrate it with the existing surface allocator in vdpau.c. The changes are a bit violent, because the vdpau API is so non-orthogonal: compared to video surfaces, output surfaces use a different ID type, different format types, and different API functions. Also, introduce IMGFMT_VDPAU_OUTPUT for VdpOutputSurfaces wrapped in mp_image, rather than hacking it. This is a bit cleaner.
Diffstat (limited to 'video')
-rw-r--r--video/img_format.c18
-rw-r--r--video/img_format.h6
-rw-r--r--video/out/vo_vdpau.c88
-rw-r--r--video/vdpau.c119
-rw-r--r--video/vdpau.h5
5 files changed, 123 insertions, 113 deletions
diff --git a/video/img_format.c b/video/img_format.c
index c8f1851a43..01bf2b2b87 100644
--- a/video/img_format.c
+++ b/video/img_format.c
@@ -42,6 +42,8 @@ struct mp_imgfmt_entry {
};
static const struct mp_imgfmt_entry mp_imgfmt_list[] = {
+ // not in ffmpeg
+ FMT("vdpau_output", IMGFMT_VDPAU_OUTPUT)
// these formats are pretty common, and the "le"/"be" suffixes enforced
// by FFmpeg are annoying
FMT("yuv420p10", IMGFMT_420P10)
@@ -128,12 +130,26 @@ const char *mp_imgfmt_to_name(int fmt)
return "unknown";
}
+static struct mp_imgfmt_desc mp_only_imgfmt_desc(int mpfmt)
+{
+ switch (mpfmt) {
+ case IMGFMT_VDPAU_OUTPUT:
+ return (struct mp_imgfmt_desc) {
+ .id = mpfmt,
+ .avformat = AV_PIX_FMT_NONE,
+ .name = mp_imgfmt_to_name(mpfmt),
+ .flags = MP_IMGFLAG_BE | MP_IMGFLAG_LE | MP_IMGFLAG_RGB,
+ };
+ }
+ return (struct mp_imgfmt_desc) {0};
+}
+
struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
{
enum AVPixelFormat fmt = imgfmt2pixfmt(mpfmt);
const AVPixFmtDescriptor *pd = av_pix_fmt_desc_get(fmt);
if (!pd || fmt == AV_PIX_FMT_NONE)
- return (struct mp_imgfmt_desc) {0};
+ return mp_only_imgfmt_desc(mpfmt);
struct mp_imgfmt_desc desc = {
.id = mpfmt,
diff --git a/video/img_format.h b/video/img_format.h
index 31c72f41be..9277b0698c 100644
--- a/video/img_format.h
+++ b/video/img_format.h
@@ -252,7 +252,8 @@ enum mp_imgfmt {
// Hardware accelerated formats. Plane data points to special data
// structures, instead of pixel data.
- IMGFMT_VDPAU,
+ IMGFMT_VDPAU, // VdpVideoSurface
+ IMGFMT_VDPAU_OUTPUT, // VdpOutputSurface
IMGFMT_VDA,
IMGFMT_VAAPI,
@@ -330,7 +331,8 @@ static inline bool IMGFMT_IS_RGB(int fmt)
#define IMGFMT_RGB_DEPTH(fmt) (mp_imgfmt_get_desc(fmt).plane_bits)
#define IMGFMT_IS_HWACCEL(fmt) \
- ((fmt) == IMGFMT_VDPAU || (fmt) == IMGFMT_VAAPI || (fmt) == IMGFMT_VDA)
+ ((fmt) == IMGFMT_VDPAU || (fmt) == IMGFMT_VDPAU_OUTPUT || \
+ (fmt) == IMGFMT_VAAPI || (fmt) == IMGFMT_VDA)
int mp_imgfmt_from_name(bstr name, bool allow_hwaccel);
const char *mp_imgfmt_to_name(int fmt);
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index 260b9dccff..b6728e79d8 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -60,7 +60,6 @@
/* number of video and output surfaces */
#define MAX_OUTPUT_SURFACES 15
-#define NUM_BUFFERED_VIDEO 5
/* Pixelformat used for output surfaces */
#define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8
@@ -83,8 +82,6 @@ struct vdpctx {
VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES];
VdpOutputSurface screenshot_surface;
int num_output_surfaces;
- VdpOutputSurface rgb_surfaces[NUM_BUFFERED_VIDEO];
- bool rgb_surfaces_used[NUM_BUFFERED_VIDEO];
VdpOutputSurface black_pixel;
struct mp_image *current_image;
@@ -177,7 +174,7 @@ static int render_video_to_output_surface(struct vo *vo,
"vdp_presentation_queue_block_until_surface_idle");
if (vc->rgb_mode) {
- VdpOutputSurface surface = (uintptr_t)mpi->planes[0];
+ VdpOutputSurface surface = (uintptr_t)mpi->planes[3];
int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0;
vdp_st = vdp->output_surface_render_output_surface(output_surface,
NULL, vc->black_pixel,
@@ -373,15 +370,6 @@ static void free_video_specific(struct vo *vo)
}
vc->screenshot_surface = VDP_INVALID_HANDLE;
- for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) {
- assert(!vc->rgb_surfaces_used[n]);
- if (vc->rgb_surfaces[n] != VDP_INVALID_HANDLE) {
- vdp_st = vdp->output_surface_destroy(vc->rgb_surfaces[n]);
- CHECK_VDP_WARNING(vo, "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_VDP_WARNING(vo, "Error when calling vdp_output_surface_destroy");
@@ -389,14 +377,6 @@ static void free_video_specific(struct vo *vo)
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;
@@ -412,17 +392,6 @@ static int initialize_vdpau_objects(struct vo *vo)
if (win_x11_init_vdpau_flip_queue(vo) < 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_VDP_ERROR(vo, "Allocating RGB surface");
- }
- }
-
if (vc->black_pixel == VDP_INVALID_HANDLE) {
vdp_st = vdp->output_surface_create(vc->vdp_device, OUTPUT_RGBA_FORMAT,
1, 1, &vc->black_pixel);
@@ -443,8 +412,6 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
{
struct vdpctx *vc = vo->priv;
- for (int i = 0; i < NUM_BUFFERED_VIDEO; i++)
- vc->rgb_surfaces[i] = VDP_INVALID_HANDLE;
forget_frames(vo, false);
vc->black_pixel = VDP_INVALID_HANDLE;
vc->video_mixer->video_mixer = VDP_INVALID_HANDLE;
@@ -502,7 +469,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
vc->vid_width = params->w;
vc->vid_height = params->h;
- vc->rgb_mode = get_rgb_format(params->imgfmt) >= 0;
+ vc->rgb_mode = mp_vdpau_get_rgb_format(params->imgfmt, NULL);
free_video_specific(vo);
@@ -872,33 +839,6 @@ static void flip_page_timed(struct vo *vo, int64_t pts_us, int duration)
vc->surface_num = WRAP_ADD(vc->surface_num, 1, vc->num_output_surfaces);
}
-static void free_rgb_surface(void *ptr)
-{
- bool *entry = ptr;
- *entry = false;
-}
-
-static struct mp_image *get_rgb_surface(struct vo *vo)
-{
- struct vdpctx *vc = vo->priv;
-
- assert(vc->rgb_mode);
-
- for (int n = 0; n < NUM_BUFFERED_VIDEO; n++) {
- bool *used = &vc->rgb_surfaces_used[n];
- if (!*used) {
- *used = true;
- struct mp_image mpi = {0};
- mp_image_setfmt(&mpi, IMGFMT_VDPAU); // not really, but keep csp flags
- mpi.planes[0] = (void *)(uintptr_t)vc->rgb_surfaces[n];
- return mp_image_new_custom_ref(&mpi, used, free_rgb_surface);
- }
- }
-
- MP_ERR(vo, "no surfaces available in get_rgb_surface\n");
- return NULL;
-}
-
static void draw_image(struct vo *vo, struct mp_image *mpi)
{
struct vdpctx *vc = vo->priv;
@@ -912,29 +852,10 @@ static void draw_image(struct vo *vo, struct mp_image *mpi)
static struct mp_image *filter_image(struct vo *vo, struct mp_image *mpi)
{
struct vdpctx *vc = vo->priv;
- struct vdp_functions *vdp = vc->vdp;
- struct mp_image *reserved_mpi = NULL;
- VdpStatus vdp_st;
check_preemption(vo);
- if (vc->rgb_mode) {
- reserved_mpi = get_rgb_surface(vo);
- if (!reserved_mpi)
- goto end;
- VdpOutputSurface rgb_surface = (uintptr_t)reserved_mpi->planes[0];
- 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_VDP_WARNING(vo, "Error when calling "
- "output_surface_put_bits_native");
- }
- } else {
- reserved_mpi = mp_vdpau_upload_video_surface(vc->mpvdp, mpi);
- }
-
+ struct mp_image *reserved_mpi = mp_vdpau_upload_video_surface(vc->mpvdp, mpi);
if (!reserved_mpi)
goto end;
@@ -1014,8 +935,7 @@ static int query_format(struct vo *vo, uint32_t format)
int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
if (mp_vdpau_get_format(format, NULL, NULL))
return flags;
- int rgb_format = get_rgb_format(format);
- if (!vc->force_yuv && rgb_format >= 0)
+ if (!vc->force_yuv && mp_vdpau_get_rgb_format(format, NULL))
return flags;
return 0;
}
diff --git a/video/vdpau.c b/video/vdpau.c
index e59befebdc..20fbf2566f 100644
--- a/video/vdpau.c
+++ b/video/vdpau.c
@@ -28,8 +28,11 @@
static void mark_vdpau_objects_uninitialized(struct mp_vdpau_ctx *ctx)
{
- for (int i = 0; i < MAX_VIDEO_SURFACES; i++)
+ for (int i = 0; i < MAX_VIDEO_SURFACES; i++) {
ctx->video_surfaces[i].surface = VDP_INVALID_HANDLE;
+ ctx->video_surfaces[i].osurface = VDP_INVALID_HANDLE;
+ ctx->video_surfaces[i].allocated = false;
+ }
ctx->vdp_device = VDP_INVALID_HANDLE;
}
@@ -181,30 +184,45 @@ static struct mp_image *create_ref(struct mp_vdpau_ctx *ctx, int index)
struct mp_image *res =
mp_image_new_custom_ref(&(struct mp_image){0}, ref,
release_decoder_surface);
- mp_image_setfmt(res, IMGFMT_VDPAU);
+ mp_image_setfmt(res, e->rgb ? IMGFMT_VDPAU_OUTPUT : IMGFMT_VDPAU);
mp_image_set_size(res, e->w, e->h);
res->planes[0] = (void *)"dummy"; // must be non-NULL, otherwise arbitrary
- res->planes[3] = (void *)(intptr_t)e->surface;
+ res->planes[3] = (void *)(intptr_t)(e->rgb ? e->osurface : e->surface);
return res;
}
-struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx,
- VdpChromaType chroma, int w, int h)
+static struct mp_image *mp_vdpau_get_surface(struct mp_vdpau_ctx *ctx,
+ VdpChromaType chroma,
+ VdpRGBAFormat rgb_format,
+ bool rgb, int w, int h)
{
struct vdp_functions *vdp = &ctx->vdp;
int surface_index = -1;
VdpStatus vdp_st;
+ if (rgb) {
+ chroma = (VdpChromaType)-1;
+ } else {
+ rgb_format = (VdpChromaType)-1;
+ }
+
pthread_mutex_lock(&ctx->pool_lock);
// Destroy all unused surfaces that don't have matching parameters
for (int n = 0; n < MAX_VIDEO_SURFACES; n++) {
struct surface_entry *e = &ctx->video_surfaces[n];
- if (!e->in_use && e->surface != VDP_INVALID_HANDLE) {
- if (e->chroma != chroma || e->w != w || e->h != h) {
- vdp_st = vdp->video_surface_destroy(e->surface);
- CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_destroy");
- e->surface = VDP_INVALID_HANDLE;
+ if (!e->in_use && e->allocated) {
+ if (e->w != w || e->h != h || e->rgb != rgb ||
+ e->chroma != chroma || e->rgb_format != rgb_format)
+ {
+ if (e->rgb) {
+ vdp_st = vdp->output_surface_destroy(e->osurface);
+ } else {
+ vdp_st = vdp->video_surface_destroy(e->surface);
+ }
+ CHECK_VDP_WARNING(ctx, "Error when destroying surface");
+ e->surface = e->osurface = VDP_INVALID_HANDLE;
+ e->allocated = false;
}
}
}
@@ -212,9 +230,11 @@ struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx,
// Try to find an existing unused surface
for (int n = 0; n < MAX_VIDEO_SURFACES; n++) {
struct surface_entry *e = &ctx->video_surfaces[n];
- if (!e->in_use && e->surface != VDP_INVALID_HANDLE) {
+ if (!e->in_use && e->allocated) {
assert(e->w == w && e->h == h);
assert(e->chroma == chroma);
+ assert(e->rgb_format == rgb_format);
+ assert(e->rgb == rgb);
surface_index = n;
goto done;
}
@@ -225,12 +245,23 @@ struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx,
struct surface_entry *e = &ctx->video_surfaces[n];
if (!e->in_use) {
assert(e->surface == VDP_INVALID_HANDLE);
+ assert(e->osurface == VDP_INVALID_HANDLE);
+ assert(!e->allocated);
e->chroma = chroma;
+ e->rgb_format = rgb_format;
+ e->rgb = rgb;
e->w = w;
e->h = h;
- vdp_st = vdp->video_surface_create(ctx->vdp_device, chroma,
- w, h, &e->surface);
- CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_create");
+ if (rgb) {
+ vdp_st = vdp->output_surface_create(ctx->vdp_device, rgb_format,
+ w, h, &e->osurface);
+ e->allocated = e->osurface != VDP_INVALID_HANDLE;
+ } else {
+ vdp_st = vdp->video_surface_create(ctx->vdp_device, chroma,
+ w, h, &e->surface);
+ e->allocated = e->surface != VDP_INVALID_HANDLE;
+ }
+ CHECK_VDP_WARNING(ctx, "Error when allocating surface");
surface_index = n;
goto done;
}
@@ -248,6 +279,12 @@ done: ;
return mpi;
}
+struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx,
+ VdpChromaType chroma, int w, int h)
+{
+ return mp_vdpau_get_surface(ctx, chroma, 0, false, w, h);
+}
+
struct mp_vdpau_ctx *mp_vdpau_create_device_x11(struct mp_log *log,
struct vo_x11_state *x11)
{
@@ -281,6 +318,10 @@ void mp_vdpau_destroy(struct mp_vdpau_ctx *ctx)
vdp_st = vdp->video_surface_destroy(ctx->video_surfaces[i].surface);
CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_destroy");
}
+ if (ctx->video_surfaces[i].osurface != VDP_INVALID_HANDLE) {
+ vdp_st = vdp->output_surface_destroy(ctx->video_surfaces[i].osurface);
+ CHECK_VDP_WARNING(ctx, "Error when calling vdp_output_surface_destroy");
+ }
}
if (vdp->device_destroy && ctx->vdp_device != VDP_INVALID_HANDLE) {
@@ -327,6 +368,22 @@ bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type,
return true;
}
+bool mp_vdpau_get_rgb_format(int imgfmt, VdpRGBAFormat *out_rgba_format)
+{
+ VdpRGBAFormat format = (VdpRGBAFormat)-1;
+
+ switch (imgfmt) {
+ case IMGFMT_BGR32:
+ format = VDP_RGBA_FORMAT_B8G8R8A8; break;
+ default:
+ return false;
+ }
+
+ if (out_rgba_format)
+ *out_rgba_format = format;
+ return true;
+}
+
// Use mp_vdpau_get_video_surface, and upload mpi to it. Return NULL on failure.
// If the image is already a vdpau video surface, just return a reference.
struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx,
@@ -335,26 +392,36 @@ struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx,
struct vdp_functions *vdp = &ctx->vdp;
VdpStatus vdp_st;
- if (mpi->imgfmt == IMGFMT_VDPAU)
+ if (mpi->imgfmt == IMGFMT_VDPAU || mpi->imgfmt == IMGFMT_VDPAU_OUTPUT)
return mp_image_new_ref(mpi);
- VdpChromaType chroma_type;
- VdpYCbCrFormat pixel_format;
- if (!mp_vdpau_get_format(mpi->imgfmt, &chroma_type, &pixel_format))
+ VdpChromaType chroma = (VdpChromaType)-1;
+ VdpYCbCrFormat ycbcr = (VdpYCbCrFormat)-1;
+ VdpRGBAFormat rgbafmt = (VdpRGBAFormat)-1;
+ bool rgb = !mp_vdpau_get_format(mpi->imgfmt, &chroma, &ycbcr);
+ if (rgb && !mp_vdpau_get_rgb_format(mpi->imgfmt, &rgbafmt))
return NULL;
struct mp_image *hwmpi =
- mp_vdpau_get_video_surface(ctx, chroma_type, mpi->w, mpi->h);
+ mp_vdpau_get_surface(ctx, chroma, rgbafmt, rgb, mpi->w, mpi->h);
if (!hwmpi)
return NULL;
- VdpVideoSurface surface = (intptr_t)hwmpi->planes[3];
- const void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]};
- if (mpi->imgfmt == IMGFMT_NV12)
- destdata[1] = destdata[2];
- vdp_st = vdp->video_surface_put_bits_y_cb_cr(surface,
- pixel_format, destdata, mpi->stride);
- CHECK_VDP_WARNING(ctx, "Error when calling vdp_video_surface_put_bits_y_cb_cr");
+ if (hwmpi->imgfmt == IMGFMT_VDPAU) {
+ VdpVideoSurface surface = (intptr_t)hwmpi->planes[3];
+ const void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]};
+ if (mpi->imgfmt == IMGFMT_NV12)
+ destdata[1] = destdata[2];
+ vdp_st = vdp->video_surface_put_bits_y_cb_cr(surface,
+ ycbcr, destdata, mpi->stride);
+ } else {
+ VdpOutputSurface rgb_surface = (intptr_t)hwmpi->planes[3];
+ vdp_st = vdp->output_surface_put_bits_native(rgb_surface,
+ &(const void *){mpi->planes[0]},
+ &(uint32_t){mpi->stride[0]},
+ NULL);
+ }
+ CHECK_VDP_WARNING(ctx, "Error when uploading surface");
mp_image_copy_attributes(hwmpi, mpi);
return hwmpi;
diff --git a/video/vdpau.h b/video/vdpau.h
index acf4280266..3aea414700 100644
--- a/video/vdpau.h
+++ b/video/vdpau.h
@@ -58,8 +58,12 @@ struct mp_vdpau_ctx {
pthread_mutex_t pool_lock;
struct surface_entry {
VdpVideoSurface surface;
+ VdpOutputSurface osurface;
+ bool allocated;
int w, h;
+ VdpRGBAFormat rgb_format;
VdpChromaType chroma;
+ bool rgb;
bool in_use;
} video_surfaces[MAX_VIDEO_SURFACES];
};
@@ -75,6 +79,7 @@ struct mp_image *mp_vdpau_get_video_surface(struct mp_vdpau_ctx *ctx,
bool mp_vdpau_get_format(int imgfmt, VdpChromaType *out_chroma_type,
VdpYCbCrFormat *out_pixel_format);
+bool mp_vdpau_get_rgb_format(int imgfmt, VdpRGBAFormat *out_rgba_format);
struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx,
struct mp_image *mpi);