Skip to content

Commit d9806bb

Browse files
authored
Merge pull request #21 from g0415shenw/main
重大更新,实现视频打开和关闭全异步化,不会再阻塞蓝图线程
2 parents 55b3f5e + 57c655e commit d9806bb

File tree

4 files changed

+162
-113
lines changed

4 files changed

+162
-113
lines changed

Content/videoUmg.uasset

1.23 KB
Binary file not shown.

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@
3434

3535
# 更新记录
3636

37-
1、2023-05-23 解决了在 5.2 版本崩溃的 bug
37+
1、2023-05-23 解决了在 5.2 版本崩溃的 bug
38+
2、2023-06-11 重大更新,实现视频打开和关闭全异步化,不会再阻塞蓝图线程

Source/InVideo/Private/InVideoWidget.cpp

Lines changed: 119 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,112 @@
77

88
void UInVideoWidget::NativeConstruct()
99
{
10+
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget NativeConstruct"));
1011
Super::NativeConstruct();
1112
}
1213
void UInVideoWidget::NativeDestruct()
1314
{
15+
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget NativeDestruct"));
1416
StopPlay();
1517
Super::NativeDestruct();
1618
}
1719

18-
bool UInVideoWidget::Init()
20+
21+
void UInVideoWidget::StartPlay(const FString VideoURL, FDelegatePlayFailed Failed, FDelegateFirstFrame FirstFrame,const bool RealMode , const int Fps)
22+
{
23+
StopPlay();
24+
m_VideoPlayPtr = MakeUnique<VideoPlay>();
25+
m_VideoPlayPtr->StartPlay(VideoURL, Failed, FirstFrame, RealMode, Fps,this);
26+
}
27+
void UInVideoWidget::StopPlay()
28+
{
29+
if (m_VideoPlayPtr.Get() == nullptr)
30+
{
31+
return;
32+
}
33+
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [ptr = MoveTemp(m_VideoPlayPtr)]()
34+
{
35+
ptr->StopPlay();
36+
});
37+
}
38+
39+
40+
41+
void VideoPlay::StartPlay(const FString VideoURL, FDelegatePlayFailed Failed, FDelegateFirstFrame FirstFrame, const bool RealMode, const int Fps, UInVideoWidget* widget)
42+
{
43+
StopPlay();
44+
m_widget = widget;
45+
m_Stopping = false;
46+
m_VideoURL = VideoURL;
47+
m_RealMode = RealMode;
48+
m_Fps = Fps;
49+
m_UpdateTime = 1000 / m_Fps;
50+
m_Failed = Failed;
51+
m_FirstFrame = FirstFrame;
52+
m_BFirstFrame = false;
53+
UE_LOG(LogTemp, Log, TEXT("VideoPlay StartPlay Enter"));
54+
m_Thread = FRunnableThread::Create(this, TEXT("Video Thread"));
55+
UE_LOG(LogTemp, Log, TEXT("VideoPlay StartPlay END"));
56+
}
57+
void VideoPlay::StopPlay()
58+
{
59+
UE_LOG(LogTemp, Log, TEXT("VideoPlay StopPlay Enter"));
60+
m_Stopping = true;
61+
if (nullptr != m_Thread)
62+
{
63+
m_Thread->Kill();
64+
delete m_Thread;
65+
m_Thread = nullptr;
66+
}
67+
if (nullptr != m_WrapOpenCv)
68+
{
69+
if (m_WrapOpenCv->m_Stream.isOpened())
70+
{
71+
m_WrapOpenCv->m_Stream.release();
72+
}
73+
delete m_WrapOpenCv;
74+
m_WrapOpenCv = nullptr;
75+
}
76+
if (nullptr != m_VideoUpdateTextureRegion)
77+
{
78+
delete m_VideoUpdateTextureRegion;
79+
m_VideoUpdateTextureRegion = nullptr;
80+
}
81+
AsyncTask(ENamedThreads::GameThread, [vt = VideoTexture]()
82+
{
83+
if (vt->IsValidLowLevel())
84+
{
85+
vt->RemoveFromRoot();
86+
}
87+
});
88+
m_VideoSize = FVector2D(0, 0);
89+
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget StopPlay END"));
90+
}
91+
bool VideoPlay::Init()
1992
{
2093
return true;
2194
}
22-
uint32 UInVideoWidget::Run()
95+
uint32 VideoPlay::Run()
2396
{
24-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget open Enter"));
97+
UE_LOG(LogTemp, Log, TEXT("VideoPlay open Enter"));
2598
if (nullptr == m_WrapOpenCv)
2699
{
27100
m_WrapOpenCv = new WrapOpenCv();
28101
}
29102
if (false == m_WrapOpenCv->m_Stream.open(TCHAR_TO_UTF8(*m_VideoURL)))
30103
{
31-
UE_LOG(LogTemp, Error, TEXT("UInVideoWidget open url=%s"), *m_VideoURL);
104+
UE_LOG(LogTemp, Error, TEXT("VideoPlay open url=%s"), *m_VideoURL);
32105
NotifyFailed();
33106
return -1;
34107
}
35-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget open END"));
108+
UE_LOG(LogTemp, Log, TEXT("VideoPlay open END"));
36109

37-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget Run Enter"));
110+
UE_LOG(LogTemp, Log, TEXT("VideoPlay Run Enter"));
38111
while (false == m_Stopping)
39112
{
40113
if (false == m_WrapOpenCv->m_Stream.isOpened())
41114
{
42-
UE_LOG(LogTemp, Error, TEXT("UInVideoWidget Run isOpened"));
115+
UE_LOG(LogTemp, Error, TEXT("VideoPlay Run isOpened"));
43116
NotifyFailed();
44117
return -1;
45118
}
@@ -62,87 +135,41 @@ uint32 UInVideoWidget::Run()
62135
NotifyFirstFrame();
63136
UpdateTexture();
64137
}
65-
138+
66139
}
67-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget Run END"));
140+
UE_LOG(LogTemp, Log, TEXT("VideoPlay Run END"));
68141
return 0;
69142
}
70-
void UInVideoWidget::Exit()
143+
void VideoPlay::Exit()
71144
{
72145

73146
}
74-
void UInVideoWidget::Stop()
147+
void VideoPlay::Stop()
75148
{
76149

77150
}
78-
79-
void UInVideoWidget::StartPlay(const FString VideoURL, FDelegatePlayFailed Failed, FDelegateFirstFrame FirstFrame,const bool RealMode , const int Fps)
80-
{
81-
StopPlay();
82-
m_Stopping = false;
83-
m_VideoURL = VideoURL;
84-
m_RealMode = RealMode;
85-
m_Fps = Fps;
86-
m_UpdateTime = 1000 / m_Fps;
87-
m_Failed = Failed;
88-
m_FirstFrame = FirstFrame;
89-
m_BFirstFrame = false;
90-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget StartPlay Enter"));
91-
m_Thread = FRunnableThread::Create(this, TEXT("Video Thread"));
92-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget StartPlay END"));
93-
}
94-
void UInVideoWidget::StopPlay()
151+
void VideoPlay::NotifyFailed()
95152
{
96-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget StopPlay Enter"));
97-
m_Stopping = true;
98-
if (nullptr != m_Thread)
99-
{
100-
m_Thread->Kill();
101-
delete m_Thread;
102-
m_Thread = nullptr;
103-
}
104-
if (nullptr != m_WrapOpenCv)
105-
{
106-
if (m_WrapOpenCv->m_Stream.isOpened())
107-
{
108-
m_WrapOpenCv->m_Stream.release();
109-
}
110-
delete m_WrapOpenCv;
111-
m_WrapOpenCv = nullptr;
112-
}
113-
114-
if (nullptr != m_VideoUpdateTextureRegion)
115-
{
116-
delete m_VideoUpdateTextureRegion;
117-
m_VideoUpdateTextureRegion = nullptr;
118-
}
119-
m_VideoSize = FVector2D(0, 0);
120-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget StopPlay END"));
121-
}
122-
void UInVideoWidget::NotifyFailed()
123-
{
124-
FDelegatePlayFailed Failed = m_Failed;
125-
AsyncTask(ENamedThreads::GameThread, [Failed]()
153+
AsyncTask(ENamedThreads::GameThread, [Failed= m_Failed]()
126154
{
127155
if (Failed.IsBound())
128156
Failed.Execute();
129157
});
130158
}
131-
void UInVideoWidget::NotifyFirstFrame()
159+
void VideoPlay::NotifyFirstFrame()
132160
{
133161
if (m_BFirstFrame)
134162
{
135163
return;
136164
}
137165
m_BFirstFrame = true;
138-
FDelegateFirstFrame FirstFrame = m_FirstFrame;
139-
AsyncTask(ENamedThreads::GameThread, [FirstFrame]()
166+
AsyncTask(ENamedThreads::GameThread, [FirstFrame = m_FirstFrame]()
140167
{
141168
if (FirstFrame.IsBound())
142169
FirstFrame.Execute();
143170
});
144171
}
145-
void UInVideoWidget::UpdateTexture()
172+
void VideoPlay::UpdateTexture()
146173
{
147174
if (nullptr == VideoTexture || m_VideoSize.X != m_WrapOpenCv->m_Frame.cols || m_VideoSize.Y != m_WrapOpenCv->m_Frame.rows)
148175
{
@@ -151,16 +178,17 @@ void UInVideoWidget::UpdateTexture()
151178
m_VideoSize = FVector2D(m_WrapOpenCv->m_Frame.cols, m_WrapOpenCv->m_Frame.rows);
152179
FEvent* SyncEvent = FGenericPlatformProcess::GetSynchEventFromPool(false);
153180
AsyncTask(ENamedThreads::GameThread, [this, SyncEvent]()
154-
{
155-
VideoTexture = UTexture2D::CreateTransient(m_VideoSize.X, m_VideoSize.Y);
156-
if (VideoTexture)
157181
{
158-
VideoTexture->UpdateResource();
159-
}
160-
m_Texture2DResource = (FTexture2DResource*)VideoTexture->GetResource();
161-
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget UpdateTexture CreateTransient"));
162-
SyncEvent->Trigger();
163-
});
182+
VideoTexture = UTexture2D::CreateTransient(m_VideoSize.X, m_VideoSize.Y);
183+
if (VideoTexture)
184+
{
185+
VideoTexture->UpdateResource();
186+
}
187+
VideoTexture->AddToRoot();
188+
m_Texture2DResource = (FTexture2DResource*)VideoTexture->GetResource();
189+
UE_LOG(LogTemp, Log, TEXT("UInVideoWidget UpdateTexture CreateTransient"));
190+
SyncEvent->Trigger();
191+
});
164192
SyncEvent->Wait();
165193
FGenericPlatformProcess::ReturnSynchEventToPool(SyncEvent);
166194

@@ -191,19 +219,27 @@ void UInVideoWidget::UpdateTexture()
191219
Data[i].R = m_WrapOpenCv->m_Frame.data[i * 3 + 2];
192220
}
193221
}
194-
UpdateTextureRegions(VideoTexture,(int32)0, (uint32)1, m_VideoUpdateTextureRegion, (uint32)(4 * m_VideoSize.X), (uint32)4, (uint8*)Data.GetData(), false);
195-
196-
if (nullptr == ImageVideo)
197-
{
198-
return;
199-
}
200-
AsyncTask(ENamedThreads::GameThread, [this]()
201-
{
202-
ImageVideo->SetBrushFromTexture(VideoTexture);
203-
});
222+
UpdateTextureRegions(VideoTexture, (int32)0, (uint32)1, m_VideoUpdateTextureRegion, (uint32)(4 * m_VideoSize.X), (uint32)4, (uint8*)Data.GetData(), false);
223+
224+
AsyncTask(ENamedThreads::GameThread, [vt = VideoTexture, widget = m_widget]()
225+
{
226+
if (false == widget->IsValidLowLevel())
227+
{
228+
return;
229+
}
230+
if (nullptr == widget->ImageVideo)
231+
{
232+
return;
233+
}
234+
if (false == vt->IsValidLowLevel())
235+
{
236+
return;
237+
}
238+
widget->ImageVideo->SetBrushFromTexture(vt);
239+
});
204240

205241
}
206-
void UInVideoWidget::UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData)
242+
void VideoPlay::UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData)
207243
{
208244
if (m_Texture2DResource)
209245
{
@@ -249,7 +285,7 @@ void UInVideoWidget::UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, u
249285
{
250286
//FMemory::Free(RegionData->Regions);
251287
//FMemory::Free(RegionData->SrcData);
252-
288+
253289
}
254290
delete RegionData->Regions;
255291
delete RegionData;

Source/InVideo/Public/InVideoWidget.h

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,30 @@
1616

1717
#include "InVideoWidget.generated.h"
1818

19+
DECLARE_DYNAMIC_DELEGATE(FDelegatePlaySucceeded);
20+
DECLARE_DYNAMIC_DELEGATE(FDelegatePlayFailed);
21+
DECLARE_DYNAMIC_DELEGATE(FDelegateFirstFrame);
1922

20-
/**
21-
*
22-
*/
23-
UCLASS()
24-
class INVIDEO_API UInVideoWidget : public UUserWidget ,public FRunnable
23+
24+
class VideoPlay :public FRunnable
2525
{
26-
GENERATED_BODY()
27-
2826
public:
29-
DECLARE_DYNAMIC_DELEGATE(FDelegatePlaySucceeded);
30-
DECLARE_DYNAMIC_DELEGATE(FDelegatePlayFailed);
31-
DECLARE_DYNAMIC_DELEGATE(FDelegateFirstFrame);
32-
33-
UFUNCTION(BlueprintCallable, Category = "InVideo")
34-
void StartPlay(const FString VideoURL, FDelegatePlayFailed Failed, FDelegateFirstFrame FirstFrame,
35-
const bool RealMode = true,const int Fps = 25);
36-
37-
UFUNCTION(BlueprintCallable, Category = "InVideo")
27+
void StartPlay(const FString VideoURL, FDelegatePlayFailed Failed, FDelegateFirstFrame FirstFrame,
28+
const bool RealMode = true, const int Fps = 25, UInVideoWidget* widget=nullptr);
3829
void StopPlay();
39-
40-
UPROPERTY(BlueprintReadOnly, Category = "InVideo")
41-
UTexture2D* VideoTexture = nullptr;
42-
43-
UPROPERTY(BlueprintReadWrite, Meta = (BindWidget),Category = "InVideo")
44-
UImage* ImageVideo;
45-
public:
46-
virtual void NativeConstruct() override;
47-
virtual void NativeDestruct() override;
48-
4930
public:
50-
bool Init() override;
51-
uint32 Run() override;
31+
bool Init() override;
32+
uint32 Run() override;
5233
void Stop() override;
5334
void Exit() override;
5435
private:
5536
void UpdateTexture();
5637
void UpdateTextureRegions(UTexture2D* Texture, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D* Regions, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, bool bFreeData);
5738
void NotifyFailed();
5839
void NotifyFirstFrame();
40+
public:
41+
UTexture2D* VideoTexture = nullptr;
42+
UInVideoWidget* m_widget = nullptr;
5943
private:
6044
FRunnableThread* m_Thread = nullptr;
6145
TAtomic<bool> m_Stopping = false;
@@ -75,11 +59,39 @@ class INVIDEO_API UInVideoWidget : public UUserWidget ,public FRunnable
7559
cv::VideoCapture m_Stream;
7660
cv::Mat m_Frame;
7761
};
78-
WrapOpenCv *m_WrapOpenCv = nullptr;
62+
WrapOpenCv* m_WrapOpenCv = nullptr;
7963

8064
FVector2D m_VideoSize = FVector2D(0, 0);
8165
FUpdateTextureRegion2D* m_VideoUpdateTextureRegion = nullptr;
8266
FTexture2DResource* m_Texture2DResource = nullptr;
8367
TArray64<FColor> Data;
8468
};
8569

70+
/**
71+
*
72+
*/
73+
UCLASS()
74+
class INVIDEO_API UInVideoWidget : public UUserWidget
75+
{
76+
GENERATED_BODY()
77+
78+
public:
79+
80+
81+
UFUNCTION(BlueprintCallable, Category = "InVideo")
82+
void StartPlay(const FString VideoURL, FDelegatePlayFailed Failed, FDelegateFirstFrame FirstFrame,
83+
const bool RealMode = true,const int Fps = 25);
84+
85+
UFUNCTION(BlueprintCallable, Category = "InVideo")
86+
void StopPlay();
87+
88+
UPROPERTY(BlueprintReadWrite, Meta = (BindWidget),Category = "InVideo")
89+
UImage* ImageVideo;
90+
public:
91+
virtual void NativeConstruct() override;
92+
virtual void NativeDestruct() override;
93+
94+
private:
95+
TUniquePtr<VideoPlay> m_VideoPlayPtr;
96+
};
97+

0 commit comments

Comments
 (0)