diff --git a/Makefile b/Makefile index b268e42..e75dfa0 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ SOURCES = \ input.cpp \ gamepad.cpp \ connectionlistener.cpp \ + viddec.cpp \ # Build rules generated by macros from common.mk: diff --git a/main.cpp b/main.cpp index 1d45e8a..db662b9 100644 --- a/main.cpp +++ b/main.cpp @@ -23,8 +23,6 @@ class MoonlightModule : public pp::Module { }; void MoonlightInstance::OnConnectionStarted(uint32_t unused) { - printf("Connection started\n"); - // Start receiving input events g_Instance->RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE); g_Instance->RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_KEYBOARD); @@ -45,7 +43,8 @@ void* MoonlightInstance::ConnectionThreadFunc(void* context) { err = LiStartConnection(s_Host, &s_StreamConfig, &MoonlightInstance::s_ClCallbacks, - NULL, NULL, + &MoonlightInstance::s_DrCallbacks, + NULL, NULL, 0, 4); if (err != 0) { pp::Var response("Starting connection failed"); @@ -94,6 +93,24 @@ bool MoonlightInstance::Init(uint32_t argc, const char* argn[], const char* argv[]) { g_Instance = this; + + int32_t context_attributes[] = { + PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, + PP_GRAPHICS3DATTRIB_BLUE_SIZE, 8, + PP_GRAPHICS3DATTRIB_GREEN_SIZE, 8, + PP_GRAPHICS3DATTRIB_RED_SIZE, 8, + PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 0, + PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 0, + PP_GRAPHICS3DATTRIB_SAMPLES, 0, + PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, + PP_GRAPHICS3DATTRIB_WIDTH, 500, + PP_GRAPHICS3DATTRIB_HEIGHT, 500, + PP_GRAPHICS3DATTRIB_NONE, + }; + m_Graphics3D = new pp::Graphics3D(this, context_attributes); + assert(!m_Graphics3D->is_null()); + assert(BindGraphics(*m_Graphics3D)); + return true; } diff --git a/moonlight.hpp b/moonlight.hpp index 6f1b86b..3a668a0 100644 --- a/moonlight.hpp +++ b/moonlight.hpp @@ -2,6 +2,8 @@ #include "ppapi/cpp/module.h" #include "ppapi/cpp/var.h" #include "ppapi/cpp/mouse_lock.h" +#include "ppapi/cpp/graphics_3d.h" +#include "ppapi/cpp/video_decoder.h" #include "ppapi/c/ppb_gamepad.h" @@ -13,7 +15,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { public: - explicit MoonlightInstance(PP_Instance instance) : + MoonlightInstance(PP_Instance instance) : pp::Instance(instance), pp::MouseLock(this), m_CallbackFactory(this), @@ -35,31 +37,35 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { void PollGamepads(); void DidLockMouse(int32_t result); - void MouseLockLost(); void OnConnectionStopped(uint32_t unused); - void OnConnectionStarted(uint32_t error); static void* ConnectionThreadFunc(void* context); static void ClStageStarting(int stage); - static void ClStageFailed(int stage, long errorCode); - static void ClConnectionStarted(void); - static void ClConnectionTerminated(long errorCode); - static void ClDisplayMessage(char* message); - static void ClDisplayTransientMessage(char* message); + + void DispatchGetPicture(uint32_t unused); + void PictureReady(int32_t result, PP_VideoPicture picture); + + static void VidDecSetup(int width, int height, int redrawRate, void* context, int drFlags); + static void VidDecCleanup(void); + static int VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit); private: + static CONNECTION_LISTENER_CALLBACKS s_ClCallbacks; + static DECODER_RENDERER_CALLBACKS s_DrCallbacks; + + pp::Graphics3D* m_Graphics3D; + pp::VideoDecoder* m_VideoDecoder; double m_LastPadTimestamps[4]; const PPB_Gamepad* m_GamepadApi; - static CONNECTION_LISTENER_CALLBACKS s_ClCallbacks; pp::CompletionCallbackFactory m_CallbackFactory; bool m_MouseLocked; }; diff --git a/viddec.cpp b/viddec.cpp new file mode 100644 index 0000000..a397ba4 --- /dev/null +++ b/viddec.cpp @@ -0,0 +1,79 @@ +#include "moonlight.hpp" + +#define INITIAL_DECODE_BUFFER_LEN 128 * 1024 + +static unsigned char* s_DecodeBuffer; +static unsigned int s_DecodeBufferLength; + +void MoonlightInstance::VidDecSetup(int width, int height, int redrawRate, void* context, int drFlags) { + g_Instance->m_VideoDecoder = new pp::VideoDecoder(g_Instance); + + s_DecodeBufferLength = INITIAL_DECODE_BUFFER_LEN; + s_DecodeBuffer = (unsigned char *)malloc(s_DecodeBufferLength); + + g_Instance->m_VideoDecoder->Initialize(*g_Instance->m_Graphics3D, + PP_VIDEOPROFILE_H264HIGH, + PP_HARDWAREACCELERATION_ONLY, + 0, + pp::BlockUntilComplete()); + + pp::Module::Get()->core()->CallOnMainThread(0, + g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::DispatchGetPicture)); +} + +void MoonlightInstance::DispatchGetPicture(uint32_t unused) { + // Queue the initial GetPicture callback on the main thread + g_Instance->m_VideoDecoder->GetPicture( + g_Instance->m_CallbackFactory.NewCallbackWithOutput(&MoonlightInstance::PictureReady)); +} + +void MoonlightInstance::VidDecCleanup(void) { + free(s_DecodeBuffer); + delete g_Instance->m_VideoDecoder; +} + +int MoonlightInstance::VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit) { + PLENTRY entry; + unsigned int offset; + + // Resize the decode buffer if needed + if (decodeUnit->fullLength > s_DecodeBufferLength) { + free(s_DecodeBuffer); + s_DecodeBufferLength = decodeUnit->fullLength; + s_DecodeBuffer = (unsigned char *)malloc(s_DecodeBufferLength); + } + + entry = decodeUnit->bufferList; + offset = 0; + while (entry != NULL) { + memcpy(&s_DecodeBuffer[offset], entry->data, entry->length); + offset += entry->length; + + entry = entry->next; + } + + // Start the decoding + g_Instance->m_VideoDecoder->Decode(0, offset, s_DecodeBuffer, pp::BlockUntilComplete()); + + return DR_OK; +} + +void MoonlightInstance::PictureReady(int32_t result, PP_VideoPicture picture) { + if (result == PP_ERROR_ABORTED) { + return; + } + + // FIXME: Draw video + + g_Instance->m_VideoDecoder->RecyclePicture(picture); + + // Queue another callback + g_Instance->m_VideoDecoder->GetPicture( + g_Instance->m_CallbackFactory.NewCallbackWithOutput(&MoonlightInstance::PictureReady)); +} + +DECODER_RENDERER_CALLBACKS MoonlightInstance::s_DrCallbacks = { + MoonlightInstance::VidDecSetup, + MoonlightInstance::VidDecCleanup, + MoonlightInstance::VidDecSubmitDecodeUnit +}; \ No newline at end of file