国外包装设计欣赏网站,本溪网站建设,网络品牌传播推广策略,扬州公司做网站0#xff0c;前言 工作需要使用C制作一个ue4的视频插件#xff0c;其中一个功能是能够选择 运行时是否自动播放 视频的功能。 在实现时遇见了一个问题#xff0c;取消自动播放之后#xff0c;运行时首帧是没有取到的#xff0c;在场景里面看是黑色的。就这个问题我想到了使…0前言 工作需要使用C制作一个ue4的视频插件其中一个功能是能够选择 运行时是否自动播放 视频的功能。 在实现时遇见了一个问题取消自动播放之后运行时首帧是没有取到的在场景里面看是黑色的。就这个问题我想到了使用了一个线程去监控纹理渲染渲染到第一帧就暂停这样的效果看起来就是取消自动播放时视频插件在场景中显示视频的第一帧。插件的代码不方便贴出来我这里只贴线程监控的代码。 大部分都是使用蓝图和UE自带的mediaplayer实现视频播放的方案直接使用UE的mediaplayer他在给plane附加纹理的时候会自动生成一个当前视频帧的材质所以看不到黑帧。但是其实在打开ue第一次运行的时候还没有读取视频视频帧的材质也是黑帧。 中间尝试了在mediaplayer中添加回调在MediaOpened事件中调用play()然后调用seek()函数在SeekCompleted事件中调用pause()函数来做到播放第一帧的效果但是play()函数只是设置rate为1渲染第一帧的工作是别的线程实现的这也就导致在SeekCompleted事件中调用pause()函数时另一个线程还没有渲染第一帧从而运行时还是显示黑帧。 1原理 查看了mediaplayer的源码大概捋了一下它的流程下面是流程图分了两个线程一个向队列里面送buffer一个从队列里面取buffer之后送去渲染 这只是其中一部分和mediaplayer有关的线程中间还有很多流程。但我们只需要了解到这个线程是怎么运行的就能够解决目前的问题。 大家可以去贴出来的函数里面打个断点跟一下下流程大概了解一下就行。 主要看一下第二天取buffer的线程也就是红框中的流程有下面的代码 while (SampleQueue-Dequeue(Sample));if (!Sample.IsValid()){// Player is active (do not clear), but we have no new data// - we do not need to trigger anything on the renderthreadreturn;}UpdateSampleInfo(Sample);RenderParams.TextureSample Sample;RenderParams.Rate CurrentPlayerPtr-GetRate();RenderParams.Time Sample-GetTime(); 其中最后一行代码 Sample-GetTime(); 这个GetTime()是纹理中player的时间我猜是记录播放时长我们利用这个来实现监控纹理。 原理就是获取视频的帧率从而获取每帧播放的时长启动一个线程监控纹理的player的播放时长在大于每帧播放时间的时候就暂停掉从而实现第一帧暂停的效果。 2实现 多线程的时候代码参考照抄了这位博主的 UE4 C 子线程的创建及使用_ue4 启动线程_北极熊的奋斗史的博客-CSDN博客
头文件
class RNGThread : public FRunnable
{
public://ConstructorRNGThread(int Count 50000, int minNumber 0, int maxNumber 1000, int chunkCount 20);//Destructor~RNGThread();// 杀死线程该线程将不能再使用想再开启的话需要重新创建//Use this method to kill the thread!!void EnsureCompletion();// 暂停线程//Pause the thread void PauseThread();// 继续线程//Continue/UnPause the threadvoid ContinueThread();// 当前线程是否处于暂停状态bool IsThreadPaused();bool setMediaPlayer(UMediaPlayer* MediaPlayer);bool setVideoComponent(UPXVideoComponent* PXVideoComponent);protected://FRunnable interface.virtual bool Init();virtual uint32 Run();virtual void Stop();private://Thread to run the worker FRunnable onFRunnableThread* Thread;UMediaPlayer* MediaPlayer nullptr;UPXVideoComponent* PXVideoComponent nullptr;FCriticalSection m_mutex; // 线程锁FEvent* m_semaphore; // 信号量int m_chunkCount;int m_amount;int m_MinInt;int m_MaxInt;//As the name states those members are Thread safeFThreadSafeBool m_Kill; // bool 类型的变量线程安全FThreadSafeBool m_Pause;};
源文件
RNGThread::RNGThread(int Count, int minNumber, int maxNumber, int chunkCount)
{m_Kill false;m_Pause false;//Initialize FEvent (as a cross platform (Confirmed Mac/Windows))m_semaphore FGenericPlatformProcess::GetSynchEventFromPool(false); // 信号量m_MinInt minNumber;m_MaxInt maxNumber;m_chunkCount chunkCount;// 启动线程Thread FRunnableThread::Create(this, TEXT(RNGThread), 0, TPri_BelowNormal);
}RNGThread::~RNGThread()
{if (m_semaphore){//Cleanup the FEventFGenericPlatformProcess::ReturnSynchEventToPool(m_semaphore);m_semaphore nullptr;}if (Thread){//Cleanup the worker threaddelete Thread;Thread nullptr;}
}bool RNGThread::Init()
{//Init the Data return true;
}/***************************************************************************************/
/*注意不要在线程中做 spawning / modifying / deleting UObjects / AActors 等等之类的事 */
/***************************************************************************************/uint32 RNGThread::Run()
{// 等待一下初始化//Initial wait before startingFPlatformProcess::Sleep(0.03);// 判断是否停止了线程while (!m_Kill){// 判断当前是否处于暂停状态if (m_Pause){//使用信号量使线程处于睡眠状态直到被唤醒m_semaphore-Wait();if (m_Kill){return 0;}}else{if(MediaPlayer ! nullptr){float framerate MediaPlayer-GetVideoTrackFrameRate(0,0);FTimespan FrameTime FTimespan::FromSeconds(1 / (FMath::IsNearlyZero(framerate) ? -1 : framerate));if (MediaPlayer-GetTime() FrameTime){while ((MediaPlayer-GetTime() FrameTime) !m_Pause);MediaPlayer-Pause();break;}}}FPlatformProcess::Sleep(0.01);}return 0;
}void RNGThread::PauseThread()
{m_Pause true;
}void RNGThread::ContinueThread()
{m_Pause false;// 启动线程if (m_semaphore){//Here is a FEvent signal Trigger() - it will wake up the thread.m_semaphore-Trigger();}
}void RNGThread::Stop()
{// 设置停止的标志m_Kill true; //Thread kill condition while (!m_Kill){...}m_Pause false;// 触发一下线程让其在下一次判断中退出if (m_semaphore){//We shall signal Trigger the FEvent (in case the Thread is sleeping it shall wake up!!)m_semaphore-Trigger();}
}//Use this method to kill the thread!!
void RNGThread::EnsureCompletion()
{// 停止线程Stop();// 等待线程运行结束if (Thread){Thread-WaitForCompletion();}if (this-MediaPlayer ! nullptr){MediaPlayer nullptr;}if (this-PXVideoComponent ! nullptr){this-PXVideoComponent-UnregisterComponent();this-PXVideoComponent-DestroyComponent();this-PXVideoComponent nullptr;}
}bool RNGThread::IsThreadPaused()
{return (bool)m_Pause;
}bool RNGThread::setMediaPlayer(UMediaPlayer* pMediaPlayer)
{this-MediaPlayer pMediaPlayer;return true;
}
bool RNGThread::setVideoComponent(UPXVideoComponent* pPXVideoComponent)
{ this-PXVideoComponent pPXVideoComponent;return true;
}
使用方法
启动线程
RNGThread * pThread new RNGThread();
pThread-setMediaPlayer(MediaPlayer);关闭线程
if (pThread ! nullptr)
{pThread-EnsureCompletion();delete pThread;pThread nullptr;
}