fna-workbench

fna-workbench Git Source Tree


Root/src/Media/Xiph/Video.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
 * Copyright 2009-2016 Ethan Lee and the MonoGame Team
 *
 * Released under the Microsoft Public License.
 * See LICENSE for details.
 */
#endregion
 
#region Using Statements
using System;
using System.IO;
using System.Threading;
#endregion
 
namespace Microsoft.Xna.Framework.Media
{
    public sealed class Video
    {
        #region Public Properties
 
        public int Width
        {
            get;
            private set;
        }
 
        public int Height
        {
            get;
            private set;
        }
 
        public float FramesPerSecond
        {
            get;
            internal set;
        }
 
        public VideoSoundtrackType VideoSoundtrackType
        {
            get;
            private set;
        }
 
        // FIXME: This is hacked, look up "This is a part of the Duration hack!"
        public TimeSpan Duration
        {
            get;
            internal set;
        }
 
        #endregion
 
        #region Internal Properties
 
        internal bool IsDisposed
        {
            get;
            private set;
        }
 
        internal bool AttachedToPlayer
        {
            get;
            set;
        }
 
        #endregion
 
        #region Internal Variables: TheoraPlay
 
        internal IntPtr theoraDecoder;
        internal IntPtr videoStream;
 
        #endregion
 
        #region Private Variables
 
        private string fileName;
 
        #endregion
 
        #region Internal Constructors
 
        internal Video(string fileName)
        {
            this.fileName = fileName;
 
            // Set everything to NULL. Yes, this actually matters later.
            theoraDecoder = IntPtr.Zero;
            videoStream = IntPtr.Zero;
 
            // Initialize the decoder nice and early...
            IsDisposed = true;
            AttachedToPlayer = false;
            Initialize();
 
            // FIXME: This is a part of the Duration hack!
            Duration = TimeSpan.MaxValue;
        }
 
        internal Video(
            string fileName,
            int durationMS,
            int width,
            int height,
            float framesPerSecond,
            VideoSoundtrackType soundtrackType
        ) : this(fileName) {
            /* If you got here, you've still got the XNB file! Well done!
             * Except if you're running FNA, you're not using the WMV anymore.
             * But surely it's the same video, right...?
             * Well, consider this a check more than anything. If this bothers
             * you, just remove the XNB file and we'll read the OGV straight up.
             * -flibit
             */
            if (width != Width || height != Height)
            {
                throw new InvalidOperationException("XNB/OGV width/height mismatch!");
            }
            if (Math.Abs(FramesPerSecond - framesPerSecond) >= 1.0f)
            {
                throw new InvalidOperationException("XNB/OGV framesPerSecond mismatch!");
            }
 
            // FIXME: Oh, hey! I wish we had this info in TheoraPlay!
            Duration = TimeSpan.FromMilliseconds(durationMS);
 
            VideoSoundtrackType = soundtrackType;
        }
 
        #endregion
 
        #region Internal Dispose Method
 
        internal void Dispose()
        {
            if (AttachedToPlayer)
            {
                return; // NOPE. VideoPlayer will do the honors.
            }
 
            // Stop and unassign the decoder.
            if (theoraDecoder != IntPtr.Zero)
            {
                TheoraPlay.THEORAPLAY_stopDecode(theoraDecoder);
                theoraDecoder = IntPtr.Zero;
            }
 
            // Free and unassign the video stream.
            if (videoStream != IntPtr.Zero)
            {
                TheoraPlay.THEORAPLAY_freeVideo(videoStream);
                videoStream = IntPtr.Zero;
            }
 
            IsDisposed = true;
        }
 
        #endregion
 
        #region Internal TheoraPlay Initialization
 
        internal void Initialize()
        {
            if (!IsDisposed)
            {
                Dispose(); // We need to start from the beginning, don't we? :P
            }
 
            // Initialize the decoder.
            theoraDecoder = TheoraPlay.THEORAPLAY_startDecodeFile(
                fileName,
                150, // Max frames to buffer.  Arbitrarily set 5 seconds, assuming 30fps.
                TheoraPlay.THEORAPLAY_VideoFormat.THEORAPLAY_VIDFMT_IYUV
            );
 
            // Wait until the decoder is ready.
            while (TheoraPlay.THEORAPLAY_isInitialized(theoraDecoder) == 0)
            {
                Thread.Sleep(10);
            }
 
            // Initialize the video stream pointer and get our first frame.
            if (TheoraPlay.THEORAPLAY_hasVideoStream(theoraDecoder) != 0)
            {
                while (videoStream == IntPtr.Zero)
                {
                    videoStream = TheoraPlay.THEORAPLAY_getVideo(theoraDecoder);
                    Thread.Sleep(10);
                }
 
                TheoraPlay.THEORAPLAY_VideoFrame frame = TheoraPlay.getVideoFrame(videoStream);
 
                // We get the FramesPerSecond from the first frame.
                FramesPerSecond = (float) frame.fps;
                Width = (int) frame.width;
                Height = (int) frame.height;
            }
 
            IsDisposed = false;
        }
 
        #endregion
    }
}

Archive Download this file

Branches

Number of commits:
Page rendered in 0.10805s using 11 queries.