connect(this,SIGNAL(GetImage(QImage)),this,SLOT(SetImageSlots(QImage)));
void MainWindow::startStream()
{
videoStreamIndex=-1;
av_register_all();
avformat_network_init();
pAVFormatContext = avformat_alloc_context();
pAVFrame=av_frame_alloc();
if (this->Init())
{
m_timerPlay->start();
}
}
bool MainWindow::Init()
{
if(m_str_url.isEmpty())
return false;
qDebug()<<"m_str_url="<<m_str_url;
//加了下面一句后不丢包
av_dict_set(&pAVDict, "rtsp_transport", "tcp", 0);
av_dict_set(&pAVDict, "strict", "1", 0);
int result=avformat_open_input(&pAVFormatContext,m_str_url.toStdString().c_str(),nullptr,&pAVDict;
if (result<0){
return false;
}
//获取视频流信息
result=avformat_find_stream_info(pAVFormatContext,nullptr);
if (result<0){
return false;
}
qDebug()<<"avformat_find_stream_info result="<<result;
//获取视频流索引
videoStreamIndex = -1;
for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}/*else if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
videoStreamIndex = i;
}*/
}
qDebug()<<"videoStreamIndex="<<videoStreamIndex;
if (videoStreamIndex==-1){
qDebug()<<"获取视频流索引失败";
return false;
}
//获取视频流的分辨率大小
pAVCodecContext = pAVFormatContext->streams[videoStreamIndex]->codec;
videoWidth=pAVCodecContext->width;
videoHeight=pAVCodecContext->height;
m_i_w = videoWidth;
m_i_h = videoHeight;
qDebug()<<"videoWidth="<<videoWidth<<",videoHeight="<<videoHeight;
avpicture_alloc(&pAVPicture,AV_PIX_FMT_RGB24,videoWidth,videoHeight);
AVCodec *pAVCodec;
//获取视频流解码器
pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
pSwsContext = sws_getContext(videoWidth,videoHeight,AV_PIX_FMT_YUV420P,videoWidth,videoHeight,AV_PIX_FMT_RGB24,SWS_BICUBIC,0,0,0);
//打开对应解码器
//result=avcodec_open2(pAVCodecContext,pAVCodec,NULL);
result = avcodec_open2(pAVCodecContext,pAVCodec,&pAVDict);
if (result<0)
{
qDebug()<<"打开解码器失败";
return false;
}
qDebug()<<"初始化视频流成功";
return true;
}
void MainWindow::playSlots()
{
static ulong frame_num = 0;
//一帧一帧读取视频
if (av_read_frame(pAVFormatContext, &pAVPacket) >= 0)
{
if(pAVPacket.stream_index==videoStreamIndex)
{
int ret = avcodec_decode_video2(pAVCodecContext, pAVFrame, &m_i_frameFinished, &pAVPacket);
if(ret < 0)
{
qDebug()<<"Decode Error.";
}
if (m_i_frameFinished)
{
mutex.lock();
sws_scale(pSwsContext,(const uint8_t* const *)pAVFrame->data,pAVFrame->linesize,0,videoHeight,pAVPicture.data,pAVPicture.linesize);
//发送获取一帧图像信号
QImage image(pAVPicture.data[0],videoWidth,videoHeight,QImage::Format_RGB888);
emit GetImage(image);
qDebug()<<"one frame time"<<QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss zzz")<<pAVFrame->pts<<frame_num<<","<<pAVFrame->key_frame;
frame_num++;
mutex.unlock();
}
}
//av_usleep(1000);
}
av_free_packet(&pAVPacket);//释放资源,否则内存会一直上升
}
void MainWindow::SetImageSlots(const QImage &image)
{
if (image.height()>0)
{
QPixmap pix = QPixmap::fromImage(image.scaled(ui->label_video->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
ui->label_video->setPixmap(pix);
}
}
qt的pro文件引用ffmpeg(4.4.2)
INCLUDEPATH += C:\ffmpeg_build\include
LIBS+= -LC:\ffmpeg_build\bin -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc -lswresample -lswscale