当前位置: 首页 > news >正文

b2b免费发布网站大全排名/站长论坛

b2b免费发布网站大全排名,站长论坛,黑龙江公司网站建设,深圳宝安股票在开发音视频播放器时,多线程设计是不可避免的挑战。音频和视频的解码、播放需要高效运行,同时还要与主线程或其他线程同步,例如通过信号通知播放进度。本文基于一个实际案例,分析了两种线程设计在死循环和信号槽使用中的表现&…

在开发音视频播放器时,多线程设计是不可避免的挑战。音频和视频的解码、播放需要高效运行,同时还要与主线程或其他线程同步,例如通过信号通知播放进度。本文基于一个实际案例,分析了两种线程设计在死循环和信号槽使用中的表现,探讨其原因,并给出选择建议。

问题表现

我在实现音频播放线程时,遇到了一个问题:主线程通过 QMetaObject::invokeMethod 调用 terminateDecode 无法终止音频线程,而直接调用 m_audioThread->terminateDecode() 却能稳定生效。后来,我将视频解码线程改为 QObject + QThread + std::thread 的设计后,invokeMethod 开始生效。这让我疑惑:为什么死循环会影响信号槽?如何选择合适的设计?

具体表现如下:

  1. 音频线程(AudioPlayerThread)
    • 使用 QThread 子类,重写 run() 为死循环。
    • 主线程调用 QMetaObject::invokeMethod(m_audioThread, "terminateDecode", Qt::QueuedConnection) 无效。
    • 直接调用 m_audioThread->terminateDecode() 生效。
  2. 视频线程(m_videoWorker)
    • 使用 QObject 移入 QThread,解码死循环在 std::thread 中。
    • QMetaObject::invokeMethod(m_videoWorker, "terminateDecode", Qt::QueuedConnection) 生效。

此外,音频线程需要发送 avClockUpdated 信号与视频同步,这在死循环中似乎不受影响。问题出在哪里?

原因分析

问题的根源在于 Qt 的信号槽机制与线程设计的关系,特别是事件循环的作用。

1. 信号发送(emit)不受死循环影响

  • 机制:在 Qt 中,emit 一个信号会根据连接类型(Qt::DirectConnection 或 Qt::QueuedConnection)直接调用槽函数或将信号放入目标线程的事件队列。emit 本身是线程安全的,不依赖事件循环。
  • 音频线程的表现
    emit avClockUpdated(current_pts);

  • 在 AudioPlayerThread 的死循环中,只要线程执行到 emit,信号就会发出,通知视频线程或其他组件。死循环不会阻止信号发送。

2. 信号接收需要事件循环

  • 机制:当使用 Qt::QueuedConnection 调用槽函数(如 terminateDecode),Qt 会将调用请求放入目标线程的事件队列,等待事件循环处理。如果线程没有事件循环,队列中的信号无法被执行。
  • 音频线程的问题
    • run() 是一个 while (true) 死循环:

void AudioPlayerThread::run() {while (true) {// 等待文件和播放逻辑}
}

 

    • 没有调用 exec(),事件循环未启动。
    • QMetaObject::invokeMethod 的调用被排队但无法处理,因此无效。
  • 直接调用的原因
    • m_audioThread->terminateDecode() 是同步调用,不依赖事件循环,直接修改 m_stopRequested 并唤醒条件变量,线程得以退出。

3. 视频线程的改进

  • 设计

    • m_videoWorker 是 QObject,通过 moveToThread 移入 QThread。
    • QThread 默认运行事件循环(exec())。
    • 解码死循环在 std::thread 中:
      class VideoWorker : public QObject {
      public:VideoWorker() {m_decodeThread = std::thread([this] { decodeLoop(); });}
      public slots:void terminateDecode() { m_stopRequested = true; }
      private:void decodeLoop() { while (!m_stopRequested) { /* 解码 */ } }std::thread m_decodeThread;std::atomic<bool> m_stopRequested{false};
      };



       

    • 结果
      • QThread 的事件循环处理 invokeMethod,触发 terminateDecode。
      • 死循环在 std::thread 中,不干扰事件循环。
    • 4. 音视频同步的需求

    • 音频线程发出 avClockUpdated 信号,视频线程接收以同步。
    • 如果视频需要控制音频(例如暂停),音频线程也需要接收信号。死循环设计在这方面受限。
    • 设计选择

      基于以上分析,我对比了两种设计:

      设计 1:AudioPlayerThread(QThread 死循环)

    • 特点
      • 重写 run() 为死循环,使用条件变量同步。
      • 通过直接调用控制线程。
    • 优点
      • 高效:无事件循环开销,适合音频实时性。
      • 简单:逻辑集中,易于实现。
    • 缺点
      • 无法接收信号:需手动检查状态。
      • 扩展性差:复杂控制需额外同步。
    • 适用场景:单一任务,实时性要求高。
    • 设计 2:m_videoWorker(QObject + QThread + std::thread)

    • 特点
      • QThread 运行事件循环,std::thread 执行死循环。
      • 通过信号槽控制。
    • 如何选择?

    • 音频实时性优先:选择设计 1,优化终止逻辑(例如在内层检查 m_stopRequested)。
    • 音视频同步和控制:选择设计 2,支持双向信号通信。
    • 我的需求:音频需要发送 avClockUpdated 与视频同步,可能还需要接收控制信号。设计 2 更合适。
    • 优化建议

      对于音视频同步,我推荐设计 2:

    • 优点
      • 支持信号槽:发送和接收信号都方便。
      • 扩展性强:适合音视频同步和复杂交互。
    • 缺点
      • 复杂性增加:多线程管理。
      • 轻微开销:事件循环和线程切换。
    • 适用场景:需要双向通信或 UI 交互。

 

// 音频工作类
class AudioWorker : public QObject {Q_OBJECT
public:AudioWorker() { m_audioThread = std::thread([this] { audioLoop(); }); }~AudioWorker() { m_stopRequested = true; if (m_audioThread.joinable()) m_audioThread.join(); }
public slots:void terminateDecode() { m_stopRequested = true; }
signals:void avClockUpdated(qint64 pts); // 发送音频时间戳
private:void audioLoop() {while (!m_stopRequested) {qint64 pts = /* 计算音频时间戳,例如 av_rescale_q */;emit avClockUpdated(pts); // 通知视频线程// 音频解码和播放逻辑std::this_thread::sleep_for(std::chrono::milliseconds(10)); // 模拟播放}}std::thread m_audioThread;std::atomic<bool> m_stopRequested{false};
};// 视频工作类
class VideoWorker : public QObject {Q_OBJECT
public:VideoWorker() { m_videoThread = std::thread([this] { videoLoop(); }); }~VideoWorker() { m_stopRequested = true; if (m_videoThread.joinable()) m_videoThread.join(); }
public slots:void terminateDecode() { m_stopRequested = true; }void syncWithAudio(qint64 audioPts) { m_currentAudioPts = audioPts; // 根据音频时间戳调整视频播放}
private:void videoLoop() {while (!m_stopRequested) {qint64 videoPts = /* 计算视频时间戳 */;if (m_currentAudioPts > 0 && std::abs(videoPts - m_currentAudioPts) > 100) {// 如果视频与音频时间差过大,调整播放(例如跳帧或等待)}// 视频解码和渲染逻辑std::this_thread::sleep_for(std::chrono::milliseconds(40)); // 模拟播放}}std::thread m_videoThread;std::atomic<bool> m_stopRequested{false};std::atomic<qint64> m_currentAudioPts{0};
};// 主线程中的管理类
class MainClass : public QObject {Q_OBJECT
public:void startAV() {// 初始化音频线程m_audioThread = new QThread();m_audioWorker = new AudioWorker();m_audioWorker->moveToThread(m_audioThread);// 初始化视频线程m_videoThread = new QThread();m_videoWorker = new VideoWorker();m_videoWorker->moveToThread(m_videoThread);// 连接音频信号到视频槽,实现同步connect(m_audioWorker, &AudioWorker::avClockUpdated, m_videoWorker, &VideoWorker::syncWithAudio, Qt::QueuedConnection);// 启动线程m_audioThread->start();m_videoThread->start();}void stopAV() {if (m_audioThread) {QMetaObject::invokeMethod(m_audioWorker, "terminateDecode", Qt::QueuedConnection);m_audioThread->quit();m_audioThread->wait();delete m_audioThread;delete m_audioWorker;}if (m_videoThread) {QMetaObject::invokeMethod(m_videoWorker, "terminateDecode", Qt::QueuedConnection);m_videoThread->quit();m_videoThread->wait();delete m_videoThread;delete m_videoWorker;}}private:QThread* m_audioThread = nullptr;AudioWorker* m_audioWorker = nullptr;QThread* m_videoThread = nullptr;VideoWorker* m_videoWorker = nullptr;
};

 

总结

  • 信号发送:死循环不影响 emit,音频可以通知视频。
  • 信号接收:死循环无事件循环,需用设计 2 或状态检查解决。
  • 选择依据:实时性选设计 1,同步和扩展性选设计 2。

通过将死循环移到 std::thread,结合 QThread 的事件循环,我实现了音频和视频的高效同步。这种设计既满足了实时性,又提供了灵活性,是音视频播放器的推荐方案。

 

http://www.whsansanxincailiao.cn/news/31966176.html

相关文章:

  • 美食网站策划书/今日国内新闻大事20条
  • 公司网站的建设/网络建站工作室
  • 电子业网站建设/小红书推广策略
  • 可以做产品宣传的网站/如何创建一个网站
  • 宣传性网站建设策划方案/长沙网络营销咨询费用
  • 做企业免费网站哪个好些/网站访问量排行榜
  • 微网站制作多少钱/seo是搜索引擎营销吗
  • 做网站公司怎么赚钱吗/整合营销沟通
  • 怎么发网址链接/宁阳网站seo推广
  • 市场营销毕业论文3000字/如何优化搜索引擎
  • 鄂尔多斯网站建设/北京发生大事了
  • 济南代做标书网站标志/关键词有哪几种
  • 电脑网站策划书/佛山市人民政府门户网站
  • ubuntu安装 wordpress/百度搜索引擎优化相关性评价
  • 一流的上海网站建设公/大连网站开发公司
  • 开发小程序定制公司/百中搜优化
  • 17. 整个网站建设中的关键是/永久免费的电销外呼系统
  • 专业的企业级cms建站系统/google play store
  • 龙岩网络施工公司/企业网站怎么优化
  • 阿里云做电脑网站/湖南网站seo
  • php与网站建设/广州关键词优化外包
  • 企业网站开发外包合同/seo网站排名优化教程
  • s网站建设/个人免费开发app
  • 建各公司网站要多少钱/seo自动推广工具
  • 网站诊断分析报告模板及优化执行方案.doc/搜索引擎推广的费用
  • 数据开放网站建设/seo点击排名工具有用吗
  • wordpress收费主题破解版/搜索引擎优化公司排行
  • 手机可怎么样做网站/百度学术论文查重免费检测
  • 智能手表网站/网站优化排名工具
  • 单页面应用的网站/阿里指数