最下方有我借鉴了雷神以及一位大哥的文章后自己写的简易播放器。免费下载。仅供大家参考。
下面的文章是雷神的文章:
class Player:public QObject
{
Q_OBJECT
public:
Player(QObject *parent = nullptr);
public:
bool isPlay;
bool isPause;
float seekPos;
bool doSeek;
signals:
void sigGetFrame(AVFrame *pFrame);
void sigGetVideoInfo(int mWidth,int mHeight);
void sigGetCurrentPts(long totalTime, long currentTime);
public slots:
void slotDoWork(const QString &add);
};
Player.cpp
#include "Player.h"
#include"CCycleBuffer.h"
static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;
CCycleBuffer* pSoundBuf;
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
void mSleep(int msec)
{
QTime n=QTime::currentTime();
QTime now;
do
{
now=QTime::currentTime();
}while (n.msecsTo(now)<=msec);
}
Player::Player(QObject *parent):QObject (parent)
{
}
void Player::slotDoWork(const QString &add)
{
AVFormatContext *avFormatContext = nullptr;
AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));
AVFrame *pFrame = nullptr,*audioFrame=nullptr;
//SDL_AudioSpec wanted_spec;
//pSoundBuf = new CCycleBuffer(192000 * 10);
int audioStream= -1;
int videoStream = -1;
int err = -1;
QByteArray ba=nullptr;
ba=add.toLatin1();
char * fileName = ba.data();
isPlay = true;
isPause = false;
doSeek = false;
int64_t in_channel_layout;
struct SwrContext *au_convert_ctx;
av_register_all();
avformat_network_init();
avFormatContext = avformat_alloc_context();
if (!avFormatContext) {
av_log(nullptr, AV_LOG_FATAL, "Could not allocate context.\n");
}
AVDictionary *dic=NULL;
int ret=av_dict_set(&dic,"bufsize","655360",0);
if(avformat_open_input(&avFormatContext, fileName, nullptr, &dic) != 0){
qDebug() << "Couldn't open file";
}
// Retrieve stream information
if(avformat_find_stream_info(avFormatContext, nullptr)<0){
qDebug() << "Couldn't find stream information";
return;
}
av_dump_format(avFormatContext, 0, fileName, false);
for(unsigned int i=0; i < avFormatContext->nb_streams; i++){
if(avFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
audioStream = static_cast<int>(i);
}
else if(avFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
videoStream = static_cast<int>(i);
}
}
if(audioStream == -1 && videoStream == -1){
qDebug() << "Didn't find a audio stream";
return;
}
pFrame = av_frame_alloc();
//视频
AVCodecContext *pVideoCodecContext = nullptr,*pAudioCodecContext=nullptr;
AVCodec *pCodecVideo,*pCodecAudio;
AVCodecParameters *pVideoChannelCodecPara = nullptr,*pAudioChannelCodecPara = nullptr;
// pAudioCodecContext=avFormatContext->streams[audioStream]->codec;
// pCodecAudio=avcodec_find_decoder(pAudioCodecContext->codec_id);
// if (avcodec_open2(pAudioCodecContext, pCodecAudio, NULL) < 0)
// {
// printf("Could not open audio codec.\n");
// }
// audioFrame=av_frame_alloc();
if(videoStream != -1)
{
//视频
pVideoChannelCodecPara = avFormatContext->streams[videoStream]->codecpar;
pVideoCodecContext = avcodec_alloc_context3(nullptr);
if (!pVideoCodecContext){
qDebug() << "avcodec_alloc_context3";
return;
}
err = avcodec_parameters_to_context(pVideoCodecContext, pVideoChannelCodecPara);
if (err < 0){
qDebug() << "avcodec_parameters_to_context";
return;
}
pCodecVideo = avcodec_find_decoder(pVideoChannelCodecPara->codec_id);
if(pCodecVideo == nullptr){
qDebug() << "avcodec_find_decoder";
return;
}
qDebug() << "编解码器名:" << pCodecVideo->long_name;
err = avcodec_open2(pVideoCodecContext, pCodecVideo, nullptr);
if(err){
qDebug() << "avcodec_open2";
return;
}
emit sigGetVideoInfo(pVideoCodecContext->width, pVideoCodecContext->height);
qDebug() << "视频宽度:" << pVideoCodecContext->width << "高度:" << pVideoCodecContext->height;
}
av_init_packet(packet);
for (;;) {
//Play
//SDL_PauseAudio(0);
if (isPause)
{
mSleep(1000);
}
else if (doSeek)
{
int64_t stamp = 0;
stamp = seekPos * avFormatContext->streams[videoStream]->duration;//当前它实际的位置
int ret = av_seek_frame(avFormatContext, videoStream, stamp,
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);//将视频移至到当前点击滑动条位置
emit sigGetCurrentPts(avFormatContext->duration * av_q2d(pVideoCodecContext->time_base),
stamp * av_q2d(pVideoCodecContext->time_base));
stamp * av_q2d(pVideoCodecContext->time_base);
qDebug() << seekPos;
doSeek = false;
mSleep(50);
}
else
{
if(av_read_frame(avFormatContext, packet) < 0){
goto end;
}
if(packet->stream_index == videoStream)
{
err = avcodec_send_packet(pVideoCodecContext, packet);
if(err != 0){
if(AVERROR(EAGAIN) == err)
continue;
qDebug() << "发送视频帧失败!"<< err;
}
//解码
while(avcodec_receive_frame(pVideoCodecContext, pFrame) == 0){
emit sigGetFrame(pFrame);
mSleep(15);
emit sigGetCurrentPts(avFormatContext->duration * av_q2d(pVideoCodecContext->time_base),
pFrame->pts * av_q2d(pVideoCodecContext->time_base));
mSleep(20);
}
}
else
{
av_packet_unref(packet); // 注意清理,容易造成内存泄漏
continue;
}
if (!isPlay)
{
goto end;
}
}
}
end:
av_frame_free(&pFrame);
avformat_close_input(&avFormatContext);
avcodec_close(pVideoCodecContext);
avformat_close_input(&avFormatContext);
qDebug() << "end of play";
}
这是我自己写的播放器的运行图片
项目下载地址我放在我自己资源里面,免费下载的,库文件可能需要大家下载一下。
免费下载,仅供参考,更深度学习请移步雷神博客。
ffmpeg+SDL2的简易流媒体播放器,仅供大家参考学习。缺少dll库,在我资源里面下载ffmpeg+SDL2较新发布那个有。-编解码文档类资源-CSDN下载