audio: add af_lavrresample, remove old resampling filters
[mplayer.git] / libvo / vo_corevideo.m
blob6dba788e2c48d47e18fa007ea575a406ca9fc754
1 /*
2  * CoreVideo video output driver
3  * Copyright (c) 2005 Nicolas Plourde <nicolasplourde@gmail.com>
4  *
5  * This file is part of MPlayer.
6  *
7  * MPlayer is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * MPlayer is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
22 #import "vo_corevideo.h"
24 // mplayer includes
25 #import "fastmemcpy.h"
26 #import "talloc.h"
27 #import "video_out.h"
28 #import "aspect.h"
29 #import "sub/sub.h"
30 #import "subopt-helper.h"
32 #import "csputils.h"
33 #import "libmpcodecs/vfcap.h"
34 #import "libmpcodecs/mp_image.h"
35 #import "osd.h"
37 #import "gl_common.h"
38 #import "cocoa_common.h"
40 struct quad {
41     GLfloat lowerLeft[2];
42     GLfloat lowerRight[2];
43     GLfloat upperRight[2];
44     GLfloat upperLeft[2];
47 #define CV_VERTICES_PER_QUAD 6
48 #define CV_MAX_OSD_PARTS 20
50 struct osd_p {
51     GLuint tex[CV_MAX_OSD_PARTS];
52     NSRect tex_rect[CV_MAX_OSD_PARTS];
53     int tex_cnt;
56 struct priv {
57     MPGLContext *mpglctx;
58     OSType pixelFormat;
59     unsigned int image_width;
60     unsigned int image_height;
61     struct mp_csp_details colorspace;
63     CVPixelBufferRef pixelBuffer;
64     CVOpenGLTextureCacheRef textureCache;
65     CVOpenGLTextureRef texture;
66     struct quad *quad;
68     struct osd_p *osd;
71 static void resize(struct vo *vo, int width, int height)
73     struct priv *p = vo->priv;
74     GL *gl = p->mpglctx->gl;
75     p->image_width = width;
76     p->image_height = height;
78     mp_msg(MSGT_VO, MSGL_V, "[vo_corevideo] New OpenGL Viewport (0, 0, %d, "
79                             "%d)\n", p->image_width, p->image_height);
81     gl->Viewport(0, 0, p->image_width, p->image_height);
82     gl->MatrixMode(GL_PROJECTION);
83     gl->LoadIdentity();
85     if (aspect_scaling()) {
86         int new_w, new_h;
87         GLdouble scale_x, scale_y;
89         aspect(vo, &new_w, &new_h, A_WINZOOM);
90         panscan_calc_windowed(vo);
91         new_w += vo->panscan_x;
92         new_h += vo->panscan_y;
93         scale_x = (GLdouble)new_w / (GLdouble)p->image_width;
94         scale_y = (GLdouble)new_h / (GLdouble)p->image_height;
95         gl->Scaled(scale_x, scale_y, 1);
96     }
98     gl->Ortho(0, p->image_width, p->image_height, 0, -1.0, 1.0);
99     gl->MatrixMode(GL_MODELVIEW);
100     gl->LoadIdentity();
102     vo_osd_changed(OSDTYPE_OSD);
104     gl->Clear(GL_COLOR_BUFFER_BIT);
105     vo->want_redraw = true;
108 static int init_gl(struct vo *vo, uint32_t d_width, uint32_t d_height)
110     struct priv *p = vo->priv;
111     GL *gl = p->mpglctx->gl;
113     const char *vendor     = gl->GetString(GL_VENDOR);
114     const char *version    = gl->GetString(GL_VERSION);
115     const char *renderer   = gl->GetString(GL_RENDERER);
117     mp_msg(MSGT_VO, MSGL_V, "[vo_corevideo] Running on OpenGL '%s' by '%s',"
118            " version '%s'\n", renderer, vendor, version);
120     gl->Disable(GL_BLEND);
121     gl->Disable(GL_DEPTH_TEST);
122     gl->DepthMask(GL_FALSE);
123     gl->Disable(GL_CULL_FACE);
124     gl->Enable(GL_TEXTURE_2D);
125     gl->DrawBuffer(GL_BACK);
126     gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
128     resize(vo, d_width, d_height);
130     gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
131     gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
132     if (gl->SwapInterval)
133         gl->SwapInterval(1);
134     return 1;
137 static void release_cv_entities(struct vo *vo) {
138     struct priv *p = vo->priv;
139     CVPixelBufferRelease(p->pixelBuffer);
140     p->pixelBuffer = NULL;
141     CVOpenGLTextureRelease(p->texture);
142     p->texture = NULL;
143     CVOpenGLTextureCacheRelease(p->textureCache);
144     p->textureCache = NULL;
148 static int config(struct vo *vo, uint32_t width, uint32_t height,
149                   uint32_t d_width, uint32_t d_height, uint32_t flags,
150                   uint32_t format)
152     struct priv *p = vo->priv;
153     release_cv_entities(vo);
154     p->image_width = width;
155     p->image_height = height;
157     if (p->mpglctx->create_window(p->mpglctx, d_width, d_height, flags) < 0)
158         return -1;
159     if (p->mpglctx->setGlWindow(p->mpglctx) == SET_WINDOW_FAILED)
160         return -1;
162     init_gl(vo, vo->dwidth, vo->dheight);
164     return 0;
167 static void check_events(struct vo *vo)
169     struct priv *p = vo->priv;
170     int e = p->mpglctx->check_events(vo);
171     if (e & VO_EVENT_RESIZE)
172         resize(vo, vo->dwidth, vo->dheight);
175 static void create_osd_texture(void *ctx, int x0, int y0, int w, int h,
176                                unsigned char *src, unsigned char *srca,
177                                int stride)
179     struct priv *p = ((struct vo *) ctx)->priv;
180     struct osd_p *osd = p->osd;
181     GL *gl = p->mpglctx->gl;
183     if (w <= 0 || h <= 0 || stride < w) {
184         mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n");
185         return;
186     }
188     if (osd->tex_cnt >= CV_MAX_OSD_PARTS) {
189         mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the"
190                                   " developers!\n");
191         return;
192     }
194     gl->GenTextures(1, &osd->tex[osd->tex_cnt]);
195     gl->BindTexture(GL_TEXTURE_2D, osd->tex[osd->tex_cnt]);
196     glCreateClearTex(gl, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA,
197                      GL_UNSIGNED_BYTE, GL_LINEAR, w, h, 0);
198     {
199         int i;
200         unsigned char *tmp = malloc(stride * h * 2);
201         // convert alpha from weird MPlayer scale.
202         for (i = 0; i < h * stride; i++) {
203             tmp[i*2+0] = src[i];
204             tmp[i*2+1] = -srca[i];
205         }
206         glUploadTex(gl, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
207                     tmp, stride * 2, 0, 0, w, h, 0);
208         free(tmp);
209     }
211     osd->tex_rect[osd->tex_cnt] = NSMakeRect(x0, y0, w, h);
213     gl->BindTexture(GL_TEXTURE_2D, 0);
214     osd->tex_cnt++;
217 static void clearOSD(struct vo *vo)
219     struct priv *p = vo->priv;
220     struct osd_p *osd = p->osd;
221     GL *gl = p->mpglctx->gl;
223     if (!osd->tex_cnt)
224         return;
225     gl->DeleteTextures(osd->tex_cnt, osd->tex);
226     osd->tex_cnt = 0;
229 static void draw_osd(struct vo *vo, struct osd_state *osd_s)
231     struct priv *p = vo->priv;
232     struct osd_p *osd = p->osd;
233     GL *gl = p->mpglctx->gl;
235     if (vo_osd_changed(0)) {
236         clearOSD(vo);
237         osd_draw_text_ext(osd_s, vo->dwidth, vo->dheight, 0, 0, 0, 0,
238                           p->image_width, p->image_height, create_osd_texture,
239                           vo);
240     }
242     if (osd->tex_cnt > 0) {
243         gl->Enable(GL_BLEND);
244         gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
246         for (int n = 0; n < osd->tex_cnt; n++) {
247             NSRect tr = osd->tex_rect[n];
248             gl->BindTexture(GL_TEXTURE_2D, osd->tex[n]);
249             glDrawTex(gl, tr.origin.x, tr.origin.y,
250                       tr.size.width, tr.size.height,
251                       0, 0, 1.0, 1.0, 1, 1, 0, 0, 0);
252         }
254         gl->Disable(GL_BLEND);
255         gl->BindTexture(GL_TEXTURE_2D, 0);
256     }
259 static void prepare_texture(struct vo *vo)
261     struct priv *p = vo->priv;
262     struct quad *q = p->quad;
263     CVReturn error;
265     CVOpenGLTextureRelease(p->texture);
266     error = CVOpenGLTextureCacheCreateTextureFromImage(NULL,
267                 p->textureCache, p->pixelBuffer, 0, &p->texture);
268     if(error != kCVReturnSuccess)
269         mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create OpenGL"
270                                  " texture(%d)\n", error);
272     CVOpenGLTextureGetCleanTexCoords(p->texture, q->lowerLeft, q->lowerRight,
273                                                  q->upperRight, q->upperLeft);
276 static void do_render(struct vo *vo)
278     struct priv *p = vo->priv;
279     struct quad *q = p->quad;
280     GL *gl = p->mpglctx->gl;
281     prepare_texture(vo);
283     float x0 = 0;
284     float y0 = 0;
285     float  w = p->image_width;
286     float  h = p->image_height;
288     // vertically flips the image
289     y0 += h;
290     h = -h;
292     float xm = x0 + w;
293     float ym = y0 + h;
295     gl->Enable(CVOpenGLTextureGetTarget(p->texture));
296     gl->BindTexture(
297             CVOpenGLTextureGetTarget(p->texture),
298             CVOpenGLTextureGetName(p->texture));
300     gl->Begin(GL_QUADS);
301     gl->TexCoord2fv(q->lowerLeft);  gl->Vertex2f(x0, y0);
302     gl->TexCoord2fv(q->upperLeft);  gl->Vertex2f(x0, ym);
303     gl->TexCoord2fv(q->upperRight); gl->Vertex2f(xm, ym);
304     gl->TexCoord2fv(q->lowerRight); gl->Vertex2f(xm, y0);
305     gl->End();
307     gl->Disable(CVOpenGLTextureGetTarget(p->texture));
310 static void flip_page(struct vo *vo)
312     struct priv *p = vo->priv;
313     p->mpglctx->swapGlBuffers(p->mpglctx);
314     p->mpglctx->gl->Clear(GL_COLOR_BUFFER_BIT);
317 static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
319     struct priv *p = vo->priv;
320     CVReturn error;
322     if (!p->textureCache || !p->pixelBuffer) {
323         error = CVOpenGLTextureCacheCreate(NULL, 0, vo_cocoa_cgl_context(vo),
324                     vo_cocoa_cgl_pixel_format(vo), 0, &p->textureCache);
325         if(error != kCVReturnSuccess)
326             mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create OpenGL"
327                                      " texture Cache(%d)\n", error);
329         error = CVPixelBufferCreateWithBytes(NULL, mpi->width, mpi->height,
330                     p->pixelFormat, mpi->planes[0], mpi->width * mpi->bpp / 8,
331                     NULL, NULL, NULL, &p->pixelBuffer);
332         if(error != kCVReturnSuccess)
333             mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create Pixel"
334                                      "Buffer(%d)\n", error);
335     }
337     do_render(vo);
338     return VO_TRUE;
341 static int query_format(struct vo *vo, uint32_t format)
343     struct priv *p = vo->priv;
344     const int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW |
345                       VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN |
346                       VOCAP_NOSLICES;
347     switch (format) {
348         case IMGFMT_YUY2:
349             p->pixelFormat = kYUVSPixelFormat;
350             return flags;
352         case IMGFMT_RGB24:
353             p->pixelFormat = k24RGBPixelFormat;
354             return flags;
356         case IMGFMT_ARGB:
357             p->pixelFormat = k32ARGBPixelFormat;
358             return flags;
360         case IMGFMT_BGRA:
361             p->pixelFormat = k32BGRAPixelFormat;
362             return flags;
363     }
364     return 0;
367 static void uninit(struct vo *vo)
369     struct priv *p = vo->priv;
370     uninit_mpglcontext(p->mpglctx);
371     release_cv_entities(vo);
375 static int preinit(struct vo *vo, const char *arg)
377     struct priv *p = vo->priv;
379     *p = (struct priv) {
380         .mpglctx = init_mpglcontext(GLTYPE_COCOA, vo),
381         .colorspace = MP_CSP_DETAILS_DEFAULTS,
382         .quad = talloc_ptrtype(p, p->quad),
383         .osd = talloc_ptrtype(p, p->osd),
384     };
386     *p->osd = (struct osd_p) {
387         .tex_cnt = 0,
388     };
390     return 0;
393 static CFStringRef get_cv_csp_matrix(struct vo *vo)
395     struct priv *p = vo->priv;
396     switch (p->colorspace.format) {
397         case MP_CSP_BT_601:
398             return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
399         case MP_CSP_BT_709:
400             return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
401         case MP_CSP_SMPTE_240M:
402             return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
403     }
404     return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
407 static void set_yuv_colorspace(struct vo *vo)
409     struct priv *p = vo->priv;
410     CVBufferSetAttachment(p->pixelBuffer,
411                           kCVImageBufferYCbCrMatrixKey, get_cv_csp_matrix(vo),
412                           kCVAttachmentMode_ShouldPropagate);
413     vo->want_redraw = true;
416 static int control(struct vo *vo, uint32_t request, void *data)
418     struct priv *p = vo->priv;
419     switch (request) {
420         case VOCTRL_DRAW_IMAGE:
421             return draw_image(vo, data);
422         case VOCTRL_QUERY_FORMAT:
423             return query_format(vo, *(uint32_t*)data);
424         case VOCTRL_ONTOP:
425             p->mpglctx->ontop(vo);
426             return VO_TRUE;
427         case VOCTRL_PAUSE:
428             if (!p->mpglctx->pause)
429                 break;
430             p->mpglctx->pause(vo);
431             return VO_TRUE;
432         case VOCTRL_RESUME:
433             if (!p->mpglctx->resume)
434                 break;
435             p->mpglctx->resume(vo);
436             return VO_TRUE;
437         case VOCTRL_FULLSCREEN:
438             p->mpglctx->fullscreen(vo);
439             resize(vo, vo->dwidth, vo->dheight);
440             return VO_TRUE;
441         case VOCTRL_GET_PANSCAN:
442             return VO_TRUE;
443         case VOCTRL_SET_PANSCAN:
444             resize(vo, vo->dwidth, vo->dheight);
445             return VO_TRUE;
446         case VOCTRL_UPDATE_SCREENINFO:
447             p->mpglctx->update_xinerama_info(vo);
448             return VO_TRUE;
449         case VOCTRL_REDRAW_FRAME:
450             do_render(vo);
451             return VO_TRUE;
452         case VOCTRL_SET_YUV_COLORSPACE:
453             p->colorspace.format = ((struct mp_csp_details *)data)->format;
454             set_yuv_colorspace(vo);
455             return VO_TRUE;
456         case VOCTRL_GET_YUV_COLORSPACE:
457             *(struct mp_csp_details *)data = p->colorspace;
458             return VO_TRUE;
459     }
460     return VO_NOTIMPL;
463 const struct vo_driver video_out_corevideo = {
464     .is_new = true,
465     .info = &(const vo_info_t) {
466         "Mac OS X Core Video",
467         "corevideo",
468         "Nicolas Plourde <nicolas.plourde@gmail.com> and others",
469         ""
470     },
471     .preinit = preinit,
472     .config = config,
473     .control = control,
474     .draw_osd = draw_osd,
475     .flip_page = flip_page,
476     .check_events = check_events,
477     .uninit = uninit,
478     .privsize = sizeof(struct priv),