Qt版的Rtsp客户端

其实这个实现还是很简单的。主要是要在编译ffmpeg的时候,开启rtsp,network,这样我们就可以直接利用avformat_open_input函数接受rtsp协议了。ffmpeg代码的编写的流程和输入文件是一样的。所以说整个实现过程还是比较简单的。同样,我这里会给出我在开发这个客户端的所有的参考资料。对于别人详细介绍的知识我就不会在赘述了。

   随便提一下,我一开始使用live555作为客户端,接受到的数据传给ffmpeg解码。但是解码现实的视频会花屏。经过测试x264编码一帧图像会产生多个slice,这也就是为什么有的NAL前面的起始码是0 0 0 1有的NAL却是0 0 1。作为第一个slice一般是用0 0 0 1,其余的则用0 0 1。而live555的frame是一个去掉了RTP包头的,以及去掉了NAL四个字节的起始码(主要是发送端去掉的)。而我通过ffmpeg测试发现,如果每次给一个NAL让ffmpeg解码是会出现错误的,应该给的是一个完整的一帧数据,也就是几个NAL(slice)。虽然实验是得出这个结论,但是我用live555接受到的数据进行组帧,发现还是无法解码。我目前还没有发现是什么问题,我想可能还是我自己某个细节没有注意到。后来听说ffmpeg可以直接接受rtsp流媒体,就测试了一下,发现OK了,于是qt版的Rtsp客户端就出来了。

   还是老样子,先给出一些我感觉比较有价值的资料链接吧。

   H.264中NAL、Slice与frame意思及相互关系 http://blog.chinaunix.net/uid-20235103-id-1970924.html。我觉得是对做流媒体来说还是比较有用的东西。

   qt我也是现学现用的,这里面还是给我一个qt的学习链接,主要是使用qtcreator来编写。http://bbs.qter.org/forum.php?mod=viewthread&tid=193

   ffmpeg的学习,感觉网上的资料还真是满丰富的。这里就给出文件的ffmpeg播放。后面我会介绍ffmpeg播放rtsp的。http://blog.csdn.net/leixiaohua1020/article/details/8652605


下面就是前面利用前面一篇文章写的rtsp服务器的。





  1. /* 
  2.  * FFmpeg.cpp 
  3.  * 
  4.  *  Created on: 2014年2月25日 
  5.  *      Author: ny 
  6.  */  
  7.   
  8. #include "FFmpeg.h"  
  9.   
  10.   
  11.   
  12. FFmpeg::FFmpeg()  
  13. {  
  14.     pCodecCtx = NULL;  
  15.     videoStream=-1;  
  16.   
  17. }  
  18.   
  19. FFmpeg::~FFmpeg()  
  20. {  
  21.     sws_freeContext(pSwsCtx);  
  22. }  
  23.   
  24. int FFmpeg::initial(QString & url)  
  25. {  
  26.     int err;  
  27.     rtspURL=url;  
  28.     AVCodec *pCodec;  
  29.     av_register_all();  
  30.     avformat_network_init();  
  31.     pFormatCtx = avformat_alloc_context();  
  32.     pFrame=avcodec_alloc_frame();  
  33.     err = avformat_open_input(&pFormatCtx, rtspURL.toStdString().c_str(), NULL,  
  34.                               NULL);  
  35.     if (err < 0)  
  36.     {  
  37.         printf("Can not open this file");  
  38.         return -1;  
  39.     }  
  40.     if (av_find_stream_info(pFormatCtx) < 0)  
  41.     {  
  42.         printf("Unable to get stream info");  
  43.         return -1;  
  44.     }  
  45.     int i = 0;  
  46.     videoStream = -1;  
  47.     for (i = 0; i < pFormatCtx->nb_streams; i++)  
  48.     {  
  49.         if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)  
  50.         {  
  51.             videoStream = i;  
  52.             break;  
  53.         }  
  54.     }  
  55.     if (videoStream == -1)  
  56.     {  
  57.         printf("Unable to find video stream");  
  58.         return -1;  
  59.     }  
  60.     pCodecCtx = pFormatCtx->streams[videoStream]->codec;  
  61.   
  62.     width=pCodecCtx->width;  
  63.     height=pCodecCtx->height;  
  64.     avpicture_alloc(&picture,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);  
  65.     pCodec = avcodec_find_decoder(pCodecCtx->codec_id);  
  66.     pSwsCtx = sws_getContext(width, height, PIX_FMT_YUV420P, width,  
  67.             height, PIX_FMT_RGB24,  
  68.             SWS_BICUBIC, 0, 0, 0);  
  69.   
  70.     if (pCodec == NULL)  
  71.     {  
  72.         printf("Unsupported codec");  
  73.         return -1;  
  74.     }  
  75.     printf("video size : width=%d height=%d \n", pCodecCtx->width,  
  76.            pCodecCtx->height);  
  77.     if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)  
  78.     {  
  79.         printf("Unable to open codec");  
  80.         return -1;  
  81.     }  
  82.     printf("initial successfully");  
  83.     return 0;  
  84. }  
  85.   
  86. int FFmpeg::h264Decodec()  
  87. {  
  88.     int frameFinished=0;  
  89.     while (av_read_frame(pFormatCtx, &packet) >= 0)  
  90.     {  
  91.         if(packet.stream_index==videoStream)  
  92.         {  
  93.             avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);  
  94.             if (frameFinished)  
  95.             {  
  96.                 printf("***************ffmpeg decodec*******************\n");  
  97.                 mutex.lock();  
  98.                 int rs = sws_scale(pSwsCtx, (const uint8_t* const *) pFrame->data,  
  99.                                    pFrame->linesize, 0,  
  100.                                    height, picture.data, picture.linesize);  
  101.                 mutex.unlock();  
  102.                 if (rs == -1)  
  103.                 {  
  104.                     printf("__________Can open to change to des imag_____________e\n");  
  105.                     return -1;  
  106.                 }  
  107.             }  
  108.         }  
  109.     }  
  110.     return 1;  
  111.   
  112. }  
  1.   
  1.   
  1.   
  1.   


FFmpeg这个类主要是对ffmpeg的一些操作,里面主要是有两个函数,一个是initial(QString & url)。其中的参数是我们用户的输入url,类型是QString。这里建议是传递QString不要传递char * 字符,很容易出现指针异常。initial主要功能就是初始化AVFormatCtx,猜想主要是利用了sps,pps初始化了。获取了图像的尺寸我们就开始初始化我,我们要转化的RGB AVPicture了。也就是我们解码后的数据通过swscale进行图像格式转化成RGB存储在picture对面里面。h264Decodec()这个函数就是我们的解码函数,里面就是不断从网络中读取packet,如果是一个视频数据我们就开始解码,再然后就是图片格式转换。当然,这里面我们采取了多线程,一个是主线程也就是UI线程,一个是我们ffmpeg解码线程(其中包括了网络数据获取和解码以及图片格式转换)。所了我们这里面对picture数据是多线程共享的,所以了我加了一个安全锁。这样做就是避免图像刷性不完全。
  1. <span style="font-family: Arial, Helvetica, sans-serif;"></span><pre code_snippet_id="215818" snippet_file_name="blog_20140303_4_771610" name="code" class="cpp">#include "video.h"  
  2. #include "ui_video.h"  
  3. #include <QPainter>  
  4. Video::Video(QWidget *parent) :  
  5.     QMainWindow(parent),  
  6.     ui(new Ui::Video)  
  7. {  
  8.     ui->setupUi(this);  
  9.     ffmpeg=NULL;  
  10. }  
  11.   
  12. Video::~Video()  
  13. {  
  14.     delete ui;  
  15. }  
  16. void Video::setFFmpeg(FFmpeg *ff)  
  17. {  
  18.     ffmpeg=ff;  
  19. }  
  20.   
  21. void Video::paintEvent(QPaintEvent *)  
  22. {  
  23.     if(ffmpeg->picture.data!=NULL)  
  24.     {  
  25.      QPainter painter(this);  
  26.     if(ffmpeg->mutex.tryLock(1000))  
  27.     {  
  28.   
  29.         QImage image=QImage(ffmpeg->picture.data[0],ffmpeg->width,ffmpeg->height,QImage::Format_RGB888);  
  30.         QPixmap  pix =  QPixmap::fromImage(image);  
  31.         painter.drawPixmap(0, 0, 640, 480, pix);  
  32.         update();  
  33.         ffmpeg->mutex.unlock();  
  34.     }  
  35.     }  
  36. }  
  37. </pre><br>  
  38. 这个是就是我们用来现实的video的,主要函数是一个回调函数<span style="font-family:Arial,Helvetica,sans-serif">paintEvent函数。里面我们是用了ffmpeg的picture来初始化Qimage,然后显示上去。关于qt二维绘图我这里就不多了,给的资料已经很详细了。</span><pre code_snippet_id="215818" snippet_file_name="blog_20140303_6_1404464" name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif;"></span><pre code_snippet_id="215818" snippet_file_name="blog_20140303_6_1404464" name="code" class="cpp">#include "login.h"  
  39. #include <QApplication>  
  40. #include <QString>  
  41. #include <stdio.h>  
  42. #include "FFmpeg.h"  
  43. #include <qthread.h>  
  44. #include "video.h"  
  45. #include <unistd.h>  
  46.   
  47.   
  48. /** 
  49.  * @brief The RtspThread class 
  50.  * Receive Thread 
  51.  */  
  52. class RtspThread : public QThread  
  53. {  
  54. public :  
  55.     void run();  
  56.     void setRtspURL(QString url);  
  57.     void setFFmpeg(FFmpeg * ff);  
  58. private:  
  59.     QString  rtspURL;// user input url  
  60.     FFmpeg * ffmpeg;//mian thread and rtspthread use the some ffmpeg object  
  61. };  
  62.   
  63. int main(int argc, char *argv[])  
  64. {  
  65.     QApplication a(argc, argv);  
  66.     Login login;// login Doialog  
  67.     Video video;//mainwindow for display video  
  68.     FFmpeg * ffmpeg;//global data for ffmpeg event  
  69.     ffmpeg=new FFmpeg();  
  70.     video.setFFmpeg(ffmpeg);  
  71.     RtspThread rtspthread;  
  72.     login.show();  
  73.   
  74.     if(login.exec()==QDialog::Accepted)  
  75.     {  
  76.         printf("%s\n",login.getRtspURL().toStdString().c_str());  
  77.         rtspthread.setRtspURL(login.getRtspURL());  
  78.         rtspthread.setFFmpeg(ffmpeg);  
  79.         rtspthread.start();  
  80.         video.show();  
  81.         return a.exec();  
  82.     }else  
  83.     {  
  84.         return 0;  
  85.     }  
  86.   
  87. }  
  88.   
  89. void  RtspThread::run()  
  90. {  
  91.     ffmpeg->initial(rtspURL);  
  92.     ffmpeg->h264Decodec();  
  93. }  
  94.   
  95. void RtspThread::setRtspURL(QString url)  
  96. {  
  97.     rtspURL=url;  
  98. }  
  99. void RtspThread::setFFmpeg(FFmpeg * ff)  
  100. {  
  101.     ffmpeg=ff;  
  102. }  
  103. </pre><br>  
  104. <p>这个就是我们程序的主函数。采用了多线方法实现的。使用了多窗口来获取用户输入。</p>  
  105. <pre></pre>  
  106. <pre></pre>  
  107. <pre></pre>  
  108. <pre></pre>  
  109. <pre></pre>  
  110. <pre></pre>  
  111. </pre>  
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RTSP(Real-Time Streaming Protocol)是一种用于实时媒体传输的协议,通常用于视频、音频等媒体的传输,是一种客户端和服务器程序之间进行的通信协议。为了能够在 Linux 操作系统上使用 RTSP 客户端,必须安装一个 RTSP 客户端程序,该程序是在 Linux 操作系统上运行的。下面我们将结合实际情况,详细介绍 RTSP 客户端在 Linux 上使用的方法。 安装 RTSP 客户端程序是在 Linux 操作系统上使用 RTSP 客户端的第一步。目前较为常用的 RTSP 客户端程序有 MPlayer、vlc 等,这些程序大多数都可以在 Linux 操作系统的软件仓库中找到并直接安装。根据不同的 Linux 发行,软件仓库的安装方法也可能不同,可参考其官网进行相应的操作。 安装好 RTSP 客户端程序后,就要使用相应的命令在终端中启动 RTSP 客户端,连接到媒体服务器。这些命令通常由客户端程序提供,用户只需要根据需要进行相应的配置即可。例如,在 MPlayer 中使用 rtsp 协议连接到服务器的命令为:mplayer rtsp://[server_address]/[filename]。 在连上媒体服务器后,用户还可以根据需要使用 RTSP 客户端程序提供的其他功能,例如,调整视频、音频的分辨率、流畅度和音量等。 总的来说,使用 RTSP 客户端程序在 Linux 上播放实时媒体是一种简单方便的方法,只需要安装相应的程序并根据需要进行一些必要的设置。此外,由于 Linux 本身具有稳定性和可靠性等优势,能够很好地支持 RTSP 功能,因此在 Linux 平台上使用 RTSP 客户端播放媒体,可以获得更好的播放效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值