Improve event management
Removed the need for nanosleep() and keeping track of number of events triggered by libmpv. Signed-off-by: Mahyar Koshkouei <mahyar.koshkouei@gmail.com>
This commit is contained in:
parent
3015ebabc4
commit
1b5c47840a
176
mpv-libretro.c
176
mpv-libretro.c
|
@ -15,9 +15,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Required for retro_sleep */
|
|
||||||
#define _POSIX_C_SOURCE 199309L
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -37,7 +34,6 @@
|
||||||
#include <mpv/opengl_cb.h>
|
#include <mpv/opengl_cb.h>
|
||||||
|
|
||||||
#include <libretro.h>
|
#include <libretro.h>
|
||||||
#include <retro_timers.h>
|
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
@ -56,11 +52,8 @@ static retro_input_state_t input_state_cb;
|
||||||
static mpv_handle *mpv;
|
static mpv_handle *mpv;
|
||||||
static mpv_opengl_cb_context *mpv_gl;
|
static mpv_opengl_cb_context *mpv_gl;
|
||||||
|
|
||||||
/* Keep track of the number of events in mpv queue */
|
|
||||||
static unsigned int event_waiting = 0;
|
|
||||||
|
|
||||||
/* Save the current playback time for context changes */
|
/* Save the current playback time for context changes */
|
||||||
static int64_t *playback_time = 0;
|
static int64_t playback_time = 0;
|
||||||
|
|
||||||
/* filepath required globaly as mpv is reopened on context change */
|
/* filepath required globaly as mpv is reopened on context change */
|
||||||
static char *filepath = NULL;
|
static char *filepath = NULL;
|
||||||
|
@ -81,52 +74,59 @@ static void fallback_log(enum retro_log_level level, const char *fmt, ...)
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_mpv_logs(void)
|
/**
|
||||||
|
* Process various events triggered by mpv, such as printing log messages.
|
||||||
|
*
|
||||||
|
* \param event_block Wait until the mpv triggers specified event. Should be
|
||||||
|
* NULL if no wait is required.
|
||||||
|
*/
|
||||||
|
static void process_mpv_events(mpv_event_id event_block)
|
||||||
{
|
{
|
||||||
/* Print out mpv logs */
|
do
|
||||||
if(event_waiting > 0)
|
|
||||||
{
|
{
|
||||||
while(1)
|
mpv_event *mp_event = mpv_wait_event(mpv, 0);
|
||||||
|
if(event_block == MPV_EVENT_NONE &&
|
||||||
|
mp_event->event_id == MPV_EVENT_NONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(mp_event->event_id == event_block)
|
||||||
|
event_block = MPV_EVENT_NONE;
|
||||||
|
|
||||||
|
if(mp_event->event_id == MPV_EVENT_LOG_MESSAGE)
|
||||||
{
|
{
|
||||||
mpv_event *mp_event = mpv_wait_event(mpv, 0);
|
struct mpv_event_log_message *msg =
|
||||||
if(mp_event->event_id == MPV_EVENT_NONE)
|
(struct mpv_event_log_message *)mp_event->data;
|
||||||
break;
|
log_cb(RETRO_LOG_INFO, "mpv: [%s] %s: %s",
|
||||||
|
msg->prefix, msg->level, msg->text);
|
||||||
if(mp_event->event_id == MPV_EVENT_LOG_MESSAGE)
|
|
||||||
{
|
|
||||||
struct mpv_event_log_message *msg =
|
|
||||||
(struct mpv_event_log_message *)mp_event->data;
|
|
||||||
log_cb(RETRO_LOG_INFO, "mpv: [%s] %s: %s",
|
|
||||||
msg->prefix, msg->level, msg->text);
|
|
||||||
}
|
|
||||||
else if(mp_event->event_id == MPV_EVENT_END_FILE)
|
|
||||||
{
|
|
||||||
struct mpv_event_end_file *eof =
|
|
||||||
(struct mpv_event_end_file *)mp_event->data;
|
|
||||||
|
|
||||||
if(eof->reason == MPV_END_FILE_REASON_EOF)
|
|
||||||
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
|
|
||||||
#if 0
|
|
||||||
/* The following could be done instead if the file was not
|
|
||||||
* closed once the end was reached - allowing the user to seek
|
|
||||||
* back without reopening the file.
|
|
||||||
*/
|
|
||||||
struct retro_message ra_msg = {
|
|
||||||
"Finished playing file", 60 * 5, /* 5 seconds */
|
|
||||||
};
|
|
||||||
|
|
||||||
environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &ra_msg);RETRO_ENVIRONMENT_SHUTDOWN
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log_cb(RETRO_LOG_INFO, "mpv: %s\n",
|
|
||||||
mpv_event_name(mp_event->event_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if(mp_event->event_id == MPV_EVENT_END_FILE)
|
||||||
|
{
|
||||||
|
struct mpv_event_end_file *eof =
|
||||||
|
(struct mpv_event_end_file *)mp_event->data;
|
||||||
|
|
||||||
event_waiting = 0;
|
if(eof->reason == MPV_END_FILE_REASON_EOF)
|
||||||
|
environ_cb(RETRO_ENVIRONMENT_SHUTDOWN, NULL);
|
||||||
|
#if 0
|
||||||
|
/* The following could be done instead if the file was not
|
||||||
|
* closed once the end was reached - allowing the user to seek
|
||||||
|
* back without reopening the file.
|
||||||
|
*/
|
||||||
|
struct retro_message ra_msg = {
|
||||||
|
"Finished playing file", 60 * 5, /* 5 seconds */
|
||||||
|
};
|
||||||
|
|
||||||
|
environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &ra_msg);RETRO_ENVIRONMENT_SHUTDOWN
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if(mp_event->event_id == MPV_EVENT_NONE)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_cb(RETRO_LOG_INFO, "mpv: %s\n",
|
||||||
|
mpv_event_name(mp_event->event_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *get_proc_address_mpv(void *fn_ctx, const char *name)
|
static void *get_proc_address_mpv(void *fn_ctx, const char *name)
|
||||||
|
@ -145,11 +145,6 @@ static void *get_proc_address_mpv(void *fn_ctx, const char *name)
|
||||||
return proc_addr;
|
return proc_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_mpv_events(void *mpv)
|
|
||||||
{
|
|
||||||
event_waiting++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void retro_init(void)
|
void retro_init(void)
|
||||||
{
|
{
|
||||||
if(mpv_client_api_version() != MPV_CLIENT_API_VERSION)
|
if(mpv_client_api_version() != MPV_CLIENT_API_VERSION)
|
||||||
|
@ -250,6 +245,7 @@ void retro_set_environment(retro_environment_t cb)
|
||||||
static void context_reset(void)
|
static void context_reset(void)
|
||||||
{
|
{
|
||||||
const char *cmd[] = {"loadfile", filepath, NULL};
|
const char *cmd[] = {"loadfile", filepath, NULL};
|
||||||
|
int ret;
|
||||||
|
|
||||||
#ifdef HAVE_LOCALE
|
#ifdef HAVE_LOCALE
|
||||||
setlocale(LC_NUMERIC, "C");
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
@ -257,23 +253,23 @@ static void context_reset(void)
|
||||||
|
|
||||||
mpv = mpv_create();
|
mpv = mpv_create();
|
||||||
|
|
||||||
if(mpv == NULL)
|
if(!mpv)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "failed creating context\n");
|
log_cb(RETRO_LOG_ERROR, "failed creating context\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mpv_initialize(mpv) < 0)
|
if((ret = mpv_initialize(mpv)) < 0)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "mpv init failed\n");
|
log_cb(RETRO_LOG_ERROR, "mpv init failed: %s\n", mpv_error_string(ret));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When normal mpv events are available. */
|
if((ret = mpv_request_log_messages(mpv, "v")) < 0)
|
||||||
mpv_set_wakeup_callback(mpv, on_mpv_events, NULL);
|
{
|
||||||
|
log_cb(RETRO_LOG_ERROR, "mpv logging failed: %s\n",
|
||||||
if(mpv_request_log_messages(mpv, "v") < 0)
|
mpv_error_string(ret));
|
||||||
log_cb(RETRO_LOG_ERROR, "mpv logging failed\n");
|
}
|
||||||
|
|
||||||
/* The OpenGL API is somewhat separate from the normal mpv API. This only
|
/* The OpenGL API is somewhat separate from the normal mpv API. This only
|
||||||
* returns NULL if no OpenGL support is compiled.
|
* returns NULL if no OpenGL support is compiled.
|
||||||
|
@ -286,18 +282,20 @@ static void context_reset(void)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address_mpv, NULL) < 0)
|
if((ret = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address_mpv, NULL)) < 0)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "failed to initialize mpv GL context\n");
|
log_cb(RETRO_LOG_ERROR, "failed to initialize mpv GL context: %s\n",
|
||||||
|
mpv_error_string(ret));
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actually using the opengl_cb state has to be explicitly requested.
|
/* Actually using the opengl_cb state has to be explicitly requested.
|
||||||
* Otherwise, mpv will create a separate platform window.
|
* Otherwise, mpv will create a separate platform window.
|
||||||
*/
|
*/
|
||||||
if(mpv_set_option_string(mpv, "vo", "opengl-cb") < 0)
|
if((ret = mpv_set_option_string(mpv, "vo", "opengl-cb")) < 0)
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "failed to set video output to OpenGL\n");
|
log_cb(RETRO_LOG_ERROR, "failed to set video output to OpenGL: %s\n",
|
||||||
|
mpv_error_string(ret));
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,27 +306,17 @@ static void context_reset(void)
|
||||||
/* Attempt to enable hardware acceleration. MPV will fallback to software
|
/* Attempt to enable hardware acceleration. MPV will fallback to software
|
||||||
* decoding on failure.
|
* decoding on failure.
|
||||||
*/
|
*/
|
||||||
if(mpv_set_option_string(mpv, "hwdec", "auto") < 0)
|
if((ret = mpv_set_option_string(mpv, "hwdec", "auto")) < 0)
|
||||||
log_cb(RETRO_LOG_ERROR, "failed to set hwdec option\n");
|
|
||||||
|
|
||||||
if(mpv_command(mpv, cmd) != 0)
|
|
||||||
{
|
{
|
||||||
log_cb(RETRO_LOG_ERROR, "failed to issue mpv_command to load file\n");
|
log_cb(RETRO_LOG_ERROR, "failed to set hwdec option: %s\n",
|
||||||
goto err;
|
mpv_error_string(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((ret = mpv_command(mpv, cmd)) != 0)
|
||||||
/* Keep trying until mpv accepts the property. This is done to seek to the
|
|
||||||
* point in the file after the previous context was destroyed. If no
|
|
||||||
* context was destroyed previously, the file seeks to 0.
|
|
||||||
*
|
|
||||||
* This also seems to fix some black screen issues.
|
|
||||||
*/
|
|
||||||
while(mpv_set_property(mpv,
|
|
||||||
"playback-time", MPV_FORMAT_INT64, &playback_time) < 0)
|
|
||||||
{
|
{
|
||||||
/* Garbage fix to overflowing log */
|
log_cb(RETRO_LOG_ERROR, "mpv_command failed to load input file: %s\n",
|
||||||
retro_sleep(10);
|
mpv_error_string(ret));
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO #2: Check for the highest samplerate in audio stream, and use that.
|
/* TODO #2: Check for the highest samplerate in audio stream, and use that.
|
||||||
|
@ -338,6 +326,23 @@ static void context_reset(void)
|
||||||
mpv_set_option_string(mpv, "audio-samplerate", "48000");
|
mpv_set_option_string(mpv, "audio-samplerate", "48000");
|
||||||
mpv_set_option_string(mpv, "opengl-swapinterval", "0");
|
mpv_set_option_string(mpv, "opengl-swapinterval", "0");
|
||||||
|
|
||||||
|
/* Process any events whilst we wait for playback to begin. */
|
||||||
|
process_mpv_events(MPV_EVENT_NONE);
|
||||||
|
|
||||||
|
/* Keep trying until mpv accepts the property. This is done to seek to the
|
||||||
|
* point in the file after the previous context was destroyed. If no
|
||||||
|
* context was destroyed previously, the file seeks to 0.
|
||||||
|
*
|
||||||
|
* This also seems to fix some black screen issues.
|
||||||
|
*/
|
||||||
|
if(playback_time == 0)
|
||||||
|
{
|
||||||
|
process_mpv_events(MPV_EVENT_PLAYBACK_RESTART);
|
||||||
|
while(mpv_set_property(mpv,
|
||||||
|
"playback-time", MPV_FORMAT_INT64, &playback_time) < 0)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
/* The following works best when vsync is switched off in Retroarch. */
|
/* The following works best when vsync is switched off in Retroarch. */
|
||||||
//mpv_set_option_string(mpv, "video-sync", "display-resample");
|
//mpv_set_option_string(mpv, "video-sync", "display-resample");
|
||||||
//mpv_set_option_string(mpv, "display-fps", "60");
|
//mpv_set_option_string(mpv, "display-fps", "60");
|
||||||
|
@ -348,7 +353,7 @@ static void context_reset(void)
|
||||||
|
|
||||||
err:
|
err:
|
||||||
/* Print mpv logs to see why mpv failed. */
|
/* Print mpv logs to see why mpv failed. */
|
||||||
print_mpv_logs();
|
process_mpv_events(MPV_EVENT_NONE);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,8 +550,6 @@ void retro_run(void)
|
||||||
updated_video_dimensions = true;
|
updated_video_dimensions = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_mpv_logs();
|
|
||||||
|
|
||||||
retropad_update_input();
|
retropad_update_input();
|
||||||
|
|
||||||
/* TODO #2: Implement an audio callback feature in to libmpv */
|
/* TODO #2: Implement an audio callback feature in to libmpv */
|
||||||
|
@ -565,6 +568,9 @@ void retro_run(void)
|
||||||
mpv_opengl_cb_draw(mpv_gl, hw_render.get_current_framebuffer(), width, height);
|
mpv_opengl_cb_draw(mpv_gl, hw_render.get_current_framebuffer(), width, height);
|
||||||
video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 0);
|
video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
process_mpv_events(MPV_EVENT_NONE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue