背景
我在开发一个播放器的缓存队列时,遇到一个bug,导致包和帧无法被下一个模块读取
找了半天,原来是队列中的包和帧数据要进行内容的刷新暂存
包数据和帧数据不能直接放入队列
cpp
//入队,包进队列
int AVPacketQueue::Push(AVPacket *val,int timeout)
{
//加作用域互斥锁:资源同一时间只能有一个线程访问,作用域结束自动释放锁
//std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock<std::mutex> lock(mutex_);//这里必须要加手动作用域互斥锁,因为wait_for需要作用域
//因为是包队列-双链表
//如果队满了,等待timeout时间
if(duration_cur>=duration_MAX) {
// 等待pop或者超时唤醒
cond_.wait_for(lock, std::chrono::milliseconds(timeout), [this] {
return duration_cur<duration_MAX;
});
}
//如果依然队满,就直接返回-1
if(duration_cur>=duration_MAX){
return -1;
}
//入队:出现问题的代码,这里是直接把包指针存放到队列中了,但是在ffmpeg中不能直接存放,必须要先搞一个新包,然后刷新暂存数据
queue_.push(val);
//增加队列缓存时间,强转成ms
long ms = static_cast<long>(av_rescale(val->duration, 1000, AV_TIME_BASE));
this->duration_cur+=ms;
cond_.notify_one();//条件变量:通知其他线程可以继续执行
return 0;
}
解决方案
cpp
//入队,包进队列
int AVPacketQueue::Push(AVPacket *val,int timeout)
{
//加作用域互斥锁:资源同一时间只能有一个线程访问,作用域结束自动释放锁
//std::lock_guard<std::mutex> lock(mutex_);
std::unique_lock<std::mutex> lock(mutex_);//这里必须要加手动作用域互斥锁,因为wait_for需要作用域
//因为是包队列-双链表
//如果队满了,等待timeout时间
if(duration_cur>=duration_MAX) {
// 等待pop或者超时唤醒
cond_.wait_for(lock, std::chrono::milliseconds(timeout), [this] {
return duration_cur<duration_MAX;
});
}
//如果依然队满,就直接返回-1
if(duration_cur>=duration_MAX){
return -1;
}
//入队:一定注意,必须要重新申请空间,不然会指向同一段地址,而且后面要释放对应的数据包av_packet_free
AVPacket *tmp_packet = av_packet_alloc();
av_packet_move_ref(tmp_packet, val);
queue_.push(tmp_packet);
//增加队列缓存时间,强转成ms
long ms = static_cast<long>(av_rescale(val->duration, 1000, AV_TIME_BASE));
this->duration_cur+=ms;
cond_.notify_one();//条件变量:通知其他线程可以继续执行
return 0;
}