当前位置:   article > 正文

FFMPEG 播放 RTSP视频流_ffmpeg rtsp

ffmpeg rtsp

功能简介:

使用QT+FFMPEG实现了RTSP视频流播放的基础操作,点击按钮后,将拉取指定地址的RTSP流,并在QT界面中通过Label显示
开发环境:

    系统环境:Ubuntu
    QT:5.12.12
    FFmpeg:4.4(当前最新)

 

参考代码:

FFMPEG官方示例:FFmpeg: decode_video.c
详细介绍:
(一)添加库文件

新建一个QT工程,在pro添加lib目录和include目录的路径。
 

  1. ##ffmpeg
  2. FFMPEG_LIB = /usr/local/ffmpeg/lib
  3. FFMPEG_INCLUDE = /usr/local/ffmpeg/include
  4. INCLUDEPATH += $$FFMPEG_INCLUDE \
  5. LIBS += $$FFMPEG_LIB/libavcodec.so \
  6. $$FFMPEG_LIB/libavdevice.so \
  7. $$FFMPEG_LIB/libavfilter.so \
  8. $$FFMPEG_LIB/libavformat.so \
  9. $$FFMPEG_LIB/libavutil.so \
  10. $$FFMPEG_LIB/libswresample.so \
  11. $$FFMPEG_LIB/libswscale.so \
(二)界面配置

在MainWindow.ui中,添加一个QPushButton和QLabel控件,并添加“转到槽”,添加on_pushButton_clicked()。

(三)Delay函数
  1. #include <QTime>
  2. //以毫秒为单位设置延时
  3. void Delay(int msec)
  4. {
  5. QTime dieTime = QTime::currentTime().addMSecs(msec);
  6. while(QTime::currentTime() < dieTime){
  7. QCoreApplication::processEvents(QEventLoop::AllEvents,100);
  8. }
  9. }
(四)FFmpeg视频解码

总体处理步骤有8步,如图所示

1.定义相关变量

  1. AVFormatContext *pFormatCtx = NULL;
  2. AVCodecContext *pCodecCtx = NULL;
  3. const AVCodec *pCodec = NULL;
  4. AVFrame *pFrame,*pFrameRGB;
  5. AVPacket *packet;
  6. struct SwsContext *img_convert_ctx;
  7. unsigned char *out_buffer;
  8. int i,videoIndex;
  9. int ret;
  10. char errors[1024] = "";
  11. //rtsp地址:
  12. char url[] = "rtsp://192.168.111.60:554/LiveMedia/ch1/Media1";

2.初始化相关模块

  1. //初始化FFMPEG 调用了这个才能正常适用编码器和解码器
  2. pFormatCtx = avformat_alloc_context(); //init FormatContext
  3. //初始化FFmpeg网络模块
  4. avformat_network_init(); //init FFmpeg network

3.打开视频文件并获取视频信息

  1. //open Media File
  2. ret = avformat_open_input(&pFormatCtx,url,NULL,NULL);
  3. if(ret != 0){
  4. av_strerror(ret,errors,sizeof(errors));
  5. cout <<"Failed to open video: ["<< ret << "]"<< errors << endl;
  6. exit(ret);
  7. }
  8. //Get audio information
  9. ret = avformat_find_stream_info(pFormatCtx,NULL);
  10. if(ret != 0){
  11. av_strerror(ret,errors,sizeof(errors));
  12. cout <<"Failed to get audio info: ["<< ret << "]"<< errors << endl;
  13. exit(ret);
  14. }

4.查找视频中的流信息

  1. //循环查找视频中包含的流信息,直到找到视频类型的流
  2. //便将其记录下来 videoIndex
  3. //这里我们现在只处理视频流 音频流先不管他
  4. for (i = 0; i < pFormatCtx->nb_streams; i++) {
  5. if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
  6. videoIndex = i;
  7. }
  8. }
  9. //如果videoIndex为-1 说明没有找到视频流
  10. if (videoIndex == -1) {
  11. printf("Didn't find a video stream.\n");
  12. return;
  13. }

5.配置编码上下文,AVCodecContext内容

  1. //配置编码上下文,AVCodecContext内容
  2. //1.查找解码器
  3. pCodec = avcodec_find_decoder(pFormatCtx->streams[videoIndex]->codecpar->codec_id);
  4. //2.初始化上下文
  5. pCodecCtx = avcodec_alloc_context3(pCodec);
  6. //3.配置上下文相关参数
  7. avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[videoIndex]->codecpar);
  8. //4.打开解码器
  9. ret = avcodec_open2(pCodecCtx, pCodec, NULL);
  10. if(ret != 0){
  11. av_strerror(ret,errors,sizeof(errors));
  12. cout <<"Failed to open Codec Context: ["<< ret << "]"<< errors << endl;
  13. exit(ret);
  14. }

6.建立视频帧,并对相关参数进行配置

  1. //初始化视频帧
  2. pFrame = av_frame_alloc();
  3. pFrameRGB = av_frame_alloc();
  4. //为out_buffer申请一段存储图像的内存空间
  5. out_buffer = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32,pCodecCtx->width,pCodecCtx->height,1));
  6. //实现AVFrame中像素数据和Bitmap像素数据的关联
  7. av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize, out_buffer,
  8. AV_PIX_FMT_RGB32,pCodecCtx->width, pCodecCtx->height,1);
  9. //为AVPacket申请内存
  10. packet = (AVPacket *)av_malloc(sizeof(AVPacket));
  11. //打印媒体信息
  12. av_dump_format(pFormatCtx,0,url,0);
  13. //初始化一个SwsContext
  14. img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
  15. pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
  16. AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);

7.通过while循环,处理每一个视频帧,并渲染到Label上

  1. //读取帧数据,并通过av_read_frame的返回值确认是不是还有视频帧
  2. while(av_read_frame(pFormatCtx,packet) >=0){
  3. //判断视频帧
  4. if(packet->stream_index == videoIndex){
  5. //解码视频帧
  6. ret = avcodec_send_packet(pCodecCtx, packet);
  7. ret = avcodec_receive_frame(pCodecCtx, pFrame);
  8. if(ret != 0){
  9. av_strerror(ret,errors,sizeof(errors));
  10. cout <<"Failed to decode video frame: ["<< ret << "]"<< errors << endl;
  11. }
  12. if (ret == 0) {
  13. //处理图像数据
  14. sws_scale(img_convert_ctx,
  15. (const unsigned char* const*) pFrame->data,
  16. pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
  17. pFrameRGB->linesize);
  18. QImage img((uchar*)pFrameRGB->data[0],pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32);
  19. ui->label->setPixmap(QPixmap::fromImage(img));
  20. //释放前需要一个延时
  21. Delay(1);
  22. }
  23. }
  24. //释放packet空间
  25. av_packet_unref(packet);
  26. }

8.结束后释放资源

  1. //close and release resource
  2. av_free(out_buffer);
  3. av_free(pFrameRGB);
  4. sws_freeContext(img_convert_ctx);
  5. avcodec_close(pCodecCtx);
  6. avcodec_free_context(&pCodecCtx);
  7. avformat_close_input(&pFormatCtx);
  8. exit(0);

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/354306
推荐阅读
相关标签
  

闽ICP备14008679号