mirror of
https://github.com/Maschell/StreamingPluginWiiU.git
synced 2025-02-20 06:52:46 +01:00
- Use the new Java Client instead of MJPEG via HTTP. See https://github.com/Maschell/StreamingPluginClient for more information.
- Add an option to choose which screen to stream.
This commit is contained in:
parent
993504ed15
commit
5c1733f55c
21
README.md
21
README.md
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
## Still an early PROOF OF CONCEPT. DON'T EXPECT MAGIC.
|
## Still an early PROOF OF CONCEPT. DON'T EXPECT MAGIC.
|
||||||
|
|
||||||
This is just a simple plugin that allows you to stream the content of the DRC to any browser.
|
This is just a simple plugin that allows you to stream the content of the Gamepad or TV screen to your Computer. With default settings streams in a resolution of 428x240 with selft adjusting quality and tries to achieve as much fps as possible.
|
||||||
Currently no configuration without recompiling is supported. It streams in a resolution of 428x240 and tries to achieve 20 fps. These numbers might improve in the future.
|
It's possible to adjust the resolution via the config menu (Press **L, DPAD DOWN and MINUS** on your Wii U Gamepad whenever using the home menu is allowed).
|
||||||
|
|
||||||
But general notes:
|
But general notes:
|
||||||
- This is still an early PoC.
|
- This is still an early PoC.
|
||||||
@ -13,14 +13,18 @@ But general notes:
|
|||||||
- No streaming of the home menu.
|
- No streaming of the home menu.
|
||||||
- Probably unstable.
|
- Probably unstable.
|
||||||
- Some games might be too dark, some might be too bright, some doesn't work at all.
|
- Some games might be too dark, some might be too bright, some doesn't work at all.
|
||||||
- Currently streaming is achieved via "MJPEG via HTTP", this might change in the future to improve performance.
|
- Currently streaming is achieved via a custom Java client.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
While the plugin is running, is possible to configure certain parameters. To open the config menu press **L, DPAD DOWN and MINUS** on your Wii U Gamepad. For more information check the [Wii U Plugin System](https://github.com/Maschell/WiiUPluginSystem).
|
||||||
|
Currently the following options are available:
|
||||||
|
- Change the resolution, possible options: 240p, 360p and 480p
|
||||||
|
- Choose the screen to stream, possible options: Gamepad, TV.
|
||||||
|
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
Simply load the plugin with the plugin loader. When the system menu is loaded, you can open `http://<ip of your ip>:8080` on your browser and should see the stream. Whenever you switch the application (e.g. load a game), you need to refresh the site in your browser.
|
Simply load the plugin with the plugin loader, after that start the [StreamingPluginClient](https://github.com/Maschell/StreamingPluginClient). The StreamingPluginClient requires a computer with Java 8. Double click on the `.jar` and enter the IP address of your Wii U console.
|
||||||
Example when the IP of your Wii U is 192.168.0.44.
|
|
||||||
```
|
|
||||||
http:/192.168.0.44:8080
|
|
||||||
```
|
|
||||||
If you don't know the IP of your Wii U, you can start for example [ftpiiu](https://github.com/dimok789/ftpiiu) which shows the IP when running.
|
If you don't know the IP of your Wii U, you can start for example [ftpiiu](https://github.com/dimok789/ftpiiu) which shows the IP when running.
|
||||||
|
|
||||||
## Wii U Plugin System
|
## Wii U Plugin System
|
||||||
@ -29,6 +33,7 @@ This is a plugin for the [Wii U Plugin System (WUPS)](https://github.com/Maschel
|
|||||||
```
|
```
|
||||||
sd:/wiiu/plugins
|
sd:/wiiu/plugins
|
||||||
```
|
```
|
||||||
|
|
||||||
When the file is placed on the SDCard you can load it with [plugin loader](https://github.com/Maschell/WiiUPluginSystem/).
|
When the file is placed on the SDCard you can load it with [plugin loader](https://github.com/Maschell/WiiUPluginSystem/).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
@ -17,20 +17,22 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "EncodingHelper.h"
|
#include "EncodingHelper.h"
|
||||||
#include "MJPEGStreamServer.hpp"
|
#include "MJPEGStreamServerUDP.hpp"
|
||||||
#include "stream_utils.h"
|
#include "stream_utils.h"
|
||||||
#include "JpegInformation.h"
|
#include "JpegInformation.h"
|
||||||
#include <gx2/event.h>
|
#include <gx2/event.h>
|
||||||
#include <gx2/surface.h>
|
#include <gx2/surface.h>
|
||||||
#include <gx2/mem.h>
|
#include <gx2/mem.h>
|
||||||
|
|
||||||
|
#include "retain_vars.hpp"
|
||||||
|
|
||||||
EncodingHelper *EncodingHelper::instance = NULL;
|
EncodingHelper *EncodingHelper::instance = NULL;
|
||||||
|
|
||||||
OSMessageQueue encodeQueue __attribute__((section(".data")));
|
OSMessageQueue encodeQueue __attribute__((section(".data")));
|
||||||
OSMessage encodeQueueMessages[ENCODE_QUEUE_MESSAGE_COUNT] __attribute__((section(".data")));
|
OSMessage encodeQueueMessages[ENCODE_QUEUE_MESSAGE_COUNT] __attribute__((section(".data")));
|
||||||
|
|
||||||
void EncodingHelper::StartAsyncThread() {
|
void EncodingHelper::StartAsyncThread() {
|
||||||
int32_t priority = 31;
|
int32_t priority = gEncodePriority;
|
||||||
this->pThread = CThread::create(DoAsyncThread, this, CThread::eAttributeAffCore0 |CThread::eAttributeAffCore2 , priority,0x40000);
|
this->pThread = CThread::create(DoAsyncThread, this, CThread::eAttributeAffCore0 |CThread::eAttributeAffCore2 , priority,0x40000);
|
||||||
this->pThread->resumeThread();
|
this->pThread->resumeThread();
|
||||||
}
|
}
|
||||||
@ -115,7 +117,9 @@ void EncodingHelper::DoAsyncThreadInternal(CThread *thread) {
|
|||||||
JpegInformation * info = convertToJpeg((uint8_t*) colorBuffer->surface.image,colorBuffer->surface.width,colorBuffer->surface.height,colorBuffer->surface.pitch,colorBuffer->surface.format, curQuality);
|
JpegInformation * info = convertToJpeg((uint8_t*) colorBuffer->surface.image,colorBuffer->surface.width,colorBuffer->surface.height,colorBuffer->surface.pitch,colorBuffer->surface.format, curQuality);
|
||||||
|
|
||||||
if(info != NULL ) {
|
if(info != NULL ) {
|
||||||
MJPEGStreamServer::getInstance()->streamJPEG(info);
|
if(mjpegServer == NULL || !mjpegServer->streamJPEG(info)){
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//DEBUG_FUNCTION_LINE("We can now kill the colorBuffer\n",colorBuffer);
|
//DEBUG_FUNCTION_LINE("We can now kill the colorBuffer\n",colorBuffer);
|
||||||
|
@ -22,10 +22,10 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <system/CThread.h>
|
#include <system/CThread.h>
|
||||||
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/messagequeue.h>
|
#include <coreinit/messagequeue.h>
|
||||||
#include <utils/logger.h>
|
#include <utils/logger.h>
|
||||||
#include <MJPEGStreamServer.hpp>
|
#include "MJPEGStreamServerUDP.hpp"
|
||||||
|
|
||||||
|
|
||||||
#define ENCODE_QUEUE_MESSAGE_COUNT 1
|
#define ENCODE_QUEUE_MESSAGE_COUNT 1
|
||||||
|
|
||||||
@ -53,7 +53,6 @@ public:
|
|||||||
delete instance;
|
delete instance;
|
||||||
instance = NULL;
|
instance = NULL;
|
||||||
}
|
}
|
||||||
MJPEGStreamServer::destroyInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool addFSQueueMSG(OSMessage message) {
|
static bool addFSQueueMSG(OSMessage message) {
|
||||||
@ -72,6 +71,16 @@ public:
|
|||||||
DCFlushRange((void*) &shouldExit,sizeof(shouldExit));
|
DCFlushRange((void*) &shouldExit,sizeof(shouldExit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMJPEGStreamServer(MJPEGStreamServer * server){
|
||||||
|
this->mjpegServer = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setThreadPriority(int32_t priority){
|
||||||
|
if(pThread != NULL){
|
||||||
|
pThread->setThreadPriority(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EncodingHelper() {
|
EncodingHelper() {
|
||||||
OSInitMessageQueue(&encodeQueue, encodeQueueMessages, ENCODE_QUEUE_MESSAGE_COUNT);
|
OSInitMessageQueue(&encodeQueue, encodeQueueMessages, ENCODE_QUEUE_MESSAGE_COUNT);
|
||||||
@ -85,6 +94,8 @@ private:
|
|||||||
|
|
||||||
CThread *pThread;
|
CThread *pThread;
|
||||||
|
|
||||||
|
MJPEGStreamServer * mjpegServer = NULL;
|
||||||
|
|
||||||
volatile bool serverRunning = false;
|
volatile bool serverRunning = false;
|
||||||
|
|
||||||
volatile bool shouldExit = false;
|
volatile bool shouldExit = false;
|
||||||
|
96
src/HeartBeatServer.cpp
Normal file
96
src/HeartBeatServer.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2018 Maschell
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "HeartBeatServer.hpp"
|
||||||
|
#include "MJPEGStreamServerUDP.hpp"
|
||||||
|
#include "EncodingHelper.h"
|
||||||
|
#include "turbojpeg.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <network/net.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <utils/StringTools.h>
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include <coreinit/time.h>
|
||||||
|
|
||||||
|
|
||||||
|
HeartBeatServer * HeartBeatServer::instance = NULL;
|
||||||
|
|
||||||
|
HeartBeatServer::HeartBeatServer(int32_t port): TCPServer(port,HeartBeatServer::getPriority()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HeartBeatServer::~HeartBeatServer() {
|
||||||
|
if(mjpegStreamServer != NULL) {
|
||||||
|
delete mjpegStreamServer;
|
||||||
|
mjpegStreamServer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL HeartBeatServer::whileLoop() {
|
||||||
|
int32_t ret;
|
||||||
|
int32_t clientfd = getClientFD();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if(shouldExit()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = checkbyte(clientfd);
|
||||||
|
if (ret < 0) {
|
||||||
|
if(socketlasterr() != 6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OSSleepTicks(OSMillisecondsToTicks(1000));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(ret == 0x15) {
|
||||||
|
sendbyte(clientfd,0x16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL HeartBeatServer::acceptConnection() {
|
||||||
|
int32_t clientfd = getClientFD();
|
||||||
|
struct sockaddr_in sockaddr = getSockAddr();
|
||||||
|
|
||||||
|
int32_t connectedIP = sockaddr.sin_addr.s_addr;
|
||||||
|
|
||||||
|
EncodingHelper::getInstance()->setMJPEGStreamServer(NULL);
|
||||||
|
|
||||||
|
if(mjpegStreamServer != NULL) {
|
||||||
|
delete mjpegStreamServer;
|
||||||
|
mjpegStreamServer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mjpegStreamServer = MJPEGStreamServerUDP::createInstance(connectedIP, DEFAULT_UDP_CLIENT_PORT);
|
||||||
|
EncodingHelper::getInstance()->setMJPEGStreamServer(mjpegStreamServer);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Handshake done! Success!\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HeartBeatServer::onConnectionClosed() {
|
||||||
|
DEBUG_FUNCTION_LINE("disconnected\n");
|
||||||
|
EncodingHelper::getInstance()->setMJPEGStreamServer(NULL);
|
||||||
|
if(mjpegStreamServer != NULL) {
|
||||||
|
delete mjpegStreamServer;
|
||||||
|
mjpegStreamServer = NULL;
|
||||||
|
}
|
||||||
|
}
|
76
src/HeartBeatServer.hpp
Normal file
76
src/HeartBeatServer.hpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2018 Maschell
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef _HEARTBEAT_SERVER_H_
|
||||||
|
#define _HEARTBEAT_SERVER_H_
|
||||||
|
|
||||||
|
#include <utils/TCPServer.hpp>
|
||||||
|
#include "MJPEGStreamServerUDP.hpp"
|
||||||
|
|
||||||
|
#define DEFAULT_TCP_PORT 8092
|
||||||
|
|
||||||
|
class HeartBeatServer: TCPServer {
|
||||||
|
|
||||||
|
public:
|
||||||
|
static HeartBeatServer *getInstance() {
|
||||||
|
if(!instance) {
|
||||||
|
instance = new HeartBeatServer(DEFAULT_TCP_PORT);
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroyInstance() {
|
||||||
|
if(instance) {
|
||||||
|
delete instance;
|
||||||
|
instance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t getPriority() {
|
||||||
|
return 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
static volatile bool isInstanceConnected() {
|
||||||
|
if(instance) {
|
||||||
|
return instance->isConnected();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile void setMJPEGServerThreadPriority(int32_t priority) {
|
||||||
|
if(mjpegStreamServer != NULL) {
|
||||||
|
mjpegStreamServer->setThreadPriority(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeartBeatServer(int32_t port);
|
||||||
|
virtual ~HeartBeatServer();
|
||||||
|
|
||||||
|
MJPEGStreamServer * getMJPEGServer(){
|
||||||
|
return this->mjpegStreamServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BOOL whileLoop();
|
||||||
|
|
||||||
|
virtual BOOL acceptConnection();
|
||||||
|
|
||||||
|
virtual void onConnectionClosed();
|
||||||
|
|
||||||
|
static HeartBeatServer * instance;
|
||||||
|
MJPEGStreamServerUDP * mjpegStreamServer = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_MJPEG_STREAM_SERVER_H_
|
@ -1,128 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* Copyright (C) 2018 Maschell
|
|
||||||
*
|
|
||||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
||||||
****************************************************************************/
|
|
||||||
#include "MJPEGStreamServer.hpp"
|
|
||||||
#include "turbojpeg.h"
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <utils/logger.h>
|
|
||||||
#include <utils/StringTools.h>
|
|
||||||
#include <coreinit/thread.h>
|
|
||||||
#include <coreinit/time.h>
|
|
||||||
|
|
||||||
OSMessageQueue streamSendQueue __attribute__((section(".data")));
|
|
||||||
OSMessage streamSendQueueMessages[STREAM_SEND_QUEUE_MESSAGE_COUNT] __attribute__((section(".data")));
|
|
||||||
|
|
||||||
MJPEGStreamServer * MJPEGStreamServer::instance = NULL;
|
|
||||||
|
|
||||||
MJPEGStreamServer::MJPEGStreamServer(int32_t port): TCPServer(port,MJPEGStreamServer::getPriority()) {
|
|
||||||
OSInitMessageQueue(&streamSendQueue, streamSendQueueMessages, STREAM_SEND_QUEUE_MESSAGE_COUNT);
|
|
||||||
}
|
|
||||||
|
|
||||||
MJPEGStreamServer::~MJPEGStreamServer() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
The sendwait from <network/net.h> is reaaally slow.
|
|
||||||
**/
|
|
||||||
int32_t mysendwait(int32_t sock, const void *buffer, int32_t len) {
|
|
||||||
int32_t ret;
|
|
||||||
while (len > 0) {
|
|
||||||
ret = send(sock, buffer, len, 0);
|
|
||||||
if(ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
len -= ret;
|
|
||||||
buffer = (void *)(((char *) buffer) + ret);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MJPEGStreamServer::sendJPEG(uint8_t * buffer, uint64_t size) {
|
|
||||||
int32_t clientfd = getClientFD();
|
|
||||||
|
|
||||||
char str[90];
|
|
||||||
snprintf(str, 90, "\r\n--boundary\r\nContent-Type: image/jpeg\r\nContent-Length: %llu \r\n\r\n", size);
|
|
||||||
|
|
||||||
|
|
||||||
mysendwait(clientfd, str, strlen(str));
|
|
||||||
mysendwait(clientfd, buffer, size);
|
|
||||||
|
|
||||||
//DEBUG_FUNCTION_LINE("Send frame\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BOOL MJPEGStreamServer::whileLoop() {
|
|
||||||
int32_t ret;
|
|
||||||
int32_t clientfd = getClientFD();
|
|
||||||
|
|
||||||
OSMessage message;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
ret = checkbyte(clientfd);
|
|
||||||
if (ret < 0) {
|
|
||||||
if(socketlasterr() != 6) {
|
|
||||||
// Ending Server on error.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//DEBUG_FUNCTION_LINE("Waiting\n",message.message,message.data1);
|
|
||||||
while(!OSReceiveMessage(&streamSendQueue,&message,OS_MESSAGE_FLAGS_NONE)) {
|
|
||||||
if(shouldExit()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
OSSleepTicks(OSMicrosecondsToTicks(500));
|
|
||||||
}
|
|
||||||
|
|
||||||
if((uint32_t) message.message == 0xDEADBEEF) {
|
|
||||||
DEBUG_FUNCTION_LINE("We should exit\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
DCFlushRange(&message,sizeof(OSMessage));
|
|
||||||
|
|
||||||
JpegInformation * info = (JpegInformation *) message.args[0];
|
|
||||||
if(info != NULL) {
|
|
||||||
DCFlushRange(info,sizeof(JpegInformation));
|
|
||||||
sendJPEG(info->getBuffer(),info->getSize());
|
|
||||||
delete info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * headerHTTP = "HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=--boundary\r\n";
|
|
||||||
|
|
||||||
BOOL MJPEGStreamServer::acceptConnection() {
|
|
||||||
int32_t clientfd = getClientFD();
|
|
||||||
DEBUG_FUNCTION_LINE("TCP Connection accepted! \n");
|
|
||||||
|
|
||||||
mysendwait(clientfd, headerHTTP, strlen(headerHTTP));
|
|
||||||
|
|
||||||
// Consume the first response of the browser.
|
|
||||||
while(checkbyte(clientfd) > 0);
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Handshake done! Success!\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MJPEGStreamServer::onConnectionClosed() {
|
|
||||||
DEBUG_FUNCTION_LINE("disconnected\n");
|
|
||||||
}
|
|
@ -14,93 +14,19 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifndef _MJPEG_STREAM_SERVER_H_
|
#ifndef _MJPEG_STREAM_SERVER_WINDOW_H_
|
||||||
#define _MJPEG_STREAM_SERVER_H_
|
#define _MJPEG_STREAM_SERVER_WINDOW_H_
|
||||||
|
|
||||||
#include <utils/TCPServer.hpp>
|
|
||||||
#include <network/net.h>
|
|
||||||
#include <coreinit/messagequeue.h>
|
|
||||||
#include "turbojpeg.h"
|
|
||||||
#include "JpegInformation.h"
|
#include "JpegInformation.h"
|
||||||
|
|
||||||
#define STREAM_SEND_QUEUE_MESSAGE_COUNT 1
|
class MJPEGStreamServer {
|
||||||
|
|
||||||
extern OSMessageQueue streamSendQueue;
|
|
||||||
extern OSMessage streamSendQueueMessages[STREAM_SEND_QUEUE_MESSAGE_COUNT];
|
|
||||||
|
|
||||||
extern uint32_t frame_counter_skipped;
|
|
||||||
|
|
||||||
class MJPEGStreamServer: TCPServer {
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static MJPEGStreamServer *getInstance() {
|
MJPEGStreamServer(){
|
||||||
if(!instance) {
|
}
|
||||||
instance = new MJPEGStreamServer(8080);
|
virtual ~MJPEGStreamServer(){
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroyInstance() {
|
virtual bool streamJPEG(JpegInformation * info) = 0;
|
||||||
if(instance) {
|
|
||||||
instance->StopAsyncThread();
|
|
||||||
while(instance->isConnected()) {
|
|
||||||
OSSleepTicks(OSMicrosecondsToTicks(1000));
|
|
||||||
}
|
|
||||||
OSSleepTicks(OSMillisecondsToTicks(500));
|
|
||||||
delete instance;
|
|
||||||
instance = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StopAsyncThread() {
|
|
||||||
DEBUG_FUNCTION_LINE("StopAsyncThread\n");
|
|
||||||
OSMessage message;
|
|
||||||
message.message = (void *)0xDEADBEEF;
|
|
||||||
OSSendMessage(&streamSendQueue,&message,OS_MESSAGE_FLAGS_BLOCKING);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32_t getPriority() {
|
|
||||||
return 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
static volatile bool isInstanceConnected() {
|
|
||||||
if(instance) {
|
|
||||||
return instance->isConnected();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MJPEGStreamServer(int32_t port);
|
|
||||||
|
|
||||||
void sendJPEG(uint8_t * buffer, uint64_t size);
|
|
||||||
|
|
||||||
virtual bool streamJPEG(JpegInformation * info) {
|
|
||||||
if(this->isConnected()) {
|
|
||||||
OSMessage message;
|
|
||||||
message.message = (void *) 0x11111;
|
|
||||||
message.args[0] = (uint32_t) info;
|
|
||||||
if(!OSSendMessage(&streamSendQueue,&message,OS_MESSAGE_FLAGS_NONE)) {
|
|
||||||
frame_counter_skipped++;
|
|
||||||
//DEBUG_FUNCTION_LINE("Dropping frame\n");
|
|
||||||
delete info;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
delete info;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MJPEGStreamServer();
|
|
||||||
|
|
||||||
virtual BOOL whileLoop();
|
|
||||||
|
|
||||||
virtual BOOL acceptConnection();
|
|
||||||
|
|
||||||
virtual void onConnectionClosed();
|
|
||||||
|
|
||||||
static MJPEGStreamServer * instance;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_MJPEG_STREAM_SERVER_H_
|
#endif //_MJPEG_STREAM_SERVER_WINDOW_H_
|
||||||
|
164
src/MJPEGStreamServerUDP.cpp
Normal file
164
src/MJPEGStreamServerUDP.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2016,2017 Maschell
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#include "MJPEGStreamServerUDP.hpp"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "retain_vars.hpp"
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <coreinit/cache.h>
|
||||||
|
#include <nsysnet/socket.h>
|
||||||
|
#include "crc32.h"
|
||||||
|
|
||||||
|
#define MAX_UDP_SIZE 0x578
|
||||||
|
|
||||||
|
extern int frame_counter_skipped;
|
||||||
|
|
||||||
|
MJPEGStreamServerUDP::MJPEGStreamServerUDP(uint32_t ip, int32_t port) {
|
||||||
|
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in connect_addr;
|
||||||
|
memset(&connect_addr, 0, sizeof(struct sockaddr_in));
|
||||||
|
connect_addr.sin_family = AF_INET;
|
||||||
|
connect_addr.sin_port = port;
|
||||||
|
connect_addr.sin_addr.s_addr = ip;
|
||||||
|
|
||||||
|
if(connect(sockfd, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) {
|
||||||
|
socketclose(sockfd);
|
||||||
|
sockfd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
crc32_init(&crc32Buffer);
|
||||||
|
|
||||||
|
OSInitMessageQueue(&dataQueue, dataQueueMessages, DATA_SEND_QUEUE_MESSAGE_COUNT);
|
||||||
|
|
||||||
|
//StartAsyncThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MJPEGStreamServerUDP::StartAsyncThread() {
|
||||||
|
int32_t priority = 31;
|
||||||
|
this->pThread = CThread::create(DoAsyncThread, this, CThread::eAttributeAffCore0 |CThread::eAttributeAffCore2, priority,0x80000);
|
||||||
|
this->pThread->resumeThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MJPEGStreamServerUDP::DoAsyncThread(CThread *thread, void *arg) {
|
||||||
|
MJPEGStreamServerUDP * arg_instance = (MJPEGStreamServerUDP *) arg;
|
||||||
|
return arg_instance->DoAsyncThreadInternal(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
MJPEGStreamServerUDP::~MJPEGStreamServerUDP() {
|
||||||
|
StopAsyncThread();
|
||||||
|
|
||||||
|
OSSleepTicks(OSMillisecondsToTicks(100));
|
||||||
|
|
||||||
|
if(pThread != NULL) {
|
||||||
|
delete pThread;
|
||||||
|
pThread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->sockfd != -1) {
|
||||||
|
socketclose(sockfd);
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE("Thread has been closed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MJPEGStreamServerUDP::DoAsyncThreadInternal(CThread *thread) {
|
||||||
|
OSMessage message;
|
||||||
|
bool breakOut = false;
|
||||||
|
while (1) {
|
||||||
|
if(breakOut) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while(!OSReceiveMessage(&dataQueue,&message,OS_MESSAGE_FLAGS_NONE)) {
|
||||||
|
if(shouldExit) {
|
||||||
|
breakOut = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OSSleepTicks(OSMicrosecondsToTicks(500));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(breakOut) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCFlushRange(&message,sizeof(OSMessage));
|
||||||
|
|
||||||
|
JpegInformation * info = (JpegInformation *) message.args[0];
|
||||||
|
if(info != NULL) {
|
||||||
|
//DEBUG_FUNCTION_LINE("GOT FRAME INFO! %08X\n",info);
|
||||||
|
DCFlushRange(info,sizeof(JpegInformation));
|
||||||
|
sendJPEG(info->getBuffer(),info->getSize());
|
||||||
|
delete info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MJPEGStreamServerUDP::streamJPEGThreaded(JpegInformation * info) {
|
||||||
|
OSMessage message;
|
||||||
|
message.message = (void *) 0x11111;
|
||||||
|
message.args[0] = (uint32_t) info;
|
||||||
|
if(!OSSendMessage(&dataQueue,&message,OS_MESSAGE_FLAGS_NONE)) {
|
||||||
|
frame_counter_skipped++;
|
||||||
|
//DEBUG_FUNCTION_LINE("Dropping frame\n");
|
||||||
|
delete info;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MJPEGStreamServerUDP::streamJPEG(JpegInformation * info) {
|
||||||
|
if(info != NULL) {
|
||||||
|
//return streamJPEGThreaded(info);
|
||||||
|
|
||||||
|
DCFlushRange(info,sizeof(JpegInformation));
|
||||||
|
sendJPEG(info->getBuffer(),info->getSize());
|
||||||
|
delete info;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MJPEGStreamServerUDP::sendJPEG(uint8_t * buffer, uint64_t size) {
|
||||||
|
uint32_t crcValue = crc32_crc(&crc32Buffer,buffer, size);
|
||||||
|
|
||||||
|
sendData((uint8_t*)&crcValue, sizeof(crcValue));
|
||||||
|
sendData((uint8_t*)&size, sizeof(size));
|
||||||
|
sendData((uint8_t*)buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MJPEGStreamServerUDP::sendData(uint8_t * data,int32_t length) {
|
||||||
|
int len = length;
|
||||||
|
int ret = -1;
|
||||||
|
while (len > 0) {
|
||||||
|
int block = len < MAX_UDP_SIZE ? len : MAX_UDP_SIZE; // take max 508 bytes per UDP packet
|
||||||
|
ret = send(sockfd, data, block, 0);
|
||||||
|
|
||||||
|
if(ret < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
len -= ret;
|
||||||
|
data += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
86
src/MJPEGStreamServerUDP.hpp
Normal file
86
src/MJPEGStreamServerUDP.hpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* Copyright (C) 2016,2017 Maschell
|
||||||
|
*
|
||||||
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef _UDPCLIENT_WINDOW_H_
|
||||||
|
#define _UDPCLIENT_WINDOW_H_
|
||||||
|
|
||||||
|
#define DEFAULT_UDP_CLIENT_PORT 9445
|
||||||
|
|
||||||
|
#include <coreinit/messagequeue.h>
|
||||||
|
#include <coreinit/cache.h>
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <system/CThread.h>
|
||||||
|
#include <nsysnet/socket.h>
|
||||||
|
#include "crc32.h"
|
||||||
|
#include "JpegInformation.h"
|
||||||
|
#include "MJPEGStreamServer.hpp"
|
||||||
|
|
||||||
|
#define DATA_SEND_QUEUE_MESSAGE_COUNT 1
|
||||||
|
|
||||||
|
class MJPEGStreamServerUDP : public MJPEGStreamServer {
|
||||||
|
public:
|
||||||
|
~MJPEGStreamServerUDP();
|
||||||
|
|
||||||
|
static MJPEGStreamServerUDP *createInstance(int32_t ip, int32_t port) {
|
||||||
|
return new MJPEGStreamServerUDP(ip, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartAsyncThread();
|
||||||
|
|
||||||
|
static void DoAsyncThread(CThread *thread, void *arg);
|
||||||
|
|
||||||
|
void DoAsyncThreadInternal(CThread *thread);
|
||||||
|
|
||||||
|
void StopAsyncThread() {
|
||||||
|
DEBUG_FUNCTION_LINE("StopAsyncThread\n");
|
||||||
|
shouldExit = true;
|
||||||
|
DCFlushRange((void*) &shouldExit,sizeof(shouldExit));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setThreadPriority(int priority) {
|
||||||
|
if(pThread != NULL) {
|
||||||
|
pThread->setThreadPriority(priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void proccessData(CThread *thread, void *arg);
|
||||||
|
|
||||||
|
bool streamJPEG(JpegInformation * info);
|
||||||
|
|
||||||
|
bool streamJPEGThreaded(JpegInformation * info);
|
||||||
|
|
||||||
|
void sendJPEG(uint8_t * buffer, uint64_t size);
|
||||||
|
|
||||||
|
bool sendData(uint8_t * data,int32_t length);
|
||||||
|
|
||||||
|
volatile int32_t sockfd = -1;
|
||||||
|
|
||||||
|
static MJPEGStreamServerUDP *instance;
|
||||||
|
|
||||||
|
crc32_t crc32Buffer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MJPEGStreamServerUDP(uint32_t ip,int32_t port);
|
||||||
|
|
||||||
|
|
||||||
|
bool shouldExit = false;
|
||||||
|
CThread * pThread = NULL;
|
||||||
|
|
||||||
|
OSMessageQueue dataQueue;
|
||||||
|
OSMessage dataQueueMessages[DATA_SEND_QUEUE_MESSAGE_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_UDPClient_WINDOW_H_
|
37
src/crc32.cpp
Normal file
37
src/crc32.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "crc32.h"
|
||||||
|
|
||||||
|
void crc32_init(crc32_t* crc) {
|
||||||
|
uint32_t v;
|
||||||
|
|
||||||
|
for(int i = 0; i < 256; ++i) {
|
||||||
|
v = i;
|
||||||
|
|
||||||
|
for(int j = 0; j < 8; ++j) {
|
||||||
|
v = (v & 1) ? (CRC32_INITIAL ^ (v >> 1)) : (v >> 1);
|
||||||
|
}
|
||||||
|
crc->table[i] = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crc32_update(crc32_t* c, uint8_t* buf, size_t len) {
|
||||||
|
for(size_t i = 0; i < len; ++i) {
|
||||||
|
c->value = c->table[(c->value ^ buf[i]) & 0xFF] ^ (c->value >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crc32_start(crc32_t* c) {
|
||||||
|
c->value = 0xfffffffful;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t crc32_finalize(crc32_t* c) {
|
||||||
|
return c->value ^ 0xfffffffful;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t crc32_crc(crc32_t* c, uint8_t* buf, size_t len) {
|
||||||
|
crc32_start(c);
|
||||||
|
crc32_update(c, buf, len);
|
||||||
|
return crc32_finalize(c);
|
||||||
|
}
|
18
src/crc32.h
Normal file
18
src/crc32.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __CRC32_H_
|
||||||
|
#define __CRC32_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
typedef struct crc32 {
|
||||||
|
uint32_t table[256];
|
||||||
|
uint32_t value;
|
||||||
|
} crc32_t;
|
||||||
|
|
||||||
|
#define CRC32_INITIAL 0xedb88320
|
||||||
|
|
||||||
|
void crc32_init(crc32_t* crc);
|
||||||
|
|
||||||
|
uint32_t crc32_crc(crc32_t* c, uint8_t* buf, size_t len);
|
||||||
|
|
||||||
|
#endif
|
@ -10,8 +10,11 @@ uint32_t count = 0;
|
|||||||
|
|
||||||
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, int32_t scan_target) {
|
DECL_FUNCTION(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, int32_t scan_target) {
|
||||||
if(gAppStatus == WUPS_APP_STATUS_FOREGROUND) {
|
if(gAppStatus == WUPS_APP_STATUS_FOREGROUND) {
|
||||||
|
int32_t use_scan_target = 4;
|
||||||
if(scan_target == 4 /*&& (count++ % 4 == 0)*/ && colorBuffer != NULL ) {
|
if(gScreen == WUPS_STREAMING_SCREEN_TV){
|
||||||
|
use_scan_target = 1;
|
||||||
|
}
|
||||||
|
if(scan_target == use_scan_target /*&& (count++ % 4 == 0)*/ && colorBuffer != NULL ) {
|
||||||
count = 0;
|
count = 0;
|
||||||
streamVideo((GX2ColorBuffer *)colorBuffer);
|
streamVideo((GX2ColorBuffer *)colorBuffer);
|
||||||
}
|
}
|
||||||
|
29
src/main.cpp
29
src/main.cpp
@ -7,7 +7,8 @@
|
|||||||
#include <utils/logger.h>
|
#include <utils/logger.h>
|
||||||
#include "retain_vars.hpp"
|
#include "retain_vars.hpp"
|
||||||
#include "EncodingHelper.h"
|
#include "EncodingHelper.h"
|
||||||
#include "MJPEGStreamServer.hpp"
|
#include "MJPEGStreamServerUDP.hpp"
|
||||||
|
#include "HeartBeatServer.hpp"
|
||||||
|
|
||||||
// Mandatory plugin information.
|
// Mandatory plugin information.
|
||||||
WUPS_PLUGIN_NAME("Gamepad streaming tool.");
|
WUPS_PLUGIN_NAME("Gamepad streaming tool.");
|
||||||
@ -19,18 +20,25 @@ WUPS_PLUGIN_LICENSE("GPL");
|
|||||||
// Something is using "write"...
|
// Something is using "write"...
|
||||||
WUPS_FS_ACCESS()
|
WUPS_FS_ACCESS()
|
||||||
|
|
||||||
void resolutionChanged(int32_t newResolution) {
|
void resolutionChanged(WUPSConfigItemMultipleValues* configItem, int32_t newResolution) {
|
||||||
DEBUG_FUNCTION_LINE("Resolution changed %d \n",newResolution);
|
DEBUG_FUNCTION_LINE("Resolution changed %d \n",newResolution);
|
||||||
gResolution = newResolution;
|
gResolution = newResolution;
|
||||||
|
|
||||||
// Restart server.
|
// Restart server.
|
||||||
EncodingHelper::destroyInstance();
|
EncodingHelper::destroyInstance();
|
||||||
MJPEGStreamServer::destroyInstance();
|
|
||||||
|
|
||||||
EncodingHelper::getInstance()->StartAsyncThread();
|
EncodingHelper::getInstance()->StartAsyncThread();
|
||||||
MJPEGStreamServer::getInstance();
|
EncodingHelper::getInstance()->setMJPEGStreamServer(HeartBeatServer::getInstance()->getMJPEGServer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void screenChanged(WUPSConfigItemMultipleValues* configItem, int32_t newScreen) {
|
||||||
|
DEBUG_FUNCTION_LINE("Screen changed %d \n",newScreen);
|
||||||
|
gScreen = newScreen;
|
||||||
|
|
||||||
|
// Restart server.
|
||||||
|
EncodingHelper::destroyInstance();
|
||||||
|
EncodingHelper::getInstance()->StartAsyncThread();
|
||||||
|
EncodingHelper::getInstance()->setMJPEGStreamServer(HeartBeatServer::getInstance()->getMJPEGServer());
|
||||||
|
}
|
||||||
|
|
||||||
WUPS_GET_CONFIG() {
|
WUPS_GET_CONFIG() {
|
||||||
WUPSConfig* config = new WUPSConfig("Streaming Plugin");
|
WUPSConfig* config = new WUPSConfig("Streaming Plugin");
|
||||||
@ -41,7 +49,12 @@ WUPS_GET_CONFIG() {
|
|||||||
resolutionValues[WUPS_STREAMING_RESOLUTION_360P] = "360p";
|
resolutionValues[WUPS_STREAMING_RESOLUTION_360P] = "360p";
|
||||||
resolutionValues[WUPS_STREAMING_RESOLUTION_480P] = "480p";
|
resolutionValues[WUPS_STREAMING_RESOLUTION_480P] = "480p";
|
||||||
|
|
||||||
|
std::map<int32_t,std::string> screenValues;
|
||||||
|
screenValues[WUPS_STREAMING_SCREEN_DRC] = "Gamepad";
|
||||||
|
screenValues[WUPS_STREAMING_SCREEN_TV] = "TV";
|
||||||
|
|
||||||
// item Type config id displayed name default value onChangeCallback.
|
// item Type config id displayed name default value onChangeCallback.
|
||||||
|
catOther->addItem(new WUPSConfigItemMultipleValues("screen", "Screen", gScreen, screenValues, screenChanged));
|
||||||
catOther->addItem(new WUPSConfigItemMultipleValues("resolution", "Streaming resolution", gResolution, resolutionValues, resolutionChanged));
|
catOther->addItem(new WUPSConfigItemMultipleValues("resolution", "Streaming resolution", gResolution, resolutionValues, resolutionChanged));
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
@ -61,16 +74,18 @@ ON_APPLICATION_START(my_args) {
|
|||||||
|
|
||||||
gAppStatus = WUPS_APP_STATUS_FOREGROUND;
|
gAppStatus = WUPS_APP_STATUS_FOREGROUND;
|
||||||
|
|
||||||
|
EncodingHelper::destroyInstance();
|
||||||
EncodingHelper::getInstance()->StartAsyncThread();
|
EncodingHelper::getInstance()->StartAsyncThread();
|
||||||
MJPEGStreamServer::getInstance();
|
EncodingHelper::getInstance()->setMJPEGStreamServer(HeartBeatServer::getInstance()->getMJPEGServer());
|
||||||
|
|
||||||
log_init();
|
log_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ON_APP_STATUS_CHANGED(status) {
|
ON_APP_STATUS_CHANGED(status) {
|
||||||
gAppStatus = status;
|
gAppStatus = status;
|
||||||
|
|
||||||
if(status == WUPS_APP_STATUS_CLOSED) {
|
if(status == WUPS_APP_STATUS_CLOSED) {
|
||||||
EncodingHelper::destroyInstance();
|
EncodingHelper::destroyInstance();
|
||||||
MJPEGStreamServer::destroyInstance();
|
HeartBeatServer::destroyInstance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
#include "retain_vars.hpp"
|
#include "retain_vars.hpp"
|
||||||
wups_loader_app_status_t gAppStatus __attribute__((section(".data"))) = WUPS_APP_STATUS_UNKNOWN;
|
wups_loader_app_status_t gAppStatus __attribute__((section(".data"))) = WUPS_APP_STATUS_UNKNOWN;
|
||||||
int32_t gResolution __attribute__((section(".data"))) = WUPS_STREAMING_RESOLUTION_240P;
|
int32_t gResolution __attribute__((section(".data"))) = WUPS_STREAMING_RESOLUTION_240P;
|
||||||
|
int32_t gScreen __attribute__((section(".data"))) = WUPS_STREAMING_SCREEN_DRC;
|
||||||
|
int32_t gSendPriority __attribute__((section(".data"))) = 31;
|
||||||
|
int32_t gEncodePriority __attribute__((section(".data"))) = 31;
|
||||||
|
@ -3,11 +3,18 @@
|
|||||||
|
|
||||||
#include <wups.h>
|
#include <wups.h>
|
||||||
|
|
||||||
|
#define WUPS_STREAMING_SCREEN_DRC 0
|
||||||
|
#define WUPS_STREAMING_SCREEN_TV 1
|
||||||
|
|
||||||
|
|
||||||
#define WUPS_STREAMING_RESOLUTION_240P 1
|
#define WUPS_STREAMING_RESOLUTION_240P 1
|
||||||
#define WUPS_STREAMING_RESOLUTION_360P 2
|
#define WUPS_STREAMING_RESOLUTION_360P 2
|
||||||
#define WUPS_STREAMING_RESOLUTION_480P 3
|
#define WUPS_STREAMING_RESOLUTION_480P 3
|
||||||
|
|
||||||
extern wups_loader_app_status_t gAppStatus;
|
extern wups_loader_app_status_t gAppStatus;
|
||||||
|
extern int32_t gScreen;
|
||||||
extern int32_t gResolution;
|
extern int32_t gResolution;
|
||||||
|
extern int32_t gSendPriority;
|
||||||
|
extern int32_t gEncodePriority;
|
||||||
|
|
||||||
#endif // _RETAINS_VARS_H_
|
#endif // _RETAINS_VARS_H_
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "stream_utils.h"
|
#include "stream_utils.h"
|
||||||
#include "retain_vars.hpp"
|
#include "retain_vars.hpp"
|
||||||
#include "EncodingHelper.h"
|
#include "EncodingHelper.h"
|
||||||
#include "MJPEGStreamServer.hpp"
|
#include "HeartBeatServer.hpp"
|
||||||
#include <fs/FSUtils.h>
|
#include <fs/FSUtils.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ bool streamVideo(GX2ColorBuffer *srcBuffer) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!MJPEGStreamServer::isInstanceConnected()) {
|
if(!HeartBeatServer::isInstanceConnected()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user