mirror of https://github.com/mpv-player/mpv
vo_rpi: attempt to survive display mode changes
Recreate all dispmanx objects after mode changes signalled by the TV callback. This is needed since dispmanx objects are marked as invalid and cease working. One important point is that the vsync callbacks will stop coming when this happens, so restoring the callback is important. Note that the MMAL renderer itself does not get trashed by the firmware on such events, but we completely reconfigure it anyway when it happens.
This commit is contained in:
parent
dfa88271a2
commit
74e3d11f21
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include <libavutil/rational.h>
|
||||
|
||||
#include "osdep/atomics.h"
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/msg.h"
|
||||
#include "options/m_config.h"
|
||||
|
@ -69,11 +67,10 @@ struct priv {
|
|||
// for RAM input
|
||||
MMAL_POOL_T *swpool;
|
||||
|
||||
atomic_bool update_display;
|
||||
|
||||
pthread_mutex_t vsync_mutex;
|
||||
pthread_cond_t vsync_cond;
|
||||
int64_t vsync_counter;
|
||||
bool reload_display;
|
||||
|
||||
int background_layer;
|
||||
int video_layer;
|
||||
|
@ -89,6 +86,8 @@ struct priv {
|
|||
#define ALIGN_W 32
|
||||
#define ALIGN_H 16
|
||||
|
||||
static void recreate_renderer(struct vo *vo);
|
||||
|
||||
// Make mpi point to buffer, assuming MMAL_ENCODING_I420.
|
||||
// buffer can be NULL.
|
||||
// Return the required buffer space.
|
||||
|
@ -255,6 +254,9 @@ 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};
|
||||
|
@ -362,7 +364,7 @@ static void wait_next_vsync(struct vo *vo)
|
|||
struct priv *p = vo->priv;
|
||||
pthread_mutex_lock(&p->vsync_mutex);
|
||||
int64_t old = p->vsync_counter;
|
||||
while (old == p->vsync_counter)
|
||||
while (old == p->vsync_counter && !p->reload_display)
|
||||
pthread_cond_wait(&p->vsync_cond, &p->vsync_mutex);
|
||||
pthread_mutex_unlock(&p->vsync_mutex);
|
||||
}
|
||||
|
@ -370,6 +372,10 @@ static void wait_next_vsync(struct vo *vo)
|
|||
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;
|
||||
|
||||
|
@ -405,6 +411,9 @@ 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);
|
||||
|
@ -506,6 +515,9 @@ static int reconfig(struct vo *vo, struct mp_image_params *params)
|
|||
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;
|
||||
|
@ -560,6 +572,9 @@ 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;
|
||||
|
@ -612,14 +627,15 @@ static int control(struct vo *vo, uint32_t request, void *data)
|
|||
case VOCTRL_SCREENSHOT_WIN:
|
||||
*(struct mp_image **)data = take_screenshot(vo);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_CHECK_EVENTS:
|
||||
if (atomic_load(&p->update_display)) {
|
||||
atomic_store(&p->update_display, false);
|
||||
update_display_size(vo);
|
||||
if (p->renderer_enabled)
|
||||
set_geometry(vo);
|
||||
}
|
||||
case VOCTRL_CHECK_EVENTS: {
|
||||
pthread_mutex_lock(&p->vsync_mutex);
|
||||
bool reload_required = p->reload_display;
|
||||
p->reload_display = false;
|
||||
pthread_mutex_unlock(&p->vsync_mutex);
|
||||
if (reload_required)
|
||||
recreate_renderer(vo);
|
||||
return VO_TRUE;
|
||||
}
|
||||
case VOCTRL_GET_DISPLAY_FPS:
|
||||
*(double *)data = p->display_fps;
|
||||
return VO_TRUE;
|
||||
|
@ -633,7 +649,10 @@ static void tv_callback(void *callback_data, uint32_t reason, uint32_t param1,
|
|||
{
|
||||
struct vo *vo = callback_data;
|
||||
struct priv *p = vo->priv;
|
||||
atomic_store(&p->update_display, true);
|
||||
pthread_mutex_lock(&p->vsync_mutex);
|
||||
p->reload_display = true;
|
||||
pthread_cond_signal(&p->vsync_cond);
|
||||
pthread_mutex_unlock(&p->vsync_mutex);
|
||||
vo_wakeup(vo);
|
||||
}
|
||||
|
||||
|
@ -647,6 +666,55 @@ static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg)
|
|||
pthread_mutex_unlock(&p->vsync_mutex);
|
||||
}
|
||||
|
||||
static void destroy_dispmanx(struct vo *vo)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
|
||||
disable_renderer(vo);
|
||||
destroy_overlays(vo);
|
||||
|
||||
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;
|
||||
|
@ -655,20 +723,10 @@ static void uninit(struct vo *vo)
|
|||
|
||||
talloc_free(p->next_image);
|
||||
|
||||
destroy_overlays(vo);
|
||||
destroy_dispmanx(vo);
|
||||
|
||||
if (p->update)
|
||||
vc_dispmanx_update_submit_sync(p->update);
|
||||
|
||||
if (p->renderer) {
|
||||
disable_renderer(vo);
|
||||
if (p->renderer)
|
||||
mmal_component_release(p->renderer);
|
||||
}
|
||||
|
||||
if (p->display) {
|
||||
vc_dispmanx_vsync_callback(p->display, NULL, NULL);
|
||||
vc_dispmanx_display_close(p->display);
|
||||
}
|
||||
|
||||
mmal_vc_deinit();
|
||||
|
||||
|
@ -693,12 +751,14 @@ static int preinit(struct vo *vo)
|
|||
return -1;
|
||||
}
|
||||
|
||||
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");
|
||||
pthread_mutex_init(&p->vsync_mutex, NULL);
|
||||
pthread_cond_init(&p->vsync_cond, NULL);
|
||||
|
||||
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))
|
||||
{
|
||||
|
@ -706,16 +766,8 @@ static int preinit(struct vo *vo)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (update_display_size(vo) < 0)
|
||||
goto fail;
|
||||
|
||||
vc_tv_register_callback(tv_callback, vo);
|
||||
|
||||
pthread_mutex_init(&p->vsync_mutex, NULL);
|
||||
pthread_cond_init(&p->vsync_cond, NULL);
|
||||
|
||||
vc_dispmanx_vsync_callback(p->display, vsync_callback, vo);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
|
Loading…
Reference in New Issue