[client] added initial decoder framework

This commit is contained in:
Geoffrey McRae 2017-12-29 22:48:21 +11:00
parent c239306d82
commit 076a45acc5
7 changed files with 349 additions and 11 deletions

View File

@ -1,12 +1,12 @@
BINARY = looking-glass-client BINARY = looking-glass-client
CFLAGS = -g -O3 -std=gnu99 -march=native -Wall -Werror -I./ -I../common -DDEBUG -DATOMIC_LOCKING CFLAGS = -g -Og -std=gnu99 -march=native -Wall -Werror -I./ -I../common -DDEBUG -DATOMIC_LOCKING
LDFLAGS = -lrt LDFLAGS = -lrt
CFLAGS += -ffast-math CFLAGS += -ffast-math
CFLAGS += -fdata-sections -ffunction-sections CFLAGS += -fdata-sections -ffunction-sections
LDFLAGS += -Wl,--gc-sections LDFLAGS += -Wl,--gc-sections
LIBS = sdl2 SDL2_ttf gl glu libssl openssl spice-protocol fontconfig x11 libconfig LIBS = sdl2 SDL2_ttf gl glu libssl openssl spice-protocol fontconfig x11 libconfig libva
CFLAGS += $(shell pkg-config --cflags $(LIBS)) CFLAGS += $(shell pkg-config --cflags $(LIBS))
LDFLAGS += $(shell pkg-config --libs $(LIBS)) LDFLAGS += $(shell pkg-config --libs $(LIBS))
BUILD ?= .build BUILD ?= .build
@ -17,6 +17,8 @@ CFLAGS += -DBUILD_VERSION='"$(shell git describe --always --long --dirty --abbr
OBJS = main.o \ OBJS = main.o \
lg-renderer.o \ lg-renderer.o \
spice/spice.o \ spice/spice.o \
decoders/null.o \
decoders/h264.o \
renderers/opengl.o renderers/opengl.o
# renderers/opengl-basic.o # renderers/opengl-basic.o

110
client/decoders/h264.c Normal file
View File

@ -0,0 +1,110 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lg-decoder.h"
#include "debug.h"
#include <stdlib.h>
#include <string.h>
struct Inst
{
bool initialized;
LG_RendererFormat format;
};
static bool lgd_h264_create (void ** opaque);
static void lgd_h264_destroy (void * opaque);
static bool lgd_h264_initialize (void * opaque, const LG_RendererFormat format);
static void lgd_h264_deinitialize (void * opaque);
static LG_OutFormat lgd_h264_get_out_format (void * opaque);
static unsigned int lgd_h264_get_frame_pitch(void * opaque);
static bool lgd_h264_decode(void * opaque, uint8_t * dst, size_t dstSize, const uint8_t * src, size_t srcSize);
static bool lgd_h264_create(void ** opaque)
{
// create our local storage
*opaque = malloc(sizeof(struct Inst));
if (!*opaque)
{
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(struct Inst));
return false;
}
memset(*opaque, 0, sizeof(struct Inst));
//struct Inst * this = (struct Inst *)*opaque;
return true;
}
static void lgd_h264_destroy(void * opaque)
{
struct Inst * this = (struct Inst *)opaque;
lgd_h264_deinitialize(opaque);
free(this);
}
static bool lgd_h264_initialize(void * opaque, const LG_RendererFormat format)
{
struct Inst * this = (struct Inst *)opaque;
if (this->initialized)
lgd_h264_deinitialize(opaque);
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
return true;
}
static void lgd_h264_deinitialize(void * opaque)
{
struct Inst * this = (struct Inst *)opaque;
if (!this->initialized)
return;
memset(this, 0, sizeof(struct Inst));
}
static LG_OutFormat lgd_h264_get_out_format(void * opaque)
{
return LG_OUTPUT_BGRA;
}
static unsigned int lgd_h264_get_frame_pitch(void * opaque)
{
struct Inst * this = (struct Inst *)opaque;
return this->format.width * 4;
}
static bool lgd_h264_decode(void * opaque, uint8_t * dst, size_t dstSize, const uint8_t * src, size_t srcSize)
{
return true;
}
const LG_Decoder LGD_H264 =
{
.name = "H.264",
.create = lgd_h264_create,
.destroy = lgd_h264_destroy,
.initialize = lgd_h264_initialize,
.deinitialize = lgd_h264_deinitialize,
.get_out_format = lgd_h264_get_out_format,
.get_frame_pitch = lgd_h264_get_frame_pitch,
.decode = lgd_h264_decode
};

97
client/decoders/null.c Normal file
View File

@ -0,0 +1,97 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lg-decoder.h"
#include "debug.h"
#include "memcpySSE.h"
#include <stdlib.h>
#include <string.h>
struct Inst
{
LG_RendererFormat format;
};
static bool lgd_null_create (void ** opaque);
static void lgd_null_destroy (void * opaque);
static bool lgd_null_initialize (void * opaque, const LG_RendererFormat format);
static void lgd_null_deinitialize (void * opaque);
static LG_OutFormat lgd_null_get_out_format (void * opaque);
static unsigned int lgd_null_get_frame_pitch(void * opaque);
static bool lgd_null_decode (void * opaque, uint8_t * dst, size_t dstSize, const uint8_t * src, size_t srcSize);
static bool lgd_null_create(void ** opaque)
{
// create our local storage
*opaque = malloc(sizeof(struct Inst));
if (!*opaque)
{
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(struct Inst));
return false;
}
memset(*opaque, 0, sizeof(struct Inst));
return true;
}
static void lgd_null_destroy(void * opaque)
{
free(opaque);
}
static bool lgd_null_initialize(void * opaque, const LG_RendererFormat format)
{
struct Inst * this = (struct Inst *)opaque;
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
return true;
}
static void lgd_null_deinitialize(void * opaque)
{
}
static LG_OutFormat lgd_null_get_out_format(void * opaque)
{
return LG_OUTPUT_BGRA;
}
static unsigned int lgd_null_get_frame_pitch(void * opaque)
{
struct Inst * this = (struct Inst *)opaque;
return this->format.pitch;
}
static bool lgd_null_decode(void * opaque, uint8_t * dst, size_t dstSize, const uint8_t * src, size_t srcSize)
{
memcpySSE(dst, src, dstSize);
return true;
}
const LG_Decoder LGD_NULL =
{
.name = "NULL",
.create = lgd_null_create,
.destroy = lgd_null_destroy,
.initialize = lgd_null_initialize,
.deinitialize = lgd_null_deinitialize,
.get_out_format = lgd_null_get_out_format,
.get_frame_pitch = lgd_null_get_frame_pitch,
.decode = lgd_null_decode
};

52
client/lg-decoder.h Normal file
View File

@ -0,0 +1,52 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "lg-renderer.h"
typedef enum LG_OutFormat
{
LG_OUTPUT_BGRA
}
LG_OutFormat;
typedef bool (* LG_DecoderCreate )(void ** opaque);
typedef void (* LG_DecoderDestroy )(void * opaque);
typedef bool (* LG_DecoderInitialize )(void * opaque, const LG_RendererFormat format);
typedef void (* LG_DecoderDeInitialize )(void * opaque);
typedef LG_OutFormat (* LG_DecoderGetOutFormat )(void * opaque);
typedef unsigned int (* LG_DecoderGetFramePitch)(void * opaque);
typedef bool (* LG_DecoderDecode )(void * opaque, uint8_t * dst, size_t dstSize, const uint8_t * src, size_t srcSize);
typedef struct LG_Decoder
{
const char * name;
LG_DecoderCreate create;
LG_DecoderDestroy destroy;
LG_DecoderInitialize initialize;
LG_DecoderDeInitialize deinitialize;
LG_DecoderGetOutFormat get_out_format;
LG_DecoderGetFramePitch get_frame_pitch;
LG_DecoderDecode decode;
}
LG_Decoder;

33
client/lg-decoders.h Normal file
View File

@ -0,0 +1,33 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once
#include "lg-decoder.h"
extern const LG_Decoder LGD_H264;
extern const LG_Decoder LGD_NULL;
const LG_Decoder * LG_Decoders[] =
{
&LGD_NULL,
&LGD_H264,
NULL // end of array sentinal
};
#define LG_DECODER_COUNT ((sizeof(LG_Decoders) / sizeof(LG_Decoder *)) - 1)

View File

@ -325,14 +325,17 @@ int frameThread(void * unused)
lgrFormat.stride = header.detail.frame.stride; lgrFormat.stride = header.detail.frame.stride;
lgrFormat.pitch = header.detail.frame.pitch; lgrFormat.pitch = header.detail.frame.pitch;
size_t dataSize;
switch(header.detail.frame.type) switch(header.detail.frame.type)
{ {
case FRAME_TYPE_ARGB: case FRAME_TYPE_ARGB:
dataSize = lgrFormat.height * lgrFormat.pitch;
lgrFormat.comp = LG_COMPRESSION_NONE; lgrFormat.comp = LG_COMPRESSION_NONE;
lgrFormat.bpp = 32; lgrFormat.bpp = 32;
break; break;
case FRAME_TYPE_H264: case FRAME_TYPE_H264:
dataSize = lgrFormat.pitch;
lgrFormat.comp = LG_COMPRESSION_H264; lgrFormat.comp = LG_COMPRESSION_H264;
lgrFormat.bpp = 0; lgrFormat.bpp = 0;
break; break;
@ -347,7 +350,6 @@ int frameThread(void * unused)
break; break;
// check the header's dataPos is sane // check the header's dataPos is sane
const size_t dataSize = lgrFormat.height * lgrFormat.pitch;
if (header.detail.frame.dataPos + dataSize > state.shmSize) if (header.detail.frame.dataPos + dataSize > state.shmSize)
{ {
DEBUG_ERROR("The guest sent an invalid dataPos"); DEBUG_ERROR("The guest sent an invalid dataPos");

View File

@ -32,6 +32,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "debug.h" #include "debug.h"
#include "memcpySSE.h" #include "memcpySSE.h"
#include "utils.h" #include "utils.h"
#include "lg-decoders.h"
#define BUFFER_COUNT 2 #define BUFFER_COUNT 2
@ -76,6 +77,8 @@ struct Inst
GLuint intFormat; GLuint intFormat;
GLuint vboFormat; GLuint vboFormat;
size_t texSize; size_t texSize;
const LG_Decoder* decoder;
void * decoderData;
uint64_t drawStart; uint64_t drawStart;
bool hasBuffers; bool hasBuffers;
@ -282,7 +285,18 @@ bool opengl_on_frame_event(void * opaque, const LG_RendererFormat format, const
// lock, perform the update, then unlock // lock, perform the update, then unlock
LG_LOCK(this->syncLock); LG_LOCK(this->syncLock);
memcpySSE(this->texPixels[this->wTexIndex], data, this->texSize); if (!this->decoder->decode(
this->decoderData,
this->texPixels[this->wTexIndex],
this->texSize,
data,
this->format.pitch
))
{
DEBUG_ERROR("decode returned failure");
LG_UNLOCK(this->syncLock);
return false;
}
this->frameUpdate = true; this->frameUpdate = true;
LG_UNLOCK(this->syncLock); LG_UNLOCK(this->syncLock);
@ -552,30 +566,52 @@ static bool configure(struct Inst * this, SDL_Window *window)
switch(this->format.comp) switch(this->format.comp)
{ {
case LG_COMPRESSION_NONE: case LG_COMPRESSION_NONE:
this->decoder = &LGD_NULL;
break; break;
case LG_COMPRESSION_H264: case LG_COMPRESSION_H264:
DEBUG_INFO("h264 not supported yet"); this->decoder = &LGD_H264;
LG_UNLOCK(this->formatLock); break;
default:
DEBUG_ERROR("Unknown/unsupported compression type");
return false; return false;
} }
// assume 32 bit formats are BGRA DEBUG_INFO("Using decoder: %s", this->decoder->name);
switch(this->format.bpp)
if (!this->decoder->create(&this->decoderData))
{ {
case 32: DEBUG_ERROR("Failed to create the decoder");
return false;
}
if (!this->decoder->initialize(
this->decoderData,
this->format
))
{
DEBUG_ERROR("Failed to initialize decoder");
return false;
}
switch(this->decoder->get_out_format(this->decoderData))
{
case LG_OUTPUT_BGRA:
this->intFormat = GL_RGBA8; this->intFormat = GL_RGBA8;
this->vboFormat = GL_BGRA; this->vboFormat = GL_BGRA;
break; break;
default: default:
DEBUG_INFO("%d bpp not supported", this->format.bpp); DEBUG_ERROR("Format not supported");
LG_UNLOCK(this->formatLock); LG_UNLOCK(this->formatLock);
return false; return false;
} }
// calculate the texture size in bytes // calculate the texture size in bytes
this->texSize = this->format.height * this->format.pitch; this->texSize =
this->format.height *
this->decoder->get_frame_pitch(this->decoderData);
// generate lists for drawing // generate lists for drawing
this->texList = glGenLists(BUFFER_COUNT); this->texList = glGenLists(BUFFER_COUNT);
@ -729,6 +765,12 @@ static void deconfigure(struct Inst * this)
this->glContext = NULL; this->glContext = NULL;
} }
if (this->decoder)
{
this->decoder->destroy(this->decoderData);
this->decoderData = NULL;
}
this->configured = false; this->configured = false;
} }