qt播放ffmpeg音频(流媒体开发学习1)(1)

一、下载ffmpeg

https://ffmpeg.zeranoe.com/builds/

qt播放ffmpeg音频(流媒体开发学习1)(2)

版本说明:

Static:这个版本只包含了ffmpeg.exe、ffplay.exe、ffprobe.exe三个可执行程序,没有头文件和库文件。

Shared:这个版本包含了ffmpeg.exe、ffplay.exe、ffprobe.exe三个可执行程序和相关动态库文件。

Dev:开发版,这个包含了头文件和库文件。

需要下载 Shared和Dev,放在文件夹。static可以不下载。

qt播放ffmpeg音频(流媒体开发学习1)(3)

二、新建 QT 项目 ffmpeg1

在.pro里添加lib和include路径:

QT = core gui greaterThan(QT_MAJOR_VERSION, 4): QT = widgets TARGET = ffmpeg1 TEMPLATE = app SOURCES = main.cpp\ widget.cpp HEADERS = widget.h FORMS = widget.ui INCLUDEPATH ="D:\\Documents\\FFMpeg\\dev\\include" LIBS = -LD:\Documents\FFMpeg\dev\lib -lavutil -lavformat -lavcodec -lavdevice -lavfilter -lpostproc -lswresample -lswscale

把shared里bin内容拷贝到exe目录下:

qt播放ffmpeg音频(流媒体开发学习1)(4)

添加两个控件

qt播放ffmpeg音频(流媒体开发学习1)(5)

三、实现一个播放器的功能

代码仓库: https://gitee.com/xundh/QT-Study/tree/master/sample5_ffmpeg1

#include "widget.h" #include "ui_widget.h" #include <QTime> #include <QDebug> extern "C"{ #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <libavutil/imgutils.h> } Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Delay(int msec){ QTime dieTime = QTime::currentTime().addMSecs(msec); while(QTime::currentTime() < dieTime) QCoreApplication::processEvents(QEventLoop::AllEvents,100); } void Widget::on_pushButton_clicked() { AVFormatContext *pFormatCtx; int i,videoindex; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame , *pFrameRGB; unsigned char *out_buffer; AVPacket *packet; int ret,got_picture; struct SwsContext *img_convert_ctx; char filepath[] = "D:/1.mp4"; // 初始化编解码库 av_register_all(); // 创建AVFormatContext对象,与码流相关的结构 pFormatCtx = avformat_alloc_context(); // 初始化pFormatCtx结构 if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0){ qDebug() << "Couldn't open input stream. . " << endl; return; } // 获取音频视频流数据信息 if(avformat_find_stream_info(pFormatCtx,NULL)<0){ qDebug() << "Couldn't find stream information. " << endl; return; } videoindex = -1; // nb_streams视音频流的个数,这里当查找到视频流时就中断了。 for(int i=0;i<pFormatCtx->nb_streams;i ){ if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){ videoindex=i; break; } } if(videoindex==-1){ qDebug() << "Didn't find a video stream. " << endl; return; } // 获取视频流编码结构 pCodecCtx = pFormatCtx->streams[videoindex]->codec; // 查找解码器 pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec==NULL){ qDebug() << "codec not found." << endl; return; } // 用于初始化pCodecCtx结构 if(avcodec_open2(pCodecCtx,pCodec,NULL)<0){ qDebug() << "Could not open codec. " << endl; return; } // 创建帧结构,此函数仅分配基本结构空间,图像数据空间需通过av_malloc分配 。 pFrame = av_frame_alloc(); pFrameRGB = av_frame_alloc(); // 创建动态内存,创建存储图像数据的空间 // av_image_get_buffer_size 获取一帧图像需要的大小 out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height,1)); av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize,out_buffer, AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height, 1); packet = (AVPacket*)av_malloc(sizeof(AVPacket)); // Output Info qDebug() << "------------ File Information -------------" << endl; // 此函数打印输入或输出的详细信息 av_dump_format(pFormatCtx, 0, filepath, 0); qDebug() << "----------------" << endl; // 初始化img_convert_ctx结构 img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL); // av_read_frame读取一帧未解码的数据 while(av_read_frame(pFormatCtx,packet)>=0){ // 如果是视频数据 if (packet->stream_index==videoindex){ // 解码一帧视频数据 ret = avcodec_decode_video2(pCodecCtx,pFrame, &got_picture, packet); if(ret<0){ qDebug() << "Decode error" << endl; return; } if(got_picture){ sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); QImage img((uchar*)pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height, QImage::Format_RGB32); ui->label->setPixmap(QPixmap::fromImage(img)); Delay(40); } } av_free_packet(packet); } sws_freeContext(img_convert_ctx); av_frame_free(&pFrameRGB); av_frame_free(&pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); }

四、错误处理‘UINT64_C’ was not declared in this scope

error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS D:\Documents\FFMpeg\dev\include\libavutil\common.h:205: error: 'UINT64_C' was not declared in this scope if ((a 0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); ^

解决方法:

libavutil/common.h 顶部增加如下代码

#ifdef __cplusplus #define __STDC_CONSTANT_MACROS #ifdef _STDINT_H #undef _STDINT_H #endif # include "stdint.h" #endif #ifndef INT64_C #define INT64_C(c) (c ## LL) #define UINT64_C(c) (c ## ULL) #endif

,