From 9646208cc671721fce2253a3c5d40b1961810a87 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 23 Mar 2012 19:14:32 +0100 Subject: vo_sharedbuffer: add this video output This OSX video output is replaces the previous shared_buffer mode of vo_corevideo. It manages a shared buffer and a Cocoa distributed object to communicate with GUIs. Splitting this code into a separate VO allows to get rid of harmful code coupling, performance inefficiencies (useless image memory copies) and ugly code (big if-else conditionals). --- libvo/video_out.c | 4 + libvo/vo_sharedbuffer.h | 37 +++++++ libvo/vo_sharedbuffer.m | 277 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 libvo/vo_sharedbuffer.h create mode 100644 libvo/vo_sharedbuffer.m (limited to 'libvo') diff --git a/libvo/video_out.c b/libvo/video_out.c index 82fe4f8550..96a5220645 100644 --- a/libvo/video_out.c +++ b/libvo/video_out.c @@ -117,6 +117,7 @@ extern struct vo_driver video_out_tdfx_vid; extern struct vo_driver video_out_xvr100; extern struct vo_driver video_out_tga; extern struct vo_driver video_out_corevideo; +extern struct vo_driver video_out_sharedbuffer; extern struct vo_driver video_out_pnm; extern struct vo_driver video_out_md5sum; @@ -180,6 +181,9 @@ const struct vo_driver *video_out_drivers[] = #if (defined CONFIG_GL && !defined CONFIG_GL_COCOA) &video_out_gl, #endif +#ifdef CONFIG_SHAREDBUFFER + &video_out_sharedbuffer, +#endif #ifdef CONFIG_GL_SDL &video_out_gl_sdl, #endif diff --git a/libvo/vo_sharedbuffer.h b/libvo/vo_sharedbuffer.h new file mode 100644 index 0000000000..c25463aa0a --- /dev/null +++ b/libvo/vo_sharedbuffer.h @@ -0,0 +1,37 @@ +/* + * OSX Shared Buffer Video Output (extracted from mplayer's corevideo) + * + * This file is part of mplayer2. + * + * mplayer2 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. + * + * mplayer2 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 mplayer2. If not, see . + */ + +#ifndef MPLAYER_VO_OSX_SHAREDBUFFER_H +#define MPLAYER_VO_OSX_SHAREDBUFFER_H + +#import + +// Protocol to communicate with the GUI +@protocol MPlayerOSXVOProto +- (int) startWithWidth: (bycopy int)width + withHeight: (bycopy int)height + withBytes: (bycopy int)bytes + withAspect: (bycopy int)aspect; +- (void) stop; +- (void) render; +- (void) toggleFullscreen; +- (void) ontop; +@end + +#endif /* MPLAYER_VO_OSX_SHAREDBUFFER_H */ diff --git a/libvo/vo_sharedbuffer.m b/libvo/vo_sharedbuffer.m new file mode 100644 index 0000000000..0b811f1848 --- /dev/null +++ b/libvo/vo_sharedbuffer.m @@ -0,0 +1,277 @@ +/* + * OSX Shared Buffer Video Output (extracted from mplayer's corevideo) + * + * This file is part of mplayer2. + * + * mplayer2 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. + * + * mplayer2 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 mplayer2. If not, see . + */ + +/* + * This video output was extracted from mplayer's corevideo. It's purpose it + * to copy mp_image data to a shared buffer using mmap and to do simple + * coordination with the GUIs using Distributed Objects. + */ + +#include + +#include "vo_sharedbuffer.h" +#include "video_out.h" +#include "subopt-helper.h" +#include "talloc.h" + +#include "libmpcodecs/vfcap.h" +#include "libmpcodecs/mp_image.h" +#include "fastmemcpy.h" + +#include "sub/sub.h" +#include "osd.h" + +// declarations +struct priv { + char *buffer_name; + unsigned char *image_data; + unsigned int image_bytespp; + unsigned int image_width; + unsigned int image_height; + + void (*vo_draw_alpha_fnc)(int w, int h, unsigned char* src, + unsigned char *srca, int srcstride, unsigned char* dstbase, + int dststride); + + NSDistantObject *mposx_proxy; + id mposx_proto; +}; + +struct priv *p; + +// implementation +static void draw_alpha(void *ctx, int x0, int y0, int w, int h, + unsigned char *src, unsigned char *srca, + int stride) +{ + p->vo_draw_alpha_fnc(w, h, src, srca, stride, + p->image_data + (x0 + y0 * p->image_width) * p->image_bytespp, + p->image_width * p->image_bytespp); +} + +static unsigned int image_bytes() +{ + return p->image_width * p->image_height * p->image_bytespp; +} + +static int preinit(struct vo *vo, const char *arg) +{ + p = talloc_zero(NULL, struct priv); + + const opt_t subopts[] = { + {"buffer_name", OPT_ARG_MSTRZ, &p->buffer_name, NULL}, + {NULL} + }; + + if (subopt_parse(arg, subopts) != 0) { + mp_msg(MSGT_VO, MSGL_FATAL, + "\n-vo sharedbuffer command line help:\n" + "Example: mplayer -vo shared_buffer:buffer_name=mybuff\n" + "\nOptions:\n" + " buffer_name=\n" + " Name of the shared buffer created with shm_open() as well as\n" + " the name of the NSConnection mplayer2 will try to open.\n" + "Example: mplayer -vo sharedbuffer\n" + "\n" ); + return -1; + } + + if (!p->buffer_name) p->buffer_name = "mplayerosx"; + + return 0; +} + +static void flip_page(struct vo *vo) +{ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + [p->mposx_proto render]; + [pool release]; +} + +static void check_events(struct vo *vo) { } + +static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) +{ + memcpy_pic(p->image_data, mpi->planes[0], + (p->image_width) * (p->image_bytespp), p->image_height, + (p->image_width) * (p->image_bytespp), mpi->stride[0]); + return 0; +} + +static void draw_osd(struct vo *vo, struct osd_state *osd) { + osd_draw_text(osd, p->image_width, p->image_height, draw_alpha, vo); +} + +static void free_buffers(void) +{ + [p->mposx_proto stop]; + p->mposx_proto = nil; + [p->mposx_proxy release]; + p->mposx_proxy = nil; + + if (p->image_data) { + if (munmap(p->image_data, image_bytes()) == -1) + mp_msg(MSGT_VO, MSGL_FATAL, "[vo_sharedbuffer] uninit: munmap " + "failed. Error: %s\n", strerror(errno)); + + if (shm_unlink(p->buffer_name) == -1) + mp_msg(MSGT_VO, MSGL_FATAL, "[vo_sharedbuffer] uninit: shm_unlink " + "failed. Error: %s\n", strerror(errno)); + } +} + +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) +{ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + free_buffers(); + + p->image_width = width; + p->image_height = height; + + mp_msg(MSGT_VO, MSGL_INFO, "[vo_sharedbuffer] writing output to a shared " + "buffer named \"%s\"\n", p->buffer_name); + + // create shared memory + int shm_fd = shm_open(p->buffer_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (shm_fd == -1) { + mp_msg(MSGT_VO, MSGL_FATAL, + "[vo_sharedbuffer] failed to open shared memory. Error: %s\n", + strerror(errno)); + goto err_out; + } + + if (ftruncate(shm_fd, image_bytes()) == -1) { + mp_msg(MSGT_VO, MSGL_FATAL, + "[vo_sharedbuffer] failed to size shared memory, possibly " + "already in use. Error: %s\n", strerror(errno)); + close(shm_fd); + shm_unlink(p->buffer_name); + goto err_out; + } + + p->image_data = mmap(NULL, image_bytes(), + PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + close(shm_fd); + + if (p->image_data == MAP_FAILED) { + mp_msg(MSGT_VO, MSGL_FATAL, + "[vo_sharedbuffer] failed to map shared memory. " + "Error: %s\n", strerror(errno)); + shm_unlink(p->buffer_name); + goto err_out; + } + + //connect to mplayerosx + p->mposx_proxy = [NSConnection + rootProxyForConnectionWithRegisteredName: + [NSString stringWithUTF8String:p->buffer_name] host:nil]; + + if ([p->mposx_proxy conformsToProtocol:@protocol(MPlayerOSXVOProto)]) { + [p->mposx_proxy setProtocolForProxy:@protocol(MPlayerOSXVOProto)]; + p->mposx_proto = (id )p->mposx_proxy; + [p->mposx_proto startWithWidth:p->image_width + withHeight:p->image_height + withBytes:p->image_bytespp + withAspect:d_width*100/d_height]; + } else { + mp_msg(MSGT_VO, MSGL_ERR, + "[vo_sharedbuffer] distributed object doesn't conform " + "to the correct protocol.\n"); + [p->mposx_proxy release]; + p->mposx_proxy = nil; + p->mposx_proto = nil; + } + + [pool release]; + return 0; +err_out: + [pool release]; + return 1; +} + +static int query_format(uint32_t format) +{ + unsigned int image_depth = 0; + switch (format) { + case IMGFMT_YUY2: + p->vo_draw_alpha_fnc = vo_draw_alpha_yuy2; + image_depth = 16; + goto supported; + case IMGFMT_RGB24: + p->vo_draw_alpha_fnc = vo_draw_alpha_rgb24; + image_depth = 24; + goto supported; + case IMGFMT_ARGB: + p->vo_draw_alpha_fnc = vo_draw_alpha_rgb32; + image_depth = 32; + goto supported; + case IMGFMT_BGRA: + p->vo_draw_alpha_fnc = vo_draw_alpha_rgb32; + image_depth = 32; + goto supported; + } + return 0; + +supported: + p->image_bytespp = (image_depth + 7) / 8; + return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | + VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | + VOCAP_NOSLICES; +} + +static void uninit(struct vo *vo) +{ + free_buffers(); +} + +static int control(struct vo *vo, uint32_t request, void *data) +{ + switch (request) { + case VOCTRL_DRAW_IMAGE: + return draw_image(vo, data); + case VOCTRL_FULLSCREEN: + [p->mposx_proto toggleFullscreen]; + return VO_TRUE; + case VOCTRL_QUERY_FORMAT: + return query_format(*(uint32_t*)data); + case VOCTRL_ONTOP: + [p->mposx_proto ontop]; + return VO_TRUE; + } + return VO_NOTIMPL; +} + +const struct vo_driver video_out_sharedbuffer = { + .is_new = true, + .info = &(const vo_info_t) { + "Mac OS X Shared Buffer (headless video output for GUIs)", + "sharedbuffer", + "Stefano Pigozzi and others.", + "" + }, + .preinit = preinit, + .config = config, + .control = control, + .flip_page = flip_page, + .check_events = check_events, + .uninit = uninit, + .draw_osd = draw_osd +}; -- cgit v1.2.3