1.构造函数
创建所用信息类,构建解码和渲染线程,并传入相关参数
关联相关槽函数
FPlayer::FPlayer(WIdid, QObject*parent): QObject{parent} { mDataInfo=newDataInfo(id); mDecode=newDecode(mDataInfo); mRender=newRender(mDataInfo); mThreadD=newQThread(); mThreadR=newQThread(); mDecode->moveToThread(mThreadD); mRender->moveToThread(mThreadR); mThreadD->start(); mThreadR->start(); connect(this, &FPlayer::signalDecode, mDecode, &Decode::slotDecode, Qt::QueuedConnection); connect(this, &FPlayer::signalRender, mRender, &Render::slotRender, Qt::QueuedConnection); connect(mRender, &Render::signalProgress, this, &FPlayer::slotProgress, Qt::QueuedConnection); connect(mRender, &Render::signalPlayStop, this, &FPlayer::slotPlayStop, Qt::QueuedConnection); }
2.析构函数
作用:改变状态为停止,清空结构体
FPlayer::~FPlayer() { stop(); releaseHandle(); } //停止voidFPlayer::stop() { mDataInfo->setPlayState(PLAY_STOP); } voidFPlayer::releaseHandle() { if (mSwrContext) { swr_close(mSwrContext); swr_free(&mSwrContext); } if (mVideoCodecCtx) { avcodec_free_context(&mVideoCodecCtx); mVideoCodecCtx=nullptr; } if (mAudioCodecCtx) { avcodec_free_context(&mAudioCodecCtx); mAudioCodecCtx=nullptr; } if (mFormatCtx) { avformat_close_input(&mFormatCtx); mFormatCtx=nullptr; } mVideoIndex=-1; mAudioIndex=-1; }
3.打开视频
boolFPlayer::open(QStringpath) { if (path.isEmpty()) returnfalse; releaseHandle(); do { mLastPath=path; //创建解复用上下文mFormatCtx=avformat_alloc_context(); if (!mFormatCtx) { qDebug() <<"avformat_alloc_context fail"; returnfalse; } //打开文件if (avformat_open_input(&mFormatCtx, path.replace("/", "\\\\").toUtf8(), nullptr, nullptr) !=0) { qDebug() <<"avformat_open_input fail"; returnfalse; } //查找流数据信息if (avformat_find_stream_info(mFormatCtx, nullptr) <0) { qDebug() <<"avformat_find_stream_info fail"; break; } //查找视频流索引constAVCodec*videoCodec=nullptr; constAVCodec*audioCodec=nullptr; //参数说明://ic:指向 AVFormatContext 结构体的指针,表示输入的多媒体文件上下文。//type:表示所需的流类型,可以是 AVMEDIA_TYPE_AUDIO(音频流)、AVMEDIA_TYPE_VIDEO(视频流)或其他流类型。//wanted_stream_nb:表示期望的流索引,如果为负数,则查找所有流并返回第一个找到的流。//related_stream:表示关联的流索引,用于查找相关的流。 //-1 用于自动选择// decoder_ret:输出参数,返回找到的解码器。//flags:指定额外的搜索标志。mVideoIndex=av_find_best_stream(mFormatCtx, AVMEDIA_TYPE_VIDEO, mVideoIndex, -1, &videoCodec, 0); mAudioIndex=av_find_best_stream(mFormatCtx, AVMEDIA_TYPE_AUDIO, mAudioIndex, -1, &audioCodec, 0); if (mVideoIndex>=0) { ////创建解码器//其中,codec参数是一个指向AVCodec结构体的指针,//表示要为之分配AVCodecContext对象的编码器或解码器。//注意,该函数不会打开编码器或解码器,只是分配一个AVCodecContext对象,//并将其字段初始化为默认值。mVideoCodecCtx=avcodec_alloc_context3(videoCodec); if (mVideoCodecCtx==nullptr) { qDebug() <<"avcodec_alloc_context3 fail"; break; } //填充解码器//avcodec_parameters_to_context 是 FFmpeg 库中的一个函数,//用于将 AVCodecParameters 结构体中的参数设置到 AVCodecContext 结构体中。//AVCodecParameters 结构体包含了音视频编解码器的参数信息,包括编码器类型、编码格式、帧率等。if (avcodec_parameters_to_context(mVideoCodecCtx, mFormatCtx->streams[mVideoIndex]->codecpar) <0) { qDebug() <<"avcodec_parameters_to_context fail"; break; } //打开解码器if (avcodec_open2(mVideoCodecCtx, videoCodec, nullptr) !=0) { qDebug() <<"avcodec_open2 fail"; break; } } AVSampleFormatoutSampleFormat=AV_SAMPLE_FMT_NONE; //输出采样位数if (mAudioIndex>=0) { //创建解码器mAudioCodecCtx=avcodec_alloc_context3(audioCodec); if (mAudioCodecCtx==nullptr) { qDebug() <<"avcodec_alloc_context3 fail"; break; } //填充解码器if (avcodec_parameters_to_context(mAudioCodecCtx, mFormatCtx->streams[mAudioIndex]->codecpar) <0) { qDebug() <<"avcodec_parameters_to_context fail"; break; } //打开解码器if (avcodec_open2(mAudioCodecCtx, audioCodec, nullptr) !=0) { qDebug() <<"avcodec_open2 fail"; break; } //转换器上下文mSwrContext=swr_alloc(); AVChannelLayoutinChannelLayout=mAudioCodecCtx->ch_layout; //输入通道intinSampleRate=mAudioCodecCtx->sample_rate; //输入采样率AVSampleFormatinSampleFormat=mAudioCodecCtx->sample_fmt; //输入采样位数AVChannelLayoutoutChannelLayout=mAudioCodecCtx->ch_layout; //输出通道intoutSampleRate=mAudioCodecCtx->sample_rate; //输出采样率switch (mAudioCodecCtx->sample_fmt) { caseAV_SAMPLE_FMT_U8P: caseAV_SAMPLE_FMT_S16P: caseAV_SAMPLE_FMT_S32P: caseAV_SAMPLE_FMT_FLTP: outSampleFormat= (AVSampleFormat)(mAudioCodecCtx->sample_fmt-5); break; caseAV_SAMPLE_FMT_DBLP: outSampleFormat=AV_SAMPLE_FMT_FLT; break; caseAV_SAMPLE_FMT_S64P: outSampleFormat=AV_SAMPLE_FMT_S32; break; default: outSampleFormat=AV_SAMPLE_FMT_U8P; break; } //swr_alloc_set_opts2是一个函数或方法,用于进行音频重采样的参数设置。//后两个为日志参数if (swr_alloc_set_opts2(&mSwrContext, &outChannelLayout, outSampleFormat, outSampleRate, &inChannelLayout, inSampleFormat, inSampleRate, 0, nullptr) <0) { qDebug() <<"swr_alloc_set_opts2 fail"; break; } //初始化转换器swr_init(mSwrContext); } if (mVideoIndex<0&&mAudioIndex<0) { qDebug() <<"av_find_best_stream fail"; break; } mDataInfo->updateInfo(mFormatCtx, mVideoCodecCtx, mAudioCodecCtx, mSwrContext, outSampleFormat, mVideoIndex, mAudioIndex); mDataInfo->setPlayState(PLAY_OPEN); emitsignalDecode(); returntrue; } while (0); returnfalse; } boolFPlayer::play() { //初始化状态if (mDataInfo->getPlayState() ==PLAY_INIT) { returnfalse; //暂停状态则打开 } elseif (mDataInfo->getPlayState() ==PLAY_STOP) { if (!open(mLastPath)) { returnfalse; } mDataInfo->setPlayState(PLAY_PLAY); emitsignalRender(); //打开状态则播放 } elseif (mDataInfo->getPlayState() ==PLAY_OPEN) { mDataInfo->setPlayState(PLAY_PLAY); emitsignalRender(); //暂停状态则播放 } elseif (mDataInfo->getPlayState() ==PLAY_PAUSE) { mDataInfo->setPlayState(PLAY_PLAY); } returntrue; } //暂停voidFPlayer::pause() { mDataInfo->setPlayState(PLAY_PAUSE); } //停止voidFPlayer::stop() { mDataInfo->setPlayState(PLAY_STOP); } //跳转voidFPlayer::seek(longlongtime) { mDataInfo->setSeekTime(time); } //前进voidFPlayer::fastForward() { mDataInfo->setSeekForward(SEEK_FORWARD); } //后退voidFPlayer::fastBackward() { mDataInfo->setSeekForward(SEEK_BACKWARD); } //长度int64_tFPlayer::getLength() { returnmDataInfo->getLength(); } voidFPlayer::getVideoSize(int&width, int&height) { width=mVideoCodecCtx->width; height=mVideoCodecCtx->height; } //速度voidFPlayer::setPlaySpeed(intspeed) { mDataInfo->setPlaySpeed(speed); } intFPlayer::getPlaySpeed() { returnmDataInfo->getPlaySpeed(); } //音量voidFPlayer::setPlayVolume(intvolume) { mDataInfo->setPlayVolume(volume); } intFPlayer::getPlayVolume() { returnmDataInfo->getPlayVolume(); } voidFPlayer::setDecodeCache(intsize) { mDataInfo->setDecodeCache(size); } voidFPlayer::slotProgress(longlongtime) { emitsignalProgress(time); } voidFPlayer::slotPlayStop() { mDataInfo->setPlayState(PLAY_STOP); emitsignalPLayStop(); }