1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-06-05 11:24:17 +03:00
occt/src/Graphic3d/Graphic3d_MediaTextureSet.cxx
kgv 98e6c6d17b 0030612: Visualization - provide texture map with video as image source
Introduced package Media wrapping FFmpeg structures.
Media_PlayerContext class manages video decoding into Media_IFrameQueue interface.
Graphic3d_MediaTextureSet implements Media_IFrameQueue interface and can be used as texture source.
AIS_MediaPlayer implements simple AIS object displaying video.
2019-04-09 14:18:35 +03:00

261 lines
8.2 KiB
C++

// 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 <Graphic3d_MediaTextureSet.hxx>
#include <Media_Frame.hxx>
#include <Media_PlayerContext.hxx>
#include <Graphic3d_ShaderProgram.hxx>
#ifdef HAVE_FFMPEG
#include <Standard_WarningsDisable.hxx>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
};
#include <Standard_WarningsRestore.hxx>
#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<Graphic3d_MediaTexture*> (Value (aPlaneIter).get()))
{
aTexture->SetFrame (aFront);
aTexture->UpdateRevision();
}
}
return Standard_True;
}