mirror of
https://github.com/vanilla-wiiu/vanilla.git
synced 2025-01-22 08:11:47 -05:00
significantly optimized video/audio packet intake
This commit is contained in:
parent
5f34f63dc9
commit
e140c1a58c
2 changed files with 72 additions and 60 deletions
|
@ -33,19 +33,22 @@ typedef struct {
|
|||
|
||||
void handle_audio_packet(gamepad_context_t *ctx, char *data, size_t len)
|
||||
{
|
||||
for (int byte = 0; byte < len; byte++) {
|
||||
//
|
||||
// === IMPORTANT NOTE! ===
|
||||
//
|
||||
// This for loop skips ap->format, ap->seq_id, and ap->timestamp to save processing.
|
||||
// If you want those, you'll have to adjust this loop.
|
||||
//
|
||||
for (int byte = 2; byte < 4; byte++) {
|
||||
data[byte] = (unsigned char) reverse_bits(data[byte], 8);
|
||||
}
|
||||
|
||||
AudioPacket *ap = (AudioPacket *) data;
|
||||
|
||||
ap->format = reverse_bits(ap->format, 3);
|
||||
ap->seq_id = reverse_bits(ap->seq_id, 10);
|
||||
// ap->format = reverse_bits(ap->format, 3);
|
||||
// ap->seq_id = reverse_bits(ap->seq_id, 10);
|
||||
ap->payload_size = reverse_bits(ap->payload_size, 16);
|
||||
ap->timestamp = reverse_bits(ap->timestamp, 32);
|
||||
for (int byte = 0; byte < ap->payload_size; ++byte) {
|
||||
ap->payload[byte] = (unsigned char) reverse_bits(ap->payload[byte], 8);
|
||||
}
|
||||
// ap->timestamp = reverse_bits(ap->timestamp, 32);
|
||||
|
||||
if (ap->type == TYPE_VIDEO) {
|
||||
AudioPacketVideoFormat *avp = (AudioPacketVideoFormat *) ap->payload;
|
||||
|
|
|
@ -29,8 +29,13 @@ typedef struct
|
|||
uint8_t payload[2048];
|
||||
} VideoPacket;
|
||||
|
||||
pthread_mutex_t video_mutex;
|
||||
int idr_is_queued = 0;
|
||||
static pthread_mutex_t video_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];
|
||||
|
||||
void request_idr()
|
||||
{
|
||||
|
@ -46,26 +51,25 @@ 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, unsigned char *data, size_t size, int socket_msg)
|
||||
void handle_video_packet(gamepad_context_t *ctx, VideoPacket *vp, size_t size, int socket_msg)
|
||||
{
|
||||
// TODO: This is all really weird. Copied from drc-sim-c but I feel like there's probably a better way.
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
//
|
||||
// === IMPORTANT NOTE! ===
|
||||
//
|
||||
// This for loop skips vp->magic, vp->packet_type, and vp->timestamp to save processing.
|
||||
// If you want those, you'll have to adjust this loop.
|
||||
//
|
||||
uint8_t *data = (uint8_t *) vp;
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
data[i] = reverse_bits(data[i], 8);
|
||||
}
|
||||
|
||||
VideoPacket *vp = (VideoPacket *) data;
|
||||
|
||||
vp->magic = reverse_bits(vp->magic, 4);
|
||||
vp->packet_type = reverse_bits(vp->packet_type, 2);
|
||||
// vp->magic = reverse_bits(vp->magic, 4);
|
||||
// vp->packet_type = reverse_bits(vp->packet_type, 2);
|
||||
// vp->timestamp = reverse_bits(vp->timestamp, 32);
|
||||
vp->seq_id = reverse_bits(vp->seq_id, 10);
|
||||
vp->payload_size = reverse_bits(vp->payload_size, 11);
|
||||
vp->timestamp = reverse_bits(vp->timestamp, 32);
|
||||
for (int byte = 0; byte < sizeof(vp->extended_header); ++byte)
|
||||
vp->extended_header[byte] = (unsigned char) reverse_bits(vp->extended_header[byte], 8);
|
||||
for (int byte = 0; byte < vp->payload_size; ++byte)
|
||||
vp->payload[byte] = (unsigned char) reverse_bits(vp->payload[byte], 8);
|
||||
|
||||
|
||||
// Check if packet is IDR (instantaneous decoder refresh)
|
||||
int is_idr = 0;
|
||||
for (int i = 0; i < sizeof(vp->extended_header); i++) {
|
||||
|
@ -90,8 +94,7 @@ void handle_video_packet(gamepad_context_t *ctx, unsigned char *data, size_t siz
|
|||
}
|
||||
|
||||
// Check if this is the beginning of the packet
|
||||
static char video_segments[1024][2048];
|
||||
static size_t video_segment_size[1024];
|
||||
static VideoPacket *video_segments[1024];
|
||||
static int video_packet_seq = -1;
|
||||
static int video_packet_seq_end = -1;
|
||||
|
||||
|
@ -116,8 +119,7 @@ void handle_video_packet(gamepad_context_t *ctx, unsigned char *data, size_t siz
|
|||
}
|
||||
pthread_mutex_unlock(&video_mutex);
|
||||
|
||||
memcpy(video_segments[vp->seq_id], vp->payload, vp->payload_size);
|
||||
video_segment_size[vp->seq_id] = vp->payload_size;
|
||||
video_segments[vp->seq_id] = vp;
|
||||
|
||||
if (vp->frame_end) {
|
||||
video_packet_seq_end = vp->seq_id;
|
||||
|
@ -126,32 +128,13 @@ void handle_video_packet(gamepad_context_t *ctx, unsigned char *data, size_t siz
|
|||
if (video_packet_seq_end != -1) {
|
||||
// int complete_frame = 1;
|
||||
if (is_streaming) {
|
||||
// Combine segments
|
||||
char video_packet[100000];
|
||||
size_t video_packet_size = 0;
|
||||
for (int i = video_packet_seq; ; i = (i + 1) % 1024) {
|
||||
memcpy(video_packet + video_packet_size, video_segments[i], video_segment_size[i]);
|
||||
video_packet_size += video_segment_size[i];
|
||||
if (i == video_packet_seq_end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Encapsulate packet data into NAL unit
|
||||
static int frame_decode_num = 0;
|
||||
size_t nals_sz = video_packet_size * 2;
|
||||
uint8_t *nals = malloc(nals_sz);
|
||||
uint8_t *nals_current = nals;
|
||||
uint8_t *nals_current = video_packet + sizeof(VANILLA_SPS_PARAMS) + sizeof(VANILLA_PPS_PARAMS);
|
||||
|
||||
int slice_header = is_idr ? 0x25b804ff : (0x21e003ff | ((frame_decode_num & 0xff) << 13));
|
||||
frame_decode_num++;
|
||||
|
||||
if (is_idr) {
|
||||
memcpy(nals_current, VANILLA_SPS_PARAMS, sizeof(VANILLA_SPS_PARAMS));
|
||||
nals_current += sizeof(VANILLA_SPS_PARAMS);
|
||||
memcpy(nals_current, VANILLA_PPS_PARAMS, sizeof(VANILLA_PPS_PARAMS));
|
||||
nals_current += sizeof(VANILLA_PPS_PARAMS);
|
||||
}
|
||||
|
||||
// begin slice nalu
|
||||
uint8_t slice[] = {0x00, 0x00, 0x00, 0x01,
|
||||
(uint8_t) ((slice_header >> 24) & 0xff),
|
||||
|
@ -162,23 +145,39 @@ void handle_video_packet(gamepad_context_t *ctx, unsigned char *data, size_t siz
|
|||
memcpy(nals_current, slice, sizeof(slice));
|
||||
nals_current += sizeof(slice);
|
||||
|
||||
// Frame
|
||||
memcpy(nals_current, video_packet, 2);
|
||||
// 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
|
||||
for (int byte = 2; byte < video_packet_size; ++byte) {
|
||||
if (video_packet[byte] <= 3 && *(nals_current - 2) == 0 && *(nals_current - 1) == 0) {
|
||||
*nals_current = 3;
|
||||
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++;
|
||||
}
|
||||
*nals_current = video_packet[byte];
|
||||
nals_current++;
|
||||
|
||||
if (current_index == video_packet_seq_end) {
|
||||
break;
|
||||
}
|
||||
|
||||
byte = 0;
|
||||
current_index = (current_index + 1) % VIDEO_PACKET_CACHE_MAX;
|
||||
}
|
||||
|
||||
// Skip IDR parameters if not an IDR frame
|
||||
uint8_t *nals = (is_idr) ? video_packet : (video_packet + sizeof(VANILLA_SPS_PARAMS) + sizeof(VANILLA_PPS_PARAMS));
|
||||
push_event(ctx->event_loop, VANILLA_EVENT_VIDEO, nals, (nals_current - nals));
|
||||
|
||||
free(nals);
|
||||
} else {
|
||||
// We didn't receive the complete frame so we'll skip it here
|
||||
}
|
||||
|
@ -189,16 +188,26 @@ void *listen_video(void *x)
|
|||
{
|
||||
// Receive video
|
||||
gamepad_context_t *info = (gamepad_context_t *) x;
|
||||
unsigned char data[2048];
|
||||
ssize_t size;
|
||||
|
||||
// Set up IDR nals on video_packet
|
||||
uint8_t *nals_current = video_packet;
|
||||
memcpy(nals_current, VANILLA_SPS_PARAMS, sizeof(VANILLA_SPS_PARAMS));
|
||||
nals_current += sizeof(VANILLA_SPS_PARAMS);
|
||||
memcpy(nals_current, VANILLA_PPS_PARAMS, sizeof(VANILLA_PPS_PARAMS));
|
||||
nals_current += sizeof(VANILLA_PPS_PARAMS);
|
||||
|
||||
pthread_mutex_init(&video_mutex, NULL);
|
||||
|
||||
do {
|
||||
size = recv(info->socket_vid, data, sizeof(data), 0);
|
||||
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);
|
||||
if (size > 0) {
|
||||
if (is_stop_code(data, size)) break;
|
||||
handle_video_packet(info, data, size, info->socket_msg);
|
||||
handle_video_packet(info, vp, size, info->socket_msg);
|
||||
}
|
||||
} while (!is_interrupted());
|
||||
|
||||
|
|
Loading…
Reference in a new issue