Exemple #1
0
        private void InitAudioStream()
        {
            // The number of buffers to queue into the source.
            const int NUM_BUFFERS = 4;

            // Generate the source.
            IntPtr audioPtr = IntPtr.Zero;

            do
            {
                audioPtr = TheoraPlay.THEORAPLAY_getAudio(Video.theoraDecoder);
            } while (audioPtr == IntPtr.Zero);
            TheoraPlay.THEORAPLAY_AudioPacket packet = TheoraPlay.getAudioPacket(audioPtr);
            audioStream = new DynamicSoundEffectInstance(
                packet.freq,
                (AudioChannels)packet.channels
                );
            audioStream.BufferNeeded += OnBufferRequest;
            UpdateVolume();

            // Fill and queue the buffers.
            for (int i = 0; i < NUM_BUFFERS; i += 1)
            {
                if (!StreamAudio())
                {
                    break;
                }
            }
        }
Exemple #2
0
        private bool StreamAudio(int buffer)
        {
            // The size of our abstracted buffer.
            const int BUFFER_SIZE = 4096 * 2;

            // Store our abstracted buffer into here.
            List <float> data = new List <float>();

            // Be sure we have an audio stream first!
            if (Video.audioStream == IntPtr.Zero)
            {
                return(false); // NOPE
            }

            // Add to the buffer from the decoder until it's large enough.
            while (data.Count < BUFFER_SIZE && State != MediaState.Stopped)
            {
                data.AddRange(
                    TheoraPlay.getSamples(
                        currentAudio.samples,
                        currentAudio.frames * currentAudio.channels
                        )
                    );

                // We've copied the audio, so free this.
                TheoraPlay.THEORAPLAY_freeAudio(Video.audioStream);

                do
                {
                    Video.audioStream = TheoraPlay.THEORAPLAY_getAudio(Video.theoraDecoder);
                    if (State == MediaState.Stopped)
                    {
                        // Screw it, just bail out ASAP.
                        return(false);
                    }
                } while (Video.audioStream == IntPtr.Zero);
                currentAudio = TheoraPlay.getAudioPacket(Video.audioStream);

                if ((BUFFER_SIZE - data.Count) < 4096)
                {
                    break;
                }
            }

            // If we actually got data, buffer it into OpenAL.
            if (data.Count > 0)
            {
                AL.BufferData(
                    buffer,
                    (currentAudio.channels == 2) ? ALFormat.StereoFloat32Ext : ALFormat.MonoFloat32Ext,
                    data.ToArray(),
                    data.Count * 2 * currentAudio.channels, // Dear OpenAL: WTF?! Love, flibit
                    currentAudio.freq
                    );
                return(true);
            }
            return(false);
        }
Exemple #3
0
        private void InitializeTheoraStream()
        {
            // Start the video if it hasn't been yet.
            if (Video.IsDisposed)
            {
                Video.Initialize();
            }

            // Grab the first bit of audio. We're trying to start the decoding ASAP.
            if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0)
            {
                // Generate the source.
                IntPtr audioPtr = IntPtr.Zero;
                do
                {
                    // The decoder miiight not be ready yet.
                    audioPtr = TheoraPlay.THEORAPLAY_getAudio(Video.theoraDecoder);
                } while (audioPtr == IntPtr.Zero);
                TheoraPlay.THEORAPLAY_AudioPacket packet = TheoraPlay.getAudioPacket(audioPtr);
                audioStream = new DynamicSoundEffectInstance(
                    packet.freq,
                    (AudioChannels)packet.channels
                    );
                audioStream.BufferNeeded += OnBufferRequest;
                UpdateVolume();

                // Fill and queue the buffers.
                for (int i = 0; i < 4; i += 1)
                {
                    if (!StreamAudio())
                    {
                        break;
                    }
                }
            }

            // Grab the first bit of video.
            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);
            }
        }
Exemple #4
0
        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();
        }
Exemple #5
0
        public void Play(Video video)
        {
            checkDisposed();

            // We need to assign this regardless of what happens next.
            Video = video;

            // FIXME: This is a part of the Duration hack!
            Video.Duration = TimeSpan.MaxValue;

            // Check the player state before attempting anything.
            if (State != MediaState.Stopped)
            {
                return;
            }

            // In rare cases, the thread might still be going. Wait until it's done.
            if (playerThread != null && playerThread.IsAlive)
            {
                Stop();
            }

            // Create new Thread instances in case we use this player multiple times.
            playerThread       = new Thread(new ThreadStart(this.RunVideo));
            audioDecoderThread = new Thread(new ThreadStart(this.DecodeAudio));

            // Update the player state now, for the thread we're about to make.
            State = MediaState.Playing;

            // Start the video if it hasn't been yet.
            if (Video.IsDisposed)
            {
                video.Initialize();
            }

            // Grab the first bit of audio. We're trying to start the decoding ASAP.
            if (TheoraPlay.THEORAPLAY_hasAudioStream(Video.theoraDecoder) != 0)
            {
                currentAudio = TheoraPlay.getAudioPacket(Video.audioStream);
                audioDecoderThread.Start();
            }
            else
            {
                audioStarted = true; // Welp.
            }

            // Grab the first bit of video, set up the texture.
            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);

                Texture2D overlap = videoTexture;
                videoTexture = new Texture2D(
                    Game.Instance.GraphicsDevice,
                    (int)currentVideo.width,
                    (int)currentVideo.height,
                    false,
                    SurfaceFormat.Color
                    );
                overlap.Dispose();
#if VIDEOPLAYER_OPENGL
                GL_setupTargets(
                    (int)currentVideo.width,
                    (int)currentVideo.height
                    );
#endif
            }

            // Initialize the thread!
            System.Console.Write("Starting Theora player...");
            playerThread.Start();
            System.Console.Write(" Waiting for initialization...");
            while (!playerThread.IsAlive)
            {
                ;
            }
            System.Console.WriteLine(" Done!");
        }