mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2026-10-28 09:43:51 +00:00
Various optimizations and refactoring (#259)
* optimizations * Update menu_game.h * try new code * use cached EGLImages * try drm cache on pi * nani? * huh? * require opengl egl * find EGL * find EGL separately * logging * add support for versions of ffmpeg less than 6.0 * disable drm cache for now * Update ui_sdl.c * use old code for now * disable avcc hdr for now * restore error message * try disabling format modifiers? * tell me what the layer is * pi decoder actually produces frames in yuv420p * print more debug info * try this * switch to faster decode path * switch to old code * Update ui_sdl.c * add more timing profiling * more printing * enable some optimizations * draw menus when not in game mode * call render present * Update ui_sdl.c * Update ui_sdl.c * remove unused code * Update CMakeLists.txt * incorporate direct DRM code * Update CMakeLists.txt * free drm context and test old decoding code * move SDL event loop to separate thread so controls are not limited by display rate * add a wait to reduce CPU thrashing * fix double free * separate video into recv and consume threads * Update ui_sdl_drm.c * Update ui_sdl_drm.c * Update gamepad.c * further optimizations * anti-alias buttons more * fix some compiler errors * only include DRM on linux * fix windows compile issues * fix includes * Update CMakeLists.txt * add htobe32 define for macOS * Update video.c * Update gamepad.c
This commit is contained in:
1 parent
6a82715263
commit
b0bbc31002
29 files changed
+2123
-2255
No files matched your search
+131
-112
@@ -2,16 +2,6 @@
|
||||
|
||||
#include "gamepad.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
typedef uint32_t in_addr_t;
|
||||
typedef uint16_t in_port_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
@@ -31,18 +21,13 @@ typedef uint16_t in_port_t;
|
||||
static uint32_t SERVER_ADDRESS = 0;
|
||||
static const int MAX_PIPE_RETRY = 5;
|
||||
|
||||
char wireless_interface[128];
|
||||
|
||||
#define EVENT_BUFFER_SIZE 65536
|
||||
#define EVENT_BUFFER_ARENA_SIZE VANILLA_MAX_EVENT_COUNT * 2
|
||||
uint8_t *EVENT_BUFFER_ARENA[EVENT_BUFFER_ARENA_SIZE] = {0};
|
||||
pthread_mutex_t event_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
typedef union {
|
||||
struct sockaddr_in in;
|
||||
#ifndef _WIN32
|
||||
struct sockaddr_un un;
|
||||
#endif
|
||||
} sockaddr_u;
|
||||
|
||||
static inline int skterr()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -52,24 +37,10 @@ static inline int skterr()
|
||||
#endif
|
||||
}
|
||||
|
||||
in_addr_t get_real_server_address()
|
||||
{
|
||||
if (SERVER_ADDRESS == VANILLA_ADDRESS_DIRECT) {
|
||||
// The Wii U always places itself at this address
|
||||
return inet_addr("192.168.1.10");
|
||||
} else if (SERVER_ADDRESS != VANILLA_ADDRESS_LOCAL) {
|
||||
// If there's a remote pipe, we send to that
|
||||
return SERVER_ADDRESS;
|
||||
}
|
||||
|
||||
// Must be local, in which case we don't care
|
||||
return INADDR_ANY;
|
||||
}
|
||||
|
||||
void create_sockaddr(sockaddr_u *addr, size_t *size, in_addr_t inaddr, uint16_t port, int delete)
|
||||
void create_sockaddr(sockaddr_u *addr, size_t *size, in_addr_t inaddr, uint16_t port, int local, int delete)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
if (SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL) {
|
||||
if (local) {
|
||||
memset(&addr->un, 0, sizeof(addr->un));
|
||||
addr->un.sun_family = AF_UNIX;
|
||||
snprintf(addr->un.sun_path, sizeof(addr->un.sun_path) - 1, VANILLA_PIPE_LOCAL_SOCKET, port);
|
||||
@@ -90,6 +61,24 @@ void create_sockaddr(sockaddr_u *addr, size_t *size, in_addr_t inaddr, uint16_t
|
||||
#endif
|
||||
}
|
||||
|
||||
void create_server_sockaddr(sockaddr_u *addr, size_t *size, uint16_t port, int delete)
|
||||
{
|
||||
// The Wii U always places itself at this address
|
||||
in_addr_t ip = (SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL) ? inet_addr("192.168.1.10") : SERVER_ADDRESS;
|
||||
return create_sockaddr(addr, size, ip, port, 0, delete);
|
||||
}
|
||||
|
||||
void send_to_sockaddr(int fd, const void *data, size_t data_size, const sockaddr_u *sockaddr, size_t sockaddr_size)
|
||||
{
|
||||
ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) sockaddr, sockaddr_size);
|
||||
if (sent == -1) {
|
||||
int err = skterr();
|
||||
if (err != 111) { // 111 is connection refused, occurs if we lose connection, but we'll already know that for other reasons so we don't need to spam the console with this error
|
||||
vanilla_log("Failed to send to Wii U socket: fd: %d, errno: %i", fd, skterr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void send_to_console(int fd, const void *data, size_t data_size, uint16_t port)
|
||||
{
|
||||
sockaddr_u addr;
|
||||
@@ -97,15 +86,9 @@ void send_to_console(int fd, const void *data, size_t data_size, uint16_t port)
|
||||
|
||||
in_port_t console_port = port - 100;
|
||||
|
||||
create_sockaddr(&addr, &addr_size, get_real_server_address(), console_port, 0);
|
||||
create_server_sockaddr(&addr, &addr_size, console_port, 0);
|
||||
|
||||
ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) &addr, addr_size);
|
||||
if (sent == -1) {
|
||||
int err = skterr();
|
||||
if (err != 111) { // 111 is connection refused, occurs if we lose connection, but we'll already know that for other reasons so we don't need to spam the console with this error
|
||||
vanilla_log("Failed to send to Wii U socket: fd: %d, port: %d, errno: %i", fd, console_port, skterr());
|
||||
}
|
||||
}
|
||||
send_to_sockaddr(fd, data, data_size, &addr, addr_size);
|
||||
}
|
||||
|
||||
void set_socket_rcvtimeo(int skt, uint64_t microseconds)
|
||||
@@ -121,14 +104,15 @@ void set_socket_rcvtimeo(int skt, uint64_t microseconds)
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
int create_socket(int *socket_out, in_port_t port)
|
||||
int create_socket(int *socket_out, in_port_t port, int pipe)
|
||||
{
|
||||
sockaddr_u addr;
|
||||
size_t addr_size;
|
||||
|
||||
create_sockaddr(&addr, &addr_size, INADDR_ANY, port, 1);
|
||||
int is_pipe_and_local = (pipe && SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL);
|
||||
int domain = is_pipe_and_local ? AF_UNIX : AF_INET;
|
||||
|
||||
int domain = (SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL) ? AF_UNIX : AF_INET;
|
||||
create_sockaddr(&addr, &addr_size, INADDR_ANY, port, is_pipe_and_local, 1);
|
||||
|
||||
int skt = socket(domain, SOCK_DGRAM, 0);
|
||||
if (skt == -1) {
|
||||
@@ -148,6 +132,22 @@ int create_socket(int *socket_out, in_port_t port)
|
||||
|
||||
set_socket_rcvtimeo(skt, 250000);
|
||||
|
||||
// int buf_sz = 16777216;
|
||||
// setsockopt(skt, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz));
|
||||
// setsockopt(skt, SOL_SOCKET, SO_SNDBUF, &buf_sz, sizeof(buf_sz));
|
||||
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
if (!pipe && SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL) {
|
||||
// Bind to wireless device
|
||||
setsockopt(skt, SOL_SOCKET, SO_BINDTODEVICE, wireless_interface, strlen(wireless_interface));
|
||||
}
|
||||
#endif
|
||||
|
||||
// int val = 1000; // microseconds to busy-poll per recv() before sleeping
|
||||
// if (setsockopt(skt, SOL_SOCKET, SO_BUSY_POLL, &val, sizeof(val)) < 0) {
|
||||
// perror("setsockopt SO_BUSY_POLL");
|
||||
// }
|
||||
|
||||
return VANILLA_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,10 @@ int send_pipe_cc(int skt, vanilla_pipe_command_t *cmd, size_t cmd_size, int wait
|
||||
sockaddr_u addr;
|
||||
size_t addr_size;
|
||||
|
||||
create_sockaddr(&addr, &addr_size, get_real_server_address(), VANILLA_PIPE_CMD_SERVER_PORT, 0);
|
||||
int pipe_is_local = (SERVER_ADDRESS == VANILLA_ADDRESS_LOCAL);
|
||||
in_addr_t pipe_addr = pipe_is_local ? INADDR_ANY : SERVER_ADDRESS;
|
||||
|
||||
create_sockaddr(&addr, &addr_size, pipe_addr, VANILLA_PIPE_CMD_SERVER_PORT, pipe_is_local, 0);
|
||||
|
||||
ssize_t read_size;
|
||||
uint8_t recv_cc;
|
||||
@@ -195,7 +198,7 @@ int connect_to_backend(int *socket, vanilla_pipe_command_t *cmd, size_t cmd_size
|
||||
{
|
||||
// Try to bind with backend
|
||||
int pipe_cc_skt = -1;
|
||||
int ret = create_socket(&pipe_cc_skt, VANILLA_PIPE_CMD_CLIENT_PORT);
|
||||
int ret = create_socket(&pipe_cc_skt, VANILLA_PIPE_CMD_CLIENT_PORT, 1);
|
||||
if (ret != VANILLA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
@@ -288,16 +291,14 @@ int install_polkit_internal(thread_data_t *data, int install)
|
||||
int ret = VANILLA_ERR_GENERIC;
|
||||
|
||||
int pipe_cc_skt = -1;
|
||||
if (SERVER_ADDRESS != VANILLA_ADDRESS_DIRECT) {
|
||||
vanilla_pipe_command_t cmd;
|
||||
cmd.control_code = install ? VANILLA_PIPE_CC_INSTALL_POLKIT : VANILLA_PIPE_CC_UNINSTALL_POLKIT;
|
||||
vanilla_pipe_command_t cmd;
|
||||
cmd.control_code = install ? VANILLA_PIPE_CC_INSTALL_POLKIT : VANILLA_PIPE_CC_UNINSTALL_POLKIT;
|
||||
|
||||
// Connect to backend pipe
|
||||
ret = connect_to_backend(&pipe_cc_skt, &cmd, sizeof(cmd.control_code) + sizeof(cmd.connection));
|
||||
// Connect to backend pipe
|
||||
ret = connect_to_backend(&pipe_cc_skt, &cmd, sizeof(cmd.control_code) + sizeof(cmd.connection));
|
||||
|
||||
// No interrupt is required here because VANILLA_PIPE_CC_INSTALL_POLKIT
|
||||
// does not start a thread in the pipe
|
||||
}
|
||||
// No interrupt is required here because VANILLA_PIPE_CC_INSTALL_POLKIT
|
||||
// does not start a thread in the pipe
|
||||
|
||||
if (pipe_cc_skt != -1) {
|
||||
// Disconnect from pipe if necessary
|
||||
@@ -320,47 +321,45 @@ void connect_as_gamepad_internal(thread_data_t *data)
|
||||
int ret = VANILLA_SUCCESS;
|
||||
|
||||
// Open all required sockets
|
||||
if (create_socket(&info.socket_vid, PORT_VID) != VANILLA_SUCCESS) goto exit_pipe;
|
||||
if (create_socket(&info.socket_msg, PORT_MSG) != VANILLA_SUCCESS) goto exit_vid;
|
||||
if (create_socket(&info.socket_hid, PORT_HID) != VANILLA_SUCCESS) goto exit_msg;
|
||||
if (create_socket(&info.socket_aud, PORT_AUD) != VANILLA_SUCCESS) goto exit_hid;
|
||||
if (create_socket(&info.socket_cmd, PORT_CMD) != VANILLA_SUCCESS) goto exit_aud;
|
||||
if (create_socket(&info.socket_vid, PORT_VID, 0) != VANILLA_SUCCESS) goto exit_pipe;
|
||||
if (create_socket(&info.socket_msg, PORT_MSG, 0) != VANILLA_SUCCESS) goto exit_vid;
|
||||
if (create_socket(&info.socket_hid, PORT_HID, 0) != VANILLA_SUCCESS) goto exit_msg;
|
||||
if (create_socket(&info.socket_aud, PORT_AUD, 0) != VANILLA_SUCCESS) goto exit_hid;
|
||||
if (create_socket(&info.socket_cmd, PORT_CMD, 0) != VANILLA_SUCCESS) goto exit_aud;
|
||||
|
||||
int pipe_cc_skt = -1;
|
||||
if (SERVER_ADDRESS != VANILLA_ADDRESS_DIRECT) {
|
||||
vanilla_pipe_command_t cmd;
|
||||
cmd.control_code = VANILLA_PIPE_CC_CONNECT;
|
||||
vanilla_pipe_command_t cmd;
|
||||
cmd.control_code = VANILLA_PIPE_CC_CONNECT;
|
||||
|
||||
cmd.connection.bssid = data->bssid;
|
||||
cmd.connection.psk = data->psk;
|
||||
cmd.connection.bssid = data->bssid;
|
||||
cmd.connection.psk = data->psk;
|
||||
|
||||
// Connect to backend pipe
|
||||
ret = connect_to_backend(&pipe_cc_skt, &cmd, sizeof(cmd.control_code) + sizeof(cmd.connection));
|
||||
if (ret == VANILLA_SUCCESS) {
|
||||
// Wait for backend to be available
|
||||
vanilla_pipe_command_t connected_state;
|
||||
ret = VANILLA_ERR_NO_CONNECTION;
|
||||
while (!is_interrupted()) {
|
||||
ssize_t read_size = recv(pipe_cc_skt, (char *) &connected_state, sizeof(connected_state), 0);
|
||||
if (read_size < 0) {
|
||||
int r = skterr();
|
||||
// Connect to backend pipe
|
||||
ret = connect_to_backend(&pipe_cc_skt, &cmd, sizeof(cmd.control_code) + sizeof(cmd.connection));
|
||||
if (ret == VANILLA_SUCCESS) {
|
||||
// Wait for backend to be available
|
||||
vanilla_pipe_command_t connected_state;
|
||||
ret = VANILLA_ERR_NO_CONNECTION;
|
||||
while (!is_interrupted()) {
|
||||
ssize_t read_size = recv(pipe_cc_skt, (char *) &connected_state, sizeof(connected_state), 0);
|
||||
if (read_size < 0) {
|
||||
int r = skterr();
|
||||
#ifdef _WIN32
|
||||
if (r != WSAETIMEDOUT) {
|
||||
if (r != WSAETIMEDOUT) {
|
||||
#else
|
||||
if (r != EAGAIN) {
|
||||
if (r != EAGAIN) {
|
||||
#endif
|
||||
vanilla_log("FAILED TO GET CONNECTED STATE: %i", r);
|
||||
ret = VANILLA_ERR_PIPE_UNRESPONSIVE;
|
||||
break;
|
||||
}
|
||||
} else if (connected_state.control_code == VANILLA_PIPE_CC_CONNECTED) {
|
||||
ret = VANILLA_SUCCESS;
|
||||
sleep(1);
|
||||
vanilla_log("FAILED TO GET CONNECTED STATE: %i", r);
|
||||
ret = VANILLA_ERR_PIPE_UNRESPONSIVE;
|
||||
break;
|
||||
}
|
||||
|
||||
vanilla_log("STILL WAITING FOR CONNECTED STATE");
|
||||
} else if (connected_state.control_code == VANILLA_PIPE_CC_CONNECTED) {
|
||||
ret = VANILLA_SUCCESS;
|
||||
sleep(1);
|
||||
break;
|
||||
}
|
||||
|
||||
vanilla_log("STILL WAITING FOR CONNECTED STATE");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,47 +438,67 @@ exit:
|
||||
wait_for_interrupt();
|
||||
}
|
||||
|
||||
int push_event(event_loop_t *loop, int type, const void *data, size_t size)
|
||||
int acquire_event(event_loop_t *loop, vanilla_event_t **event)
|
||||
{
|
||||
int ret = VANILLA_SUCCESS;
|
||||
int ret = VANILLA_SUCCESS;
|
||||
|
||||
pthread_mutex_lock(&loop->mutex);
|
||||
|
||||
if (size <= EVENT_BUFFER_SIZE) {
|
||||
// Prevent rollover by skipping oldest event if necessary
|
||||
if (loop->new_index == loop->used_index + VANILLA_MAX_EVENT_COUNT) {
|
||||
vanilla_free_event(&loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT]);
|
||||
vanilla_log("SKIPPED EVENT TO PREVENT ROLLOVER (%lu > %lu + %lu)", loop->new_index, loop->used_index, VANILLA_MAX_EVENT_COUNT);
|
||||
loop->used_index++;
|
||||
}
|
||||
// Prevent rollover by skipping oldest event if necessary
|
||||
if (loop->new_index == loop->used_index + VANILLA_MAX_EVENT_COUNT) {
|
||||
vanilla_free_event(&loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT]);
|
||||
vanilla_log("SKIPPED EVENT TO PREVENT ROLLOVER (%lu > %lu + %lu)", loop->new_index, loop->used_index, VANILLA_MAX_EVENT_COUNT);
|
||||
loop->used_index++;
|
||||
}
|
||||
|
||||
vanilla_event_t *ev = &loop->events[loop->new_index % VANILLA_MAX_EVENT_COUNT];
|
||||
vanilla_event_t *ev = &loop->events[loop->new_index % VANILLA_MAX_EVENT_COUNT];
|
||||
|
||||
assert(!ev->data);
|
||||
assert(!ev->data);
|
||||
|
||||
ev->data = get_event_buffer();
|
||||
if (!ev->data) {
|
||||
vanilla_log("OUT OF MEMORY FOR NEW EVENTS");
|
||||
ret = VANILLA_ERR_OUT_OF_MEMORY;
|
||||
goto exit;
|
||||
}
|
||||
ev->data = get_event_buffer();
|
||||
// if (!ev->data) {
|
||||
// vanilla_log("OUT OF MEMORY FOR NEW EVENTS");
|
||||
// ret = VANILLA_ERR_OUT_OF_MEMORY;
|
||||
// }
|
||||
|
||||
ev->type = type;
|
||||
memcpy(ev->data, data, size);
|
||||
ev->size = size;
|
||||
*event = ev;
|
||||
|
||||
loop->new_index++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pthread_cond_broadcast(&loop->waitcond);
|
||||
} else {
|
||||
vanilla_log("FAILED TO PUSH EVENT: wanted %lu, only had %lu. This is a bug, please report to developers.", size, EVENT_BUFFER_SIZE);
|
||||
ret = VANILLA_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
int release_event(event_loop_t *loop)
|
||||
{
|
||||
loop->new_index++;
|
||||
|
||||
pthread_cond_broadcast(&loop->waitcond);
|
||||
|
||||
// } else {
|
||||
// vanilla_log("FAILED TO PUSH EVENT: wanted %lu, only had %lu. This is a bug, please report to developers.", size, EVENT_BUFFER_SIZE);
|
||||
// ret = VANILLA_ERR_INVALID_ARGUMENT;
|
||||
// }
|
||||
|
||||
exit:
|
||||
pthread_mutex_unlock(&loop->mutex);
|
||||
|
||||
return ret;
|
||||
return VANILLA_SUCCESS;
|
||||
}
|
||||
|
||||
int push_event(event_loop_t *loop, int type, const void *data, size_t size)
|
||||
{
|
||||
vanilla_event_t *ev;
|
||||
|
||||
int ret = acquire_event(loop, &ev);
|
||||
if (ret != VANILLA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ev->type = type;
|
||||
memcpy(ev->data, data, size);
|
||||
ev->size = size;
|
||||
|
||||
ret = release_event(loop);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_event(event_loop_t *loop, vanilla_event_t *event, int wait)
|
||||
|
||||
+26
-3
@@ -1,16 +1,28 @@
|
||||
#ifndef VANILLA_GAMEPAD_H
|
||||
#define VANILLA_GAMEPAD_H
|
||||
|
||||
#include "vanilla.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
typedef uint32_t in_addr_t;
|
||||
typedef uint16_t in_port_t;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#include "vanilla.h"
|
||||
|
||||
#include "../pipe/ports.h"
|
||||
|
||||
struct wpa_ctrl;
|
||||
|
||||
#define VANILLA_MAX_EVENT_COUNT 20
|
||||
extern char wireless_interface[];
|
||||
|
||||
#define VANILLA_MAX_EVENT_COUNT 100
|
||||
typedef struct
|
||||
{
|
||||
vanilla_event_t events[VANILLA_MAX_EVENT_COUNT];
|
||||
@@ -43,12 +55,23 @@ typedef struct thread_data_t
|
||||
vanilla_psk_t psk;
|
||||
} thread_data_t;
|
||||
|
||||
typedef union {
|
||||
struct sockaddr_in in;
|
||||
#ifndef _WIN32
|
||||
struct sockaddr_un un;
|
||||
#endif
|
||||
} sockaddr_u;
|
||||
|
||||
void sync_internal(thread_data_t *data);
|
||||
void connect_as_gamepad_internal(thread_data_t *data);
|
||||
int install_polkit_internal(thread_data_t *data, int install);
|
||||
void create_server_sockaddr(sockaddr_u *addr, size_t *size, uint16_t port, int delete);
|
||||
void send_to_sockaddr(int fd, const void *data, size_t data_size, const sockaddr_u *sockaddr, size_t sockaddr_size);
|
||||
void send_to_console(int fd, const void *data, size_t data_size, uint16_t port);
|
||||
int push_event(event_loop_t *loop, int type, const void *data, size_t size);
|
||||
int get_event(event_loop_t *loop, vanilla_event_t *event, int wait);
|
||||
int acquire_event(event_loop_t *loop, vanilla_event_t **event);
|
||||
int release_event(event_loop_t *loop);
|
||||
|
||||
void init_event_buffer_arena();
|
||||
void free_event_buffer_arena();
|
||||
|
||||
+12
-8
@@ -112,7 +112,7 @@ uint16_t resolve_axis_value(float axis, float neg, float pos, int flip)
|
||||
if (flip) {
|
||||
val = -val;
|
||||
}
|
||||
|
||||
|
||||
return ((int) (val * 1024)) + 2048;
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ void set_battery_status(int status)
|
||||
pthread_mutex_unlock(&button_mtx);
|
||||
}
|
||||
|
||||
void send_input(int socket_hid)
|
||||
void send_input(int socket_hid, const sockaddr_u *addr, size_t addr_size)
|
||||
{
|
||||
InputPacket ip;
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
@@ -213,7 +213,7 @@ void send_input(int socket_hid)
|
||||
ip.buttons = htons(button_mask);
|
||||
|
||||
button_mask = 0;
|
||||
|
||||
|
||||
if (current_buttons[VANILLA_BTN_L3]) button_mask |= 0x80;
|
||||
if (current_buttons[VANILLA_BTN_R3]) button_mask |= 0x40;
|
||||
if (current_buttons[VANILLA_BTN_TV]) button_mask |= 0x20;
|
||||
@@ -242,7 +242,7 @@ void send_input(int socket_hid)
|
||||
|
||||
ip.fw_version_neg = 215;
|
||||
|
||||
send_to_console(socket_hid, &ip, sizeof(ip), PORT_HID);
|
||||
send_to_sockaddr(socket_hid, &ip, sizeof(ip), addr, addr_size);
|
||||
}
|
||||
|
||||
void *listen_input(void *x)
|
||||
@@ -251,14 +251,18 @@ void *listen_input(void *x)
|
||||
|
||||
pthread_mutex_init(&button_mtx, NULL);
|
||||
|
||||
sockaddr_u addr;
|
||||
size_t addr_size;
|
||||
create_server_sockaddr(&addr, &addr_size, PORT_HID - 100, 0);
|
||||
|
||||
do {
|
||||
send_input(info->socket_hid);
|
||||
usleep(5 * 1000); // Produces 200Hz input, probably no need to go higher for the Wii U (supposedly the real gamepad is 180Hz)
|
||||
send_input(info->socket_hid, &addr, addr_size);
|
||||
usleep(5555); // Roughly 180Hz, same as the original gamepad
|
||||
} while (!is_interrupted());
|
||||
|
||||
pthread_mutex_destroy(&button_mtx);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
+322
-115
@@ -20,6 +20,12 @@
|
||||
#include "vanilla.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
// macOS has no htobe32
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#define htobe32(x) OSSwapHostToBigInt32(x)
|
||||
#endif // __APPLE__
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned magic : 4;
|
||||
@@ -36,15 +42,15 @@ typedef struct
|
||||
uint8_t payload[2048];
|
||||
} VideoPacket;
|
||||
|
||||
static pthread_mutex_t video_mutex;
|
||||
static pthread_mutex_t idr_mutex;
|
||||
static int idr_is_queued = 0;
|
||||
|
||||
#define VIDEO_PACKET_CACHE_MAX 1024
|
||||
static VideoPacket video_packet_cache[VIDEO_PACKET_CACHE_MAX];
|
||||
static size_t video_packet_cache_index = 0;
|
||||
static uint8_t video_packet[100000];
|
||||
|
||||
static size_t generated_sps_params_size = 0;
|
||||
#define VIDEO_PACKET_QUEUE_MAX 1024
|
||||
static VideoPacket video_packet_queue[VIDEO_PACKET_QUEUE_MAX];
|
||||
static size_t video_packet_min = 0;
|
||||
static size_t video_packet_max = 0;
|
||||
static pthread_mutex_t video_packet_mutex;
|
||||
static pthread_cond_t video_packet_cond;
|
||||
|
||||
static const uint8_t VANILLA_PPS_PARAMS[] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x06, 0x0c, 0xe8
|
||||
@@ -52,9 +58,9 @@ static const uint8_t VANILLA_PPS_PARAMS[] = {
|
||||
|
||||
void request_idr()
|
||||
{
|
||||
pthread_mutex_lock(&video_mutex);
|
||||
pthread_mutex_lock(&idr_mutex);
|
||||
idr_is_queued = 1;
|
||||
pthread_mutex_unlock(&video_mutex);
|
||||
pthread_mutex_unlock(&idr_mutex);
|
||||
}
|
||||
|
||||
void send_idr_request_to_console(int socket_msg)
|
||||
@@ -65,7 +71,80 @@ void send_idr_request_to_console(int socket_msg)
|
||||
send_to_console(socket_msg, idr_request, sizeof(idr_request), PORT_MSG);
|
||||
}
|
||||
|
||||
void handle_video_packet(gamepad_context_t *ctx, VideoPacket *vp, size_t size, int socket_msg)
|
||||
static uint8_t *write_slice_nal(int is_idr, int frame_decode_num, uint8_t *out)
|
||||
{
|
||||
uint32_t slice_header = is_idr ? 0x25b804ff : (0x21e003ff | ((frame_decode_num & 0xff) << 13));
|
||||
*((uint32_t *)out) = htobe32(slice_header);
|
||||
return out + sizeof(uint32_t);
|
||||
|
||||
static uint8_t idr_num = 0;
|
||||
|
||||
uint8_t slice_nal[200];
|
||||
size_t bit_index = 0;
|
||||
|
||||
// forbidden_zero_bit
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, 0, 1);
|
||||
|
||||
// nal_ref_idc
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, is_idr ? 3 : 1, 2);
|
||||
|
||||
// nal_unit_type
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, is_idr ? 5 : 1, 5);
|
||||
|
||||
// first_mb_in_slice
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0);
|
||||
|
||||
// slice_type
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, is_idr ? 2 : 0);
|
||||
|
||||
// pic_parameter_set_id
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0);
|
||||
|
||||
// frame_num
|
||||
const int fn_bits = 8;
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, frame_decode_num, fn_bits);
|
||||
|
||||
if (is_idr) {
|
||||
// idr_pic_id
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, idr_num);
|
||||
idr_num++;
|
||||
|
||||
// dec_ref_pic_marking() for IDR:
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, 0, 1); // no_output_of_prior_pics_flag
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, 0, 1); // long_term_reference_flag
|
||||
} else {
|
||||
// num_ref_idx_active_override_flag
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, 1, 1);
|
||||
|
||||
// num_ref_idx_l0_active_minus1
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0);
|
||||
|
||||
// ref_pic_list_modification_flag_l0 = 0 (no modifications)
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, 0, 1);
|
||||
|
||||
// dec_ref_pic_marking() for non-IDR:
|
||||
write_bits(slice_nal, sizeof(slice_nal), &bit_index, 0, 1); // adaptive_ref_pic_marking_mode_flag = 0
|
||||
|
||||
// CABAC: entropy_coding_mode_flag==1 and P-slice → must write cabac_init_idc
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0); // cabac_init_idc = 0 (good default)
|
||||
}
|
||||
|
||||
// slice_qp_delta
|
||||
write_signed_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0);
|
||||
|
||||
// deblocking_filter_control_present_flag == 1 → must write
|
||||
write_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0); // disable_deblocking_filter_idc = 0
|
||||
write_signed_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0); // slice_alpha_c0_offset_div2
|
||||
write_signed_exp_golomb(slice_nal, sizeof(slice_nal), &bit_index, 0); // slice_beta_offset_div2
|
||||
|
||||
size_t bytes = (bit_index + 7) >> 3;
|
||||
memcpy(out, slice_nal, bytes);
|
||||
out += bytes;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void handle_video_packet(gamepad_context_t *ctx, VideoPacket *vp)
|
||||
{
|
||||
//
|
||||
// === IMPORTANT NOTE! ===
|
||||
@@ -88,123 +167,211 @@ void handle_video_packet(gamepad_context_t *ctx, VideoPacket *vp, size_t size, i
|
||||
int is_idr = 0;
|
||||
for (int i = 0; i < sizeof(vp->extended_header); i++) {
|
||||
if (vp->extended_header[i] == 0x80) {
|
||||
// vanilla_log("GOT IDR");
|
||||
|
||||
is_idr = 1;
|
||||
|
||||
// pthread_mutex_lock(&video_mutex);
|
||||
// if (idr_is_queued) {
|
||||
// idr_is_queued = 0;
|
||||
// }
|
||||
// pthread_mutex_unlock(&video_mutex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check seq ID
|
||||
static int seq_id_expected = -1;
|
||||
int seq_matched = 1;
|
||||
if (seq_id_expected == -1) {
|
||||
seq_id_expected = vp->seq_id;
|
||||
} else if (seq_id_expected != vp->seq_id) {
|
||||
seq_matched = 0;
|
||||
}
|
||||
seq_id_expected = (vp->seq_id + 1) & 0x3ff; // 10 bit number
|
||||
static int is_streaming = 0;
|
||||
if (!seq_matched) {
|
||||
is_streaming = 0;
|
||||
}
|
||||
|
||||
// Check if this is the beginning of the packet
|
||||
static VideoPacket *video_segments[1024];
|
||||
static VideoPacket *video_segments[VIDEO_PACKET_QUEUE_MAX];
|
||||
static int video_packet_seq = -1;
|
||||
static int video_packet_seq_end = -1;
|
||||
static int video_complete_frame = 0;
|
||||
|
||||
static uint8_t frame_decode_num = 0;
|
||||
|
||||
if (vp->frame_begin) {
|
||||
video_packet_seq = vp->seq_id;
|
||||
video_packet_seq_end = -1;
|
||||
|
||||
if (!is_streaming) {
|
||||
if (is_idr) {
|
||||
is_streaming = 1;
|
||||
} else {
|
||||
send_idr_request_to_console(socket_msg);
|
||||
return;
|
||||
}
|
||||
memset(video_segments, 0, sizeof(video_segments));
|
||||
|
||||
frame_decode_num++;
|
||||
|
||||
if (!video_complete_frame && !is_idr) {
|
||||
send_idr_request_to_console(ctx->socket_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
video_complete_frame = 0;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&video_mutex);
|
||||
pthread_mutex_lock(&idr_mutex);
|
||||
if (idr_is_queued) {
|
||||
send_idr_request_to_console(socket_msg);
|
||||
send_idr_request_to_console(ctx->socket_msg);
|
||||
idr_is_queued = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&video_mutex);
|
||||
pthread_mutex_unlock(&idr_mutex);
|
||||
|
||||
// vanilla_log("set seq_id %i = %p", vp->seq_id, vp);
|
||||
video_segments[vp->seq_id] = vp;
|
||||
|
||||
if (vp->frame_end) {
|
||||
if (vp->frame_end)
|
||||
video_packet_seq_end = vp->seq_id;
|
||||
}
|
||||
|
||||
if (video_packet_seq_end != -1) {
|
||||
// int complete_frame = 1;
|
||||
if (is_streaming) {
|
||||
// Encapsulate packet data into NAL unit
|
||||
static int frame_decode_num = 0;
|
||||
uint8_t *nals_current = video_packet + generated_sps_params_size;
|
||||
|
||||
int slice_header = is_idr ? 0x25b804ff : (0x21e003ff | ((frame_decode_num & 0xff) << 13));
|
||||
|
||||
// begin slice nalu
|
||||
uint8_t slice[] = {0x00, 0x00, 0x00, 0x01,
|
||||
(uint8_t) ((slice_header >> 24) & 0xff),
|
||||
(uint8_t) ((slice_header >> 16) & 0xff),
|
||||
(uint8_t) ((slice_header >> 8) & 0xff),
|
||||
(uint8_t) (slice_header & 0xff)
|
||||
};
|
||||
memcpy(nals_current, slice, sizeof(slice));
|
||||
nals_current += sizeof(slice);
|
||||
|
||||
// Get pointer to first packet's payload
|
||||
if (video_packet_seq != -1 && video_packet_seq_end != -1) {
|
||||
int complete_frame = 1;
|
||||
{
|
||||
int current_index = video_packet_seq;
|
||||
uint8_t *from = video_segments[current_index]->payload;
|
||||
|
||||
memcpy(nals_current, from, 2);
|
||||
nals_current += 2;
|
||||
|
||||
// Escape codes
|
||||
int byte = 2;
|
||||
while (1) {
|
||||
uint8_t *data = video_segments[current_index]->payload;
|
||||
size_t pkt_size = video_segments[current_index]->payload_size;
|
||||
while (byte < pkt_size) {
|
||||
if (data[byte] <= 3 && *(nals_current - 2) == 0 && *(nals_current - 1) == 0) {
|
||||
*nals_current = 3;
|
||||
nals_current++;
|
||||
}
|
||||
*nals_current = data[byte];
|
||||
nals_current++;
|
||||
byte++;
|
||||
if (!video_segments[current_index]) {
|
||||
complete_frame = 0;
|
||||
vanilla_log("damn, incomplete frame (missing %i)", current_index);
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_index == video_packet_seq_end) {
|
||||
break;
|
||||
}
|
||||
|
||||
byte = 0;
|
||||
current_index = (current_index + 1) % VIDEO_PACKET_CACHE_MAX;
|
||||
current_index = (current_index + 1) % VIDEO_PACKET_QUEUE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip IDR parameters if not an IDR frame
|
||||
uint8_t *nals = (is_idr) ? video_packet : (video_packet + generated_sps_params_size);
|
||||
push_event(ctx->event_loop, VANILLA_EVENT_VIDEO, nals, (nals_current - nals));
|
||||
if (complete_frame) {
|
||||
video_complete_frame = 1;
|
||||
|
||||
// Encapsulate packet data into NAL unit
|
||||
vanilla_event_t *event;
|
||||
int ret = acquire_event(ctx->event_loop, &event);
|
||||
|
||||
event->type = VANILLA_EVENT_VIDEO;
|
||||
|
||||
uint8_t *video_packet = event->data;
|
||||
|
||||
const int OLD_CODE = 1;
|
||||
if (OLD_CODE) {
|
||||
uint8_t *nals_current = video_packet;
|
||||
static const char *frame_start_word = "\x00\x00\x00\x01";
|
||||
|
||||
if (is_idr) {
|
||||
uint8_t sps[200], pps[200];
|
||||
size_t sps_size = generate_sps_params(sps, sizeof(sps));
|
||||
size_t pps_size = generate_pps_params(pps, sizeof(pps));
|
||||
|
||||
memcpy(nals_current, frame_start_word, 4);
|
||||
nals_current += 4;
|
||||
|
||||
memcpy(nals_current, sps, sps_size);
|
||||
nals_current += sps_size;
|
||||
|
||||
memcpy(nals_current, pps, pps_size);
|
||||
nals_current += pps_size;
|
||||
}
|
||||
|
||||
memcpy(nals_current, frame_start_word, 4);
|
||||
nals_current += 4;
|
||||
|
||||
nals_current = write_slice_nal(is_idr, frame_decode_num, nals_current);
|
||||
|
||||
// Get pointer to first packet's payload
|
||||
int current_index = video_packet_seq;
|
||||
uint8_t *from = video_segments[current_index]->payload;
|
||||
|
||||
memcpy(nals_current, from, 2);
|
||||
nals_current += 2;
|
||||
|
||||
// Escape codes
|
||||
int byte = 2;
|
||||
while (1) {
|
||||
uint8_t *data = video_segments[current_index]->payload;
|
||||
size_t pkt_size = video_segments[current_index]->payload_size;
|
||||
while (byte < pkt_size) {
|
||||
if (data[byte] <= 3 && *(nals_current - 2) == 0 && *(nals_current - 1) == 0) {
|
||||
*nals_current = 3;
|
||||
nals_current++;
|
||||
}
|
||||
*nals_current = data[byte];
|
||||
nals_current++;
|
||||
byte++;
|
||||
}
|
||||
|
||||
if (current_index == video_packet_seq_end) {
|
||||
break;
|
||||
}
|
||||
|
||||
byte = 0;
|
||||
current_index = (current_index + 1) % VIDEO_PACKET_QUEUE_MAX;
|
||||
}
|
||||
|
||||
event->size = (nals_current - video_packet);
|
||||
} else {
|
||||
uint8_t *out = video_packet;
|
||||
out += 4; // Make room for size
|
||||
|
||||
out = write_slice_nal(is_idr, frame_decode_num, out);
|
||||
|
||||
// vanilla_log_no_newline("generated slice NAL header:");
|
||||
// for (size_t i = 0; i < bytes; i++) {
|
||||
// vanilla_log_no_newline(" %02x", slice_nal[i] & 0xFF);
|
||||
// }
|
||||
// vanilla_log_no_newline("\n");
|
||||
|
||||
// uint32_t slice_header = is_idr ? 0x25b804ff : (0x21e003ff | ((0 & 0xff) << 13));
|
||||
// *(uint32_t*)out = htobe32(slice_header);
|
||||
// out += sizeof(uint32_t);
|
||||
|
||||
int i = video_packet_seq;
|
||||
|
||||
size_t offset = 0;
|
||||
while (1) {
|
||||
uint8_t *data = video_segments[i]->payload;
|
||||
size_t sz = video_segments[i]->payload_size - offset;
|
||||
|
||||
memcpy(out, data + offset, sz);
|
||||
out += sz;
|
||||
|
||||
offset = 0;
|
||||
|
||||
if (i == video_packet_seq_end) {
|
||||
break;
|
||||
}
|
||||
|
||||
i = (i + 1) % VIDEO_PACKET_QUEUE_MAX;
|
||||
}
|
||||
|
||||
// Go back and write size
|
||||
*((uint32_t *)video_packet) = htobe32(out - (video_packet + 4));
|
||||
|
||||
event->size = (out - video_packet);
|
||||
}
|
||||
|
||||
// vanilla_log_no_newline("a few bytes from the packet:");
|
||||
// for (size_t i = 0; i < 64; i++) {
|
||||
// // vanilla_log_no_newline(" %02x", video_segments[video_packet_seq]->payload[i] & 0xFF);
|
||||
// vanilla_log_no_newline(" %02x", video_packet[i] & 0xFF);
|
||||
// }
|
||||
// vanilla_log_no_newline("\n");
|
||||
|
||||
release_event(ctx->event_loop);
|
||||
} else {
|
||||
// We didn't receive the complete frame so we'll skip it here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *consume_video_packets(void *data)
|
||||
{
|
||||
gamepad_context_t *ctx = (gamepad_context_t *) data;
|
||||
|
||||
pthread_mutex_lock(&video_packet_mutex);
|
||||
|
||||
while (!is_interrupted()) {
|
||||
while (video_packet_min < video_packet_max) {
|
||||
VideoPacket *vp = &video_packet_queue[video_packet_min % VIDEO_PACKET_QUEUE_MAX];
|
||||
|
||||
pthread_mutex_unlock(&video_packet_mutex);
|
||||
handle_video_packet(ctx, vp);
|
||||
pthread_mutex_lock(&video_packet_mutex);
|
||||
|
||||
video_packet_min++;
|
||||
}
|
||||
pthread_cond_wait(&video_packet_cond, &video_packet_mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&video_packet_mutex);
|
||||
}
|
||||
|
||||
size_t generate_h264_header(void *data, size_t size)
|
||||
{
|
||||
uint8_t *output = (uint8_t *) data;
|
||||
@@ -228,36 +395,33 @@ void *listen_video(void *x)
|
||||
gamepad_context_t *info = (gamepad_context_t *) x;
|
||||
ssize_t size;
|
||||
|
||||
// Set up IDR nals on video_packet
|
||||
uint8_t *nals_current = video_packet;
|
||||
pthread_mutex_init(&idr_mutex, NULL);
|
||||
pthread_mutex_init(&video_packet_mutex, NULL);
|
||||
pthread_cond_init(&video_packet_cond, NULL);
|
||||
|
||||
static const char *frame_start_word = "\x00\x00\x00\x01";
|
||||
memcpy(nals_current, frame_start_word, 4);
|
||||
nals_current += 4;
|
||||
generated_sps_params_size += 4;
|
||||
|
||||
size_t generated_sps = generate_sps_params(nals_current, sizeof(video_packet));
|
||||
nals_current += generated_sps;
|
||||
generated_sps_params_size += generated_sps;
|
||||
|
||||
memcpy(nals_current, VANILLA_PPS_PARAMS, sizeof(VANILLA_PPS_PARAMS));
|
||||
nals_current += sizeof(VANILLA_PPS_PARAMS);
|
||||
generated_sps_params_size += sizeof(VANILLA_PPS_PARAMS);
|
||||
|
||||
pthread_mutex_init(&video_mutex, NULL);
|
||||
pthread_t video_consumer_thread;
|
||||
pthread_create(&video_consumer_thread, 0, consume_video_packets, info);
|
||||
|
||||
do {
|
||||
VideoPacket *vp = &video_packet_cache[video_packet_cache_index % VIDEO_PACKET_CACHE_MAX];
|
||||
video_packet_cache_index++;
|
||||
void *data = vp;
|
||||
|
||||
size = recv(info->socket_vid, data, sizeof(VideoPacket), 0);
|
||||
VideoPacket *vp = &video_packet_queue[video_packet_max % VIDEO_PACKET_QUEUE_MAX];
|
||||
size = recv(info->socket_vid, (void *) vp, sizeof(VideoPacket), 0);
|
||||
if (size > 0) {
|
||||
handle_video_packet(info, vp, size, info->socket_msg);
|
||||
pthread_mutex_lock(&video_packet_mutex);
|
||||
video_packet_max++;
|
||||
if (video_packet_max == video_packet_min + VIDEO_PACKET_QUEUE_MAX) {
|
||||
vanilla_log("WARNING: ROLLED OVER VIDEO PACKET QUEUE");
|
||||
}
|
||||
pthread_cond_broadcast(&video_packet_cond);
|
||||
pthread_mutex_unlock(&video_packet_mutex);
|
||||
// (info, vp, size, info->socket_msg);
|
||||
}
|
||||
} while (!is_interrupted());
|
||||
|
||||
pthread_mutex_destroy(&video_mutex);
|
||||
pthread_join(video_consumer_thread, 0);
|
||||
|
||||
pthread_cond_destroy(&video_packet_cond);
|
||||
pthread_mutex_destroy(&video_packet_mutex);
|
||||
pthread_mutex_destroy(&idr_mutex);
|
||||
|
||||
pthread_exit(NULL);
|
||||
|
||||
@@ -269,7 +433,7 @@ void write_bits(void *data, size_t buffer_size, size_t *bit_index, uint8_t value
|
||||
const size_t size_of_byte = 8;
|
||||
|
||||
assert(bit_width <= size_of_byte);
|
||||
|
||||
|
||||
// Calculate offsets
|
||||
size_t offset = *bit_index;
|
||||
uint8_t *bytes = (uint8_t *) data;
|
||||
@@ -325,7 +489,7 @@ void write_exp_golomb(void *data, size_t buffer_size, size_t *bit_index, uint64_
|
||||
int bit_width = ((sizeof(value) * size_of_byte) - leading_zeros);
|
||||
|
||||
int exp_golomb_leading_zeros = bit_width - 1;
|
||||
|
||||
|
||||
for (int i = 0; i < exp_golomb_leading_zeros; i += size_of_byte) {
|
||||
write_bits(data, buffer_size, bit_index, 0, MIN(size_of_byte, exp_golomb_leading_zeros - i));
|
||||
}
|
||||
@@ -348,8 +512,31 @@ void write_exp_golomb(void *data, size_t buffer_size, size_t *bit_index, uint64_
|
||||
}
|
||||
}
|
||||
|
||||
// void write_signed_exp_golomb(void *data, size_t buffer_size, size_t *bit_index, int64_t value)
|
||||
// {
|
||||
// uint64_t codeNum = (value <= 0) ? (uint64_t)(-value*2) : (uint64_t)(value*2-1);
|
||||
// write_exp_golomb(data, buffer_size, bit_index, codeNum-1);
|
||||
// }
|
||||
|
||||
void write_signed_exp_golomb(void *data, size_t buffer_size, size_t *bit_index, int64_t value)
|
||||
{
|
||||
uint64_t codeNum;
|
||||
|
||||
if (value > 0) {
|
||||
codeNum = ((uint64_t)value << 1) - 1; // 2*v - 1
|
||||
} else {
|
||||
// value <= 0
|
||||
codeNum = (uint64_t)(-value) << 1; // -2*v
|
||||
}
|
||||
|
||||
write_exp_golomb(data, buffer_size, bit_index, codeNum);
|
||||
}
|
||||
|
||||
size_t generate_sps_params(void *data, size_t size)
|
||||
{
|
||||
// memcpy(data, VANILLA_SPS_PARAMS, MIN(sizeof(VANILLA_SPS_PARAMS), size));
|
||||
// return sizeof(VANILLA_SPS_PARAMS);
|
||||
|
||||
//
|
||||
// Reference: https://www.cardinalpeak.com/blog/the-h-264-sequence-parameter-set
|
||||
//
|
||||
@@ -409,7 +596,7 @@ size_t generate_sps_params(void *data, size_t size)
|
||||
|
||||
// seq_scaling_matrix_present_flag
|
||||
write_bits(data, size, &bit_index, 0, 1);
|
||||
|
||||
|
||||
// log2_max_frame_num_minus4
|
||||
write_exp_golomb(data, size, &bit_index, 4);
|
||||
|
||||
@@ -420,7 +607,7 @@ size_t generate_sps_params(void *data, size_t size)
|
||||
write_exp_golomb(data, size, &bit_index, 1);
|
||||
|
||||
// gaps_in_frame_num_value_allowed_flag
|
||||
write_bits(data, size, &bit_index, 0, 1);
|
||||
write_bits(data, size, &bit_index, 1, 1);
|
||||
|
||||
// pic_width_in_mbs_minus1
|
||||
write_exp_golomb(data, size, &bit_index, 53);
|
||||
@@ -508,7 +695,7 @@ size_t generate_sps_params(void *data, size_t size)
|
||||
|
||||
// RBSP trailing stop bit
|
||||
write_bits(data, size, &bit_index, 1, 1);
|
||||
|
||||
|
||||
// Alignment
|
||||
const int align = 8;
|
||||
if (bit_index % align != 0) {
|
||||
@@ -522,4 +709,24 @@ size_t generate_pps_params(void *data, size_t size)
|
||||
{
|
||||
memcpy(data, VANILLA_PPS_PARAMS, MIN(sizeof(VANILLA_PPS_PARAMS), size));
|
||||
return sizeof(VANILLA_PPS_PARAMS);
|
||||
|
||||
// size_t bit_index = 0;
|
||||
|
||||
// // forbidden_zero_bit
|
||||
// write_bits(data, size, &bit_index, 0, 1);
|
||||
|
||||
// // nal_ref_idc = 3 (important)
|
||||
// write_bits(data, size, &bit_index, 3, 2);
|
||||
|
||||
// // nal_unit_type = 8 (PPS)
|
||||
// write_bits(data, size, &bit_index, 7, 5);
|
||||
|
||||
// // pic_parameter_set_id
|
||||
// write_exp_golomb(data, size, &bit_index, 0);
|
||||
|
||||
// // seq_parameter_set_id
|
||||
// write_exp_golomb(data, size, &bit_index, 0);
|
||||
|
||||
// // entropy_coding_mode_flag
|
||||
// write_exp_golomb(data, size, &bit_index, 0);
|
||||
}
|
||||
+2
-1
@@ -11,5 +11,6 @@ size_t generate_pps_params(void *data, size_t size);
|
||||
size_t generate_h264_header(void *data, size_t size);
|
||||
void write_bits(void *data, size_t size, size_t *bit_index, uint8_t value, size_t bit_width);
|
||||
void write_exp_golomb(void *data, size_t buffer_size, size_t *bit_index, uint64_t value);
|
||||
void write_signed_exp_golomb(void *data, size_t buffer_size, size_t *bit_index, int64_t value);
|
||||
|
||||
#endif // GAMEPAD_VIDEO_H
|
||||
#endif // GAMEPAD_VIDEO_H
|
||||
@@ -255,3 +255,8 @@ void vanilla_send_audio(const void *data, size_t size)
|
||||
{
|
||||
send_audio_packet(data, size);
|
||||
}
|
||||
|
||||
void vanilla_set_wireless_interface(const char *intf)
|
||||
{
|
||||
strcpy(wireless_interface, intf);
|
||||
}
|
||||
+4
-3
@@ -23,7 +23,6 @@ extern "C" {
|
||||
#define VANILLA_ERR_DISCONNECTED -11
|
||||
|
||||
static const uint32_t VANILLA_ADDRESS_LOCAL = 0xFFFFFFFF;
|
||||
static const uint32_t VANILLA_ADDRESS_DIRECT = 0x0;
|
||||
|
||||
enum VanillaGamepadButtons
|
||||
{
|
||||
@@ -125,6 +124,8 @@ typedef struct {
|
||||
int vanilla_start(uint32_t server_address, vanilla_bssid_t bssid, vanilla_psk_t psk);
|
||||
int vanilla_sync(uint16_t code, uint32_t server_address);
|
||||
|
||||
void vanilla_set_wireless_interface(const char *intf);
|
||||
|
||||
int vanilla_install_polkit(uint32_t server_address);
|
||||
int vanilla_uninstall_polkit(uint32_t server_address);
|
||||
|
||||
@@ -134,8 +135,6 @@ int vanilla_free_event(vanilla_event_t *event);
|
||||
|
||||
/**
|
||||
* Attempt to stop the current action
|
||||
*
|
||||
* This can be called from another thread to safely exit a blocking call to vanilla_start().
|
||||
*/
|
||||
void vanilla_stop();
|
||||
|
||||
@@ -195,6 +194,8 @@ void vanilla_set_battery_status(int battery_status);
|
||||
/**
|
||||
* Retrieve SPS/PPS parameters for H.264 packeting
|
||||
*/
|
||||
size_t vanilla_generate_sps_params(void *data, size_t data_size);
|
||||
size_t vanilla_generate_pps_params(void *data, size_t data_size);
|
||||
size_t vanilla_generate_h264_header(void *data, size_t size);
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user