mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-06-05 11:24:17 +03:00
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.
261 lines
8.2 KiB
C++
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;
|
|
}
|