Skip to content
This repository has been archived by the owner on Jul 30, 2022. It is now read-only.

Commit

Permalink
cleanup, add appsrc
Browse files Browse the repository at this point in the history
  • Loading branch information
wongfei committed Jul 21, 2021
1 parent a7a8563 commit f8b7279
Show file tree
Hide file tree
Showing 30 changed files with 452 additions and 429 deletions.
6 changes: 4 additions & 2 deletions Config/DefaultEngine.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ DefaultGraphicsPerformance=Maximum
AppliedDefaultGraphicsPerformance=Maximum

[/Script/EngineSettings.GameMapsSettings]
EditorStartupMap=/Game/TestLevel.TestLevel
GameDefaultMap=/Game/TestLevel.TestLevel
EditorStartupMap=/Game/GStreamer/TestLevel.TestLevel
GameDefaultMap=/Game/GStreamer/TestLevel.TestLevel

[/Script/Engine.PhysicsSettings]
DefaultGravityZ=-980.000000
Expand Down Expand Up @@ -62,3 +62,5 @@ DefaultBroadphaseSettings=(bUseMBPOnClient=False,bUseMBPOnServer=False,MBPBounds
r.VSync=0
r.DefaultFeature.AutoExposure=False
r.DefaultFeature.Bloom=False
r.DefaultFeature.MotionBlur=False

Binary file added Content/GStreamer/BP_AppSink.uasset
Binary file not shown.
Binary file added Content/GStreamer/BP_AppSrc.uasset
Binary file not shown.
Binary file added Content/GStreamer/MAT_SimpleVideo.uasset
Binary file not shown.
Binary file added Content/GStreamer/MAT_TexturePreview.uasset
Binary file not shown.
Binary file removed Content/GStreamer/M_SimpleVideo.uasset
Binary file not shown.
Binary file added Content/GStreamer/TestLevel.umap
Binary file not shown.
Binary file not shown.
Binary file removed Content/GStreamer/VideoPlayer.uasset
Binary file not shown.
Binary file removed Content/TestLevel.umap
Binary file not shown.
27 changes: 16 additions & 11 deletions Plugins/GStreamer/Source/GStreamer/GStreamer.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ public class GStreamer : ModuleRules
{
public GStreamer(ReadOnlyTargetRules Target) : base(Target)
{
const string GStreamerRoot = @"C:\dev\gstreamer_dev\1.0\msvc_x86_64";

DefaultBuildSettings = BuildSettingsVersion.V2;
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
bEnableUndefinedIdentifierWarnings = false;
Expand All @@ -25,14 +23,21 @@ public GStreamer(ReadOnlyTargetRules Target) : base(Target)
}
);

PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "include"));
PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "include", "gstreamer-1.0"));
PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "include", "glib-2.0"));
PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "lib", "glib-2.0", "include"));
PublicLibraryPaths.Add(Path.Combine(GStreamerRoot, "lib"));
PublicAdditionalLibraries.Add("glib-2.0.lib");
PublicAdditionalLibraries.Add("gobject-2.0.lib");
PublicAdditionalLibraries.Add("gstreamer-1.0.lib");
PublicAdditionalLibraries.Add("gstvideo-1.0.lib");
if (Target.Platform == UnrealTargetPlatform.Win64)
{
const string GStreamerRoot = @"C:\dev\gstreamer_dev\1.0\msvc_x86_64"; // path to gstreamer development package

PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "include"));
PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "include", "gstreamer-1.0"));
PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "include", "glib-2.0"));
PublicIncludePaths.Add(Path.Combine(GStreamerRoot, "lib", "glib-2.0", "include"));
PublicLibraryPaths.Add(Path.Combine(GStreamerRoot, "lib"));

PublicAdditionalLibraries.Add("glib-2.0.lib");
PublicAdditionalLibraries.Add("gobject-2.0.lib");
PublicAdditionalLibraries.Add("gstreamer-1.0.lib");
PublicAdditionalLibraries.Add("gstvideo-1.0.lib");
PublicAdditionalLibraries.Add("gstapp-1.0.lib");
}
}
}
23 changes: 16 additions & 7 deletions Plugins/GStreamer/Source/GStreamer/Private/GStreamerModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,31 @@ void FGStreamerModule::StartupModule()

INIT_PROFILER;

FString BinPath, PluginPath;

#if PLATFORM_WINDOWS
FString RootPath = GetGstRoot();
if (!RootPath.IsEmpty())
{
UE_LOG(LogGStreamer, Display, TEXT("GSTREAMER_ROOT: \"%s\""), *RootPath);
BinPath = FPaths::Combine(RootPath, TEXT("bin"));
if (!FPaths::DirectoryExists(BinPath))
{
UE_LOG(LogGStreamer, Error, TEXT("Directory not found: \"%s\""), *BinPath);
BinPath = "";
}
PluginPath = FPaths::Combine(RootPath, TEXT("lib"), TEXT("gstreamer-1.0"));
if (!FPaths::DirectoryExists(PluginPath))
{
UE_LOG(LogGStreamer, Error, TEXT("Directory not found: \"%s\""), *PluginPath);
PluginPath = "";
}
}
else
{
UE_LOG(LogGStreamer, Error, TEXT("GSTREAMER_ROOT not found"));
}

FString BinPath = FPaths::Combine(RootPath, TEXT("bin"));
FString PluginPath = FPaths::Combine(RootPath, TEXT("lib"), TEXT("gstreamer-1.0"));
if (!FPaths::DirectoryExists(BinPath))
{
UE_LOG(LogGStreamer, Error, TEXT("Directory not found: \"%s\""), *BinPath);
}
#endif

if (FGstCoreImpl::Init(TCHAR_TO_ANSI(*BinPath), TCHAR_TO_ANSI(*PluginPath)))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ void UGstAppSinkComponent::UninitializeComponent()

void UGstAppSinkComponent::ResetState()
{
if (AppSink) AppSink->Disconnect();
if (AppSink)
AppSink->Disconnect();
SafeDestroy(Texture);
SafeDestroy(AppSink);
}
Expand Down
19 changes: 11 additions & 8 deletions Plugins/GStreamer/Source/GStreamer/Private/GstAppSinkComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@ class GSTREAMER_API UGstAppSinkComponent : public UGstElementComponent, public I

UGstAppSinkComponent();

virtual void UninitializeComponent() override;
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
// UActorComponent
void UninitializeComponent() override;
void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

virtual void CbPipelineStart(class IGstPipeline* Pipeline);
virtual void CbPipelineStop();
virtual void CbGstSampleReceived(class IGstSample* Sample);
virtual void CbGstTextureCreated();
// UGstElementComponent
void CbPipelineStart(class IGstPipeline* Pipeline) override;
void CbPipelineStop() override;

UPROPERTY(Category="GstAppSink", EditAnywhere, BlueprintReadWrite)
FString PipelineName;
// IGstAppSinkCallback
void CbGstSampleReceived(class IGstSample* Sample) override;

// IGstTextureCallback
void CbGstTextureCreated() override;

UPROPERTY(Category="GstAppSink", EditAnywhere, BlueprintReadWrite)
FString AppSinkName;
Expand Down
179 changes: 179 additions & 0 deletions Plugins/GStreamer/Source/GStreamer/Private/GstAppSrcComponent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include "GstAppSrcComponent.h"
#include "GstPipelineImpl.h"
#include "Engine/TextureRenderTarget2D.h"
#include "Components/SceneCaptureComponent2D.h"

class FGstAppSrcBuffer : public IGstAppSrcBuffer
{
public:
FGstAppSrcBuffer(UGstAppSrcComponent* InOwner) : Owner(InOwner) { ColorBuffer.Reserve(1920 * 1080); }

virtual void Release() { Owner->ReleaseBuffer(this); }
virtual void* GetDataPtr() { return ColorBuffer.GetData(); }
virtual size_t GetDataSize() { return ColorBuffer.Num() * sizeof(FColor); }

public:
UGstAppSrcComponent* Owner;
TArray<FColor> ColorBuffer;
FRenderCommandFence Fence;
size_t FrameId = 0;
};

UGstAppSrcComponent::UGstAppSrcComponent()
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.TickInterval = 1.0f / 60.0f;
}

void UGstAppSrcComponent::UninitializeComponent()
{
ResetState();
}

void UGstAppSrcComponent::ResetState()
{
if (AppSrc)
AppSrc->Disconnect();
SafeDestroy(AppSrc);
DestroyBuffers();
FrameId = 0;
}

void UGstAppSrcComponent::CbPipelineStart(IGstPipeline* Pipeline)
{
ResetState();

if (AppSrcEnabled && !AppSrcName.IsEmpty())
{
AppSrc = IGstAppSrc::CreateInstance();
AppSrc->Connect(Pipeline, TCHAR_TO_ANSI(*AppSrcName));
}
}

void UGstAppSrcComponent::CbPipelineStop()
{
ResetState();
}

void UGstAppSrcComponent::SetCaptureInterval(float Interval)
{
PrimaryComponentTick.TickInterval = Interval;
}

void UGstAppSrcComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

if (AppSrc)
{
AActor* Actor = GetOwner();
for (FComponentReference& ComponentReference : AppSrcCaptures)
{
USceneCaptureComponent2D* CaptureComponent = Cast<USceneCaptureComponent2D>(ComponentReference.GetComponent(Actor));
if (CaptureComponent)
{
UTextureRenderTarget2D* TextureTarget = CaptureComponent->TextureTarget;
if (TextureTarget)
{
FTextureRenderTargetResource* TextureResource = TextureTarget->GameThread_GetRenderTargetResource();
PushBufferAsync(TextureResource);
}
}
}

if (BufferQueue.Num() > 0)
{
auto* Buffer = BufferQueue[0];
if (Buffer->Fence.IsFenceComplete())
{
BufferQueue.RemoveAt(0);
AppSrc->PushBuffer(Buffer);
}
}
}

FrameId++;
}

void UGstAppSrcComponent::PushBufferAsync(FTextureRenderTargetResource* TextureResource)
{
if (BufferQueue.Num() > MaxQueueLength)
{
GST_LOG_ERR(TEXT("PushBufferAsync overflow"));
return;
}

FIntPoint Size = TextureResource->GetSizeXY();
FIntRect InRect = FIntRect(0, 0, Size.X, Size.Y);
FReadSurfaceDataFlags InFlags = FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX);

FGstAppSrcBuffer* Buffer = GetBuffer();
Buffer->ColorBuffer.SetNum(Size.X * Size.Y);
Buffer->FrameId = FrameId;
BufferQueue.Add(Buffer);

struct FReadSurfaceContext
{
UGstAppSrcComponent* AppSrc;
FGstAppSrcBuffer* Buffer;
FRenderTarget* SrcRenderTarget;
FIntRect Rect;
FReadSurfaceDataFlags Flags;
};

FReadSurfaceContext Context =
{
this,
Buffer,
TextureResource,
InRect,
InFlags
};

ENQUEUE_RENDER_COMMAND(ReadSurfaceCommand)(
[Context](FRHICommandListImmediate& RHICmdList)
{
RHICmdList.ReadSurfaceData(
Context.SrcRenderTarget->GetRenderTargetTexture(),
Context.Rect,
Context.Buffer->ColorBuffer,
Context.Flags
);
});

Buffer->Fence.BeginFence();
}

FGstAppSrcBuffer* UGstAppSrcComponent::GetBuffer()
{
if (BufferPool.Num() > 0)
{
FScopeLock Lock(&PoolMx);
if (BufferPool.Num() > 0)
return BufferPool.Pop();
}
return new FGstAppSrcBuffer(this);
}

void UGstAppSrcComponent::ReleaseBuffer(FGstAppSrcBuffer* Buffer)
{
FScopeLock Lock(&PoolMx);
BufferPool.Add(Buffer);
}

template<typename T> inline void DestroyBufferList(T& Container)
{
for (auto* Buf : Container)
delete Buf;
Container.SetNum(0);
}

void UGstAppSrcComponent::DestroyBuffers()
{
if (BufferQueue.Num() > 0)
{
FlushRenderingCommands();
DestroyBufferList(BufferQueue);
}
DestroyBufferList(BufferPool);
}
59 changes: 59 additions & 0 deletions Plugins/GStreamer/Source/GStreamer/Private/GstAppSrcComponent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include "GstElementComponent.h"
#include "GstAppSrcImpl.h"
#include "GstVideoFormat.h"
#include "GstAppSrcComponent.generated.h"

class FGstAppSrcBuffer;

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class GSTREAMER_API UGstAppSrcComponent : public UGstElementComponent
{
GENERATED_BODY()

public:
UGstAppSrcComponent();

// UActorComponent
void UninitializeComponent() override;
void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

// UGstElementComponent
void CbPipelineStart(class IGstPipeline* Pipeline) override;
void CbPipelineStop() override;

UPROPERTY(Category = "GstAppSrc", EditAnywhere, BlueprintReadWrite)
FString AppSrcName;

UPROPERTY(Category = "GstAppSrc", EditAnywhere, BlueprintReadWrite)
bool AppSrcEnabled;

UPROPERTY(Category = "GstAppSrc", EditAnywhere)
TArray<FComponentReference> AppSrcCaptures;

UPROPERTY(Category = "GstAppSrc", EditAnywhere, BlueprintReadWrite, meta=(ClampMin="1", ClampMax="10", UIMin="1", UIMax="10"))
int MaxQueueLength = 5;

UFUNCTION(Category="GstAppSrc", BlueprintCallable)
void SetCaptureInterval(float Interval);

protected:

void ResetState();

void PushBufferAsync(class FTextureRenderTargetResource* TextureResource);

friend class FGstAppSrcBuffer;
FGstAppSrcBuffer* GetBuffer();
void ReleaseBuffer(FGstAppSrcBuffer* Buffer);
void DestroyBuffers();

protected:

IGstAppSrc* AppSrc = nullptr;
TArray<FGstAppSrcBuffer*> BufferPool;
TArray<FGstAppSrcBuffer*> BufferQueue;
FCriticalSection PoolMx;
size_t FrameId = 0;
};
Loading

0 comments on commit f8b7279

Please sign in to comment.