live555直播v4l2读取的视频

使用live555 直播来自v4l2的摄像头数据,在我的这个工程中,基本思路是:使用V4L2采集摄像头数据,然后使用x264库对摄像头数据进行编码,编成H264数据格式,然后把数据写入到命名管道中。最后使用live555 从管道中读出数据发送出去,实现视频的直播。

    在我的工程调试过程中,使用的是罗技C270摄像头,出来的是YUYV数据格式。x264和live555 使用最新的库。工程目录如下:

[html]  view plain  copy
  1. ├── H264FramedLiveSource.cpp  
  2. ├── H264VideoStreamer.cpp  
  3. ├── include  
  4. │   ├── encoder  
  5. │   │   ├── encoder_define.hh  
  6. │   │   ├── H264FramedLiveSource.hh  
  7. │   │   └── stdint.h  
  8. │   ├── live555  
  9. │   │   ├── basicUsageEnvironment  
  10. │   │   ├── groupsock  
  11. │   │   ├── liveMedia  
  12. │   │   └── usageEnvironment  
  13. │   └── x264  
  14. │       ├── x264_config.h  
  15. │       └── x264.h  
  16. ├── lib  
  17. │   ├── livelib  
  18. │   │   ├── libBasicUsageEnvironment.a  
  19. │   │   ├── libgroupsock.a  
  20. │   │   ├── libliveMedia.a  
  21. │   │   └── libUsageEnvironment.a  
  22. │   └── x264lib  
  23. │       ├── libx264.a  
  24. │       └── libx264.so.148  
  25. └── Makefile  
    H264FramedLiveSource.cpp 中新建了一个Device 类,用来实现v4l2数据的采集和x264编码的实现。其函数定义如下:

[objc]  view plain  copy
  1. /*============================================================================= 
  2.  * #     FileName: H264FramedLiveSource.hh 
  3.  * #         Desc:  
  4.  * #                
  5.  * #       Author: licaibiao 
  6.  * #      Version:  
  7.  * #   LastChange: 2017-02-24  
  8.  * =============================================================================*/  
  9. #ifndef _H264FRAMEDLIVESOURCE_HH  
  10. #define _H264FRAMEDLIVESOURCE_HH  
  11. #include   
  12. #include   
  13. #include "encoder_define.hh"  
  14.   
  15. class Device  
  16. {  
  17. public:  
  18.     void init_mmap(void);  
  19.     void init_camera(void);  
  20.     void init_encoder(void);  
  21.     void open_camera(void);    
  22.     void close_camera(void);  
  23.     void read_one_frame(void);  
  24.     void getnextframe(void);  
  25.     void start_capture(void);  
  26.     void stop_capture(void);  
  27.     void close_encoder();   
  28.     int  camera_able_read(void);  
  29.     void compress_begin(Encoder *en, int width, int height);  
  30.     int  compress_frame(Encoder *en, int type, charchar *in, int len, charchar *out);  
  31.     void compress_end(Encoder *en);  
  32.     void Init();  
  33.     void intoloop();;  
  34.     void Destory();  
  35. public:  
  36.     int fd;  
  37.     FILEFILE *save_fd;  
  38.     int n_nal;  
  39.     int frame_len;  
  40.     charchar *h264_buf;  
  41.     unsigned int n_buffer;  
  42.     Encoder en;  
  43.     FILEFILE *h264_fp;  
  44.     BUFTYPE *usr_buf;  
  45.     FILEFILE *pipe_fd;  
  46. };  
  47. #endif  
    H264VideoStreamer.cpp 实现RTSP的创建。其代码实现如下:

[html]  view plain  copy
  1. /**********  
  2. This library is free software; you can redistribute it and/or modify it under  
  3. the terms of the GNU Lesser General Public License as published by the  
  4. Free Software Foundation; either version 3 of the License, or (at your  
  5. option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)  
  6.   
  7. This library is distributed in the hope that it will be useful, but WITHOUT  
  8. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS  
  9. FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for  
  10. more details.  
  11.   
  12. You should have received a copy of the GNU Lesser General Public License  
  13. along with this library; if not, write to the Free Software Foundation, Inc.,  
  14. 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA  
  15. **********/  
  16. // Copyright (c) 1996-2017, Live Networks, Inc.  All rights reserved  
  17. // A test program that reads a H.264 Elementary Stream video file  
  18. // and streams it using RTP  
  19. // main program  
  20. //  
  21. // NOTE: For this application to work, the H.264 Elementary Stream video file *must* contain SPS and PPS NAL units,  
  22. // ideally at or near the start of the file.  These SPS and PPS NAL units are used to specify 'configuration' information  
  23. // that is set in the output stream's SDP description (by the RTSP server that is built in to this application).  
  24. // Note also that - unlike some other "*Streamer" demo applications - the resulting stream can be received only using a  
  25. // RTSP client (such as "openRTSP")  
  26.   
  27. #include <liveMedia.hh>  
  28. #include <BasicUsageEnvironment.hh>  
  29. #include <GroupsockHelper.hh>  
  30. #include <H264FramedLiveSource.hh>  
  31. #include <sys/types.h>    
  32. #include <sys/stat.h>   
  33.   
  34. UsageEnvironment* env;  
  35. char const* inputFileName = "/tmp/fifo";  
  36. char *ptr;  
  37. H264VideoStreamFramer* videoSource;  
  38. RTPSink* videoSink;  
  39. class Device Camera;   
  40.   
  41. void play(); // forward  
  42.   
  43. EventTriggerId DeviceSource::eventTriggerId = 0;  
  44.   
  45. int main(int argc, char** argv) {  
  46.   // Begin by setting up our usage environment:  
  47.   TaskScheduler* scheduler = BasicTaskScheduler::createNew();  
  48.   env = BasicUsageEnvironment::createNew(*scheduler);  
  49.   
  50.   // Create 'groupsocks' for RTP and RTCP:  
  51.   struct in_addr destinationAddress;  
  52.   destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env);  
  53.   // Note: This is a multicast address.  If you wish instead to stream  
  54.   // using unicast, then you should use the "testOnDemandRTSPServer"  
  55.   // test program - not this test program - as a model.  
  56.   
  57.   const unsigned short rtpPortNum = 18888;  
  58.   const unsigned short rtcpPortNum = rtpPortNum+1;  
  59.   const unsigned char ttl = 255;  
  60.   
  61.   const Port rtpPort(rtpPortNum);  
  62.   const Port rtcpPort(rtcpPortNum);  
  63.   
  64.   Camera.Init();  
  65.   mkfifo(inputFileName, 0777);  
  66.   if(0 == fork())  
  67.   {  
  68.     Camera.pipe_fd = fopen(inputFileName, "w");  
  69.     if(NULL == Camera.pipe_fd)  
  70.     {  
  71.         printf("===============child process open pipe err =======\n ");  
  72.     }  
  73.     while(1)  
  74.     {  
  75.         usleep(15000);  
  76.         Camera.getnextframe();  
  77.     }  
  78.       
  79.   }  
  80.   
  81.   Groupsock rtpGroupsock(*env, destinationAddress, rtpPort, ttl);  
  82.   rtpGroupsock.multicastSendOnly(); // we're a SSM source  
  83.   Groupsock rtcpGroupsock(*env, destinationAddress, rtcpPort, ttl);  
  84.   rtcpGroupsock.multicastSendOnly(); // we're a SSM source  
  85.   
  86.     
  87.           
  88.   // Create a 'H264 Video RTP' sink from the RTP 'groupsock':  
  89.   OutPacketBuffer::maxSize = 600000;  
  90.   videoSink = H264VideoRTPSink::createNew(*env, &rtpGroupsock, 96);  
  91.   
  92.   // Create (and start) a 'RTCP instance' for this RTP sink:  
  93.   const unsigned estimatedSessionBandwidth = 10000; // in kbps; for RTCP b/w share  
  94.   const unsigned maxCNAMElen = 100;  
  95.   unsigned char CNAME[maxCNAMElen+1];  
  96.   gethostname((char*)CNAME, maxCNAMElen);  
  97.   CNAME[maxCNAMElen] = '\0'; // just in case  
  98.   RTCPInstance* rtcp  
  99.   = RTCPInstance::createNew(*env, &rtcpGroupsock,  
  100.                 estimatedSessionBandwidth, CNAME,  
  101.                 videoSink, NULL /* we're a server */,  
  102.                 True /* we're a SSM source */);  
  103.   // Note: This starts RTCP running automatically  
  104.   
  105.   RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554);  
  106.   if (rtspServer == NULL) {  
  107.     *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";  
  108.     exit(1);  
  109.   }  
  110.   ServerMediaSession* sms  
  111.     = ServerMediaSession::createNew(*env, "testStream", inputFileName,  
  112.            "Session streamed by \"testH264VideoStreamer\"",  
  113.                        True /*SSM*/);  
  114.   sms->addSubsession(PassiveServerMediaSubsession::createNew(*videoSink, rtcp));  
  115.   rtspServer->addServerMediaSession(sms);  
  116.   
  117.   char* url = rtspServer->rtspURL(sms);  
  118.   *env << "Play this stream using the URL \"" << url << "\"\n";  
  119.   delete[] url;  
  120.   
  121.   // Start the streaming:  
  122.   *env << "Beginning streaming...\n";  
  123.   play();  
  124.   
  125.   env->taskScheduler().doEventLoop(); // does not return  
  126.   
  127.   return 0; // only to prevent compiler warning  
  128. }  
  129.   
  130. void afterPlaying(void* /*clientData*/) {  
  131.   *env << "...done reading from file\n";  
  132.   videoSink->stopPlaying();  
  133.   Medium::close(videoSource);  
  134.   Camera.Destory();  
  135.   // Note that this also closes the input file that this source read from.  
  136.   
  137.   // Start playing once again:  
  138.   play();  
  139. }  
  140.   
  141. void play() {  
  142.   // Open the input file as a 'byte-stream file source':  
  143.   ByteStreamFileSource* fileSource  
  144.     = ByteStreamFileSource::createNew(*env, inputFileName);  
  145.   if (fileSource == NULL) {  
  146.     *env << "Unable to open file \"" << inputFileName  
  147.          << "\" as a byte-stream file source\n";  
  148.     exit(1);  
  149.   }  
  150.   
  151.   FramedSource* videoES = fileSource;  
  152.   
  153.   // Create a framer for the Video Elementary Stream:  
  154.   videoSource = H264VideoStreamFramer::createNew(*env, videoES);  
  155.   
  156.   // Finally, start playing:  
  157.   *env << "Beginning to read from file...\n";  
  158.   videoSink->startPlaying(*videoSource, afterPlaying, videoSink);  
  159. }  
   x264 和live555库的下载编译安装,在前面的博客中已经讲过,这里不再重复。编译运行整个工程如下:

[objc]  view plain  copy
  1. [root@redhat pipelive]# ls  
  2. H264FramedLiveSource.cpp  H264FramedLiveSource.o  H264VideoStreamer  H264VideoStreamer.cpp  H264VideoStreamer.o  include  lib  Makefile  
  3. [root@redhat pipelive]# ./H264VideoStreamer  
  4.   
  5. camera driver name is : uvcvideo  
  6. camera device name is : UVC Camera (046d:0825)  
  7. camera bus information: usb-0000:00:1a.0-1.1  
  8. n_buffer = 4  
  9. x264 [warning]: lookaheadless mb-tree requires intra refresh or infinite keyint  
  10. x264 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX  
  11. x264 [info]: profile High 4:2:2, level 3.0, 4:2:2 8-bit  
  12. Play this stream using the URL "rtsp://192.168.0.127:8554/testStream"  
  13. Beginning streaming...  
  14. Beginning to read from file...  
    在VLC 播放器中打开网络流rtsp://192.168.0.127:8554/testStream 可以看到摄像头中的数据:




     实际测试,使用管道来传输摄像头数据会出现一些延时,如果图片尺寸设置在320*240 延时会很小,但是图片尺寸设置在640*480,延时现象就会非常明显。这与我使用的摄像头也有关系,UVC摄像头读取数据相对会比较慢。

    完整的工程可以从这里下载:live555直播来自v4l2 的摄像头数据


原文:http://blog.csdn.net/li_wen01/article/details/59523963


你可能感兴趣的:(视频压缩直播)