significantly optimized video/audio packet intake

This commit is contained in:
itsmattkc 2024-10-27 18:22:08 -07:00
parent 5f34f63dc9
commit e140c1a58c
2 changed files with 72 additions and 60 deletions

View file

@ -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;

View file

@ -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());