diff --git a/index.html b/index.html index 3c0419c..ef5dad4 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@ - +
diff --git a/input.cpp b/input.cpp index abb33da..e9ca6bc 100644 --- a/input.cpp +++ b/input.cpp @@ -112,14 +112,25 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) { } case PP_INPUTEVENT_TYPE_WHEEL: { + signed char fullTicks; + if (!m_MouseLocked) { return false; } pp::WheelInputEvent wheelEvent(event); - // FIXME: Handle fractional scroll ticks - LiSendScrollEvent((signed char) wheelEvent.GetTicks().y()); + // Accumulate the current tick value + m_AccumulatedTicks += wheelEvent.GetTicks().y(); + + // Compute the number of full ticks + fullTicks = (signed char) m_AccumulatedTicks; + + // Send a scroll event if we've completed a full tick + if (fullTicks != 0) { + LiSendScrollEvent(fullTicks); + m_AccumulatedTicks -= fullTicks; + } return true; } diff --git a/main.cpp b/main.cpp index 2c6e088..2bc1e8e 100644 --- a/main.cpp +++ b/main.cpp @@ -174,6 +174,9 @@ void MoonlightInstance::handleStartStream(int32_t callbackId, pp::VarArray args) m_StreamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO; m_ServerMajorVersion = 5; + + // Initialize the rendering surface before starting the connection + InitializeRenderingSurface(m_StreamConfig.width, m_StreamConfig.height); // Store the host from the start message m_Host = host; diff --git a/moonlight.hpp b/moonlight.hpp index 20172f9..cafe17e 100644 --- a/moonlight.hpp +++ b/moonlight.hpp @@ -6,6 +6,7 @@ #include "ppapi/cpp/graphics_3d.h" #include "ppapi/cpp/video_decoder.h" #include "ppapi/cpp/audio.h" +#include "ppapi/cpp/text_input_controller.h" #include "ppapi/c/ppb_gamepad.h" #include "ppapi/c/pp_input_event.h" @@ -47,11 +48,14 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { m_MouseLocked(false), m_KeyModifiers(0), m_WaitingForAllModifiersUp(false), + m_AccumulatedTicks(0), openHttpThread(this) { // This function MUST be used otherwise sockets don't work (nacl_io_init() doesn't work!) nacl_io_init_ppapi(pp_instance(), pp::Module::Get()->get_browser_interface()); LiInitializeStreamConfiguration(&m_StreamConfig); + + pp::TextInputController(this).SetTextInputType(PP_TEXTINPUT_TYPE_NONE); m_GamepadApi = static_cast(pp::Module::Get()->GetBrowserInterface(PPB_GAMEPAD_INTERFACE)); @@ -102,6 +106,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { void DispatchGetPicture(uint32_t unused); void PictureReady(int32_t result, PP_VideoPicture picture); void PaintPicture(void); + void InitializeRenderingSurface(int width, int height); static void VidDecSetup(int width, int height, int redrawRate, void* context, int drFlags); static void VidDecCleanup(void); @@ -132,7 +137,6 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { pp::Graphics3D m_Graphics3D; pp::VideoDecoder* m_VideoDecoder; - pp::Size m_ViewSize; Shader m_Texture2DShader; Shader m_RectangleArbShader; Shader m_ExternalOesShader; @@ -149,7 +153,8 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock { bool m_MouseLocked; char m_KeyModifiers; bool m_WaitingForAllModifiersUp; - + float m_AccumulatedTicks; + pp::SimpleThread openHttpThread; }; diff --git a/viddec.cpp b/viddec.cpp index 8b87e14..39c2168 100644 --- a/viddec.cpp +++ b/viddec.cpp @@ -13,6 +13,8 @@ static unsigned char* s_DecodeBuffer; static unsigned int s_DecodeBufferLength; static int s_LastTextureType; static int s_LastTextureId; +static int s_NextDecodeFrameNumber; +static int s_LastDisplayFrameNumber; static unsigned char s_LastSps[256]; static unsigned char s_LastPps[256]; static unsigned int s_LastSpsLength; @@ -68,39 +70,27 @@ void MoonlightInstance::DidChangeFocus(bool got_focus) { } } -void MoonlightInstance::DidChangeView(const pp::Rect& position, - const pp::Rect& clip) { - - if (position.width() == 0 || position.height() == 0) { - return; - } - if (m_ViewSize.width()) { - assert(position.size() == m_ViewSize); - return; - } - - m_ViewSize = position.size(); - printf("View size: %dx%d\n", m_ViewSize.width(), m_ViewSize.height()); - +void MoonlightInstance::InitializeRenderingSurface(int width, int height) { if (!glInitializePPAPI(pp::Module::Get()->get_browser_interface())) { return; } int32_t contextAttributes[] = { - 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, position.size().width(), - PP_GRAPHICS3DATTRIB_HEIGHT, position.size().height(), + PP_GRAPHICS3DATTRIB_WIDTH, width, + PP_GRAPHICS3DATTRIB_HEIGHT, height, PP_GRAPHICS3DATTRIB_NONE }; g_Instance->m_Graphics3D = pp::Graphics3D(this, contextAttributes); + int32_t swapBehaviorAttribute[] = { + PP_GRAPHICS3DATTRIB_SWAP_BEHAVIOR, PP_GRAPHICS3DATTRIB_BUFFER_DESTROYED, + PP_GRAPHICS3DATTRIB_NONE + }; + g_Instance->m_Graphics3D.SetAttribs(swapBehaviorAttribute); + if (!BindGraphics(m_Graphics3D)) { fprintf(stderr, "Unable to bind 3d context!\n"); m_Graphics3D = pp::Graphics3D(); @@ -112,7 +102,7 @@ void MoonlightInstance::DidChangeView(const pp::Rect& position, glDisable(GL_DITHER); - glViewport(0, 0, m_ViewSize.width(), m_ViewSize.height()); + glViewport(0, 0, width, height); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -146,6 +136,8 @@ void MoonlightInstance::VidDecSetup(int width, int height, int redrawRate, void* s_LastTextureId = 0; s_LastSpsLength = 0; s_LastPpsLength = 0; + s_NextDecodeFrameNumber = 0; + s_LastDisplayFrameNumber = 0; g_Instance->m_VideoDecoder->Initialize(g_Instance->m_Graphics3D, PP_VIDEOPROFILE_H264HIGH, @@ -284,7 +276,7 @@ int MoonlightInstance::VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit) { } // Start the decoding - g_Instance->m_VideoDecoder->Decode(0, offset, s_DecodeBuffer, pp::BlockUntilComplete()); + g_Instance->m_VideoDecoder->Decode(s_NextDecodeFrameNumber++, offset, s_DecodeBuffer, pp::BlockUntilComplete()); return DR_OK; } @@ -415,12 +407,21 @@ void MoonlightInstance::PictureReady(int32_t result, PP_VideoPicture picture) { return; } - m_PendingPictureQueue.push(picture); + // Ensure we only push newer frames onto the display queue + if (picture.decode_id > s_LastDisplayFrameNumber) { + m_PendingPictureQueue.push(picture); + s_LastDisplayFrameNumber = picture.decode_id; + } + else { + // This picture is older than the last one we displayed. Discard + // it without displaying. + g_Instance->m_VideoDecoder->RecyclePicture(picture); + } g_Instance->m_VideoDecoder->GetPicture( g_Instance->m_CallbackFactory.NewCallbackWithOutput(&MoonlightInstance::PictureReady)); - if (!m_IsPainting) { + if (!m_IsPainting && !m_PendingPictureQueue.empty()) { PaintPicture(); } }