Skip to content

Commit ba0f4cc

Browse files
authored
Merge pull request #5 from g0415shenw/main
增加运行时保存图像画面为视频
2 parents 931e3e0 + 18463f4 commit ba0f4cc

File tree

7 files changed

+478
-2
lines changed

7 files changed

+478
-2
lines changed

InVideo.uplugin

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
{
1919
"Name": "InVideo",
2020
"Type": "Runtime",
21-
"LoadingPhase": "Default"
21+
"LoadingPhase": "Default",
22+
"WhitelistPlatforms": [
23+
"Win64"
24+
]
2225
}
2326
]
2427
}

Source/InVideo/InVideo.Build.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public InVideo(ReadOnlyTargetRules Target) : base(Target)
4242
"Engine",
4343
"RHI",
4444
"RenderCore",
45-
45+
"InputCore"
4646

4747
}
4848
);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Fill out your copyright notice in the Description page of Project Settings.
2+
3+
4+
#include "InRecordGameViewportClient.h"
5+
#include "Slate/SceneViewport.h"
6+
7+
void UInRecordGameViewportClient::RequestFrame()
8+
{
9+
m_CanRecord = true;
10+
}
11+
12+
void UInRecordGameViewportClient::Draw(FViewport* InViewport, FCanvas* SceneCanvas)
13+
{
14+
Super::Draw(InViewport, SceneCanvas);
15+
16+
if (false == m_CanRecord)
17+
{
18+
return;
19+
}
20+
m_CanRecord = false;
21+
22+
auto SceneViewport = GetGameViewport();
23+
24+
TArray<FColor> Bitmap;
25+
int BitmapX = InViewport->GetSizeXY().X;
26+
int BitmapY = InViewport->GetSizeXY().Y;
27+
28+
auto ReadRet = SceneViewport->ReadPixels(Bitmap, FReadSurfaceDataFlags());
29+
if (false == ReadRet)
30+
{
31+
return;
32+
}
33+
OnFrameData.ExecuteIfBound(Bitmap, BitmapX, BitmapY);
34+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Fill out your copyright notice in the Description page of Project Settings.
2+
3+
4+
#include "InSceneRecord.h"
5+
#include "InRecordGameViewportClient.h"
6+
7+
#include <string>
8+
9+
// Sets default values
10+
AInSceneRecord::AInSceneRecord()
11+
{
12+
13+
}
14+
15+
void AInSceneRecord::Destroyed()
16+
{
17+
if (nullptr != m_ImageBuf)
18+
{
19+
delete[] m_ImageBuf;
20+
m_ImageBuf = nullptr;
21+
}
22+
if (nullptr != m_WrapOpenCv)
23+
{
24+
m_WrapOpenCv->m_VideoWriter.release();
25+
delete m_WrapOpenCv;
26+
m_WrapOpenCv = nullptr;
27+
}
28+
29+
}
30+
void AInSceneRecord::StartRecord(const FString FilePath, const int Fps)
31+
{
32+
UE_LOG(LogTemp, Log, TEXT("AInSceneRecord StartRecord FilePath=%s"),*FilePath);
33+
if (true == m_IsRecording)
34+
{
35+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord StartRecord IsRecording ture"));
36+
return;
37+
}
38+
m_IsRecording = true;
39+
m_FilePath = FilePath;
40+
m_Fps = Fps;
41+
if (false == FPaths::ValidatePath(m_FilePath))
42+
{
43+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord StartRecord ValidatePath m_FilePath=%s"), *m_FilePath);
44+
return;
45+
}
46+
FString FoldPath = FPaths::GetPath(m_FilePath);
47+
if (false == FPaths::DirectoryExists(FoldPath))
48+
{
49+
UE_LOG(LogTemp, Log, TEXT("AInSceneRecord StartRecord CreateDirectoryTree=%s"), *FoldPath);
50+
FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*FoldPath);
51+
}
52+
auto world = GetWorld();
53+
if (nullptr == world)
54+
{
55+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord StartRecord GetWorld false"));
56+
return;
57+
}
58+
59+
UInRecordGameViewportClient* ViewPortClient = Cast<UInRecordGameViewportClient>(
60+
world->GetGameViewport());
61+
if (nullptr == ViewPortClient)
62+
{
63+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord StartRecord UInRecordGameViewportClient nullptr"));
64+
return;
65+
}
66+
if (true == ViewPortClient->OnFrameData.IsBound())
67+
{
68+
ViewPortClient->OnFrameData.Unbind();
69+
}
70+
ViewPortClient->OnFrameData.BindUObject(this, &AInSceneRecord::HandleFrameData);
71+
72+
if (nullptr != m_ImageBuf)
73+
{
74+
delete[] m_ImageBuf;
75+
m_ImageBuf = nullptr;
76+
}
77+
if (nullptr == m_WrapOpenCv)
78+
{
79+
m_WrapOpenCv = new WrapOpenCv();
80+
}
81+
82+
GetWorld()->GetTimerManager().SetTimer(m_TimeHandle,this, &AInSceneRecord::OnRequestFrame,1.0f/ Fps, true, 0);
83+
}
84+
85+
void AInSceneRecord::StoptRecord()
86+
{
87+
UE_LOG(LogTemp, Log, TEXT("AInSceneRecord StoptRecord "));
88+
if (false == m_IsRecording)
89+
{
90+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord StoptRecord IsRecording false"));
91+
return;
92+
}
93+
GetWorld()->GetTimerManager().ClearTimer(m_TimeHandle);
94+
95+
if (nullptr != m_ImageBuf)
96+
{
97+
delete[] m_ImageBuf;
98+
m_ImageBuf = nullptr;
99+
}
100+
m_WrapOpenCv->m_VideoWriter.release();
101+
}
102+
103+
void AInSceneRecord::OnRequestFrame()
104+
{
105+
auto world = GetWorld();
106+
if (nullptr == world)
107+
{
108+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord OnRequestFrame GetWorld false"));
109+
return;
110+
}
111+
112+
UInRecordGameViewportClient* ViewPortClient = Cast<UInRecordGameViewportClient>(
113+
world->GetGameViewport());
114+
115+
if (nullptr == ViewPortClient)
116+
{
117+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord OnRequestFrame UInRecordGameViewportClient nullptr"));
118+
return;
119+
}
120+
ViewPortClient->RequestFrame();
121+
}
122+
void AInSceneRecord::HandleFrameData(TArray<FColor> Bitmap, int32 x, int32 y)
123+
{
124+
int length = Bitmap.Num() * 3;
125+
if (nullptr != m_ImageBuf)
126+
{
127+
if (m_ImageX != x || m_ImageY != y)
128+
{
129+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord HandleFrameData m_ImageX=%d m_ImageY=%d x=%d y=%d"), m_ImageX, m_ImageY,x,y);
130+
return;
131+
}
132+
}
133+
if (nullptr == m_ImageBuf)
134+
{
135+
UE_LOG(LogTemp, Log, TEXT("AInSceneRecord HandleFrameData x=%d y=%d"), x,y);
136+
137+
m_ImageBuf = new char[length];
138+
m_ImageX = x;
139+
m_ImageY = y;
140+
std::string cvFilePath(TCHAR_TO_UTF8(*m_FilePath));
141+
142+
m_WrapOpenCv->m_VideoWriter.release();
143+
m_WrapOpenCv->m_VideoWriter.open(cvFilePath, cv::VideoWriter::fourcc('X', 'V', 'I', 'D'), m_Fps, cv::Size(m_ImageX, m_ImageY));
144+
}
145+
146+
int count = 0;
147+
for (int i = 0; i < Bitmap.Num(); i++)
148+
{
149+
m_ImageBuf[count] = Bitmap[i].B;
150+
m_ImageBuf[count + 1] = Bitmap[i].G;
151+
m_ImageBuf[count + 2] = Bitmap[i].R;
152+
count += 3;
153+
}
154+
155+
if (false == m_WrapOpenCv->m_VideoWriter.isOpened())
156+
{
157+
UE_LOG(LogTemp, Error, TEXT("AInSceneRecord m_VideoWriter isOpened"));
158+
return;
159+
}
160+
cv::Mat img(m_ImageY,m_ImageX,CV_8UC3, (unsigned char*)m_ImageBuf);
161+
m_WrapOpenCv->m_VideoWriter.write(img);
162+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Fill out your copyright notice in the Description page of Project Settings.
2+
3+
#pragma once
4+
5+
#include "CoreMinimal.h"
6+
#include "Engine/GameViewportClient.h"
7+
#include "InRecordGameViewportClient.generated.h"
8+
9+
/**
10+
*
11+
*/
12+
UCLASS()
13+
class INVIDEO_API UInRecordGameViewportClient : public UGameViewportClient
14+
{
15+
GENERATED_BODY()
16+
17+
public:
18+
void RequestFrame();
19+
20+
DECLARE_DELEGATE_ThreeParams(FFrameDelegate, TArray<FColor>, int32, int32);
21+
FFrameDelegate OnFrameData;
22+
23+
virtual void Draw(FViewport* InViewport, FCanvas* SceneCanvas) override;
24+
private:
25+
bool m_CanRecord = false;
26+
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Fill out your copyright notice in the Description page of Project Settings.
2+
3+
#pragma once
4+
5+
#include "CoreMinimal.h"
6+
#include "GameFramework/Actor.h"
7+
#include "PreOpenCVHeaders.h"
8+
#include <opencv2/core.hpp>
9+
#include <opencv2/imgproc.hpp>
10+
#include <opencv2/videoio.hpp>
11+
#include "PostOpenCVHeaders.h"
12+
13+
#include "InSceneRecord.generated.h"
14+
15+
UCLASS()
16+
class INVIDEO_API AInSceneRecord : public AActor
17+
{
18+
GENERATED_BODY()
19+
20+
public:
21+
// Sets default values for this actor's properties
22+
AInSceneRecord();
23+
24+
virtual void Destroyed() override;
25+
26+
UFUNCTION(BlueprintCallable, Category = "InVideo")
27+
void StartRecord(const FString FilePath,const int Fps = 25);
28+
29+
UFUNCTION(BlueprintCallable, Category = "InVideo")
30+
void StoptRecord();
31+
32+
void OnRequestFrame();
33+
void HandleFrameData(TArray<FColor> Bitmap, int32 x, int32 y);
34+
private:
35+
bool m_IsRecording = false;
36+
FString m_FilePath;
37+
int m_Fps = 0;
38+
FTimerHandle m_TimeHandle;
39+
char* m_ImageBuf = nullptr;
40+
int32 m_ImageX = 0;
41+
int32 m_ImageY = 0;
42+
43+
class WrapOpenCv
44+
{
45+
public:
46+
cv::VideoWriter m_VideoWriter;
47+
};
48+
WrapOpenCv* m_WrapOpenCv = nullptr;
49+
};

0 commit comments

Comments
 (0)