mirror of
https://github.com/mpv-player/mpv
synced 2025-03-10 08:13:03 +00:00
Decoding H264 using Video Decode Acceleration used the custom 'vda_h264_dec' decoder in FFmpeg. The Good: This new implementation has some advantages over the previous one: - It works with Libav: vda_h264_dec never got into Libav since they prefer client applications to use the hwaccel API. - It is way more efficient: in my tests this implementation yields a reduction of CPU usage of roughly ~50% compared to using `vda_h264_dec` and ~65-75% compared to h264 software decoding. This is mainly because `vo_corevideo` was adapted to perform direct rendering of the `CVPixelBufferRefs` created by the Video Decode Acceleration API Framework. The Bad: - `vo_corevideo` is required to use VDA decoding acceleration. - only works with versions of ffmpeg/libav new enough (needs reference refcounting). That is FFmpeg 2.0+ and Libav's git master currently. The Ugly: VDA was hardcoded to use UYVY (2vuy) for the uploaded video texture. One one end this makes the code simple since Apple's OpenGL implementation actually supports this out of the box. It would be nice to support other output image formats and choose the best format depending on the input, or at least making it configurable. My tests indicate that CPU usage actually increases with a 420p IMGFMT output which is not what I would have expected. NOTE: There is a small memory leak with old versions of FFmpeg and with Libav since the CVPixelBufferRef is not automatically released when the AVFrame is deallocated. This can cause leaks inside libavcodec for decoded frames that are discarded before mpv wraps them inside a refcounted mp_image (this only happens on seeks). For frames that enter mpv's refcounting facilities, this is not a problem since we rewrap the CVPixelBufferRef in our mp_image that properly forwards CVPixelBufferRetain/CvPixelBufferRelease calls to the underying CVPixelBufferRef. So, for FFmpeg use something more recent than `b3d63995` for Libav the patch was posted to the dev ML in July and in review since, apparently, the proposed fix is rather hacky.
601 lines
16 KiB
C
601 lines
16 KiB
C
/*
|
|
* CoreVideo video output driver
|
|
* Copyright (c) 2005 Nicolas Plourde <nicolasplourde@gmail.com>
|
|
* Copyright (c) 2012-2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
|
|
*
|
|
* This file is part of MPlayer.
|
|
*
|
|
* MPlayer is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MPlayer is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <QuartzCore/QuartzCore.h>
|
|
#if CONFIG_VDA
|
|
#include <IOSurface/IOSurface.h>
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
|
|
#include "talloc.h"
|
|
#include "video/out/vo.h"
|
|
#include "sub/sub.h"
|
|
#include "mpvcore/m_option.h"
|
|
|
|
#include "video/csputils.h"
|
|
#include "video/vfcap.h"
|
|
#include "video/mp_image.h"
|
|
|
|
#include "gl_common.h"
|
|
#include "gl_osd.h"
|
|
#include "cocoa_common.h"
|
|
|
|
struct quad {
|
|
GLfloat lowerLeft[2];
|
|
GLfloat lowerRight[2];
|
|
GLfloat upperRight[2];
|
|
GLfloat upperLeft[2];
|
|
};
|
|
|
|
struct cv_priv {
|
|
CVPixelBufferRef pbuf;
|
|
CVOpenGLTextureCacheRef texture_cache;
|
|
CVOpenGLTextureRef texture;
|
|
OSType pixfmt;
|
|
};
|
|
|
|
struct dr_priv {
|
|
CVPixelBufferRef pbuf;
|
|
bool texture_allocated;
|
|
GLuint texture;
|
|
GLuint texture_target;
|
|
};
|
|
|
|
struct cv_functions {
|
|
void (*init)(struct vo *vo);
|
|
void (*uninit)(struct vo *vo);
|
|
void (*prepare_texture)(struct vo *vo, struct mp_image *mpi);
|
|
void (*bind_texture)(struct vo *vo);
|
|
void (*unbind_texture)(struct vo *vo);
|
|
mp_image_t *(*get_screenshot)(struct vo *vo);
|
|
int (*set_colormatrix)(struct vo *vo, struct mp_csp_details *csp);
|
|
};
|
|
|
|
struct priv {
|
|
MPGLContext *mpglctx;
|
|
unsigned int image_width;
|
|
unsigned int image_height;
|
|
struct mp_csp_details colorspace;
|
|
struct mp_rect src_rect;
|
|
struct mp_rect dst_rect;
|
|
struct mp_osd_res osd_res;
|
|
|
|
// state for normal CoreVideo rendering path: uploads mp_image data as
|
|
// OpenGL textures.
|
|
struct cv_priv cv;
|
|
|
|
// state for IOSurface based direct rendering path: accesses the IOSurface
|
|
// wrapped by the CVPixelBuffer returned by VDADecoder and directly
|
|
// renders it to the screen.
|
|
struct dr_priv dr;
|
|
|
|
struct quad *quad;
|
|
struct mpgl_osd *osd;
|
|
|
|
// functions to to deal with the the OpenGL texture for containing the
|
|
// video frame (behaviour changes depending on the rendering path).
|
|
struct cv_functions fns;
|
|
};
|
|
|
|
static void resize(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
gl->Viewport(0, 0, vo->dwidth, vo->dheight);
|
|
gl->MatrixMode(GL_MODELVIEW);
|
|
gl->LoadIdentity();
|
|
gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1);
|
|
|
|
vo_get_src_dst_rects(vo, &p->src_rect, &p->dst_rect, &p->osd_res);
|
|
|
|
gl->Clear(GL_COLOR_BUFFER_BIT);
|
|
vo->want_redraw = true;
|
|
}
|
|
|
|
static int init_gl(struct vo *vo, uint32_t d_width, uint32_t d_height)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
gl->Disable(GL_BLEND);
|
|
gl->Disable(GL_DEPTH_TEST);
|
|
gl->DepthMask(GL_FALSE);
|
|
gl->Disable(GL_CULL_FACE);
|
|
gl->Enable(GL_TEXTURE_2D);
|
|
gl->DrawBuffer(GL_BACK);
|
|
gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
if (!p->osd)
|
|
p->osd = mpgl_osd_init(gl, true);
|
|
|
|
resize(vo);
|
|
|
|
gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
if (gl->SwapInterval)
|
|
gl->SwapInterval(1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int config(struct vo *vo, uint32_t width, uint32_t height,
|
|
uint32_t d_width, uint32_t d_height, uint32_t flags,
|
|
uint32_t format)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
p->fns.uninit(vo);
|
|
|
|
p->image_width = width;
|
|
p->image_height = height;
|
|
|
|
int mpgl_caps = MPGL_CAP_GL_LEGACY;
|
|
if (!mpgl_config_window(p->mpglctx, mpgl_caps, d_width, d_height, flags))
|
|
return -1;
|
|
|
|
init_gl(vo, vo->dwidth, vo->dheight);
|
|
p->fns.init(vo);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// map x/y (in range 0..1) to the video texture, and emit OpenGL vertexes
|
|
static void video_vertex(struct vo *vo, float x, float y)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
struct quad *q = p->quad;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
double tx0 = q->upperLeft[0];
|
|
double ty0 = q->upperLeft[1];
|
|
double tw = q->lowerRight[0] - tx0;
|
|
double th = q->lowerRight[1] - ty0;
|
|
|
|
double sx0 = p->src_rect.x0 / (double)p->image_width;
|
|
double sy0 = p->src_rect.y0 / (double)p->image_height;
|
|
double sw = (p->src_rect.x1 - p->src_rect.x0) / (double)p->image_width;
|
|
double sh = (p->src_rect.y1 - p->src_rect.y0) / (double)p->image_height;
|
|
|
|
gl->TexCoord2f(tx0 + (sx0 + x * sw) * tw,
|
|
ty0 + (sy0 + y * sh) * th);
|
|
gl->Vertex2f(p->dst_rect.x1 * x + p->dst_rect.x0 * (1 - x),
|
|
p->dst_rect.y1 * y + p->dst_rect.y0 * (1 - y));
|
|
}
|
|
|
|
static void do_render(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
p->fns.bind_texture(vo);
|
|
|
|
gl->Begin(GL_QUADS);
|
|
video_vertex(vo, 0, 0);
|
|
video_vertex(vo, 0, 1);
|
|
video_vertex(vo, 1, 1);
|
|
video_vertex(vo, 1, 0);
|
|
gl->End();
|
|
|
|
p->fns.unbind_texture(vo);
|
|
}
|
|
|
|
static void flip_page(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
p->mpglctx->swapGlBuffers(p->mpglctx);
|
|
p->mpglctx->gl->Clear(GL_COLOR_BUFFER_BIT);
|
|
}
|
|
|
|
static void draw_image(struct vo *vo, struct mp_image *mpi)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
p->fns.prepare_texture(vo, mpi);
|
|
do_render(vo);
|
|
}
|
|
|
|
static void uninit(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
if (p->osd)
|
|
mpgl_osd_destroy(p->osd);
|
|
p->fns.uninit(vo);
|
|
mpgl_uninit(p->mpglctx);
|
|
}
|
|
|
|
|
|
static int preinit(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
|
|
*p = (struct priv) {
|
|
.mpglctx = mpgl_init(vo, "cocoa"),
|
|
.colorspace = MP_CSP_DETAILS_DEFAULTS,
|
|
.quad = talloc_ptrtype(p, p->quad),
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void draw_osd(struct vo *vo, struct osd_state *osd)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
assert(p->osd);
|
|
|
|
mpgl_osd_draw_legacy(p->osd, osd, p->osd_res);
|
|
}
|
|
|
|
static CFStringRef get_cv_csp_matrix(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
switch (p->colorspace.format) {
|
|
case MP_CSP_BT_601:
|
|
return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
|
|
case MP_CSP_BT_709:
|
|
return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
|
|
case MP_CSP_SMPTE_240M:
|
|
return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static int set_yuv_colorspace(struct vo *vo, CVPixelBufferRef pbuf,
|
|
struct mp_csp_details *csp)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
p->colorspace = *csp;
|
|
CFStringRef cv_csp = get_cv_csp_matrix(vo);
|
|
|
|
if (cv_csp) {
|
|
CVBufferSetAttachment(p->cv.pbuf, kCVImageBufferYCbCrMatrixKey, cv_csp,
|
|
kCVAttachmentMode_ShouldNotPropagate);
|
|
vo->want_redraw = true;
|
|
return VO_TRUE;
|
|
} else {
|
|
return VO_NOTIMPL;
|
|
}
|
|
}
|
|
|
|
static int get_yuv_colorspace(struct vo *vo, struct mp_csp_details *csp)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
*csp = p->colorspace;
|
|
return VO_TRUE;
|
|
}
|
|
|
|
static int get_image_fmt(struct vo *vo, CVPixelBufferRef pbuf)
|
|
{
|
|
OSType pixfmt = CVPixelBufferGetPixelFormatType(pbuf);
|
|
switch (pixfmt) {
|
|
case kYUVSPixelFormat: return IMGFMT_YUYV;
|
|
case k2vuyPixelFormat: return IMGFMT_UYVY;
|
|
case k24RGBPixelFormat: return IMGFMT_RGB24;
|
|
case k32ARGBPixelFormat: return IMGFMT_ARGB;
|
|
case k32BGRAPixelFormat: return IMGFMT_BGRA;
|
|
}
|
|
MP_ERR(vo, "Failed to convert pixel format. Please contact the "
|
|
"developers. PixelFormat: %d\n", pixfmt);
|
|
return -1;
|
|
}
|
|
|
|
static mp_image_t *get_screenshot(struct vo *vo, CVPixelBufferRef pbuf)
|
|
{
|
|
int img_fmt = get_image_fmt(vo, pbuf);
|
|
if (img_fmt < 0) return NULL;
|
|
|
|
struct priv *p = vo->priv;
|
|
CVPixelBufferLockBaseAddress(pbuf, 0);
|
|
void *base = CVPixelBufferGetBaseAddress(pbuf);
|
|
size_t width = CVPixelBufferGetWidth(pbuf);
|
|
size_t height = CVPixelBufferGetHeight(pbuf);
|
|
size_t stride = CVPixelBufferGetBytesPerRow(pbuf);
|
|
|
|
struct mp_image img = {0};
|
|
mp_image_setfmt(&img, img_fmt);
|
|
mp_image_set_size(&img, width, height);
|
|
img.planes[0] = base;
|
|
img.stride[0] = stride;
|
|
|
|
struct mp_image *image = mp_image_new_copy(&img);
|
|
mp_image_set_display_size(image, vo->aspdat.prew, vo->aspdat.preh);
|
|
mp_image_set_colorspace_details(image, &p->colorspace);
|
|
CVPixelBufferUnlockBaseAddress(pbuf, 0);
|
|
|
|
return image;
|
|
}
|
|
|
|
static int control(struct vo *vo, uint32_t request, void *data)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
switch (request) {
|
|
case VOCTRL_GET_PANSCAN:
|
|
return VO_TRUE;
|
|
case VOCTRL_SET_PANSCAN:
|
|
resize(vo);
|
|
return VO_TRUE;
|
|
case VOCTRL_REDRAW_FRAME:
|
|
do_render(vo);
|
|
return VO_TRUE;
|
|
case VOCTRL_SET_YUV_COLORSPACE:
|
|
return p->fns.set_colormatrix(vo, data);
|
|
case VOCTRL_GET_YUV_COLORSPACE:
|
|
return get_yuv_colorspace(vo, data);
|
|
case VOCTRL_SCREENSHOT: {
|
|
struct voctrl_screenshot_args *args = data;
|
|
if (args->full_window)
|
|
args->out_image = glGetWindowScreenshot(p->mpglctx->gl);
|
|
else
|
|
args->out_image = p->fns.get_screenshot(vo);
|
|
return VO_TRUE;
|
|
}
|
|
}
|
|
|
|
int events = 0;
|
|
int r = p->mpglctx->vo_control(vo, &events, request, data);
|
|
if (events & VO_EVENT_RESIZE)
|
|
resize(vo);
|
|
|
|
return r;
|
|
}
|
|
|
|
static void dummy_cb(struct vo *vo) { }
|
|
|
|
static void cv_uninit(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
CVPixelBufferRelease(p->cv.pbuf);
|
|
p->cv.pbuf = NULL;
|
|
CVOpenGLTextureRelease(p->cv.texture);
|
|
p->cv.texture = NULL;
|
|
CVOpenGLTextureCacheRelease(p->cv.texture_cache);
|
|
p->cv.texture_cache = NULL;
|
|
}
|
|
|
|
static void cv_bind_texture(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
gl->Enable(CVOpenGLTextureGetTarget(p->cv.texture));
|
|
gl->BindTexture(CVOpenGLTextureGetTarget(p->cv.texture),
|
|
CVOpenGLTextureGetName(p->cv.texture));
|
|
|
|
}
|
|
|
|
static void cv_unbind_texture(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
gl->Disable(CVOpenGLTextureGetTarget(p->cv.texture));
|
|
}
|
|
|
|
static void upload_opengl_texture(struct vo *vo, struct mp_image *mpi)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
if (!p->cv.texture_cache || !p->cv.pbuf) {
|
|
CVReturn error;
|
|
error = CVOpenGLTextureCacheCreate(NULL, 0, vo_cocoa_cgl_context(vo),
|
|
vo_cocoa_cgl_pixel_format(vo), 0, &p->cv.texture_cache);
|
|
if(error != kCVReturnSuccess)
|
|
MP_ERR(vo, "Failed to create OpenGL texture Cache(%d)\n", error);
|
|
|
|
error = CVPixelBufferCreateWithBytes(NULL, mpi->w, mpi->h,
|
|
p->cv.pixfmt, mpi->planes[0], mpi->stride[0],
|
|
NULL, NULL, NULL, &p->cv.pbuf);
|
|
if(error != kCVReturnSuccess)
|
|
MP_ERR(vo, "Failed to create PixelBuffer(%d)\n", error);
|
|
}
|
|
|
|
struct quad *q = p->quad;
|
|
CVReturn error;
|
|
|
|
CVOpenGLTextureRelease(p->cv.texture);
|
|
error = CVOpenGLTextureCacheCreateTextureFromImage(NULL,
|
|
p->cv.texture_cache, p->cv.pbuf, 0, &p->cv.texture);
|
|
if(error != kCVReturnSuccess)
|
|
MP_ERR(vo, "Failed to create OpenGL texture(%d)\n", error);
|
|
|
|
CVOpenGLTextureGetCleanTexCoords(p->cv.texture,
|
|
q->lowerLeft, q->lowerRight, q->upperRight, q->upperLeft);
|
|
}
|
|
|
|
static mp_image_t *cv_get_screenshot(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
return get_screenshot(vo, p->cv.pbuf);
|
|
}
|
|
|
|
static int cv_set_colormatrix(struct vo *vo, struct mp_csp_details *csp)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
return set_yuv_colorspace(vo, p->cv.pbuf, csp);
|
|
}
|
|
|
|
static struct cv_functions cv_functions = {
|
|
.init = dummy_cb,
|
|
.uninit = cv_uninit,
|
|
.bind_texture = cv_bind_texture,
|
|
.unbind_texture = cv_unbind_texture,
|
|
.prepare_texture = upload_opengl_texture,
|
|
.get_screenshot = cv_get_screenshot,
|
|
.set_colormatrix = cv_set_colormatrix,
|
|
};
|
|
|
|
#if CONFIG_VDA
|
|
static void iosurface_init(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
p->dr.texture_target = GL_TEXTURE_RECTANGLE_ARB;
|
|
p->fns.bind_texture(vo);
|
|
gl->GenTextures(1, &p->dr.texture);
|
|
p->fns.unbind_texture(vo);
|
|
|
|
p->dr.texture_allocated = true;
|
|
}
|
|
|
|
static void iosurface_uninit(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
if (p->dr.texture_allocated) {
|
|
gl->DeleteTextures(1, &p->dr.texture);
|
|
p->dr.texture_allocated = false;
|
|
}
|
|
}
|
|
|
|
static void iosurface_bind_texture(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
gl->Enable(p->dr.texture_target);
|
|
gl->BindTexture(p->dr.texture_target, p->dr.texture);
|
|
gl->MatrixMode(GL_TEXTURE);
|
|
gl->LoadIdentity();
|
|
gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
}
|
|
|
|
static void iosurface_unbind_texture(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
GL *gl = p->mpglctx->gl;
|
|
|
|
gl->BindTexture(p->dr.texture_target, 0);
|
|
gl->Disable(p->dr.texture_target);
|
|
}
|
|
|
|
static void extract_texture_from_iosurface(struct vo *vo, struct mp_image *mpi)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
CVPixelBufferRelease(p->dr.pbuf);
|
|
p->dr.pbuf = (CVPixelBufferRef)mpi->planes[3];
|
|
CVPixelBufferRetain(p->dr.pbuf);
|
|
IOSurfaceRef surface = CVPixelBufferGetIOSurface(p->dr.pbuf);
|
|
MP_DBG(vo, "iosurface id: %d\n", IOSurfaceGetID(surface));
|
|
|
|
p->fns.bind_texture(vo);
|
|
|
|
CGLError err = CGLTexImageIOSurface2D(
|
|
vo_cocoa_cgl_context(vo), p->dr.texture_target, GL_RGB8,
|
|
p->image_width, p->image_height,
|
|
GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, surface, 0);
|
|
|
|
if (err != kCGLNoError)
|
|
MP_ERR(vo, "error creating IOSurface texture: %s (%x)\n",
|
|
CGLErrorString(err), glGetError());
|
|
|
|
p->fns.unbind_texture(vo);
|
|
|
|
// video_vertex flips the coordinates.. so feed in a flipped quad
|
|
*p->quad = (struct quad) {
|
|
.lowerRight = { p->image_width, p->image_height },
|
|
.upperLeft = { 0.0, 0.0 },
|
|
};
|
|
}
|
|
|
|
static mp_image_t *iosurface_get_screenshot(struct vo *vo)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
return get_screenshot(vo, p->dr.pbuf);
|
|
}
|
|
|
|
static int iosurface_set_colormatrix(struct vo *vo, struct mp_csp_details *csp)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
return set_yuv_colorspace(vo, p->dr.pbuf, csp);
|
|
}
|
|
|
|
static struct cv_functions iosurface_functions = {
|
|
.init = iosurface_init,
|
|
.uninit = iosurface_uninit,
|
|
.bind_texture = iosurface_bind_texture,
|
|
.unbind_texture = iosurface_unbind_texture,
|
|
.prepare_texture = extract_texture_from_iosurface,
|
|
.get_screenshot = iosurface_get_screenshot,
|
|
.set_colormatrix = iosurface_set_colormatrix,
|
|
};
|
|
#endif /* CONFIG_VDA */
|
|
|
|
static int query_format(struct vo *vo, uint32_t format)
|
|
{
|
|
struct priv *p = vo->priv;
|
|
const int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW;
|
|
|
|
switch (format) {
|
|
#if CONFIG_VDA
|
|
case IMGFMT_VDA:
|
|
p->fns = iosurface_functions;
|
|
return flags;
|
|
#endif
|
|
|
|
case IMGFMT_YUYV:
|
|
p->fns = cv_functions;
|
|
p->cv.pixfmt = kYUVSPixelFormat;
|
|
return flags;
|
|
|
|
case IMGFMT_UYVY:
|
|
p->fns = cv_functions;
|
|
p->cv.pixfmt = k2vuyPixelFormat;
|
|
return flags;
|
|
|
|
case IMGFMT_RGB24:
|
|
p->fns = cv_functions;
|
|
p->cv.pixfmt = k24RGBPixelFormat;
|
|
return flags;
|
|
|
|
case IMGFMT_ARGB:
|
|
p->fns = cv_functions;
|
|
p->cv.pixfmt = k32ARGBPixelFormat;
|
|
return flags;
|
|
|
|
case IMGFMT_BGRA:
|
|
p->fns = cv_functions;
|
|
p->cv.pixfmt = k32BGRAPixelFormat;
|
|
return flags;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const struct vo_driver video_out_corevideo = {
|
|
.info = &(const vo_info_t) {
|
|
"Mac OS X Core Video",
|
|
"corevideo",
|
|
"Nicolas Plourde <nicolas.plourde@gmail.com> and others",
|
|
""
|
|
},
|
|
.preinit = preinit,
|
|
.query_format = query_format,
|
|
.config = config,
|
|
.control = control,
|
|
.draw_image = draw_image,
|
|
.draw_osd = draw_osd,
|
|
.flip_page = flip_page,
|
|
.uninit = uninit,
|
|
.priv_size = sizeof(struct priv),
|
|
};
|