mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-21 00:59:22 +00:00
* WIP * Add libretro * Update input retro * Update cloud retro input: * Integrate libretro remove GL * Launch emulator by game type * Save and load * Update deeplink to game directly * Done channel for naemulator * each server handle only one session * Only provide available clients * Emulator based on game * Remove all OpenGL related * Retroarch audio * Audio encoding mono * Experiment with libretro audio * Audio without datachannel * Audio opus internal * Remove unnecessary code * Resampled * Limit time frame * Start Room and Audio by game * Dynamic video image allocation * Dynamic Video buffer allocation based on video resolution * Move encoder to room * width and height from emulator * Padding images to fix multipler of 64 * Remove OpenGL * Remove Open AL * Remove OpenGL from Go mod * Move away nanoarch logic in naemulator * Remove unecessary savefiles.go * Optimize Docker for caching * Update ReadME * Update README to introduce Retro * Update README * Update README.md
89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
// credit to https://github.com/poi5305/go-yuv2webRTC/blob/master/webrtc/webrtc.go
|
|
package util
|
|
|
|
import (
|
|
"image"
|
|
"log"
|
|
"os/user"
|
|
"unsafe"
|
|
)
|
|
|
|
// https://stackoverflow.com/questions/9465815/rgb-to-yuv420-algorithm-efficiency
|
|
|
|
/*
|
|
void rgba2yuv(void *destination, void *source, int width, int height, int stride) {
|
|
const int image_size = width * height;
|
|
unsigned char *rgba = source;
|
|
unsigned char *dst_y = destination;
|
|
unsigned char *dst_u = destination + image_size;
|
|
unsigned char *dst_v = destination + image_size + image_size/4;
|
|
|
|
// Y plane
|
|
for( int y=0; y<height; ++y ) {
|
|
for( int x=0; x<width; ++x ) {
|
|
const int i = y*(width+stride) + x;
|
|
*dst_y++ = ( ( 66*rgba[4*i] + 129*rgba[4*i+1] + 25*rgba[4*i+2] ) >> 8 ) + 16;
|
|
}
|
|
}
|
|
// U plane
|
|
for( int y=0; y<height; y+=2 ) {
|
|
for( int x=0; x<width; x+=2 ) {
|
|
const int i = y*(width+stride) + x;
|
|
*dst_u++ = ( ( -38*rgba[4*i] + -74*rgba[4*i+1] + 112*rgba[4*i+2] ) >> 8 ) + 128;
|
|
}
|
|
}
|
|
// V plane
|
|
for( int y=0; y<height; y+=2 ) {
|
|
for( int x=0; x<width; x+=2 ) {
|
|
const int i = y*(width+stride) + x;
|
|
*dst_v++ = ( ( 112*rgba[4*i] + -94*rgba[4*i+1] + -18*rgba[4*i+2] ) >> 8 ) + 128;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
import "C"
|
|
|
|
// RgbaToYuv convert to yuv from rgba
|
|
func RgbaToYuv(rgba *image.RGBA) []byte {
|
|
w := rgba.Rect.Max.X
|
|
h := rgba.Rect.Max.Y
|
|
size := int(float32(w*h) * 1.5)
|
|
stride := rgba.Stride - w*4
|
|
yuv := make([]byte, size, size)
|
|
C.rgba2yuv(unsafe.Pointer(&yuv[0]), unsafe.Pointer(&rgba.Pix[0]), C.int(w), C.int(h), C.int(stride))
|
|
return yuv
|
|
}
|
|
|
|
// RgbaToYuvInplace convert to yuv from rgba inplace to yuv. Avoid reallocation
|
|
func RgbaToYuvInplace(rgba *image.RGBA, yuv []byte, width, height int) {
|
|
stride := rgba.Stride - width*4
|
|
C.rgba2yuv(unsafe.Pointer(&yuv[0]), unsafe.Pointer(&rgba.Pix[0]), C.int(width), C.int(height), C.int(stride))
|
|
}
|
|
|
|
var homeDir string
|
|
|
|
func init() {
|
|
u, err := user.Current()
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
homeDir = u.HomeDir
|
|
}
|
|
|
|
// GetSavePath returns save location of game based on roomID
|
|
func GetSavePath(roomID string) string {
|
|
return savePath(roomID)
|
|
}
|
|
|
|
// GetSRAMPath returns SRAM location of game based on roomID
|
|
func GetSRAMPath(hash string) string {
|
|
return homeDir + "/.nes/sram/" + hash + ".dat"
|
|
}
|
|
|
|
func sramPath(hash string) string {
|
|
return homeDir + "/.nes/sram/" + hash + ".dat"
|
|
}
|
|
|
|
func savePath(hash string) string {
|
|
return homeDir + "/.nes/save/" + hash + ".dat"
|
|
}
|