gpt4 book ai didi

c++ - FFmpeg C++ 在单独的线程中解码

转载 作者:行者123 更新时间:2023-11-30 04:46:48 26 4
gpt4 key购买 nike

我正在尝试使用 FFmpeg 解码视频并将其转换为 openGL 纹理并在 cocos2dx 引擎中显示它。我已经设法做到了,它按照我的意愿显示了视频,现在问题是性能方面的问题。我每帧都有一个 Sprite 更新(游戏固定为 60fps,视频固定为 30fps)所以我所做的是我可以互换地解码和转换帧,效果不佳,现在我将它设置为有一个单独的线程,我在其中解码使用 sleep() 的无限 while 循环只是为了不占用 cpu/程序。我目前设置的是 2 个 pbo 帧缓冲区和一个 bool 标志来告诉我的 ffmpeg 线程循环解码另一个帧,因为我不知道如何手动等待何时解码另一个帧。我在网上搜索了对此类问题的解决方案,但没有得到任何答案。

我看过这个:Decoding video directly into a texture in separate thread但它并没有解决我的问题,因为它只是在 opengl 着色器中将 YUV 转换为 RGB,我还没有完成,但目前不是问题。

可能有用的其他信息是,在应用程序退出之前我不需要结束线程,并且我愿意使用任何视频格式,包括无损。

好的,所以主解码循环看起来像这样:

//.. this is inside of a constructor / init
//adding thread to array in order to save the thread
global::global_pending_futures.push_back(std::async(std::launch::async, [=] {
while (true) {
if (isPlaying) {
this->decodeLoop();
}
else {
std::this_thread::sleep_for(std::chrono::milliseconds(3));
}
}
}));

我使用 bool 来检查帧是否被使用的原因是因为主解码函数在调试时需要大约 5 毫秒才能完成,然后应该等待大约 11 毫秒才能显示帧,所以我不知道帧是什么时候被使用的显示,我也不知道解码需要多长时间。

解码函数:

void video::decodeLoop() { //this should loop in a separate thread
frameData* buff = nullptr;
if (buf1.needsRefill) {
/// buf1.bufferLock.lock();
buff = &buf1;
buf1.needsRefill = false;
firstBuff = true;
}
else if (buf2.needsRefill) {
///buf2.bufferLock.lock();
buff = &buf2;
buf2.needsRefill = false;
firstBuff = false;
}

if (buff == nullptr) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return;//error? //wait?
}

//pack pixel buffer?

if (getNextFrame(buff)) {
getCurrentRBGConvertedFrame(buff);
}
else {
loopedTimes++;
if (loopedTimes >= repeatTimes) {
stop();
}
else {
restartVideoPlay(&buf1);//restart both
restartVideoPlay(&buf2);
if (getNextFrame(buff)) {
getCurrentRBGConvertedFrame(buff);
}
}
}
/// buff->bufferLock.unlock();

return;
}

如您所知,我首先使用 bool needsRefill 检查是否使用了缓冲区,然后解码另一帧。

框架数据结构:

    struct frameData {
frameData() {};
~frameData() {};

AVFrame* frame;
AVPacket* pkt;
unsigned char* pdata;
bool needsRefill = true;
std::string name = "";

std::mutex bufferLock;

///unsigned int crrFrame
GLuint pboid = 0;
};

这称为每一帧:

void video::actualDraw() { //meant for cocos implementation
if (this->isVisible()) {
if (this->getOpacity() > 0) {
if (isPlaying) {
if (loopedTimes >= repeatTimes) { //ignore -1 because comparing unsgined to signed
this->stop();
}
}

if (isPlaying) {
this->setVisible(true);

if (!display) { //skip frame
///this->getNextFrame();
display = true;
}
else if (display) {
display = false;
auto buff = this->getData();
width = this->getWidth();
height = this->getHeight();
if (buff) {
if (buff->pdata) {

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buff->pboid);
glBufferData(GL_PIXEL_UNPACK_BUFFER, 3 * (width*height), buff->pdata, GL_DYNAMIC_DRAW);


glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, 0);///buff->pdata); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}

buff->needsRefill = true;
}
}
}
else { this->setVisible(false); }
}
}
}

getData 函数告诉它使用哪个 frambuffer

video::frameData* video::getData() {
if (firstBuff) {
if (buf1.needsRefill == false) {
///firstBuff = false;
return &buf1;///.pdata;
}
}
else { //if false
if (buf2.needsRefill == false) {
///firstBuff = true;
return &buf2;///.pdata;
}
}
return nullptr;
}

我不确定还包括什么我将整个代码粘贴到 pastebin。视频.cpp:https://pastebin.com/cWGT6APn视频.h https://pastebin.com/DswAXwXV

问题总结:

我如何在单独的线程中正确实现解码/我如何优化当前代码?

当前,当其他线程或主线程变得繁重并且解码速度不够快时,视频会滞后。

最佳答案

你需要:

  • 两个缓冲区,一个可以被解码器填充,另一个是复制到 GPU。此外,使用 var(例如 bool useFirst)来告诉哪个缓冲区用于读取,哪个缓冲区用于写入。
  • 解码帧并填充缓冲区的工作线程。此线程读取 useFirst 以告知填充哪个缓冲区。它不需要使用互斥锁来保护缓冲区。
  • A std::condition that makes the thread to wait用于来自 FFmpeg 的新帧用于缓冲区可写。
  • 一个计时器,每 1/60 秒触发一次并执行一个函数将数据传输到 GPU(如果缓冲区已满),然后更新 useFirst 和条件变量。
  • 可能是第二个线程从 FFmpeg 读取帧,但不对其进行解码。

线程[s] 应该是可分离的(而不是可连接的),这样它们才能“永远”存在。他们必须检查另一个使他们完成并删除的标志/条件/通知。

您也可以只使用一个缓冲区,大小增加一倍或更多,并交换写入/读取部分,如 Asynchronous Buffer Transfers 中所述。 .

关于c++ - FFmpeg C++ 在单独的线程中解码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56562905/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com