diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:13:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:13:14 +0000 |
commit | 5a3b54c78ce63d899f76dbb3db72e4894b40bd53 (patch) | |
tree | 50693d13eeefc4d683bdf5417f0861b0ef274a0c /video/out/vo_rpi.c | |
parent | Adding debian version 0.37.0-1. (diff) | |
download | mpv-5a3b54c78ce63d899f76dbb3db72e4894b40bd53.tar.xz mpv-5a3b54c78ce63d899f76dbb3db72e4894b40bd53.zip |
Merging upstream version 0.38.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'video/out/vo_rpi.c')
-rw-r--r-- | video/out/vo_rpi.c | 938 |
1 files changed, 0 insertions, 938 deletions
diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c deleted file mode 100644 index 55f1a68..0000000 --- a/video/out/vo_rpi.c +++ /dev/null @@ -1,938 +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 <EGL/egl.h> -#include <EGL/eglext.h> - -#include <libavutil/rational.h> - -#include "common/common.h" -#include "common/msg.h" -#include "opengl/common.h" -#include "options/m_config.h" -#include "osdep/timer.h" -#include "vo.h" -#include "win_state.h" -#include "video/mp_image.h" -#include "sub/osd.h" - -#include "opengl/ra_gl.h" -#include "gpu/video.h" - -struct mp_egl_rpi { - struct mp_log *log; - struct GL *gl; - struct ra *ra; - 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; -}; - -struct priv { - DISPMANX_DISPLAY_HANDLE_T display; - DISPMANX_ELEMENT_HANDLE_T window; - DISPMANX_ELEMENT_HANDLE_T osd_overlay; - DISPMANX_UPDATE_HANDLE_T update; - uint32_t w, h; - uint32_t x, y; - double display_fps; - - double osd_pts; - struct mp_osd_res osd_res; - struct m_config_cache *opts_cache; - - struct mp_egl_rpi egl; - struct gl_video *gl_video; - struct mpgl_osd *osd; - - MMAL_COMPONENT_T *renderer; - bool renderer_enabled; - - bool display_synced, skip_osd; - struct mp_image *next_image; - - // for RAM input - MMAL_POOL_T *swpool; - - mp_mutex display_mutex; - mp_cond display_cond; - int64_t vsync_counter; - bool reload_display; - - int background_layer; - int video_layer; - int osd_layer; - - int display_nr; - int layer; - bool background; - bool enable_osd; -}; - -// Magic alignments (in pixels) expected by the MMAL internals. -#define ALIGN_W 32 -#define ALIGN_H 16 - -static void recreate_renderer(struct vo *vo); - -static void *get_proc_address(const GLubyte *name) -{ - void *p = eglGetProcAddress(name); - // EGL 1.4 (supported by the RPI firmware) does not necessarily return - // function pointers for core functions. - if (!p) { - void *h = dlopen("/opt/vc/lib/libbrcmGLESv2.so", RTLD_LAZY); - if (h) { - p = dlsym(h, name); - dlclose(h); - } - } - return p; -} - -static EGLConfig select_fb_config_egl(struct mp_egl_rpi *p) -{ - EGLint attributes[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE - }; - - EGLint config_count; - EGLConfig config; - - eglChooseConfig(p->egl_display, attributes, &config, 1, &config_count); - - if (!config_count) { - MP_FATAL(p, "Could find EGL configuration!\n"); - return NULL; - } - - return config; -} - -static void mp_egl_rpi_destroy(struct mp_egl_rpi *p) -{ - if (p->egl_display) { - eglMakeCurrent(p->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - } - if (p->egl_surface) - eglDestroySurface(p->egl_display, p->egl_surface); - if (p->egl_context) - eglDestroyContext(p->egl_display, p->egl_context); - p->egl_context = EGL_NO_CONTEXT; - eglReleaseThread(); - p->egl_display = EGL_NO_DISPLAY; - talloc_free(p->gl); - p->gl = NULL; -} - -static int mp_egl_rpi_init(struct mp_egl_rpi *p, DISPMANX_ELEMENT_HANDLE_T window, - int w, int h) -{ - p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (!eglInitialize(p->egl_display, NULL, NULL)) { - MP_FATAL(p, "EGL failed to initialize.\n"); - goto fail; - } - - eglBindAPI(EGL_OPENGL_ES_API); - - EGLConfig config = select_fb_config_egl(p); - if (!config) - goto fail; - - p->egl_window = (EGL_DISPMANX_WINDOW_T){ - .element = window, - .width = w, - .height = h, - }; - p->egl_surface = eglCreateWindowSurface(p->egl_display, config, - &p->egl_window, NULL); - - if (p->egl_surface == EGL_NO_SURFACE) { - MP_FATAL(p, "Could not create EGL surface!\n"); - goto fail; - } - - EGLint context_attributes[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - }; - p->egl_context = eglCreateContext(p->egl_display, config, - EGL_NO_CONTEXT, context_attributes); - - if (p->egl_context == EGL_NO_CONTEXT) { - MP_FATAL(p, "Could not create EGL context!\n"); - goto fail; - } - - eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, - p->egl_context); - - p->gl = talloc_zero(NULL, struct GL); - - const char *exts = eglQueryString(p->egl_display, EGL_EXTENSIONS); - mpgl_load_functions(p->gl, get_proc_address, exts, p->log); - - if (!p->gl->version && !p->gl->es) - goto fail; - - p->ra = ra_create_gl(p->gl, p->log); - if (!p->ra) - goto fail; - - return 0; - -fail: - mp_egl_rpi_destroy(p); - return -1; -} - -// 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 void update_osd(struct vo *vo) -{ - struct priv *p = vo->priv; - if (!p->enable_osd) - return; - - if (!gl_video_check_osd_change(p->gl_video, &p->osd_res, p->osd_pts)) { - p->skip_osd = true; - return; - } - - MP_STATS(vo, "start rpi_osd"); - - struct vo_frame frame = {0}; - struct ra_fbo target = { - .tex = ra_create_wrapped_fb(p->egl.ra, 0, p->osd_res.w, p->osd_res.h), - .flip = true, - }; - gl_video_set_osd_pts(p->gl_video, p->osd_pts); - gl_video_render_frame(p->gl_video, &frame, target, RENDER_FRAME_DEF); - ra_tex_free(p->egl.ra, &target.tex); - - MP_STATS(vo, "stop rpi_osd"); -} - -static void resize(struct vo *vo) -{ - struct priv *p = vo->priv; - MMAL_PORT_T *input = p->renderer->input[0]; - - struct mp_rect src, dst; - - vo_get_src_dst_rects(vo, &src, &dst, &p->osd_res); - - 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 + p->x, .y = dst.y0 + p->y, - .width = dst_w, .height = dst_h }, - .layer = p->video_layer, - .display_num = p->display_nr, - .pixel_x = p_x, - .pixel_y = p_y, - .transform = rotate[vo->params ? vo->params->rotate / 90 : 0], - .fullscreen = vo->opts->fullscreen, - .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 (vo->params && (vo->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(vo, "could not set video rectangle\n"); - - if (p->gl_video) - gl_video_resize(p->gl_video, &src, &dst, &p->osd_res); -} - -static void destroy_overlays(struct vo *vo) -{ - struct priv *p = vo->priv; - - if (p->window) - vc_dispmanx_element_remove(p->update, p->window); - p->window = 0; - - gl_video_uninit(p->gl_video); - p->gl_video = NULL; - ra_free(&p->egl.ra); - mp_egl_rpi_destroy(&p->egl); - - if (p->osd_overlay) - vc_dispmanx_element_remove(p->update, p->osd_overlay); - p->osd_overlay = 0; -} - -static int update_display_size(struct vo *vo) -{ - struct priv *p = vo->priv; - - uint32_t n_w = 0, n_h = 0; - if (graphics_get_display_size(0, &n_w, &n_h) < 0) { - MP_FATAL(vo, "Could not get display size.\n"); - return -1; - } - - if (p->w == n_w && p->h == n_h) - return 0; - - p->w = n_w; - p->h = n_h; - - MP_VERBOSE(vo, "Display size: %dx%d\n", p->w, p->h); - - return 0; -} - -static int create_overlays(struct vo *vo) -{ - struct priv *p = vo->priv; - destroy_overlays(vo); - - if (!p->display) - return -1; - - if (vo->opts->fullscreen && p->background) { - // Use the whole screen. - VC_RECT_T dst = {.width = p->w, .height = p->h}; - VC_RECT_T src = {.width = 1 << 16, .height = 1 << 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, - p->background_layer, - &dst, 0, &src, - DISPMANX_PROTECTION_NONE, - &alpha, 0, 0); - if (!p->window) { - MP_FATAL(vo, "Could not add DISPMANX element.\n"); - return -1; - } - } - - if (p->enable_osd) { - VC_RECT_T dst = {.x = p->x, .y = p->y, - .width = p->osd_res.w, .height = p->osd_res.h}; - VC_RECT_T src = {.width = p->osd_res.w << 16, .height = p->osd_res.h << 16}; - VC_DISPMANX_ALPHA_T alpha = { - .flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE, - .opacity = 0xFF, - }; - p->osd_overlay = vc_dispmanx_element_add(p->update, p->display, - p->osd_layer, - &dst, 0, &src, - DISPMANX_PROTECTION_NONE, - &alpha, 0, 0); - if (!p->osd_overlay) { - MP_FATAL(vo, "Could not add DISPMANX element.\n"); - return -1; - } - - if (mp_egl_rpi_init(&p->egl, p->osd_overlay, - p->osd_res.w, p->osd_res.h) < 0) - { - MP_FATAL(vo, "EGL/GLES initialization for OSD renderer failed.\n"); - return -1; - } - p->gl_video = gl_video_init(p->egl.ra, vo->log, vo->global); - gl_video_set_clear_color(p->gl_video, (struct m_color){.a = 0}); - gl_video_set_osd_source(p->gl_video, vo->osd); - } - - 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; - } - } - - resize(vo); - - vo_event(vo, VO_EVENT_WIN_STATE); - - vc_dispmanx_update_submit_sync(p->update); - p->update = vc_dispmanx_update_start(10); - - return 0; -} - -static int set_geometry(struct vo *vo) -{ - struct priv *p = vo->priv; - - if (vo->opts->fullscreen) { - vo->dwidth = p->w; - vo->dheight = p->h; - 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(vo, &screenrc, &geo); - vo_apply_window_geometry(vo, &geo); - - p->x = geo.win.x0; - p->y = geo.win.y0; - } - - resize(vo); - - if (create_overlays(vo) < 0) - return -1; - - return 0; -} - -static void wait_next_vsync(struct vo *vo) -{ - struct priv *p = vo->priv; - mp_mutex_lock(&p->display_mutex); - int64_t end = mp_time_ns() + MP_TIME_MS_TO_NS(50); - int64_t old = p->vsync_counter; - while (old == p->vsync_counter && !p->reload_display) { - if (mp_cond_timedwait_until(&p->display_cond, &p->display_mutex, end)) - break; - } - mp_mutex_unlock(&p->display_mutex); -} - -static void flip_page(struct vo *vo) -{ - struct priv *p = vo->priv; - - if (!p->renderer_enabled) - return; - - struct mp_image *mpi = p->next_image; - p->next_image = NULL; - - // For OSD - if (!p->skip_osd && p->egl.gl) - eglSwapBuffers(p->egl.egl_display, p->egl.egl_surface); - p->skip_osd = false; - - if (mpi) { - MMAL_PORT_T *input = p->renderer->input[0]; - 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(input, ref)) { - MP_ERR(vo, "could not queue picture!\n"); - talloc_free(mpi); - } - } - - if (p->display_synced) - wait_next_vsync(vo); -} - -static void free_mmal_buffer(void *arg) -{ - MMAL_BUFFER_HEADER_T *buffer = arg; - mmal_buffer_header_release(buffer); -} - -static void draw_frame(struct vo *vo, struct vo_frame *frame) -{ - struct priv *p = vo->priv; - - if (!p->renderer_enabled) - return; - - mp_image_t *mpi = NULL; - if (!frame->redraw && !frame->repeat) - mpi = mp_image_new_ref(frame->current); - - talloc_free(p->next_image); - p->next_image = NULL; - - if (mpi) - p->osd_pts = mpi->pts; - - // Redraw only if the OSD has meaningfully changed, which we assume it - // hasn't when a frame is merely repeated for display sync. - p->skip_osd = !frame->redraw && frame->repeat; - - if (!p->skip_osd && p->egl.gl) - update_osd(vo); - - p->display_synced = frame->display_synced; - - if (mpi && mpi->imgfmt != IMGFMT_MMAL) { - MMAL_BUFFER_HEADER_T *buffer = mmal_queue_wait(p->swpool->queue); - if (!buffer) { - talloc_free(mpi); - MP_ERR(vo, "Can't allocate buffer.\n"); - return; - } - 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); - talloc_free(mpi); - MP_ERR(vo, "Out of memory.\n"); - return; - } - - mp_image_setfmt(new_ref, IMGFMT_MMAL); - new_ref->planes[3] = (void *)buffer; - - struct mp_image dmpi = {0}; - buffer->length = layout_buffer(&dmpi, buffer, vo->params); - mp_image_copy(&dmpi, mpi); - - talloc_free(mpi); - mpi = new_ref; - } - - p->next_image = mpi; -} - -static int query_format(struct vo *vo, int format) -{ - return format == IMGFMT_MMAL || format == IMGFMT_420P; -} - -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 vo *vo) -{ - struct priv *p = vo->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; -} - -static int reconfig(struct vo *vo, struct mp_image_params *params) -{ - struct priv *p = vo->priv; - MMAL_PORT_T *input = p->renderer->input[0]; - bool opaque = params->imgfmt == IMGFMT_MMAL; - - if (!p->display) - return -1; - - disable_renderer(vo); - - 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(vo, "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(vo, "Could not allocate buffer pool.\n"); - return -1; - } - } - - if (set_geometry(vo) < 0) - return -1; - - 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(vo, "Failed to enable video renderer.\n"); - return -1; - } - - resize(vo); - - return 0; -} - -static struct mp_image *take_screenshot(struct vo *vo) -{ - struct priv *p = vo->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 void set_fullscreen(struct vo *vo) { - struct priv *p = vo->priv; - - if (p->renderer_enabled) - set_geometry(vo); - vo->want_redraw = true; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct priv *p = vo->priv; - - switch (request) { - case VOCTRL_VO_OPTS_CHANGED: { - void *opt; - while (m_config_cache_get_next_changed(p->opts_cache, &opt)) { - struct mp_vo_opts *opts = p->opts_cache->opts; - if (&opts->fullscreen == opt) - set_fullscreen(vo); - } - return VO_TRUE; - } - case VOCTRL_SET_PANSCAN: - if (p->renderer_enabled) - resize(vo); - vo->want_redraw = true; - return VO_TRUE; - case VOCTRL_REDRAW_FRAME: - update_osd(vo); - return VO_TRUE; - case VOCTRL_SCREENSHOT_WIN: - *(struct mp_image **)data = take_screenshot(vo); - return VO_TRUE; - case VOCTRL_CHECK_EVENTS: { - mp_mutex_lock(&p->display_mutex); - bool reload_required = p->reload_display; - p->reload_display = false; - mp_mutex_unlock(&p->display_mutex); - if (reload_required) - recreate_renderer(vo); - return VO_TRUE; - } - case VOCTRL_GET_DISPLAY_FPS: - *(double *)data = p->display_fps; - return VO_TRUE; - case VOCTRL_GET_DISPLAY_RES: - ((int *)data)[0] = p->w; - ((int *)data)[1] = p->h; - return VO_TRUE; - } - - return VO_NOTIMPL; -} - -static void tv_callback(void *callback_data, uint32_t reason, uint32_t param1, - uint32_t param2) -{ - struct vo *vo = callback_data; - struct priv *p = vo->priv; - mp_mutex_lock(&p->display_mutex); - p->reload_display = true; - mp_cond_signal(&p->display_cond); - mp_mutex_unlock(&p->display_mutex); - vo_wakeup(vo); -} - -static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg) -{ - struct vo *vo = arg; - struct priv *p = vo->priv; - mp_mutex_lock(&p->display_mutex); - p->vsync_counter += 1; - mp_cond_signal(&p->display_cond); - mp_mutex_unlock(&p->display_mutex); -} - -static void destroy_dispmanx(struct vo *vo) -{ - struct priv *p = vo->priv; - - disable_renderer(vo); - destroy_overlays(vo); - - if (p->update) - vc_dispmanx_update_submit_sync(p->update); - p->update = 0; - - if (p->display) { - vc_dispmanx_vsync_callback(p->display, NULL, NULL); - vc_dispmanx_display_close(p->display); - } - p->display = 0; -} - -static int recreate_dispmanx(struct vo *vo) -{ - struct priv *p = vo->priv; - - p->display = vc_dispmanx_display_open(p->display_nr); - p->update = vc_dispmanx_update_start(0); - if (!p->display || !p->update) { - MP_FATAL(vo, "Could not get DISPMANX objects.\n"); - if (p->display) - vc_dispmanx_display_close(p->display); - p->display = 0; - p->update = 0; - return -1; - } - - update_display_size(vo); - - vc_dispmanx_vsync_callback(p->display, vsync_callback, vo); - - return 0; -} - -static void recreate_renderer(struct vo *vo) -{ - MP_WARN(vo, "Recreating renderer after display change.\n"); - - destroy_dispmanx(vo); - recreate_dispmanx(vo); - - if (vo->params) { - if (reconfig(vo, vo->params) < 0) - MP_FATAL(vo, "Recreation failed.\n"); - } -} - -static void uninit(struct vo *vo) -{ - struct priv *p = vo->priv; - - vc_tv_unregister_callback_full(tv_callback, vo); - - talloc_free(p->next_image); - - destroy_dispmanx(vo); - - if (p->renderer) - mmal_component_release(p->renderer); - - mmal_vc_deinit(); - - mp_cond_destroy(&p->display_cond); - mp_mutex_destroy(&p->display_mutex); -} - -static int preinit(struct vo *vo) -{ - struct priv *p = vo->priv; - - p->background_layer = p->layer; - p->video_layer = p->layer + 1; - p->osd_layer = p->layer + 2; - - p->egl.log = vo->log; - - bcm_host_init(); - - if (mmal_vc_init()) { - MP_FATAL(vo, "Could not initialize MMAL.\n"); - return -1; - } - - mp_mutex_init(&p->display_mutex); - mp_cond_init(&p->display_cond); - - p->opts_cache = m_config_cache_alloc(p, vo->global, &vo_sub_opts); - - if (recreate_dispmanx(vo) < 0) - goto fail; - - if (update_display_size(vo) < 0) - goto fail; - - if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &p->renderer)) - { - MP_FATAL(vo, "Could not create MMAL renderer.\n"); - goto fail; - } - - vc_tv_register_callback(tv_callback, vo); - - return 0; - -fail: - uninit(vo); - return -1; -} - -#define OPT_BASE_STRUCT struct priv -static const struct m_option options[] = { - {"display", OPT_INT(display_nr)}, - {"layer", OPT_INT(layer), OPTDEF_INT(-10)}, - {"background", OPT_BOOL(background)}, - {"osd", OPT_BOOL(enable_osd), OPTDEF_INT(1)}, - {0}, -}; - -const struct vo_driver video_out_rpi = { - .description = "Raspberry Pi (MMAL)", - .name = "rpi", - .caps = VO_CAP_ROTATE90, - .preinit = preinit, - .query_format = query_format, - .reconfig = reconfig, - .control = control, - .draw_frame = draw_frame, - .flip_page = flip_page, - .uninit = uninit, - .priv_size = sizeof(struct priv), - .options = options, - .options_prefix = "rpi", -}; |