// Created by: Kirill GAVRILOV // Copyright (c) 2019 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. // activate some C99 macros like UINT64_C in "stdint.h" which used by FFmpeg #ifndef __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS #endif #include #include #include #include #ifdef HAVE_FFMPEG #include extern "C" { #include #include }; #include #endif IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_MediaTextureSet, Graphic3d_TextureSet) // ================================================================ // Function : Graphic3d_MediaTexture // Purpose : // ================================================================ Graphic3d_MediaTextureSet::Graphic3d_MediaTextureSet() : Graphic3d_TextureSet (4), myMutex (new Media_HMutex()), myCallbackFunction(NULL), myCallbackUserPtr (NULL), myProgress (0.0), myDuration (0.0), myFront (0), myToPresentFrame (Standard_False), myIsPlanarYUV (Standard_False), myIsFullRangeYUV (Standard_True) { myFramePair[0] = new Media_Frame(); myFramePair[1] = new Media_Frame(); for (Standard_Integer aPlaneIter = 0; aPlaneIter < Size(); ++aPlaneIter) { Handle(Graphic3d_MediaTexture) aTexture = new Graphic3d_MediaTexture (myMutex, aPlaneIter); SetValue (Lower() + aPlaneIter, aTexture); } #define EOL "\n" TCollection_AsciiString aSrcVert = EOL"out vec2 TexCoord;" EOL"void main()" EOL"{" EOL" TexCoord = occTexCoord.st;" EOL " gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;" EOL"}"; TCollection_AsciiString F_SHADER_YUV2RGB_MPEG = EOL"const float TheRangeBits = 1.0;" EOL"vec3 convertToRGB (in vec3 theYUV)" EOL"{" EOL" vec3 aYUV = theYUV.rgb;" EOL" aYUV *= TheRangeBits;" EOL" aYUV.x = 1.1643 * (aYUV.x - 0.0625);" EOL" aYUV.y -= 0.5;" EOL" aYUV.z -= 0.5;" EOL" vec3 aColor = vec3(0.0);" EOL" aColor.r = aYUV.x + 1.5958 * aYUV.z;" EOL" aColor.g = aYUV.x - 0.39173 * aYUV.y - 0.81290 * aYUV.z;" EOL" aColor.b = aYUV.x + 2.017 * aYUV.y;" EOL" return aColor;" EOL"}"; TCollection_AsciiString F_SHADER_YUV2RGB_FULL = EOL"const float TheRangeBits = 1.0;" EOL"vec3 convertToRGB (in vec3 theYUV)" EOL"{" EOL" vec3 aYUV = theYUV.rgb;" EOL" aYUV *= TheRangeBits;" EOL" aYUV.x = aYUV.x;" EOL" aYUV.y -= 0.5;" EOL" aYUV.z -= 0.5;" EOL" vec3 aColor = vec3(0.0);" EOL" aColor.r = aYUV.x + 1.402 * aYUV.z;" EOL" aColor.g = aYUV.x - 0.344 * aYUV.y - 0.714 * aYUV.z;" EOL" aColor.b = aYUV.x + 1.772 * aYUV.y;" EOL" return aColor;" EOL"}"; TCollection_AsciiString aSrcFrag = EOL"in vec2 TexCoord;" EOL"uniform sampler2D occSampler1;" EOL"uniform sampler2D occSampler2;" EOL"vec3 convertToRGB (in vec3 theYUV);" EOL"void main()" EOL"{" EOL" vec3 aYUV = vec3 (occTexture2D (occSampler0, TexCoord.st).r," EOL" occTexture2D (occSampler1, TexCoord.st).r," EOL" occTexture2D (occSampler2, TexCoord.st).r);" EOL " occSetFragColor (vec4 (convertToRGB (aYUV), 1.0));" EOL"}"; myShaderYUV = new Graphic3d_ShaderProgram(); myShaderYUV->SetHeader ("#version 150"); myShaderYUV->SetNbLightsMax (0); myShaderYUV->SetNbClipPlanesMax (0); myShaderYUV->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX, aSrcVert)); myShaderYUV->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag + F_SHADER_YUV2RGB_MPEG)); myShaderYUVJ = new Graphic3d_ShaderProgram(); myShaderYUVJ->SetHeader ("#version 150"); myShaderYUVJ->SetNbLightsMax (0); myShaderYUVJ->SetNbClipPlanesMax (0); myShaderYUVJ->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX, aSrcVert)); myShaderYUVJ->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag + F_SHADER_YUV2RGB_FULL)); } // ======================================================================= // function : SetCallback // purpose : // ======================================================================= void Graphic3d_MediaTextureSet::SetCallback (CallbackOnUpdate_t theCallbackFunction, void* theCallbackUserPtr) { myCallbackFunction = theCallbackFunction; myCallbackUserPtr = theCallbackUserPtr; } // ======================================================================= // function : Notify // purpose : // ======================================================================= void Graphic3d_MediaTextureSet::Notify() { if (myCallbackFunction != NULL) { myCallbackFunction (myCallbackUserPtr); } } // ======================================================================= // function : OpenInput // purpose : // ======================================================================= void Graphic3d_MediaTextureSet::OpenInput (const TCollection_AsciiString& thePath, Standard_Boolean theToWait) { if (myPlayerCtx.IsNull()) { if (thePath.IsEmpty()) { myInput.Clear(); return; } myPlayerCtx = new Media_PlayerContext (this); } myProgress = 0.0; myDuration = 0.0; myPlayerCtx->SetInput (thePath, theToWait); myInput = thePath; } // ======================================================================= // function : LockFrame // purpose : // ======================================================================= Handle(Media_Frame) Graphic3d_MediaTextureSet::LockFrame() { { Standard_Mutex::Sentry aLock (myMutex.get()); if (!myToPresentFrame) { Handle(Media_Frame) aFrame = myFramePair[myFront == 0 ? 1 : 0]; if (aFrame->IsLocked()) { return Handle(Media_Frame)(); } aFrame->SetLocked (true); return aFrame; } } Notify(); return Handle(Media_Frame)(); } // ======================================================================= // function : ReleaseFrame // purpose : // ======================================================================= void Graphic3d_MediaTextureSet::ReleaseFrame (const Handle(Media_Frame)& theFrame) { { Standard_Mutex::Sentry aLock (myMutex.get()); theFrame->SetLocked (false); myToPresentFrame = true; } if (myCallbackFunction != NULL) { myCallbackFunction (myCallbackUserPtr); } } // ================================================================ // Function : SwapFrames // Purpose : // ================================================================ Standard_Boolean Graphic3d_MediaTextureSet::SwapFrames() { if (myPlayerCtx.IsNull()) { return Standard_False; } Standard_Boolean isPaused = Standard_False; myPlayerCtx->PlaybackState (isPaused, myProgress, myDuration); Standard_Mutex::Sentry aLock (myMutex.get()); if (!myToPresentFrame) { return Standard_False; } myToPresentFrame = false; myFront = myFront == 0 ? 1 : 0; const Handle(Media_Frame)& aFront = myFramePair[myFront]; myFrameSize = aFront->Size(); #ifdef HAVE_FFMPEG myIsPlanarYUV = aFront->Format() == AV_PIX_FMT_YUV420P || aFront->Format() == AV_PIX_FMT_YUVJ420P; #endif myIsFullRangeYUV = aFront->IsFullRangeYUV(); for (int aPlaneIter = Lower(); aPlaneIter <= Upper(); ++aPlaneIter) { if (Graphic3d_MediaTexture* aTexture = dynamic_cast (Value (aPlaneIter).get())) { aTexture->SetFrame (aFront); aTexture->UpdateRevision(); } } return Standard_True; }