From 3b236d176dbebddad6fcbae74d0990ecfb0412d0 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Thu, 1 Aug 2013 08:28:16 +0200 Subject: vo_corevideo: move to C from Objective-C This file was alredy written in C. The only remaining part was the file exension and `#import`s. --- video/out/vo_corevideo.c | 401 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 video/out/vo_corevideo.c (limited to 'video/out/vo_corevideo.c') diff --git a/video/out/vo_corevideo.c b/video/out/vo_corevideo.c new file mode 100644 index 0000000000..cf89dc78c2 --- /dev/null +++ b/video/out/vo_corevideo.c @@ -0,0 +1,401 @@ +/* + * CoreVideo video output driver + * Copyright (c) 2005 Nicolas Plourde + * + * 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 +#include + +#include "talloc.h" +#include "video/out/vo.h" +#include "sub/sub.h" +#include "core/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 priv { + MPGLContext *mpglctx; + OSType pixelFormat; + 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; + + CVPixelBufferRef pixelBuffer; + CVOpenGLTextureCacheRef textureCache; + CVOpenGLTextureRef texture; + struct quad *quad; + + struct mpgl_osd *osd; +}; + +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; + + const char *vendor = gl->GetString(GL_VENDOR); + const char *version = gl->GetString(GL_VERSION); + const char *renderer = gl->GetString(GL_RENDERER); + + mp_msg(MSGT_VO, MSGL_V, "[vo_corevideo] Running on OpenGL '%s' by '%s'," + " version '%s'\n", renderer, vendor, version); + + 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 void release_cv_entities(struct vo *vo) { + struct priv *p = vo->priv; + CVPixelBufferRelease(p->pixelBuffer); + p->pixelBuffer = NULL; + CVOpenGLTextureRelease(p->texture); + p->texture = NULL; + CVOpenGLTextureCacheRelease(p->textureCache); + p->textureCache = NULL; +} + +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; + release_cv_entities(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); + + return 0; +} + +static void prepare_texture(struct vo *vo) +{ + struct priv *p = vo->priv; + struct quad *q = p->quad; + CVReturn error; + + CVOpenGLTextureRelease(p->texture); + error = CVOpenGLTextureCacheCreateTextureFromImage(NULL, + p->textureCache, p->pixelBuffer, 0, &p->texture); + if(error != kCVReturnSuccess) + mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create OpenGL" + " texture(%d)\n", error); + + CVOpenGLTextureGetCleanTexCoords(p->texture, q->lowerLeft, q->lowerRight, + q->upperRight, q->upperLeft); +} + +// 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; + prepare_texture(vo); + + gl->Enable(CVOpenGLTextureGetTarget(p->texture)); + gl->BindTexture( + CVOpenGLTextureGetTarget(p->texture), + CVOpenGLTextureGetName(p->texture)); + + 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(); + + gl->Disable(CVOpenGLTextureGetTarget(p->texture)); +} + +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, mp_image_t *mpi) +{ + struct priv *p = vo->priv; + CVReturn error; + + if (!p->textureCache || !p->pixelBuffer) { + error = CVOpenGLTextureCacheCreate(NULL, 0, vo_cocoa_cgl_context(vo), + vo_cocoa_cgl_pixel_format(vo), 0, &p->textureCache); + if(error != kCVReturnSuccess) + mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create OpenGL" + " texture Cache(%d)\n", error); + + error = CVPixelBufferCreateWithBytes(NULL, mpi->w, mpi->h, + p->pixelFormat, mpi->planes[0], mpi->stride[0], + NULL, NULL, NULL, &p->pixelBuffer); + if(error != kCVReturnSuccess) + mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create Pixel" + "Buffer(%d)\n", error); + } + + do_render(vo); +} + +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) { + case IMGFMT_YUYV: + p->pixelFormat = kYUVSPixelFormat; + return flags; + + case IMGFMT_RGB24: + p->pixelFormat = k24RGBPixelFormat; + return flags; + + case IMGFMT_ARGB: + p->pixelFormat = k32ARGBPixelFormat; + return flags; + + case IMGFMT_BGRA: + p->pixelFormat = k32BGRAPixelFormat; + return flags; + } + return 0; +} + +static void uninit(struct vo *vo) +{ + struct priv *p = vo->priv; + if (p->osd) + mpgl_osd_destroy(p->osd); + release_cv_entities(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 kCVImageBufferYCbCrMatrix_ITU_R_601_4; + } +} + +static void set_yuv_colorspace(struct vo *vo) +{ + struct priv *p = vo->priv; + CVBufferSetAttachment(p->pixelBuffer, + kCVImageBufferYCbCrMatrixKey, get_cv_csp_matrix(vo), + kCVAttachmentMode_ShouldPropagate); + vo->want_redraw = true; +} + +static int get_image_fmt(struct vo *vo) +{ + struct priv *p = vo->priv; + switch (p->pixelFormat) { + case kYUVSPixelFormat: return IMGFMT_YUYV; + case k24RGBPixelFormat: return IMGFMT_RGB24; + case k32ARGBPixelFormat: return IMGFMT_ARGB; + case k32BGRAPixelFormat: return IMGFMT_BGRA; + } + mp_msg(MSGT_VO, MSGL_ERR, "[vo_corevideo] Failed to convert pixel format. " + "Please contact the developers. PixelFormat: %d\n", p->pixelFormat); + return -1; +} + +static mp_image_t *get_screenshot(struct vo *vo) +{ + int img_fmt = get_image_fmt(vo); + if (img_fmt < 0) return NULL; + + struct priv *p = vo->priv; + void *base = CVPixelBufferGetBaseAddress(p->pixelBuffer); + + size_t width = CVPixelBufferGetWidth(p->pixelBuffer); + size_t height = CVPixelBufferGetHeight(p->pixelBuffer); + size_t stride = CVPixelBufferGetBytesPerRow(p->pixelBuffer); + + 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); + + 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: + p->colorspace.format = ((struct mp_csp_details *)data)->format; + set_yuv_colorspace(vo); + return VO_TRUE; + case VOCTRL_GET_YUV_COLORSPACE: + *(struct mp_csp_details *)data = p->colorspace; + return VO_TRUE; + case VOCTRL_SCREENSHOT: { + struct voctrl_screenshot_args *args = data; + if (args->full_window) + args->out_image = glGetWindowScreenshot(p->mpglctx->gl); + else + args->out_image = 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; +} + +const struct vo_driver video_out_corevideo = { + .info = &(const vo_info_t) { + "Mac OS X Core Video", + "corevideo", + "Nicolas Plourde 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), +}; -- cgit v1.2.3