diff options
Diffstat (limited to 'video/out/opengl')
-rw-r--r-- | video/out/opengl/common.c | 2 | ||||
-rw-r--r-- | video/out/opengl/context_drm_egl.c | 4 | ||||
-rw-r--r-- | video/out/opengl/context_glx.c | 2 | ||||
-rw-r--r-- | video/out/opengl/context_rpi.c | 327 | ||||
-rw-r--r-- | video/out/opengl/context_wayland.c | 4 | ||||
-rw-r--r-- | video/out/opengl/context_win.c | 22 | ||||
-rw-r--r-- | video/out/opengl/egl_helpers.c | 10 | ||||
-rw-r--r-- | video/out/opengl/formats.c | 2 | ||||
-rw-r--r-- | video/out/opengl/hwdec_rpi.c | 384 |
9 files changed, 31 insertions, 726 deletions
diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c index ee26508..e3fc1ba 100644 --- a/video/out/opengl/common.c +++ b/video/out/opengl/common.c @@ -398,7 +398,7 @@ static const struct gl_functions gl_functions[] = { .provides = MPGL_CAP_NESTED_ARRAY, }, // Swap control, always an OS specific extension - // The OSX code loads this manually. + // The macOS code loads this manually. { .extension = "GLX_SGI_swap_control", .functions = (const struct gl_function[]) { diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c index 2db428f..ff4de18 100644 --- a/video/out/opengl/context_drm_egl.c +++ b/video/out/opengl/context_drm_egl.c @@ -616,6 +616,10 @@ static bool drm_egl_init(struct ra_ctx *ctx) xrgb_format = GBM_FORMAT_XBGR8888; break; default: + if (drm->opts->drm_format != DRM_OPTS_FORMAT_XRGB8888) { + MP_VERBOSE(ctx->vo, "Requested format not supported by context, " + "falling back to xrgb8888\n"); + } argb_format = GBM_FORMAT_ARGB8888; xrgb_format = GBM_FORMAT_XRGB8888; break; diff --git a/video/out/opengl/context_glx.c b/video/out/opengl/context_glx.c index 4062224..a2a63e1 100644 --- a/video/out/opengl/context_glx.c +++ b/video/out/opengl/context_glx.c @@ -25,7 +25,7 @@ #define GLX_CONTEXT_FLAGS_ARB 0x2094 #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 #ifndef __APPLE__ -// These are respectively 0x00000001 and 0x00000002 on OSX +// These are respectively 0x00000001 and 0x00000002 on macOS #define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 #endif diff --git a/video/out/opengl/context_rpi.c b/video/out/opengl/context_rpi.c deleted file mode 100644 index 0b6babb..0000000 --- a/video/out/opengl/context_rpi.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <assert.h> -#include <stdatomic.h> -#include <stddef.h> - -#include <bcm_host.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include "common/common.h" -#include "video/out/win_state.h" -#include "context.h" -#include "egl_helpers.h" - -struct priv { - struct GL gl; - DISPMANX_DISPLAY_HANDLE_T display; - DISPMANX_ELEMENT_HANDLE_T window; - DISPMANX_UPDATE_HANDLE_T update; - EGLDisplay egl_display; - EGLConfig egl_config; - EGLContext egl_context; - EGLSurface egl_surface; - // yep, the API keeps a pointer to it - EGL_DISPMANX_WINDOW_T egl_window; - int x, y, w, h; - double display_fps; - atomic_int reload_display; - int win_params[4]; -}; - -static void tv_callback(void *callback_data, uint32_t reason, uint32_t param1, - uint32_t param2) -{ - struct ra_ctx *ctx = callback_data; - struct priv *p = ctx->priv; - atomic_store(&p->reload_display, true); - vo_wakeup(ctx->vo); -} - -static void destroy_dispmanx(struct ra_ctx *ctx) -{ - struct priv *p = ctx->priv; - - if (p->egl_surface) { - eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - eglDestroySurface(p->egl_display, p->egl_surface); - p->egl_surface = EGL_NO_SURFACE; - } - - if (p->window) - vc_dispmanx_element_remove(p->update, p->window); - p->window = 0; - if (p->display) - vc_dispmanx_display_close(p->display); - p->display = 0; - if (p->update) - vc_dispmanx_update_submit_sync(p->update); - p->update = 0; -} - -static void rpi_uninit(struct ra_ctx *ctx) -{ - struct priv *p = ctx->priv; - ra_gl_ctx_uninit(ctx); - - vc_tv_unregister_callback_full(tv_callback, ctx); - - destroy_dispmanx(ctx); - - if (p->egl_context) - eglDestroyContext(p->egl_display, p->egl_context); - p->egl_context = EGL_NO_CONTEXT; - eglReleaseThread(); - p->egl_display = EGL_NO_DISPLAY; -} - -static bool recreate_dispmanx(struct ra_ctx *ctx) -{ - struct priv *p = ctx->priv; - int display_nr = 0; - int layer = 0; - - MP_VERBOSE(ctx, "Recreating DISPMANX state...\n"); - - destroy_dispmanx(ctx); - - p->display = vc_dispmanx_display_open(display_nr); - p->update = vc_dispmanx_update_start(0); - if (!p->display || !p->update) { - MP_FATAL(ctx, "Could not get DISPMANX objects.\n"); - goto fail; - } - - uint32_t dispw, disph; - if (graphics_get_display_size(0, &dispw, &disph) < 0) { - MP_FATAL(ctx, "Could not get display size.\n"); - goto fail; - } - p->w = dispw; - p->h = disph; - - if (ctx->vo->opts->fullscreen) { - p->x = p->y = 0; - } else { - struct vo_win_geometry geo; - struct mp_rect screenrc = {0, 0, p->w, p->h}; - - vo_calc_window_geometry(ctx->vo, &screenrc, &geo); - - mp_rect_intersection(&geo.win, &screenrc); - - p->x = geo.win.x0; - p->y = geo.win.y0; - p->w = geo.win.x1 - geo.win.x0; - p->h = geo.win.y1 - geo.win.y0; - } - - // dispmanx is like a neanderthal version of Wayland - you can add an - // overlay any place on the screen. - VC_RECT_T dst = {.x = p->x, .y = p->y, .width = p->w, .height = p->h}; - VC_RECT_T src = {.width = p->w << 16, .height = p->h << 16}; - VC_DISPMANX_ALPHA_T alpha = { - .flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, - .opacity = 0xFF, - }; - p->window = vc_dispmanx_element_add(p->update, p->display, layer, &dst, 0, - &src, DISPMANX_PROTECTION_NONE, &alpha, - 0, 0); - if (!p->window) { - MP_FATAL(ctx, "Could not add DISPMANX element.\n"); - goto fail; - } - - vc_dispmanx_update_submit_sync(p->update); - p->update = vc_dispmanx_update_start(0); - - p->egl_window = (EGL_DISPMANX_WINDOW_T){ - .element = p->window, - .width = p->w, - .height = p->h, - }; - p->egl_surface = eglCreateWindowSurface(p->egl_display, p->egl_config, - &p->egl_window, NULL); - - if (p->egl_surface == EGL_NO_SURFACE) { - MP_FATAL(ctx, "Could not create EGL surface!\n"); - goto fail; - } - - if (!eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, - p->egl_context)) - { - MP_FATAL(ctx, "Failed to set context!\n"); - goto fail; - } - - p->display_fps = 0; - TV_GET_STATE_RESP_T tvstate; - TV_DISPLAY_STATE_T tvstate_disp; - if (!vc_tv_get_state(&tvstate) && !vc_tv_get_display_state(&tvstate_disp)) { - if (tvstate_disp.state & (VC_HDMI_HDMI | VC_HDMI_DVI)) { - p->display_fps = tvstate_disp.display.hdmi.frame_rate; - - HDMI_PROPERTY_PARAM_T param = { - .property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE, - }; - if (!vc_tv_hdmi_get_property(¶m) && - param.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC) - p->display_fps = p->display_fps / 1.001; - } else { - p->display_fps = tvstate_disp.display.sdtv.frame_rate; - } - } - - p->win_params[0] = display_nr; - p->win_params[1] = layer; - p->win_params[2] = p->x; - p->win_params[3] = p->y; - - ctx->vo->dwidth = p->w; - ctx->vo->dheight = p->h; - if (ctx->swapchain) - ra_gl_ctx_resize(ctx->swapchain, p->w, p->h, 0); - - ctx->vo->want_redraw = true; - - vo_event(ctx->vo, VO_EVENT_WIN_STATE); - return true; - -fail: - destroy_dispmanx(ctx); - return false; -} - -static void rpi_swap_buffers(struct ra_ctx *ctx) -{ - struct priv *p = ctx->priv; - eglSwapBuffers(p->egl_display, p->egl_surface); -} - -static bool rpi_init(struct ra_ctx *ctx) -{ - struct priv *p = ctx->priv = talloc_zero(ctx, struct priv); - - bcm_host_init(); - - vc_tv_register_callback(tv_callback, ctx); - - p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (!eglInitialize(p->egl_display, NULL, NULL)) { - MP_FATAL(ctx, "EGL failed to initialize.\n"); - goto fail; - } - - if (!mpegl_create_context(ctx, p->egl_display, &p->egl_context, &p->egl_config)) - goto fail; - - if (!recreate_dispmanx(ctx)) - goto fail; - - mpegl_load_functions(&p->gl, ctx->log); - - struct ra_gl_ctx_params params = { - .swap_buffers = rpi_swap_buffers, - }; - - if (!ra_gl_ctx_init(ctx, &p->gl, params)) - goto fail; - - ra_add_native_resource(ctx->ra, "MPV_RPI_WINDOW", p->win_params); - - ra_gl_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight, 0); - return true; - -fail: - rpi_uninit(ctx); - return false; -} - -static bool rpi_reconfig(struct ra_ctx *ctx) -{ - return recreate_dispmanx(ctx); -} - -static struct mp_image *take_screenshot(struct ra_ctx *ctx) -{ - struct priv *p = ctx->priv; - - if (!p->display) - return NULL; - - struct mp_image *img = mp_image_alloc(IMGFMT_BGR0, p->w, p->h); - if (!img) - return NULL; - - DISPMANX_RESOURCE_HANDLE_T resource = - vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, - img->w | ((img->w * 4) << 16), img->h, - &(int32_t){0}); - if (!resource) - goto fail; - - if (vc_dispmanx_snapshot(p->display, resource, 0)) - goto fail; - - VC_RECT_T rc = {.width = img->w, .height = img->h}; - if (vc_dispmanx_resource_read_data(resource, &rc, img->planes[0], img->stride[0])) - goto fail; - - vc_dispmanx_resource_delete(resource); - return img; - -fail: - vc_dispmanx_resource_delete(resource); - talloc_free(img); - return NULL; -} - -static int rpi_control(struct ra_ctx *ctx, int *events, int request, void *arg) -{ - struct priv *p = ctx->priv; - - switch (request) { - case VOCTRL_SCREENSHOT_WIN: - *(struct mp_image **)arg = take_screenshot(ctx); - return VO_TRUE; - case VOCTRL_CHECK_EVENTS: - if (atomic_fetch_and(&p->reload_display, 0)) { - MP_WARN(ctx, "Recovering from display mode switch...\n"); - recreate_dispmanx(ctx); - } - return VO_TRUE; - case VOCTRL_GET_DISPLAY_FPS: - *(double *)arg = p->display_fps; - return VO_TRUE; - } - - return VO_NOTIMPL; -} - -const struct ra_ctx_fns ra_ctx_rpi = { - .type = "opengl", - .name = "rpi", - .reconfig = rpi_reconfig, - .control = rpi_control, - .init = rpi_init, - .uninit = rpi_uninit, -}; diff --git a/video/out/opengl/context_wayland.c b/video/out/opengl/context_wayland.c index 26c5268..2c5611b 100644 --- a/video/out/opengl/context_wayland.c +++ b/video/out/opengl/context_wayland.c @@ -47,14 +47,14 @@ static void resize(struct ra_ctx *ctx) const int32_t width = mp_rect_w(wl->geometry); const int32_t height = mp_rect_h(wl->geometry); + vo_wayland_handle_scale(wl); + vo_wayland_set_opaque_region(wl, ctx->opts.want_alpha); if (p->egl_window) wl_egl_window_resize(p->egl_window, width, height, 0, 0); wl->vo->dwidth = width; wl->vo->dheight = height; - - vo_wayland_handle_fractional_scale(wl); } static bool wayland_egl_check_visible(struct ra_ctx *ctx) diff --git a/video/out/opengl/context_win.c b/video/out/opengl/context_win.c index 968b176..a582e28 100644 --- a/video/out/opengl/context_win.c +++ b/video/out/opengl/context_win.c @@ -96,6 +96,7 @@ static bool create_dc(struct ra_ctx *ctx) pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 24; + pfd.cAlphaBits = 8; pfd.iLayerType = PFD_MAIN_PLANE; int pf = ChoosePixelFormat(hdc, &pfd); @@ -293,6 +294,9 @@ static bool wgl_init(struct ra_ctx *ctx) if (!vo_w32_init(ctx->vo)) goto fail; + if (ctx->opts.want_alpha) + vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha); + vo_w32_run_on_thread(ctx->vo, create_ctx, ctx); if (!p->context) goto fail; @@ -368,11 +372,17 @@ static int wgl_control(struct ra_ctx *ctx, int *events, int request, void *arg) return ret; } +static void wgl_update_render_opts(struct ra_ctx *ctx) +{ + vo_w32_set_transparency(ctx->vo, ctx->opts.want_alpha); +} + const struct ra_ctx_fns ra_ctx_wgl = { - .type = "opengl", - .name = "win", - .init = wgl_init, - .reconfig = wgl_reconfig, - .control = wgl_control, - .uninit = wgl_uninit, + .type = "opengl", + .name = "win", + .init = wgl_init, + .reconfig = wgl_reconfig, + .control = wgl_control, + .update_render_opts = wgl_update_render_opts, + .uninit = wgl_uninit, }; diff --git a/video/out/opengl/egl_helpers.c b/video/out/opengl/egl_helpers.c index 3bf6239..18d9027 100644 --- a/video/out/opengl/egl_helpers.c +++ b/video/out/opengl/egl_helpers.c @@ -192,18 +192,20 @@ static bool create_context(struct ra_ctx *ctx, EGLDisplay display, } if (!egl_ctx) { // Fallback for EGL 1.4 without EGL_KHR_create_context or GLES - // Add the context flags only for GLES - GL has been attempted above EGLint attrs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - es ? EGL_CONTEXT_FLAGS_KHR : EGL_NONE, ctx_flags, + EGL_CONTEXT_FLAGS_KHR, ctx_flags, + es ? EGL_CONTEXT_CLIENT_VERSION : EGL_NONE, 2, EGL_NONE }; egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, attrs); + if (!egl_ctx) + egl_ctx = eglCreateContext(display, config, EGL_NO_CONTEXT, &attrs[2]); } if (!egl_ctx) { - MP_MSG(ctx, msgl, "Could not create EGL context for %s!\n", name); + MP_MSG(ctx, msgl, "Could not create EGL context for %s (error=%d)!\n", + name, eglGetError()); return false; } diff --git a/video/out/opengl/formats.c b/video/out/opengl/formats.c index a0b79e2..dd0e89d 100644 --- a/video/out/opengl/formats.c +++ b/video/out/opengl/formats.c @@ -94,7 +94,7 @@ const struct gl_format gl_formats[] = { // Special formats. {"rgb565", GL_RGB8, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, F_TF | F_GL2 | F_GL3}, - // Worthless, but needed by OSX videotoolbox interop on old Apple hardware. + // Worthless, but needed by macOS videotoolbox interop on old Apple hardware. {"appleyp", GL_RGB, GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, F_TF | F_APPL}, diff --git a/video/out/opengl/hwdec_rpi.c b/video/out/opengl/hwdec_rpi.c deleted file mode 100644 index 5362832..0000000 --- a/video/out/opengl/hwdec_rpi.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <stdbool.h> -#include <assert.h> - -#include <bcm_host.h> -#include <interface/mmal/mmal.h> -#include <interface/mmal/util/mmal_util.h> -#include <interface/mmal/util/mmal_default_components.h> -#include <interface/mmal/vc/mmal_vc_api.h> - -#include <libavutil/rational.h> - -#include "common/common.h" -#include "common/msg.h" -#include "video/mp_image.h" -#include "video/out/gpu/hwdec.h" - -#include "common.h" - -struct priv { - struct mp_log *log; - - struct mp_image_params params; - - MMAL_COMPONENT_T *renderer; - bool renderer_enabled; - - // for RAM input - MMAL_POOL_T *swpool; - - struct mp_image *current_frame; - - struct mp_rect src, dst; - int cur_window[4]; // raw user params -}; - -// Magic alignments (in pixels) expected by the MMAL internals. -#define ALIGN_W 32 -#define ALIGN_H 16 - -// Make mpi point to buffer, assuming MMAL_ENCODING_I420. -// buffer can be NULL. -// Return the required buffer space. -static size_t layout_buffer(struct mp_image *mpi, MMAL_BUFFER_HEADER_T *buffer, - struct mp_image_params *params) -{ - assert(params->imgfmt == IMGFMT_420P); - mp_image_set_params(mpi, params); - int w = MP_ALIGN_UP(params->w, ALIGN_W); - int h = MP_ALIGN_UP(params->h, ALIGN_H); - uint8_t *cur = buffer ? buffer->data : NULL; - size_t size = 0; - for (int i = 0; i < 3; i++) { - int div = i ? 2 : 1; - mpi->planes[i] = cur; - mpi->stride[i] = w / div; - size_t plane_size = h / div * mpi->stride[i]; - if (cur) - cur += plane_size; - size += plane_size; - } - return size; -} - -static MMAL_FOURCC_T map_csp(enum mp_csp csp) -{ - switch (csp) { - case MP_CSP_BT_601: return MMAL_COLOR_SPACE_ITUR_BT601; - case MP_CSP_BT_709: return MMAL_COLOR_SPACE_ITUR_BT709; - case MP_CSP_SMPTE_240M: return MMAL_COLOR_SPACE_SMPTE240M; - default: return MMAL_COLOR_SPACE_UNKNOWN; - } -} - -static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) -{ - mmal_buffer_header_release(buffer); -} - -static void input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) -{ - struct mp_image *mpi = buffer->user_data; - talloc_free(mpi); -} - -static void disable_renderer(struct ra_hwdec *hw) -{ - struct priv *p = hw->priv; - - if (p->renderer_enabled) { - mmal_port_disable(p->renderer->control); - mmal_port_disable(p->renderer->input[0]); - - mmal_port_flush(p->renderer->control); - mmal_port_flush(p->renderer->input[0]); - - mmal_component_disable(p->renderer); - } - mmal_pool_destroy(p->swpool); - p->swpool = NULL; - p->renderer_enabled = false; -} - -// check_window_only: assume params and dst/src rc are unchanged -static void update_overlay(struct ra_hwdec *hw, bool check_window_only) -{ - struct priv *p = hw->priv; - MMAL_PORT_T *input = p->renderer->input[0]; - struct mp_rect src = p->src; - struct mp_rect dst = p->dst; - - int defs[4] = {0, 0, 0, 0}; - int *z = ra_get_native_resource(hw->ra_ctx->ra, "MPV_RPI_WINDOW"); - if (!z) - z = defs; - - // As documented in the libmpv openglcb headers. - int display = z[0]; - int layer = z[1]; - int x = z[2]; - int y = z[3]; - - if (check_window_only && memcmp(z, p->cur_window, sizeof(p->cur_window)) == 0) - return; - - memcpy(p->cur_window, z, sizeof(p->cur_window)); - - int rotate[] = {MMAL_DISPLAY_ROT0, - MMAL_DISPLAY_ROT90, - MMAL_DISPLAY_ROT180, - MMAL_DISPLAY_ROT270}; - - int src_w = src.x1 - src.x0, src_h = src.y1 - src.y0, - dst_w = dst.x1 - dst.x0, dst_h = dst.y1 - dst.y0; - int p_x, p_y; - av_reduce(&p_x, &p_y, dst_w * src_h, src_w * dst_h, 16000); - MMAL_DISPLAYREGION_T dr = { - .hdr = { .id = MMAL_PARAMETER_DISPLAYREGION, - .size = sizeof(MMAL_DISPLAYREGION_T), }, - .src_rect = { .x = src.x0, .y = src.y0, - .width = src_w, .height = src_h }, - .dest_rect = { .x = dst.x0 + x, .y = dst.y0 + y, - .width = dst_w, .height = dst_h }, - .layer = layer - 1, // under the GL layer - .display_num = display, - .pixel_x = p_x, - .pixel_y = p_y, - .transform = rotate[p->params.rotate / 90], - .fullscreen = 0, - .set = MMAL_DISPLAY_SET_SRC_RECT | MMAL_DISPLAY_SET_DEST_RECT | - MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_NUM | - MMAL_DISPLAY_SET_PIXEL | MMAL_DISPLAY_SET_TRANSFORM | - MMAL_DISPLAY_SET_FULLSCREEN, - }; - - if (p->params.rotate % 180 == 90) { - MPSWAP(int, dr.src_rect.x, dr.src_rect.y); - MPSWAP(int, dr.src_rect.width, dr.src_rect.height); - } - - if (mmal_port_parameter_set(input, &dr.hdr)) - MP_WARN(p, "could not set video rectangle\n"); -} - -static int enable_renderer(struct ra_hwdec *hw) -{ - struct priv *p = hw->priv; - MMAL_PORT_T *input = p->renderer->input[0]; - struct mp_image_params *params = &p->params; - - if (p->renderer_enabled) - return 0; - - if (!params->imgfmt) - return -1; - - bool opaque = params->imgfmt == IMGFMT_MMAL; - - input->format->encoding = opaque ? MMAL_ENCODING_OPAQUE : MMAL_ENCODING_I420; - input->format->es->video.width = MP_ALIGN_UP(params->w, ALIGN_W); - input->format->es->video.height = MP_ALIGN_UP(params->h, ALIGN_H); - input->format->es->video.crop = (MMAL_RECT_T){0, 0, params->w, params->h}; - input->format->es->video.par = (MMAL_RATIONAL_T){params->p_w, params->p_h}; - input->format->es->video.color_space = map_csp(params->color.space); - - if (mmal_port_format_commit(input)) - return -1; - - input->buffer_num = MPMAX(input->buffer_num_min, - input->buffer_num_recommended) + 3; - input->buffer_size = MPMAX(input->buffer_size_min, - input->buffer_size_recommended); - - if (!opaque) { - size_t size = layout_buffer(&(struct mp_image){0}, NULL, params); - if (input->buffer_size != size) { - MP_FATAL(hw, "We disagree with MMAL about buffer sizes.\n"); - return -1; - } - - p->swpool = mmal_pool_create(input->buffer_num, input->buffer_size); - if (!p->swpool) { - MP_FATAL(hw, "Could not allocate buffer pool.\n"); - return -1; - } - } - - update_overlay(hw, false); - - p->renderer_enabled = true; - - if (mmal_port_enable(p->renderer->control, control_port_cb)) - return -1; - - if (mmal_port_enable(input, input_port_cb)) - return -1; - - if (mmal_component_enable(p->renderer)) { - MP_FATAL(hw, "Failed to enable video renderer.\n"); - return -1; - } - - return 0; -} - -static void free_mmal_buffer(void *arg) -{ - MMAL_BUFFER_HEADER_T *buffer = arg; - mmal_buffer_header_release(buffer); -} - -static struct mp_image *upload(struct ra_hwdec *hw, struct mp_image *hw_image) -{ - struct priv *p = hw->priv; - - MMAL_BUFFER_HEADER_T *buffer = mmal_queue_wait(p->swpool->queue); - if (!buffer) { - MP_ERR(hw, "Can't allocate buffer.\n"); - return NULL; - } - mmal_buffer_header_reset(buffer); - - struct mp_image *new_ref = mp_image_new_custom_ref(NULL, buffer, - free_mmal_buffer); - if (!new_ref) { - mmal_buffer_header_release(buffer); - MP_ERR(hw, "Out of memory.\n"); - return NULL; - } - - mp_image_setfmt(new_ref, IMGFMT_MMAL); - new_ref->planes[3] = (void *)buffer; - - struct mp_image dmpi = {0}; - buffer->length = layout_buffer(&dmpi, buffer, &p->params); - mp_image_copy(&dmpi, hw_image); - - return new_ref; -} - -static int overlay_frame(struct ra_hwdec *hw, struct mp_image *hw_image, - struct mp_rect *src, struct mp_rect *dst, bool newframe) -{ - struct priv *p = hw->priv; - - if (hw_image && !mp_image_params_equal(&p->params, &hw_image->params)) { - p->params = hw_image->params; - - disable_renderer(hw); - mp_image_unrefp(&p->current_frame); - - if (enable_renderer(hw) < 0) - return -1; - } - - if (hw_image && p->current_frame && !newframe) { - if (!mp_rect_equals(&p->src, src) ||mp_rect_equals(&p->dst, dst)) { - p->src = *src; - p->dst = *dst; - update_overlay(hw, false); - } - return 0; // don't reupload - } - - mp_image_unrefp(&p->current_frame); - - if (!hw_image) { - disable_renderer(hw); - return 0; - } - - if (enable_renderer(hw) < 0) - return -1; - - update_overlay(hw, true); - - struct mp_image *mpi = NULL; - if (hw_image->imgfmt == IMGFMT_MMAL) { - mpi = mp_image_new_ref(hw_image); - } else { - mpi = upload(hw, hw_image); - } - - if (!mpi) { - disable_renderer(hw); - return -1; - } - - MMAL_BUFFER_HEADER_T *ref = (void *)mpi->planes[3]; - - // Assume this field is free for use by us. - ref->user_data = mpi; - - if (mmal_port_send_buffer(p->renderer->input[0], ref)) { - MP_ERR(hw, "could not queue picture!\n"); - talloc_free(mpi); - return -1; - } - - return 0; -} - -static void destroy(struct ra_hwdec *hw) -{ - struct priv *p = hw->priv; - - disable_renderer(hw); - - if (p->renderer) - mmal_component_release(p->renderer); - - mmal_vc_deinit(); -} - -static int create(struct ra_hwdec *hw) -{ - struct priv *p = hw->priv; - p->log = hw->log; - - bcm_host_init(); - - if (mmal_vc_init()) { - MP_FATAL(hw, "Could not initialize MMAL.\n"); - return -1; - } - - if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &p->renderer)) - { - MP_FATAL(hw, "Could not create MMAL renderer.\n"); - mmal_vc_deinit(); - return -1; - } - - return 0; -} - -const struct ra_hwdec_driver ra_hwdec_rpi_overlay = { - .name = "rpi-overlay", - .priv_size = sizeof(struct priv), - .imgfmts = {IMGFMT_MMAL, IMGFMT_420P, 0}, - .init = create, - .overlay_frame = overlay_frame, - .uninit = destroy, -}; |