|
| 1 | +/* |
| 2 | + * OSX Shared Buffer Video Output (extracted from mplayer's corevideo) |
| 3 | + * |
| 4 | + * This file is part of mplayer2. |
| 5 | + * |
| 6 | + * mplayer2 is free software; you can redistribute it and/or modify |
| 7 | + * it under the terms of the GNU General Public License as published by |
| 8 | + * the Free Software Foundation; either version 2 of the License, or |
| 9 | + * (at your option) any later version. |
| 10 | + * |
| 11 | + * mplayer2 is distributed in the hope that it will be useful, |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | + * GNU General Public License for more details. |
| 15 | + * |
| 16 | + * You should have received a copy of the GNU General Public License along |
| 17 | + * with mplayer2. If not, see <http://www.gnu.org/licenses/>. |
| 18 | + */ |
| 19 | + |
| 20 | +/* |
| 21 | + * This video output was extracted from mplayer's corevideo. Its purpose is |
| 22 | + * to copy mp_image data to a shared buffer using mmap and to do simple |
| 23 | + * coordination with the GUIs using Distributed Objects. |
| 24 | + */ |
| 25 | + |
| 26 | + |
| 27 | +#include "vo_sharedbuffer.h" |
| 28 | +#include "vo.h" |
| 29 | +#include "video/mp_image.h" |
| 30 | +#include "sub/osd.h" |
| 31 | + |
| 32 | +#include <sys/mman.h> |
| 33 | +#include <sys/stat.h> |
| 34 | +#include <fcntl.h> |
| 35 | +#include <errno.h> |
| 36 | +#include <unistd.h> |
| 37 | + |
| 38 | + |
| 39 | +// declarations |
| 40 | +struct priv { |
| 41 | + char *buffer_name; |
| 42 | + unsigned char *image_data; |
| 43 | + uint32_t image_bytes; |
| 44 | + uint32_t image_width; |
| 45 | + uint32_t image_height; |
| 46 | + uint32_t image_format; |
| 47 | + uint32_t image_stride; |
| 48 | + uint32_t buffer_size; |
| 49 | + |
| 50 | + NSDistantObject *mposx_proxy; |
| 51 | + id <MPlayerOSXVOProto> mposx_proto; |
| 52 | +}; |
| 53 | + |
| 54 | + |
| 55 | +static int preinit(struct vo *vo) |
| 56 | +{ |
| 57 | + MP_INFO(vo, "preinit \n"); |
| 58 | + return 0; |
| 59 | +} |
| 60 | + |
| 61 | +static void flip_page(struct vo *vo) |
| 62 | +{ |
| 63 | + //MP_INFO(vo, "flip_page \n"); |
| 64 | + |
| 65 | + struct priv *p = vo->priv; |
| 66 | + NSAutoreleasePool *pool = [NSAutoreleasePool new]; |
| 67 | + [p->mposx_proto render]; |
| 68 | + [pool release]; |
| 69 | +} |
| 70 | + |
| 71 | +static void draw_image(struct vo *vo, mp_image_t *mpi) |
| 72 | +{ |
| 73 | + //MP_INFO(vo, "draw_image \n"); |
| 74 | + |
| 75 | + struct priv *p = vo->priv; |
| 76 | + struct mp_osd_res dim = osd_res_from_image_params(vo->params); |
| 77 | + osd_draw_on_image(vo->osd, dim, mpi->pts, 0, mpi); |
| 78 | + |
| 79 | + if (p->image_format == IMGFMT_420P) { |
| 80 | + unsigned char * ptr = p->image_data; |
| 81 | + int size = p->image_stride * p->image_height; |
| 82 | + memcpy_pic(ptr, mpi->planes[0], p->image_width, p->image_height, p->image_stride, mpi->stride[0]); |
| 83 | + ptr += size; |
| 84 | + size = (p->image_width * p->image_height) / 2; |
| 85 | + memcpy_pic(ptr, mpi->planes[1], p->image_width / 2, p->image_height / 2, p->image_width / 2, mpi->stride[1]); |
| 86 | + ptr += size; |
| 87 | + memcpy_pic(ptr, mpi->planes[2], p->image_width / 2, p->image_height / 2, p->image_width / 2, mpi->stride[2]); |
| 88 | + } else { |
| 89 | + memcpy_pic(p->image_data, mpi->planes[0], |
| 90 | + p->image_width * p->image_bytes, p->image_height, |
| 91 | + p->image_stride, mpi->stride[0]); |
| 92 | + } |
| 93 | + talloc_free(mpi); |
| 94 | +} |
| 95 | + |
| 96 | +static void free_buffers(struct vo *vo) |
| 97 | +{ |
| 98 | + struct priv *p = vo->priv; |
| 99 | + [p->mposx_proto stop]; |
| 100 | + p->mposx_proto = nil; |
| 101 | + [p->mposx_proxy release]; |
| 102 | + p->mposx_proxy = nil; |
| 103 | + |
| 104 | + if (p->image_data) { |
| 105 | + if (munmap(p->image_data, p->buffer_size) == -1) { |
| 106 | + MP_FATAL(vo, "uninit: munmap failed. Error: %s\n", strerror(errno)); |
| 107 | + } |
| 108 | + if (shm_unlink(p->buffer_name) == -1) { |
| 109 | + MP_FATAL(vo, "uninit: shm_unlink failed. Error: %s\n", strerror(errno)); |
| 110 | + } |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +static int reconfig(struct vo *vo, struct mp_image_params *params) |
| 115 | +{ |
| 116 | + MP_INFO(vo, "reconfig w: %d h: %d format: %d \n", params->w, params->h, params->imgfmt); |
| 117 | + |
| 118 | + struct priv *p = vo->priv; |
| 119 | + NSAutoreleasePool *pool = [NSAutoreleasePool new]; |
| 120 | + free_buffers(vo); |
| 121 | + |
| 122 | + p->image_width = params->w; |
| 123 | + p->image_height = params->h; |
| 124 | + p->image_format = params->imgfmt; |
| 125 | + |
| 126 | + switch (p->image_format) |
| 127 | + { |
| 128 | + case IMGFMT_RGB24: |
| 129 | + p->image_bytes = 3; |
| 130 | + break; |
| 131 | + case IMGFMT_RGB565: |
| 132 | + p->image_bytes = 2; |
| 133 | + break; |
| 134 | + case IMGFMT_420P: |
| 135 | + p->image_bytes = 1; |
| 136 | + break; |
| 137 | + case IMGFMT_NV12: |
| 138 | + case IMGFMT_UYVY: |
| 139 | + p->image_bytes = 2; |
| 140 | + break; |
| 141 | + default: |
| 142 | + p->image_bytes = 3; |
| 143 | + } |
| 144 | + p->image_stride = p->image_width * p->image_bytes; |
| 145 | + p->buffer_size = p->image_stride * p->image_height; |
| 146 | + if (p->image_format == IMGFMT_420P) { |
| 147 | + p->buffer_size = p->image_width * p->image_height * 2; |
| 148 | + } |
| 149 | + |
| 150 | + MP_INFO(vo, "writing output to a shared buffer named \"%s\"\n", p->buffer_name); |
| 151 | + |
| 152 | + // create shared memory |
| 153 | + int shm_fd = shm_open(p->buffer_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); |
| 154 | + if (shm_fd == -1) { |
| 155 | + MP_FATAL(vo, "failed to open shared memory. Error: %s\n", strerror(errno)); |
| 156 | + goto err_out; |
| 157 | + } |
| 158 | + |
| 159 | + MP_INFO(vo, "dw: %d dh: %d\n", vo->dwidth, vo->dheight); |
| 160 | + MP_INFO(vo, "w: %d h: %d bytes: %d buffer size: %d\n", p->image_width, p->image_height, p->image_bytes, p->buffer_size); |
| 161 | + |
| 162 | + if (ftruncate(shm_fd, p->buffer_size) == -1) { |
| 163 | + close(shm_fd); |
| 164 | + shm_unlink(p->buffer_name); |
| 165 | + goto err_out; |
| 166 | + } |
| 167 | + |
| 168 | + p->image_data = mmap(NULL, p->buffer_size, |
| 169 | + PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); |
| 170 | + close(shm_fd); |
| 171 | + |
| 172 | + if (p->image_data == MAP_FAILED) { |
| 173 | + MP_FATAL(vo, "failed to map shared memory. Error: %s\n", strerror(errno)); |
| 174 | + shm_unlink(p->buffer_name); |
| 175 | + goto err_out; |
| 176 | + } |
| 177 | + |
| 178 | + //connect to mplayerosx |
| 179 | + p->mposx_proxy = [NSConnection |
| 180 | + rootProxyForConnectionWithRegisteredName: |
| 181 | + [NSString stringWithUTF8String:p->buffer_name] host:nil]; |
| 182 | + |
| 183 | + if ([p->mposx_proxy conformsToProtocol:@protocol(MPlayerOSXVOProto)]) { |
| 184 | + [p->mposx_proxy setProtocolForProxy:@protocol(MPlayerOSXVOProto)]; |
| 185 | + p->mposx_proto = (id <MPlayerOSXVOProto>)p->mposx_proxy; |
| 186 | + [p->mposx_proto startWithWidth:p->image_width |
| 187 | + withHeight:p->image_height |
| 188 | + withBytes:p->image_bytes |
| 189 | + withAspect:vo->dwidth*100/vo->dheight]; |
| 190 | + } else { |
| 191 | + MP_ERR(vo, "distributed object doesn't conform to the correct protocol.\n"); |
| 192 | + [p->mposx_proxy release]; |
| 193 | + p->mposx_proxy = nil; |
| 194 | + p->mposx_proto = nil; |
| 195 | + } |
| 196 | + |
| 197 | + [pool release]; |
| 198 | + return 0; |
| 199 | +err_out: |
| 200 | + [pool release]; |
| 201 | + return -1; |
| 202 | +} |
| 203 | + |
| 204 | +static int query_format(struct vo *vo, int format) |
| 205 | +{ |
| 206 | + //MP_INFO(vo, "query_format: %d \n", format); |
| 207 | + |
| 208 | + switch (format) { |
| 209 | + case IMGFMT_420P: |
| 210 | + //case IMGFMT_YUY2: |
| 211 | + case IMGFMT_UYVY: |
| 212 | + case IMGFMT_RGB24: |
| 213 | + //case IMGFMT_ARGB: |
| 214 | + //case IMGFMT_BGRA: |
| 215 | + return 1; |
| 216 | + } |
| 217 | + return 0; |
| 218 | +} |
| 219 | + |
| 220 | +static void uninit(struct vo *vo) |
| 221 | +{ |
| 222 | + free_buffers(vo); |
| 223 | +} |
| 224 | + |
| 225 | +static int control(struct vo *vo, uint32_t request, void *data) |
| 226 | +{ |
| 227 | + //MP_INFO(vo, "control: request: %d \n", request); |
| 228 | + return VO_NOTIMPL; |
| 229 | +} |
| 230 | + |
| 231 | + |
| 232 | +#undef OPT_BASE_STRUCT |
| 233 | +#define OPT_BASE_STRUCT struct priv |
| 234 | + |
| 235 | +const struct vo_driver video_out_sharedbuffer = { |
| 236 | + .name = "sharedbuffer", |
| 237 | + .description = "Mac OS X Shared Buffer (headless video output for GUIs)", |
| 238 | + .preinit = preinit, |
| 239 | + .reconfig = reconfig, |
| 240 | + .control = control, |
| 241 | + .flip_page = flip_page, |
| 242 | + .query_format = query_format, |
| 243 | + .draw_image = draw_image, |
| 244 | + .uninit = uninit, |
| 245 | + .priv_size = sizeof(struct priv), |
| 246 | + .options = (const struct m_option[]) { |
| 247 | + {"name", OPT_STRING(buffer_name)}, |
| 248 | + {0} |
| 249 | + }, |
| 250 | + .priv_defaults = &(const struct priv) { |
| 251 | + .buffer_name = "mpv", |
| 252 | + }, |
| 253 | + .options_prefix = "sharedbuffer", |
| 254 | +}; |
0 commit comments