public void Stop() { checkDisposed(); // Check the player state before attempting anything. if (State == MediaState.Stopped) { return; } // Update the player state. State = MediaState.Stopped; // Wait for the player to end if it's still going. System.Console.Write("Signaled Theora player to stop, waiting..."); timer.Stop(); timer.Reset(); if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } if (previousFrame != IntPtr.Zero) { TheoraPlay.THEORAPLAY_freeVideo(previousFrame); } Video.AttachedToPlayer = false; Video.Dispose(); System.Console.WriteLine(" Done!"); }
public Texture2D GetTexture() { checkDisposed(); // Be sure we can even get something from TheoraPlay... if (State == MediaState.Stopped || Video.theoraDecoder == IntPtr.Zero || TheoraPlay.THEORAPLAY_isInitialized(Video.theoraDecoder) == 0 || TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) == 0) { return(videoTexture); // Screw it, give them the old one. } // Get the latest video frames. bool missedFrame = false; while (nextVideo.playms <= timer.ElapsedMilliseconds && !missedFrame) { currentVideo = nextVideo; IntPtr nextFrame = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); if (nextFrame != IntPtr.Zero) { TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = Video.videoStream; Video.videoStream = nextFrame; nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); missedFrame = false; } else { // Don't mind me, just ignoring that complete failure above! missedFrame = true; } if (TheoraPlay.THEORAPLAY_isDecoding(Video.theoraDecoder) == 0) { // FIXME: This is part of the Duration hack! Video.Duration = new TimeSpan(0, 0, 0, 0, (int)currentVideo.playms); // Stop and reset the timer. If we're looping, the loop will start it again. timer.Stop(); timer.Reset(); // If looping, go back to the start. Otherwise, we'll be exiting. if (IsLooped && State == MediaState.Playing) { // Kill the audio, no matter what. if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } // Free everything and start over. TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = IntPtr.Zero; Video.AttachedToPlayer = false; Video.Dispose(); Video.AttachedToPlayer = true; Video.Initialize(); // Grab the initial audio again. if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0) { InitAudioStream(); } // Grab the initial video again. if (TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) != 0) { currentVideo = TheoraPlay.getVideoFrame(Video.videoStream); previousFrame = Video.videoStream; do { // The decoder miiight not be ready yet. Video.videoStream = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); } while (Video.videoStream == IntPtr.Zero); nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); } // Start! Again! timer.Start(); if (audioStream != null) { audioStream.Play(); } } else { // Stop everything, clean up. We out. State = MediaState.Stopped; if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } TheoraPlay.THEORAPLAY_freeVideo(previousFrame); Video.AttachedToPlayer = false; Video.Dispose(); // We're done, so give them the last frame. return(videoTexture); } } } #if VIDEOPLAYER_OPENGL // Set up an environment to muck about in. GL_pushState(); // Bind our shader program. currentDevice.GLDevice.glUseProgram(shaderProgram); // We're using client-side arrays like CAVEMEN currentDevice.GLDevice.BindVertexBuffer(OpenGLDevice.OpenGLVertexBuffer.NullBuffer); // Set up the vertex pointers/arrays. currentDevice.GLDevice.AttributeEnabled[0] = true; currentDevice.GLDevice.AttributeEnabled[1] = true; for (int i = 2; i < currentDevice.GLDevice.AttributeEnabled.Length; i += 1) { currentDevice.GLDevice.AttributeEnabled[i] = false; } currentDevice.GLDevice.FlushGLVertexAttributes(); currentDevice.GLDevice.VertexAttribPointer( 0, 2, VertexElementFormat.Single, false, 2 * sizeof(float), vertPosPtr ); currentDevice.GLDevice.VertexAttribPointer( 1, 2, VertexElementFormat.Single, false, 2 * sizeof(float), vertTexPtr ); // Bind our target framebuffer. currentDevice.GLDevice.BindDrawFramebuffer(rgbaFramebuffer); // Prepare YUV GL textures with our current frame data currentDevice.GLDevice.glActiveTexture( OpenGLDevice.GLenum.GL_TEXTURE0 ); currentDevice.GLDevice.glBindTexture( OpenGLDevice.GLenum.GL_TEXTURE_2D, yuvTextures[0] ); currentDevice.GLDevice.glTexSubImage2D( OpenGLDevice.GLenum.GL_TEXTURE_2D, 0, 0, 0, (int)currentVideo.width, (int)currentVideo.height, OpenGLDevice.GLenum.GL_LUMINANCE, OpenGLDevice.GLenum.GL_UNSIGNED_BYTE, currentVideo.pixels ); currentDevice.GLDevice.glActiveTexture( OpenGLDevice.GLenum.GL_TEXTURE0 + 1 ); currentDevice.GLDevice.glBindTexture( OpenGLDevice.GLenum.GL_TEXTURE_2D, yuvTextures[1] ); currentDevice.GLDevice.glTexSubImage2D( OpenGLDevice.GLenum.GL_TEXTURE_2D, 0, 0, 0, (int)(currentVideo.width / 2), (int)(currentVideo.height / 2), OpenGLDevice.GLenum.GL_LUMINANCE, OpenGLDevice.GLenum.GL_UNSIGNED_BYTE, new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) ) ); currentDevice.GLDevice.glActiveTexture( OpenGLDevice.GLenum.GL_TEXTURE0 + 2 ); currentDevice.GLDevice.glBindTexture( OpenGLDevice.GLenum.GL_TEXTURE_2D, yuvTextures[2] ); currentDevice.GLDevice.glTexSubImage2D( OpenGLDevice.GLenum.GL_TEXTURE_2D, 0, 0, 0, (int)(currentVideo.width / 2), (int)(currentVideo.height / 2), OpenGLDevice.GLenum.GL_LUMINANCE, OpenGLDevice.GLenum.GL_UNSIGNED_BYTE, new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) + (currentVideo.width / 2 * currentVideo.height / 2) ) ); // Flip the viewport, because loldirectx currentDevice.GLDevice.glViewport( 0, 0, (int)currentVideo.width, (int)currentVideo.height ); // Draw the YUV textures to the framebuffer with our shader. currentDevice.GLDevice.glDrawArrays( OpenGLDevice.GLenum.GL_TRIANGLE_STRIP, 0, 4 ); // Clean up after ourselves. GL_popState(); #else // Just copy it to an array, since it's RGBA anyway. try { byte[] theoraPixels = TheoraPlay.getPixels( currentVideo.pixels, (int)currentVideo.width * (int)currentVideo.height * 4 ); // TexImage2D. videoTexture.SetData <byte>(theoraPixels); } catch (Exception e) { // I hope we've still got something in videoTexture! System.Console.WriteLine( "WARNING: THEORA FRAME COPY FAILED: " + e.Message ); } #endif return(videoTexture); }
public Texture2D GetTexture() { checkDisposed(); // Be sure we can even get something from TheoraPlay... if (State == MediaState.Stopped || Video.theoraDecoder == IntPtr.Zero || TheoraPlay.THEORAPLAY_isInitialized(Video.theoraDecoder) == 0 || TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) == 0) { return(videoTexture); // Screw it, give them the old one. } // Get the latest video frames. bool missedFrame = false; while (nextVideo.playms <= timer.ElapsedMilliseconds && !missedFrame) { currentVideo = nextVideo; IntPtr nextFrame = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); if (nextFrame != IntPtr.Zero) { TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = Video.videoStream; Video.videoStream = nextFrame; nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); missedFrame = false; } else { // Don't mind me, just ignoring that complete failure above! missedFrame = true; } if (TheoraPlay.THEORAPLAY_isDecoding(Video.theoraDecoder) == 0) { // FIXME: This is part of the Duration hack! Video.Duration = new TimeSpan(0, 0, 0, 0, (int)currentVideo.playms); // Stop and reset the timer. If we're looping, the loop will start it again. timer.Stop(); timer.Reset(); // If looping, go back to the start. Otherwise, we'll be exiting. if (IsLooped && State == MediaState.Playing) { // Kill the audio, no matter what. if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } // Free everything and start over. TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = IntPtr.Zero; Video.AttachedToPlayer = false; Video.Dispose(); Video.AttachedToPlayer = true; Video.Initialize(); // Grab the initial audio again. if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0) { InitAudioStream(); } // Grab the initial video again. if (TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) != 0) { currentVideo = TheoraPlay.getVideoFrame(Video.videoStream); previousFrame = Video.videoStream; do { // The decoder miiight not be ready yet. Video.videoStream = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); } while (Video.videoStream == IntPtr.Zero); nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); } // Start! Again! timer.Start(); if (audioStream != null) { audioStream.Play(); } } else { // Stop everything, clean up. We out. State = MediaState.Stopped; if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } TheoraPlay.THEORAPLAY_freeVideo(previousFrame); Video.AttachedToPlayer = false; Video.Dispose(); // We're done, so give them the last frame. return(videoTexture); } } } #if VIDEOPLAYER_OPENGL // Set up an environment to muck about in. GL_pushState(); // Bind our shader program. GL.UseProgram(shaderProgram); // Set up the vertex pointers/arrays. OpenGLDevice.Instance.Attributes[0].CurrentBuffer = int.MaxValue; OpenGLDevice.Instance.Attributes[1].CurrentBuffer = int.MaxValue; GL.VertexAttribPointer( 0, 2, VertexAttribPointerType.Float, false, 2 * sizeof(float), vert_pos ); GL.VertexAttribPointer( 1, 2, VertexAttribPointerType.Float, false, 2 * sizeof(float), vert_tex ); GL.EnableVertexAttribArray(0); GL.EnableVertexAttribArray(1); // Bind our target framebuffer. OpenGLDevice.Framebuffer.BindFramebuffer(rgbaFramebuffer); // Prepare YUV GL textures with our current frame data GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, yuvTextures[0]); GL.TexSubImage2D( TextureTarget.Texture2D, 0, 0, 0, (int)currentVideo.width, (int)currentVideo.height, PixelFormat.Luminance, PixelType.UnsignedByte, currentVideo.pixels ); GL.ActiveTexture(TextureUnit.Texture1); GL.BindTexture(TextureTarget.Texture2D, yuvTextures[1]); GL.TexSubImage2D( TextureTarget.Texture2D, 0, 0, 0, (int)currentVideo.width / 2, (int)currentVideo.height / 2, PixelFormat.Luminance, PixelType.UnsignedByte, new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) ) ); GL.ActiveTexture(TextureUnit.Texture2); GL.BindTexture(TextureTarget.Texture2D, yuvTextures[2]); GL.TexSubImage2D( TextureTarget.Texture2D, 0, 0, 0, (int)currentVideo.width / 2, (int)currentVideo.height / 2, PixelFormat.Luminance, PixelType.UnsignedByte, new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) + (currentVideo.width / 2 * currentVideo.height / 2) ) ); // Flip the viewport, because loldirectx GL.Viewport( 0, 0, (int)currentVideo.width, (int)currentVideo.height ); // Draw the YUV textures to the framebuffer with our shader. GL.DrawArrays(BeginMode.TriangleStrip, 0, 4); // Clean up after ourselves. GL_popState(); #else // Just copy it to an array, since it's RGBA anyway. try { byte[] theoraPixels = TheoraPlay.getPixels( currentVideo.pixels, (int)currentVideo.width * (int)currentVideo.height * 4 ); // TexImage2D. videoTexture.SetData <byte>(theoraPixels); } catch (Exception e) { // I hope we've still got something in videoTexture! System.Console.WriteLine( "WARNING: THEORA FRAME COPY FAILED: " + e.Message ); } #endif return(videoTexture); }
public Texture2D GetTexture() { checkDisposed(); if (Video == null) { throw new InvalidOperationException(); } // Be sure we can even get something from TheoraPlay... if (State == MediaState.Stopped || Video.theoraDecoder == IntPtr.Zero || TheoraPlay.THEORAPLAY_isInitialized(Video.theoraDecoder) == 0 || TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) == 0) { // Screw it, give them the old one. return(videoTexture[0].RenderTarget as Texture2D); } // Get the latest video frames. bool hasFrames = true; while (nextVideo.playms <= timer.ElapsedMilliseconds && hasFrames) { currentVideo = nextVideo; hasFrames = TheoraPlay.THEORAPLAY_availableVideo(Video.theoraDecoder) > 0; if (hasFrames) { IntPtr nextFrame = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = Video.videoStream; Video.videoStream = nextFrame; nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); } } // Check for the end... if (TheoraPlay.THEORAPLAY_isDecoding(Video.theoraDecoder) == 0) { // FIXME: This is part of the Duration hack! if (Video.needsDurationHack) { Video.Duration = new TimeSpan(0, 0, 0, 0, (int)currentVideo.playms); } // Stop and reset the timer. If we're looping, the loop will start it again. timer.Stop(); timer.Reset(); // Kill whatever audio/video we've got if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } TheoraPlay.THEORAPLAY_freeVideo(previousFrame); Video.AttachedToPlayer = false; Video.Dispose(); // If looping, go back to the start. Otherwise, we'll be exiting. if (IsLooped && State == MediaState.Playing) { // Starting over! Video.AttachedToPlayer = true; InitializeTheoraStream(); // Start! Again! timer.Start(); if (audioStream != null) { audioStream.Play(); } } else { // We out, give them the last frame. State = MediaState.Stopped; return(videoTexture[0].RenderTarget as Texture2D); } } // Set up an environment to muck about in. GL_pushState(); // Prepare YUV GL textures with our current frame data currentDevice.GLDevice.SetTextureData2DPointer( yuvTextures[0], currentVideo.pixels ); currentDevice.GLDevice.SetTextureData2DPointer( yuvTextures[1], new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) ) ); currentDevice.GLDevice.SetTextureData2DPointer( yuvTextures[2], new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) + (currentVideo.width / 2 * currentVideo.height / 2) ) ); // Draw the YUV textures to the framebuffer with our shader. currentDevice.DrawPrimitives( PrimitiveType.TriangleStrip, 0, 2 ); // Clean up after ourselves. GL_popState(); // Finally. return(videoTexture[0].RenderTarget as Texture2D); }
public Texture2D GetTexture() { checkDisposed(); // Be sure we can even get something from TheoraPlay... if (State == MediaState.Stopped || Video.theoraDecoder == IntPtr.Zero || TheoraPlay.THEORAPLAY_isInitialized(Video.theoraDecoder) == 0 || TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) == 0) { // Screw it, give them the old one. return(videoTexture[0].RenderTarget as Texture2D); } // Get the latest video frames. bool missedFrame = false; while (nextVideo.playms <= timer.ElapsedMilliseconds && !missedFrame) { currentVideo = nextVideo; IntPtr nextFrame = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); if (nextFrame != IntPtr.Zero) { TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = Video.videoStream; Video.videoStream = nextFrame; nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); missedFrame = false; } else { // Don't mind me, just ignoring that complete failure above! missedFrame = true; } if (TheoraPlay.THEORAPLAY_isDecoding(Video.theoraDecoder) == 0) { // FIXME: This is part of the Duration hack! Video.Duration = new TimeSpan(0, 0, 0, 0, (int)currentVideo.playms); // Stop and reset the timer. If we're looping, the loop will start it again. timer.Stop(); timer.Reset(); // If looping, go back to the start. Otherwise, we'll be exiting. if (IsLooped && State == MediaState.Playing) { // Kill the audio, no matter what. if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } // Free everything and start over. TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = IntPtr.Zero; Video.AttachedToPlayer = false; Video.Dispose(); Video.AttachedToPlayer = true; Video.Initialize(); // Grab the initial audio again. if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0) { InitAudioStream(); } // Grab the initial video again. if (TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) != 0) { currentVideo = TheoraPlay.getVideoFrame(Video.videoStream); previousFrame = Video.videoStream; do { // The decoder miiight not be ready yet. Video.videoStream = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); } while (Video.videoStream == IntPtr.Zero); nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); } // Start! Again! timer.Start(); if (audioStream != null) { audioStream.Play(); } } else { // Stop everything, clean up. We out. State = MediaState.Stopped; if (audioStream != null) { audioStream.Stop(); audioStream.Dispose(); audioStream = null; } TheoraPlay.THEORAPLAY_freeVideo(previousFrame); Video.AttachedToPlayer = false; Video.Dispose(); // We're done, so give them the last frame. return(videoTexture[0].RenderTarget as Texture2D); } } } // Set up an environment to muck about in. GL_pushState(); // Prepare YUV GL textures with our current frame data currentDevice.GLDevice.SetTextureData2DPointer( yuvTextures[0], currentVideo.pixels ); currentDevice.GLDevice.SetTextureData2DPointer( yuvTextures[1], new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) ) ); currentDevice.GLDevice.SetTextureData2DPointer( yuvTextures[2], new IntPtr( currentVideo.pixels.ToInt64() + (currentVideo.width * currentVideo.height) + (currentVideo.width / 2 * currentVideo.height / 2) ) ); // Draw the YUV textures to the framebuffer with our shader. currentDevice.DrawPrimitives( PrimitiveType.TriangleStrip, 0, 2 ); // Clean up after ourselves. GL_popState(); // Finally. return(videoTexture[0].RenderTarget as Texture2D); }
private void RunVideo() { // FIXME: Maybe use an actual thread synchronization technique. while (!audioStarted && State != MediaState.Stopped) { ; } while (State != MediaState.Stopped) { // Someone needs to look at their memory management... if (Game.Instance == null) { System.Console.WriteLine("Game exited before video player! Halting..."); State = MediaState.Stopped; } // Sleep when paused, update the video state when playing. if (State == MediaState.Paused) { // Pause the OpenAL source. if (AL.GetSourceState(audioSourceIndex) == ALSourceState.Playing) { AL.SourcePause(audioSourceIndex); } // Stop the timer in here so we know when we really stopped. if (timer.IsRunning) { timer.Stop(); } // Arbitrarily 1 frame in a 30fps movie. Thread.Sleep(33); } else { // Start the timer, whether we're starting or unpausing. if (!timer.IsRunning) { timer.Start(); } // If we're getting here, we should be playing the audio... if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0) { if (AL.GetSourceState(audioSourceIndex) != ALSourceState.Playing) { AL.SourcePlay(audioSourceIndex); } } // Get the next video from from the decoder, if a stream exists. if (TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) != 0) { // Only step when it's time to do so. if (nextVideo.playms <= timer.ElapsedMilliseconds) { // Wait until GetTexture() is done. // FIXME: Maybe use an actual thread synchronization technique. while (frameLocked) { ; } // Assign the new currentVideo, free the old one. currentVideo = nextVideo; // Get the next frame ready, free the old one. IntPtr oldestFrame = previousFrame; previousFrame = Video.videoStream; Video.videoStream = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); if (Video.videoStream != IntPtr.Zero) { // Assign next frame, if it exists. nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); // Then free the _really_ old frame. TheoraPlay.THEORAPLAY_freeVideo(oldestFrame); } } } // If we're done decoding, we hit the end. if (TheoraPlay.THEORAPLAY_isDecoding(Video.theoraDecoder) == 0) { // FIXME: This is a part of the Duration hack! Video.Duration = new TimeSpan(0, 0, 0, 0, (int)currentVideo.playms); // Stop and reset the timer. // If we're looping, the loop will start it again. timer.Stop(); timer.Reset(); // If looping, go back to the start. Otherwise, we'll be exiting. if (IsLooped && State == MediaState.Playing) { // Wait for the audio thread to end. State = MediaState.Stopped; audioDecoderThread.Join(); // Now we pretend we're playing again. State = MediaState.Playing; // Free everything and start over. TheoraPlay.THEORAPLAY_freeVideo(previousFrame); previousFrame = IntPtr.Zero; Video.Dispose(); Video.Initialize(); // Grab the initial audio again. if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0) { currentAudio = TheoraPlay.getAudioPacket(Video.audioStream); audioDecoderThread = new Thread(new ThreadStart(DecodeAudio)); audioDecoderThread.Start(); } else { audioStarted = true; // Welp. } // Grab the initial video again. if (TheoraPlay.THEORAPLAY_hasVideoStream(Video.theoraDecoder) != 0) { currentVideo = TheoraPlay.getVideoFrame(Video.videoStream); previousFrame = Video.videoStream; do { // The decoder miiight not be ready yet. Video.videoStream = TheoraPlay.THEORAPLAY_getVideo(Video.theoraDecoder); } while (Video.videoStream == IntPtr.Zero); nextVideo = TheoraPlay.getVideoFrame(Video.videoStream); } // FIXME: Maybe use an actual thread synchronization technique. while (!audioStarted && State != MediaState.Stopped) { ; } } else { State = MediaState.Stopped; } } } } // Reset the video timer. timer.Stop(); timer.Reset(); // Stop the decoding, we don't need it anymore. audioDecoderThread.Join(); // We're desperately trying to keep this until the very end. TheoraPlay.THEORAPLAY_freeVideo(previousFrame); // We're not playing any video anymore. Video.Dispose(); }