mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 04:20:28 +00:00
Start integrating video processor code
This commit is contained in:
parent
31143e5f5e
commit
afee38109d
@ -1027,11 +1027,13 @@ ifeq ($(HAVE_ZLIB_DEFLATE),1)
|
||||
DEFINES += -DHAVE_ZLIB_DEFLATE
|
||||
endif
|
||||
|
||||
# Camera
|
||||
# Video4Linux 2
|
||||
|
||||
ifeq ($(HAVE_V4L2),1)
|
||||
OBJ += camera/drivers/video4linux2.o
|
||||
OBJ += camera/drivers/video4linux2.o \
|
||||
cores/libretro-video-processor/video_processor_v4l2.o
|
||||
DEFINES += -DHAVE_V4L2
|
||||
LIBS += $(V4L2_LIBS)
|
||||
endif
|
||||
|
||||
# Things that depend on network availability
|
||||
|
@ -22,7 +22,8 @@ enum rarch_core_type
|
||||
CORE_TYPE_DUMMY,
|
||||
CORE_TYPE_FFMPEG,
|
||||
CORE_TYPE_IMAGEVIEWER,
|
||||
CORE_TYPE_NETRETROPAD
|
||||
CORE_TYPE_NETRETROPAD,
|
||||
CORE_TYPE_VIDEOPROCESSOR
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -240,4 +240,60 @@ size_t libretro_netretropad_retro_get_memory_size(unsigned id);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_V4L2)
|
||||
/* Internal video processor core. */
|
||||
|
||||
void libretro_videoprocessor_retro_init(void);
|
||||
|
||||
void libretro_videoprocessor_retro_deinit(void);
|
||||
|
||||
unsigned libretro_videoprocessor_retro_api_version(void);
|
||||
|
||||
void libretro_videoprocessor_retro_get_system_info(struct retro_system_info *info);
|
||||
|
||||
void libretro_videoprocessor_retro_get_system_av_info(struct retro_system_av_info *info);
|
||||
|
||||
void libretro_videoprocessor_retro_set_environment(retro_environment_t cb);
|
||||
|
||||
void libretro_videoprocessor_retro_set_video_refresh(retro_video_refresh_t cb);
|
||||
|
||||
void libretro_videoprocessor_retro_set_audio_sample(retro_audio_sample_t cb);
|
||||
|
||||
void libretro_videoprocessor_retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);
|
||||
|
||||
void libretro_videoprocessor_retro_set_input_poll(retro_input_poll_t cb);
|
||||
|
||||
void libretro_videoprocessor_retro_set_input_state(retro_input_state_t cb);
|
||||
|
||||
void libretro_videoprocessor_retro_set_controller_port_device(unsigned port, unsigned device);
|
||||
|
||||
void libretro_videoprocessor_retro_reset(void);
|
||||
|
||||
void libretro_videoprocessor_retro_run(void);
|
||||
|
||||
size_t libretro_videoprocessor_retro_serialize_size(void);
|
||||
|
||||
bool libretro_videoprocessor_retro_serialize(void *data, size_t size);
|
||||
|
||||
bool libretro_videoprocessor_retro_unserialize(const void *data, size_t size);
|
||||
|
||||
void libretro_videoprocessor_retro_cheat_reset(void);
|
||||
|
||||
void libretro_videoprocessor_retro_cheat_set(unsigned index, bool enabled, const char *code);
|
||||
|
||||
bool libretro_videoprocessor_retro_load_game(const struct retro_game_info *game);
|
||||
|
||||
bool libretro_videoprocessor_retro_load_game_special(unsigned game_type,
|
||||
const struct retro_game_info *info, size_t num_info);
|
||||
|
||||
void libretro_videoprocessor_retro_unload_game(void);
|
||||
|
||||
unsigned libretro_videoprocessor_retro_get_region(void);
|
||||
|
||||
void *libretro_videoprocessor_retro_get_memory_data(unsigned id);
|
||||
|
||||
size_t libretro_videoprocessor_retro_get_memory_size(unsigned id);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
1
cores/libretro-video-processor/internal_cores.h
Normal file
1
cores/libretro-video-processor/internal_cores.h
Normal file
@ -0,0 +1 @@
|
||||
#include "../internal_cores.h"
|
@ -43,6 +43,13 @@
|
||||
#include <linux/videodev2.h>
|
||||
#include <libv4l2.h>
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#include "internal_cores.h"
|
||||
#define VIDEOPROC_CORE_PREFIX(s) libretro_videoprocessor_##s
|
||||
#else
|
||||
#define VIDEOPROC_CORE_PREFIX(s) s
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ALSA
|
||||
#include <alsa/asoundlib.h>
|
||||
#endif
|
||||
@ -76,22 +83,24 @@ static snd_pcm_t *audio_handle;
|
||||
/*
|
||||
* Libretro API callbacks
|
||||
*/
|
||||
static retro_environment_t environment_cb;
|
||||
static retro_video_refresh_t video_refresh_cb;
|
||||
static retro_audio_sample_t audio_sample_cb;
|
||||
static retro_audio_sample_batch_t audio_sample_batch_cb;
|
||||
static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
static retro_environment_t VIDEOPROC_CORE_PREFIX(environment_cb);
|
||||
static retro_video_refresh_t VIDEOPROC_CORE_PREFIX(video_refresh_cb);
|
||||
static retro_audio_sample_t VIDEOPROC_CORE_PREFIX(audio_sample_cb);
|
||||
static retro_audio_sample_batch_t VIDEOPROC_CORE_PREFIX(audio_sample_batch_cb);
|
||||
static retro_input_poll_t VIDEOPROC_CORE_PREFIX(input_poll_cb);
|
||||
static retro_input_state_t VIDEOPROC_CORE_PREFIX(input_state_cb);
|
||||
|
||||
#ifdef HAVE_ALSA
|
||||
static void
|
||||
audio_callback(void)
|
||||
static void audio_callback(void)
|
||||
{
|
||||
int16_t audio_data[128];
|
||||
int i, frame;
|
||||
|
||||
if (audio_handle) {
|
||||
const int frames = snd_pcm_readi(audio_handle, audio_data, sizeof(audio_data) / 4);
|
||||
if (audio_handle)
|
||||
{
|
||||
const int frames = snd_pcm_readi(audio_handle,
|
||||
audio_data, sizeof(audio_data) / 4);
|
||||
|
||||
for (frame = 0, i = 0; frame < frames; frame++, i += 2)
|
||||
audio_sample_cb(audio_data[i+0], audio_data[i+1]);
|
||||
}
|
||||
@ -106,9 +115,7 @@ audio_set_state(bool enable)
|
||||
static void
|
||||
appendstr(char *dst, const char *src, size_t dstsize)
|
||||
{
|
||||
size_t resid;
|
||||
|
||||
resid = dstsize - (strlen(dst) + 1);
|
||||
size_t resid = dstsize - (strlen(dst) + 1);
|
||||
if (resid == 0)
|
||||
return;
|
||||
strncat(dst, src, resid);
|
||||
@ -123,21 +130,22 @@ enumerate_video_devices(char *buf, size_t buflen)
|
||||
|
||||
#ifdef HAVE_UDEV
|
||||
/* Get a list of devices matching the "video4linux" subsystem from udev */
|
||||
struct udev *udev;
|
||||
int ndevs;
|
||||
struct udev_device *dev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *dev_list_entry;
|
||||
const char *path, *name;
|
||||
int ndevs;
|
||||
struct udev *udev = udev_new();
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
if (!udev)
|
||||
{
|
||||
printf("Cannot create udev context\n");
|
||||
return;
|
||||
}
|
||||
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
if (!enumerate) {
|
||||
if (!enumerate)
|
||||
{
|
||||
printf("Cannot create enumerate context\n");
|
||||
udev_unref(udev);
|
||||
return;
|
||||
@ -147,7 +155,8 @@ enumerate_video_devices(char *buf, size_t buflen)
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
if (!devices) {
|
||||
if (!devices)
|
||||
{
|
||||
printf("Cannot get video device list\n");
|
||||
udev_enumerate_unref(enumerate);
|
||||
udev_unref(udev);
|
||||
@ -155,12 +164,14 @@ enumerate_video_devices(char *buf, size_t buflen)
|
||||
}
|
||||
|
||||
ndevs = 0;
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
udev_list_entry_foreach(dev_list_entry, devices)
|
||||
{
|
||||
path = udev_list_entry_get_name(dev_list_entry);
|
||||
dev = udev_device_new_from_syspath(udev, path);
|
||||
name = udev_device_get_devnode(dev);
|
||||
|
||||
if (strncmp(name, "/dev/video", strlen("/dev/video")) == 0) {
|
||||
if (strncmp(name, "/dev/video", strlen("/dev/video")) == 0)
|
||||
{
|
||||
if (ndevs > 0)
|
||||
appendstr(buf, "|", buflen);
|
||||
appendstr(buf, name, buflen);
|
||||
@ -194,11 +205,14 @@ enumerate_audio_devices(char *buf, size_t buflen)
|
||||
return;
|
||||
|
||||
ndevs = 0;
|
||||
for (n = hints; *n; n++) {
|
||||
for (n = hints; *n; n++)
|
||||
{
|
||||
name = snd_device_name_get_hint(*n, "NAME");
|
||||
ioid = snd_device_name_get_hint(*n, "IOID");
|
||||
if ((ioid == NULL || strcmp(ioid, "Input") == 0) &&
|
||||
(strncmp(name, "hw:", strlen("hw:")) == 0 || strncmp(name, "default:", strlen("default:")) == 0)) {
|
||||
if ((ioid == NULL || !strcmp(ioid, "Input")) &&
|
||||
(!strncmp(name, "hw:", strlen("hw:")) ||
|
||||
!strncmp(name, "default:", strlen("default:"))))
|
||||
{
|
||||
if (ndevs > 0)
|
||||
appendstr(buf, "|", buflen);
|
||||
appendstr(buf, name, buflen);
|
||||
@ -212,19 +226,18 @@ enumerate_audio_devices(char *buf, size_t buflen)
|
||||
#endif
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_environment(retro_environment_t cb)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_environment)(retro_environment_t cb)
|
||||
{
|
||||
char video_devices[ENVVAR_BUFLEN];
|
||||
char audio_devices[ENVVAR_BUFLEN];
|
||||
|
||||
environment_cb = cb;
|
||||
VIDEOPROC_CORE_PREFIX(environment_cb) = cb;
|
||||
|
||||
#ifdef HAVE_ALSA
|
||||
struct retro_audio_callback audio_cb;
|
||||
audio_cb.callback = audio_callback;
|
||||
audio_cb.set_state = audio_set_state;
|
||||
environment_cb(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, &audio_cb);
|
||||
VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK, &audio_cb);
|
||||
#endif
|
||||
|
||||
enumerate_video_devices(video_devices, sizeof(video_devices));
|
||||
@ -236,46 +249,39 @@ retro_set_environment(retro_environment_t cb)
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
environment_cb(RETRO_ENVIRONMENT_SET_VARIABLES, envvars);
|
||||
VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_VARIABLES, envvars);
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_video_refresh(retro_video_refresh_t cb)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_video_refresh)(retro_video_refresh_t cb)
|
||||
{
|
||||
video_refresh_cb = cb;
|
||||
VIDEOPROC_CORE_PREFIX(video_refresh_cb) = cb;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_audio_sample(retro_audio_sample_t cb)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_audio_sample)(retro_audio_sample_t cb)
|
||||
{
|
||||
audio_sample_cb = cb;
|
||||
VIDEOPROC_CORE_PREFIX(audio_sample_cb) = cb;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_audio_sample_batch)(retro_audio_sample_batch_t cb)
|
||||
{
|
||||
audio_sample_batch_cb = cb;
|
||||
VIDEOPROC_CORE_PREFIX(audio_sample_batch_cb) = cb;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_input_poll(retro_input_poll_t cb)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_input_poll)(retro_input_poll_t cb)
|
||||
{
|
||||
input_poll_cb = cb;
|
||||
VIDEOPROC_CORE_PREFIX(input_poll_cb) = cb;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_input_state(retro_input_state_t cb)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_input_state)(retro_input_state_t cb)
|
||||
{
|
||||
input_state_cb = cb;
|
||||
VIDEOPROC_CORE_PREFIX(input_state_cb) = cb;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_init(void)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_init)(void)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
open_devices(void)
|
||||
static bool open_devices(void)
|
||||
{
|
||||
struct retro_variable videodev = { "v4l2_videodev", NULL };
|
||||
struct retro_variable audiodev = { "v4l2_audiodev", NULL };
|
||||
@ -283,25 +289,28 @@ open_devices(void)
|
||||
int error;
|
||||
|
||||
/* Get the video and audio capture device names from the environment */
|
||||
environment_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev);
|
||||
environment_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev);
|
||||
VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &videodev);
|
||||
VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_GET_VARIABLE, &audiodev);
|
||||
|
||||
/* Video device is required */
|
||||
if (videodev.value == NULL) {
|
||||
if (videodev.value == NULL)
|
||||
{
|
||||
printf("v4l2_videodev not defined\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Open the V4L2 device */
|
||||
video_fd = v4l2_open(videodev.value, O_RDWR, 0);
|
||||
if (video_fd == -1) {
|
||||
if (video_fd == -1)
|
||||
{
|
||||
printf("Couldn't open %s: %s\n", videodev.value, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Query V4L2 device capabilities */
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_QUERYCAP, &caps);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_QUERYCAP failed: %s\n", strerror(errno));
|
||||
v4l2_close(video_fd);
|
||||
return false;
|
||||
@ -311,10 +320,12 @@ open_devices(void)
|
||||
printf(" Driver: %s\n", caps.driver);
|
||||
printf(" Card: %s\n", caps.card);
|
||||
printf(" Bus Info: %s\n", caps.bus_info);
|
||||
printf(" Version: %u.%u.%u\n", (caps.version >> 16) & 0xff, (caps.version >> 8) & 0xff, caps.version & 0xff);
|
||||
printf(" Version: %u.%u.%u\n", (caps.version >> 16) & 0xff,
|
||||
(caps.version >> 8) & 0xff, caps.version & 0xff);
|
||||
|
||||
#ifdef HAVE_ALSA
|
||||
if (audiodev.value) {
|
||||
if (audiodev.value)
|
||||
{
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
unsigned int rate;
|
||||
|
||||
@ -322,55 +333,65 @@ open_devices(void)
|
||||
* Open the audio capture device and configure it for 48kHz, 16-bit stereo
|
||||
*/
|
||||
error = snd_pcm_open(&audio_handle, audiodev.value, SND_PCM_STREAM_CAPTURE, 0);
|
||||
if (error < 0) {
|
||||
if (error < 0)
|
||||
{
|
||||
printf("Couldn't open %s: %s\n", audiodev.value, snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
error = snd_pcm_hw_params_malloc(&hw_params);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't allocate hw param structure: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
error = snd_pcm_hw_params_any(audio_handle, hw_params);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't initialize hw param structure: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
error = snd_pcm_hw_params_set_access(audio_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't set hw param access type: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
error = snd_pcm_hw_params_set_format(audio_handle, hw_params, SND_PCM_FORMAT_S16_LE);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't set hw param format to SND_PCM_FORMAT_S16_LE: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
rate = AUDIO_SAMPLE_RATE;
|
||||
error = snd_pcm_hw_params_set_rate_near(audio_handle, hw_params, &rate, 0);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't set hw param sample rate to %u: %s\n", rate, snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
if (rate != AUDIO_SAMPLE_RATE) {
|
||||
if (rate != AUDIO_SAMPLE_RATE)
|
||||
{
|
||||
printf("Hardware doesn't support sample rate %u (returned %u)\n", AUDIO_SAMPLE_RATE, rate);
|
||||
return false;
|
||||
}
|
||||
error = snd_pcm_hw_params_set_channels(audio_handle, hw_params, 2);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't set hw param channels to 2: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
error = snd_pcm_hw_params(audio_handle, hw_params);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't set hw params: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
error = snd_pcm_prepare(audio_handle);
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
printf("Couldn't prepare audio interface for use: %s\n", snd_strerror(error));
|
||||
return false;
|
||||
}
|
||||
@ -382,36 +403,34 @@ open_devices(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
close_devices(void)
|
||||
static void close_devices(void)
|
||||
{
|
||||
#ifdef HAVE_ALSA
|
||||
if (audio_handle) {
|
||||
if (audio_handle)
|
||||
{
|
||||
snd_pcm_close(audio_handle);
|
||||
audio_handle = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (video_fd != -1) {
|
||||
if (video_fd != -1)
|
||||
{
|
||||
v4l2_close(video_fd);
|
||||
video_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_deinit(void)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_deinit)(void)
|
||||
{
|
||||
close_devices();
|
||||
}
|
||||
|
||||
RETRO_API unsigned
|
||||
retro_api_version(void)
|
||||
RETRO_API unsigned VIDEOPROC_CORE_PREFIX(retro_api_version)(void)
|
||||
{
|
||||
return RETRO_API_VERSION;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_get_system_info(struct retro_system_info *info)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_info)(struct retro_system_info *info)
|
||||
{
|
||||
info->library_name = LIBRARY_NAME;
|
||||
info->library_version = LIBRARY_VERSION;
|
||||
@ -420,8 +439,7 @@ retro_get_system_info(struct retro_system_info *info)
|
||||
info->block_extract = true;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_get_system_av_info)(struct retro_system_av_info *info)
|
||||
{
|
||||
struct v4l2_cropcap cc;
|
||||
int error;
|
||||
@ -432,39 +450,38 @@ retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
memset(&cc, 0, sizeof(cc));
|
||||
cc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_CROPCAP, &cc);
|
||||
if (error == 0) {
|
||||
info->geometry.aspect_ratio = (double)cc.pixelaspect.denominator / (double)cc.pixelaspect.numerator;
|
||||
}
|
||||
if (error == 0)
|
||||
info->geometry.aspect_ratio = (double)cc.pixelaspect.denominator
|
||||
/ (double)cc.pixelaspect.numerator;
|
||||
|
||||
info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width;
|
||||
info->geometry.base_width = info->geometry.max_width = video_format.fmt.pix.width;
|
||||
info->geometry.base_height = info->geometry.max_height = video_format.fmt.pix.height;
|
||||
info->timing.fps = (double)video_standard.frameperiod.denominator / (double)video_standard.frameperiod.numerator;
|
||||
info->timing.sample_rate = AUDIO_SAMPLE_RATE;
|
||||
info->timing.fps = (double)video_standard.frameperiod.denominator /
|
||||
(double)video_standard.frameperiod.numerator;
|
||||
info->timing.sample_rate = AUDIO_SAMPLE_RATE;
|
||||
|
||||
printf("Resolution %ux%u %f fps\n", info->geometry.base_width, info->geometry.base_height, info->timing.fps);
|
||||
printf("Resolution %ux%u %f fps\n", info->geometry.base_width,
|
||||
info->geometry.base_height, info->timing.fps);
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_set_controller_port_device(unsigned port, unsigned device)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_set_controller_port_device)(unsigned port, unsigned device)
|
||||
{
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_reset(void)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_reset)(void)
|
||||
{
|
||||
close_devices();
|
||||
open_devices();
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_run(void)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_run)(void)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
uint8_t *src;
|
||||
uint16_t *dst;
|
||||
int i, error;
|
||||
|
||||
input_poll_cb();
|
||||
VIDEOPROC_CORE_PREFIX(input_poll_cb)();
|
||||
|
||||
if (video_fd == -1)
|
||||
return;
|
||||
@ -474,9 +491,10 @@ retro_run(void)
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_DQBUF, &buf);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_DQBUF failed: %s\n", strerror(errno));
|
||||
video_refresh_cb(NULL, 0, 0, 0);
|
||||
VIDEOPROC_CORE_PREFIX(video_refresh_cb)(NULL, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -484,47 +502,41 @@ retro_run(void)
|
||||
dst = conv_data;
|
||||
|
||||
/* RGB24 to RGB565 */
|
||||
for (i = 0; i < video_format.fmt.pix.width * video_format.fmt.pix.height; i++, src += 3, dst += 1) {
|
||||
for (i = 0; i < video_format.fmt.pix.width * video_format.fmt.pix.height; i++, src += 3, dst += 1)
|
||||
*dst = ((src[0] >> 3) << 11) | ((src[1] >> 2) << 5) | ((src[2] >> 3) << 0);
|
||||
}
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_QBUF, &buf);
|
||||
if (error != 0)
|
||||
printf("VIDIOC_QBUF failed: %s\n", strerror(errno));
|
||||
|
||||
video_refresh_cb(conv_data, video_format.fmt.pix.width, video_format.fmt.pix.height, video_format.fmt.pix.width * 2);
|
||||
VIDEOPROC_CORE_PREFIX(video_refresh_cb)(conv_data, video_format.fmt.pix.width,
|
||||
video_format.fmt.pix.height, video_format.fmt.pix.width * 2);
|
||||
}
|
||||
|
||||
RETRO_API size_t
|
||||
retro_serialize_size(void)
|
||||
RETRO_API size_t VIDEOPROC_CORE_PREFIX(retro_serialize_size)(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RETRO_API bool
|
||||
retro_serialize(void *data, size_t size)
|
||||
RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_serialize)(void *data, size_t size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RETRO_API bool
|
||||
retro_unserialize(const void *data, size_t size)
|
||||
RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_unserialize)(const void *data, size_t size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_cheat_reset(void)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_reset)(void)
|
||||
{
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_cheat_set(unsigned index, bool enabled, const char *code)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_cheat_set)(unsigned index, bool enabled, const char *code)
|
||||
{
|
||||
}
|
||||
|
||||
RETRO_API bool
|
||||
retro_load_game(const struct retro_game_info *game)
|
||||
RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game)(const struct retro_game_info *game)
|
||||
{
|
||||
enum retro_pixel_format pixel_format;
|
||||
struct v4l2_standard std;
|
||||
@ -537,7 +549,8 @@ retro_load_game(const struct retro_game_info *game)
|
||||
bool std_found;
|
||||
int error;
|
||||
|
||||
if (open_devices() == false) {
|
||||
if (open_devices() == false)
|
||||
{
|
||||
printf("Couldn't open capture device\n");
|
||||
close_devices();
|
||||
return false;
|
||||
@ -547,35 +560,43 @@ retro_load_game(const struct retro_game_info *game)
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_G_FMT, &fmt);
|
||||
if (error != 0) {
|
||||
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_G_FMT failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_S_FMT, &fmt);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_S_FMT failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_G_STD, &std_id);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_G_STD failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
for (index = 0, std_found = false; ; index++) {
|
||||
for (index = 0, std_found = false; ; index++)
|
||||
{
|
||||
memset(&std, 0, sizeof(std));
|
||||
std.index = index;
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_ENUMSTD, &std);
|
||||
if (error)
|
||||
break;
|
||||
if (std.id == std_id) {
|
||||
if (std.id == std_id)
|
||||
{
|
||||
video_standard = std;
|
||||
std_found = true;
|
||||
}
|
||||
printf("VIDIOC_ENUMSTD[%u]: %s%s\n", index, std.name, std.id == std_id ? " [*]" : "");
|
||||
}
|
||||
if (!std_found) {
|
||||
if (!std_found)
|
||||
{
|
||||
printf("VIDIOC_ENUMSTD did not contain std ID %08x\n", (unsigned)std_id);
|
||||
return false;
|
||||
}
|
||||
@ -588,61 +609,72 @@ retro_load_game(const struct retro_game_info *game)
|
||||
reqbufs.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_REQBUFS, &reqbufs);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_REQBUFS failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
video_nbuffers = reqbufs.count;
|
||||
|
||||
for (index = 0; index < video_nbuffers; index++) {
|
||||
for (index = 0; index < video_nbuffers; index++)
|
||||
{
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.index = index;
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_QUERYBUF, &buf);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_QUERYBUF failed for %u: %s\n", index, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
video_buffer[index].len = buf.length;
|
||||
video_buffer[index].start = v4l2_mmap(NULL, buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, buf.m.offset);
|
||||
if (video_buffer[index].start == MAP_FAILED) {
|
||||
video_buffer[index].start = v4l2_mmap(NULL, buf.length,
|
||||
PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, buf.m.offset);
|
||||
if (video_buffer[index].start == MAP_FAILED)
|
||||
{
|
||||
printf("v4l2_mmap failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0; index < video_nbuffers; index++) {
|
||||
for (index = 0; index < video_nbuffers; index++)
|
||||
{
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.index = index;
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_QBUF, &buf);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_QBUF failed for %u: %s\n", index, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
conv_data = calloc(1, video_format.fmt.pix.width * video_format.fmt.pix.height * 2);
|
||||
if (conv_data == NULL) {
|
||||
if (conv_data == NULL)
|
||||
{
|
||||
printf("Cannot allocate conversion buffer\n");
|
||||
return false;
|
||||
}
|
||||
printf("Allocated %u byte conversion buffer\n", video_format.fmt.pix.width * video_format.fmt.pix.height * 2);
|
||||
printf("Allocated %u byte conversion buffer\n",
|
||||
video_format.fmt.pix.width * video_format.fmt.pix.height * 2);
|
||||
|
||||
pixel_format = RETRO_PIXEL_FORMAT_RGB565;
|
||||
if (!environment_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pixel_format)) {
|
||||
if (!VIDEOPROC_CORE_PREFIX(environment_cb)(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pixel_format))
|
||||
{
|
||||
printf("Cannot set pixel format\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_STREAMON, &type);
|
||||
if (error != 0) {
|
||||
if (error != 0)
|
||||
{
|
||||
printf("VIDIOC_STREAMON failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
@ -650,14 +682,14 @@ retro_load_game(const struct retro_game_info *game)
|
||||
return true;
|
||||
}
|
||||
|
||||
RETRO_API void
|
||||
retro_unload_game(void)
|
||||
RETRO_API void VIDEOPROC_CORE_PREFIX(retro_unload_game)(void)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
uint32_t index;
|
||||
int error;
|
||||
|
||||
if (video_fd != -1) {
|
||||
if (video_fd != -1)
|
||||
{
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
error = v4l2_ioctl(video_fd, VIDIOC_STREAMOFF, &type);
|
||||
if (error != 0)
|
||||
@ -673,26 +705,23 @@ retro_unload_game(void)
|
||||
close_devices();
|
||||
}
|
||||
|
||||
RETRO_API bool
|
||||
retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
|
||||
RETRO_API bool VIDEOPROC_CORE_PREFIX(retro_load_game_special)(unsigned game_type,
|
||||
const struct retro_game_info *info, size_t num_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RETRO_API unsigned
|
||||
retro_get_region(void)
|
||||
RETRO_API unsigned VIDEOPROC_CORE_PREFIX(retro_get_region)(void)
|
||||
{
|
||||
return (video_standard.id & V4L2_STD_NTSC) != 0 ? RETRO_REGION_NTSC : RETRO_REGION_PAL;
|
||||
}
|
||||
|
||||
RETRO_API void *
|
||||
retro_get_memory_data(unsigned id)
|
||||
RETRO_API void *VIDEOPROC_CORE_PREFIX(retro_get_memory_data)(unsigned id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RETRO_API size_t
|
||||
retro_get_memory_size(unsigned id)
|
||||
RETRO_API size_t VIDEOPROC_CORE_PREFIX(retro_get_memory_size)(unsigned id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
41
dynamic.c
41
dynamic.c
@ -81,6 +81,10 @@ static dylib_t lib_handle;
|
||||
#define SYMBOL_NETRETROPAD(x) current_core->x = libretro_netretropad_##x
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_V4L2)
|
||||
#define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x
|
||||
#endif
|
||||
|
||||
static bool ignore_environment_cb;
|
||||
|
||||
const struct retro_subsystem_info *libretro_find_subsystem_info(
|
||||
@ -543,6 +547,43 @@ static void load_symbols(enum rarch_core_type type, struct retro_core_t *current
|
||||
SYMBOL_NETRETROPAD(retro_get_region);
|
||||
SYMBOL_NETRETROPAD(retro_get_memory_data);
|
||||
SYMBOL_NETRETROPAD(retro_get_memory_size);
|
||||
#endif
|
||||
break;
|
||||
case CORE_TYPE_VIDEOPROCESSOR:
|
||||
#if defined(HAVE_NETWORKGAMEPAD) && defined(HAVE_NETPLAY)
|
||||
SYMBOL_VIDEOPROCESSOR(retro_init);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_deinit);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_api_version);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_get_system_info);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_get_system_av_info);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_environment);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_video_refresh);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_audio_sample);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_audio_sample_batch);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_input_poll);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_input_state);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_set_controller_port_device);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_reset);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_run);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_serialize_size);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_serialize);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_unserialize);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_cheat_reset);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_cheat_set);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_load_game);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_load_game_special);
|
||||
|
||||
SYMBOL_VIDEOPROCESSOR(retro_unload_game);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_get_region);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_get_memory_data);
|
||||
SYMBOL_VIDEOPROCESSOR(retro_get_memory_size);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user