98e6c6d1 |
1 | // Created by: Kirill GAVRILOV |
2 | // Copyright (c) 2019 OPEN CASCADE SAS |
3 | // |
4 | // This file is part of Open CASCADE Technology software library. |
5 | // |
6 | // This library is free software; you can redistribute it and/or modify it under |
7 | // the terms of the GNU Lesser General Public License version 2.1 as published |
8 | // by the Free Software Foundation, with special exception defined in the file |
9 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
10 | // distribution for complete text of the license and disclaimer of any warranty. |
11 | // |
12 | // Alternatively, this file may be used under the terms of Open CASCADE |
13 | // commercial license or contractual agreement. |
14 | |
15 | // activate some C99 macros like UINT64_C in "stdint.h" which used by FFmpeg |
16 | #ifndef __STDC_CONSTANT_MACROS |
17 | #define __STDC_CONSTANT_MACROS |
18 | #endif |
19 | |
20 | #include <Graphic3d_MediaTextureSet.hxx> |
21 | |
22 | #include <Media_Frame.hxx> |
23 | #include <Media_PlayerContext.hxx> |
24 | #include <Graphic3d_ShaderProgram.hxx> |
25 | |
26 | #ifdef HAVE_FFMPEG |
27 | #include <Standard_WarningsDisable.hxx> |
28 | extern "C" |
29 | { |
30 | #include <libavcodec/avcodec.h> |
31 | #include <libavutil/imgutils.h> |
32 | }; |
33 | #include <Standard_WarningsRestore.hxx> |
34 | #endif |
35 | |
36 | IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_MediaTextureSet, Graphic3d_TextureSet) |
37 | |
38 | // ================================================================ |
39 | // Function : Graphic3d_MediaTexture |
40 | // Purpose : |
41 | // ================================================================ |
42 | Graphic3d_MediaTextureSet::Graphic3d_MediaTextureSet() |
43 | : Graphic3d_TextureSet (4), |
44 | myMutex (new Media_HMutex()), |
45 | myCallbackFunction(NULL), |
46 | myCallbackUserPtr (NULL), |
47 | myProgress (0.0), |
48 | myDuration (0.0), |
49 | myFront (0), |
50 | myToPresentFrame (Standard_False), |
51 | myIsPlanarYUV (Standard_False), |
52 | myIsFullRangeYUV (Standard_True) |
53 | { |
54 | myFramePair[0] = new Media_Frame(); |
55 | myFramePair[1] = new Media_Frame(); |
56 | |
57 | for (Standard_Integer aPlaneIter = 0; aPlaneIter < Size(); ++aPlaneIter) |
58 | { |
59 | Handle(Graphic3d_MediaTexture) aTexture = new Graphic3d_MediaTexture (myMutex, aPlaneIter); |
60 | SetValue (Lower() + aPlaneIter, aTexture); |
61 | } |
62 | |
63 | #define EOL "\n" |
64 | TCollection_AsciiString aSrcVert = |
65 | EOL"out vec2 TexCoord;" |
66 | EOL"void main()" |
67 | EOL"{" |
68 | EOL" TexCoord = occTexCoord.st;" |
69 | EOL " gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;" |
70 | EOL"}"; |
71 | |
72 | TCollection_AsciiString F_SHADER_YUV2RGB_MPEG = |
73 | EOL"const float TheRangeBits = 1.0;" |
74 | EOL"vec3 convertToRGB (in vec3 theYUV)" |
75 | EOL"{" |
76 | EOL" vec3 aYUV = theYUV.rgb;" |
77 | EOL" aYUV *= TheRangeBits;" |
78 | EOL" aYUV.x = 1.1643 * (aYUV.x - 0.0625);" |
79 | EOL" aYUV.y -= 0.5;" |
80 | EOL" aYUV.z -= 0.5;" |
81 | EOL" vec3 aColor = vec3(0.0);" |
82 | EOL" aColor.r = aYUV.x + 1.5958 * aYUV.z;" |
83 | EOL" aColor.g = aYUV.x - 0.39173 * aYUV.y - 0.81290 * aYUV.z;" |
84 | EOL" aColor.b = aYUV.x + 2.017 * aYUV.y;" |
85 | EOL" return aColor;" |
86 | EOL"}"; |
87 | |
88 | TCollection_AsciiString F_SHADER_YUV2RGB_FULL = |
89 | EOL"const float TheRangeBits = 1.0;" |
90 | EOL"vec3 convertToRGB (in vec3 theYUV)" |
91 | EOL"{" |
92 | EOL" vec3 aYUV = theYUV.rgb;" |
93 | EOL" aYUV *= TheRangeBits;" |
94 | EOL" aYUV.x = aYUV.x;" |
95 | EOL" aYUV.y -= 0.5;" |
96 | EOL" aYUV.z -= 0.5;" |
97 | EOL" vec3 aColor = vec3(0.0);" |
98 | EOL" aColor.r = aYUV.x + 1.402 * aYUV.z;" |
99 | EOL" aColor.g = aYUV.x - 0.344 * aYUV.y - 0.714 * aYUV.z;" |
100 | EOL" aColor.b = aYUV.x + 1.772 * aYUV.y;" |
101 | EOL" return aColor;" |
102 | EOL"}"; |
103 | |
104 | TCollection_AsciiString aSrcFrag = |
105 | EOL"in vec2 TexCoord;" |
106 | EOL"uniform sampler2D occSampler1;" |
107 | EOL"uniform sampler2D occSampler2;" |
108 | EOL"vec3 convertToRGB (in vec3 theYUV);" |
109 | EOL"void main()" |
110 | EOL"{" |
111 | EOL" vec3 aYUV = vec3 (occTexture2D (occSampler0, TexCoord.st).r," |
112 | EOL" occTexture2D (occSampler1, TexCoord.st).r," |
113 | EOL" occTexture2D (occSampler2, TexCoord.st).r);" |
114 | EOL " occSetFragColor (vec4 (convertToRGB (aYUV), 1.0));" |
115 | EOL"}"; |
116 | |
117 | myShaderYUV = new Graphic3d_ShaderProgram(); |
118 | myShaderYUV->SetHeader ("#version 150"); |
119 | myShaderYUV->SetNbLightsMax (0); |
120 | myShaderYUV->SetNbClipPlanesMax (0); |
121 | myShaderYUV->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX, aSrcVert)); |
122 | myShaderYUV->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag + F_SHADER_YUV2RGB_MPEG)); |
123 | |
124 | myShaderYUVJ = new Graphic3d_ShaderProgram(); |
125 | myShaderYUVJ->SetHeader ("#version 150"); |
126 | myShaderYUVJ->SetNbLightsMax (0); |
127 | myShaderYUVJ->SetNbClipPlanesMax (0); |
128 | myShaderYUVJ->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX, aSrcVert)); |
129 | myShaderYUVJ->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag + F_SHADER_YUV2RGB_FULL)); |
130 | } |
131 | |
132 | // ======================================================================= |
133 | // function : SetCallback |
134 | // purpose : |
135 | // ======================================================================= |
136 | void Graphic3d_MediaTextureSet::SetCallback (CallbackOnUpdate_t theCallbackFunction, |
137 | void* theCallbackUserPtr) |
138 | { |
139 | myCallbackFunction = theCallbackFunction; |
140 | myCallbackUserPtr = theCallbackUserPtr; |
141 | } |
142 | |
143 | // ======================================================================= |
144 | // function : Notify |
145 | // purpose : |
146 | // ======================================================================= |
147 | void Graphic3d_MediaTextureSet::Notify() |
148 | { |
149 | if (myCallbackFunction != NULL) |
150 | { |
151 | myCallbackFunction (myCallbackUserPtr); |
152 | } |
153 | } |
154 | |
155 | // ======================================================================= |
156 | // function : OpenInput |
157 | // purpose : |
158 | // ======================================================================= |
159 | void Graphic3d_MediaTextureSet::OpenInput (const TCollection_AsciiString& thePath, |
160 | Standard_Boolean theToWait) |
161 | { |
162 | if (myPlayerCtx.IsNull()) |
163 | { |
164 | if (thePath.IsEmpty()) |
165 | { |
166 | myInput.Clear(); |
167 | return; |
168 | } |
169 | |
170 | myPlayerCtx = new Media_PlayerContext (this); |
171 | } |
172 | |
173 | myProgress = 0.0; |
174 | myDuration = 0.0; |
175 | |
176 | myPlayerCtx->SetInput (thePath, theToWait); |
177 | myInput = thePath; |
178 | } |
179 | |
180 | // ======================================================================= |
181 | // function : LockFrame |
182 | // purpose : |
183 | // ======================================================================= |
184 | Handle(Media_Frame) Graphic3d_MediaTextureSet::LockFrame() |
185 | { |
186 | { |
187 | Standard_Mutex::Sentry aLock (myMutex.get()); |
188 | if (!myToPresentFrame) |
189 | { |
190 | Handle(Media_Frame) aFrame = myFramePair[myFront == 0 ? 1 : 0]; |
191 | if (aFrame->IsLocked()) |
192 | { |
193 | return Handle(Media_Frame)(); |
194 | } |
195 | |
196 | aFrame->SetLocked (true); |
197 | return aFrame; |
198 | } |
199 | } |
200 | |
201 | Notify(); |
202 | return Handle(Media_Frame)(); |
203 | } |
204 | |
205 | // ======================================================================= |
206 | // function : ReleaseFrame |
207 | // purpose : |
208 | // ======================================================================= |
209 | void Graphic3d_MediaTextureSet::ReleaseFrame (const Handle(Media_Frame)& theFrame) |
210 | { |
211 | { |
212 | Standard_Mutex::Sentry aLock (myMutex.get()); |
213 | theFrame->SetLocked (false); |
214 | myToPresentFrame = true; |
215 | } |
216 | |
217 | if (myCallbackFunction != NULL) |
218 | { |
219 | myCallbackFunction (myCallbackUserPtr); |
220 | } |
221 | } |
222 | |
223 | // ================================================================ |
224 | // Function : SwapFrames |
225 | // Purpose : |
226 | // ================================================================ |
227 | Standard_Boolean Graphic3d_MediaTextureSet::SwapFrames() |
228 | { |
229 | if (myPlayerCtx.IsNull()) |
230 | { |
231 | return Standard_False; |
232 | } |
233 | Standard_Boolean isPaused = Standard_False; |
234 | myPlayerCtx->PlaybackState (isPaused, myProgress, myDuration); |
235 | |
236 | Standard_Mutex::Sentry aLock (myMutex.get()); |
237 | if (!myToPresentFrame) |
238 | { |
239 | return Standard_False; |
240 | } |
241 | |
242 | myToPresentFrame = false; |
243 | myFront = myFront == 0 ? 1 : 0; |
244 | const Handle(Media_Frame)& aFront = myFramePair[myFront]; |
245 | myFrameSize = aFront->Size(); |
246 | #ifdef HAVE_FFMPEG |
247 | myIsPlanarYUV = aFront->Format() == AV_PIX_FMT_YUV420P |
248 | || aFront->Format() == AV_PIX_FMT_YUVJ420P; |
249 | #endif |
250 | myIsFullRangeYUV = aFront->IsFullRangeYUV(); |
251 | for (int aPlaneIter = Lower(); aPlaneIter <= Upper(); ++aPlaneIter) |
252 | { |
253 | if (Graphic3d_MediaTexture* aTexture = dynamic_cast<Graphic3d_MediaTexture*> (Value (aPlaneIter).get())) |
254 | { |
255 | aTexture->SetFrame (aFront); |
256 | aTexture->UpdateRevision(); |
257 | } |
258 | } |
259 | return Standard_True; |
260 | } |