1、加入多线程
用主线程同时处理音视频编解码会导致视频出现卡顿,音频出现电音的情况。为避免这种情况,在项目中添加多线程,并将音频和视频解码分开能有效解决该问题。新建AudioInfo类来实现音频
解码和播放的逻辑,并将其放入一个独立的线程中。
为了配合多线程播放音视频的功能,你需要对VideoInfo
类进行以下调整:
-
确保
VideoInfo
类可以独立处理视频解码和渲染。 -
将视频解码和渲染放入独立的线程中运行,以避免与音频解码的线程发生冲突。
需要让VideoInfo
类继承自QThread
,以便它可以在单独的线程中运行。除此之外,代码结构保持不变,只是解码和渲染的逻辑将放入run()
方法中。
代码如下:
AudioInfo.h
#ifndef AUDIOINFO_H
#define AUDIOINFO_H
#include <QObject>
#include <QAudioSink>
#include <QBuffer>
#include<QThread>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
}
class AudioInfo : public QObject
{
Q_OBJECT
public:
explicit AudioInfo(QObject *parent = nullptr);
~AudioInfo();
bool openFile(const QString &filePath);
bool initializeAudio();
void startPlayback();
void stopPlayback();
private:
AVFormatContext *formatContext;
AVCodecContext *codecContext;
AVFrame *frame;
AVPacket *packet;
SwrContext *swrContext;
int audioStreamIndex;
QAudioSink *audioSink;
QBuffer audioBuffer;
void decodeAndPlayAudio();
signals:
void playbackFinished();
};
#endif // AUDIOINFO_H
AudioInfo.cpp
#include "audioinfo.h"
#include <QDebug>
#include <QMediaDevices>
#include <QAudioSink>
#include <QBuffer>
#include <QThread>
AudioInfo::AudioInfo(QObject *parent)
: QObject(parent), formatContext(nullptr), codecContext(nullptr),
frame(nullptr), packet(nullptr), swrContext(nullptr),
audioStreamIndex(-1), audioSink(nullptr)
{
avformat_network_init();
}
AudioInfo::~AudioInfo()
{
if (frame) av_frame_free(&frame);
if (packet) av_packet_free(&packet);
if (codecContext) avcodec_free_context(&codecContext);
if (formatContext) avformat_close_input(&formatContext);
if (swrContext) swr_free(&swrContext);
if (audioSink) delete audioSink;
}
bool AudioInfo::openFile(const QString &filePath)
{
if (avformat_open_input(&formatContext, filePath.toStdString().c_str(), nullptr, nullptr) != 0) {
qWarning() << "Could not open file:" << filePath;
return false;
}
if (avformat_find_stream_info(formatContext, nullptr) < 0) {
qWarning() << "Could not find stream information";
return false;
}
av_dump_format(formatContext, 0, filePath.toStdString().c_str(), 0);
audioStreamIndex = -1;
for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audioStreamIndex = i;
break;
}
}
if (audioStreamIndex == -1) {
qWarning() << "Could not find audio stream";
return false;
}
AVCodecParameters *codecParameters = formatContext->streams[audioStreamIndex]->codecpar;
const AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);
if (!codec) {
qWarning() << "Unsupported codec!";
return false;
}
codecContext = avcodec_alloc_context3(codec);
if (!codecContext) {
qWarning() << "Could not