RTSP流媒体播放器实现

来源:互联网 发布:战姬天下完美转生数据 编辑:程序博客网 时间:2024/04/27 20:12

ARM+mplayer+QT+流媒体项目源代码包下载(刘继光著)

http://download.csdn.net/index.php/mobile/source/download/liuji_guang/2771211

Videojs播放RTMP流媒体

http://blog.csdn.net/dong_18383219470/article/details/52998278

FFmpeg3.3.2+SDL2实现流媒体音频播放

http://blog.csdn.net/ywl5320/article/details/76383099

Qt+VLC编写的流媒体播放器

https://sh.qihoo.com/ctranscode?userid=1a4f8abeb7b38703c3e907bc82ac9bde&fast=1&&360sodetail=1&u=http%3A%2F%2Fblog.csdn.net%2Fu012952807%2Farticle%2Fdetails%2F51659446&m=2faad55a1713f4197f47c4be009fa606a2a0b9dd&q=qt%20%20%20%20%20%E6%B5%81%E5%AA%92%E4%BD%93%E6%92%AD%E6%94%BE&t=news&sid=d9d0cc4e29c791f47f9a37b4e4bdb72b&tc_mode=news_recom

RTSP流媒体播放器实现

        最近需要做一个RTSP流媒体播放器,研究了一下,封装了一个RTSP播放类CRTSPPlayer,解码库采用ffmpeg。由于需求比较简单,时间也有限,目前只实现了播放、停止、暂停几个基本的接口。下面是基于CRTSPPlayer类实现的简单RTSP播放器。

                                   

       目前视频只测试了H264格式,其它格式的视频还未做测试。播放器也支持直接打开本地视频播放,但播放的帧率和原始视频的码率不同步。目前还不清楚如何处理这个问题,希望懂这方面的大侠指教。

       另外,还有一个开源的库VLC也可以用来开发流媒体播放器,它支持多种流媒体协议,如RTP、RTSP等,CodeProject上已经有牛人在VLCLib的基础上封装可更易使用的库VLCWrapper(地址:http://www.codeproject.com/Articles/38952/VLCWrapper-A-Little-C-wrapper-Around-libvlc)。用它可以很方便的开发视频播放器。

        以下是CRTSPPlayer完整的代码:

头文件:

[cpp] view plain copy
  1. /********************************************************************  
  2. filename:   CRTSPPlayer.h  
  3. created:    2013-03-25  
  4. author:     firehood  
  5. purpose:    ffmpeg库实现的RTSP视频播放器 
  6. *********************************************************************/   
  7. #pragma once  
  8. #include "windows.h"  
  9.   
  10. extern "C"  
  11. {  
  12. #include "libavformat\avformat.h"  
  13. #include "libavcodec\avcodec.h"  
  14. #include "libswscale\swscale.h"  
  15. };  
  16.   
  17. // 播放状态  
  18. enum RTSP_PLAYSTATUS  
  19. {  
  20.     RTSP_PLAYSTATUS_NONE,       // 未知状态(未播放)  
  21.     RTSP_PLAYSTATUS_PLAYING,    // 正在播放  
  22.     RTSP_PLAYSTATUS_PAUSE,      // 已暂停  
  23.     RTSP_PLAYSTATUS_STOP,       // 已停止  
  24. };  
  25.   
  26. class CRTSPPlayer  
  27. {  
  28. public:  
  29.     CRTSPPlayer(HWND hWnd, LPRECT lpRect);  
  30.     ~CRTSPPlayer(void);  
  31. public:  
  32.     // 打开媒体文件  
  33.     BOOL OpenMedia(LPCTSTR pFileName);  
  34.     // 播放  
  35.     void Play();  
  36.     // 暂停  
  37.     void Pause();  
  38.     // 停止  
  39.     void Stop();  
  40.     // 获取播放状态  
  41.     RTSP_PLAYSTATUS GetPlayStatus(void);  
  42. private:  
  43.     // 解码初始化  
  44.     int DecodeInit(LPCTSTR pFileName);  
  45.     // 卸载  
  46.     void DecodeUninit();  
  47.     // 开始解码线程  
  48.     BOOL StartDecodeThread();  
  49.     // 停止解码线程  
  50.     void StopDecodeThread();  
  51.     // 解码线程  
  52.     static int WINAPI ThreadDecodeVideo(LPVOID lpParam);  
  53.     // 开始解码任务  
  54.     int BeginDecode();  
  55.     // 显示  
  56.     void Display();  
  57.     // 图像转换  
  58.     int ImgConvert(AVPicture * dst, PixelFormat dstFormt, const AVPicture * src, PixelFormat srcFormt, int src_width, int src_height);  
  59.     // 设置播放状态  
  60.     void SetPlayStatus(RTSP_PLAYSTATUS playStatus);  
  61. private:  
  62.     HANDLE  m_hDecodeThread;  
  63.     BOOL    m_bExitDecodeThread;  
  64.     TCHAR   m_strFilePath[MAX_PATH];  
  65.   
  66.     AVFormatContext* m_pFormatContext;  
  67.     AVCodecContext*  m_pCodecContext;  
  68.     AVCodec* m_pCodec;  
  69.     AVPacket m_struPacket;  
  70.     int m_nStreamIndex;  
  71.     AVFrame* m_pFrameYUV;  
  72.     AVFrame* m_pFrameRGB;  
  73.     int     m_nFrameWidth;   
  74.     int     m_nFrameHeight;  
  75.     BYTE*   m_pBufRGB;        // 解码后的RGB数据  
  76.   
  77.     RTSP_PLAYSTATUS  m_nPlayStatus;  
  78.     HWND    m_hWnd;  
  79.     RECT    m_rcWnd;  
  80. };  


源文件:

[cpp] view plain copy
  1. /********************************************************************  
  2. filename:   CRTSPPlayer.cpp  
  3. created:    2013-03-25  
  4. author:     firehood  
  5. purpose:    ffmpeg库实现的RTSP视频播放器 
  6. *********************************************************************/   
  7. #include "StdAfx.h"  
  8. #include "RTSPPlayer.h"  
  9.   
  10. #pragma comment(lib, "avformat.lib")  
  11. #pragma comment(lib, "avcodec.lib")  
  12. #pragma comment(lib, "swscale.lib")  
  13. #pragma comment(lib, "avutil.lib")  
  14.   
  15. #define SHOW_TITLE  
  16.   
  17. const char* WcharToUtf8(const wchar_t *pwStr)    
  18. {    
  19.     if (pwStr == NULL)    
  20.     {    
  21.         return NULL;    
  22.     }    
  23.   
  24.     int len = WideCharToMultiByte(CP_UTF8, 0, pwStr, -1, NULL, 0, NULL, NULL);    
  25.     if (len <= 0)    
  26.     {    
  27.         return NULL;    
  28.     }    
  29.     char *pStr = new char[len];    
  30.     WideCharToMultiByte(CP_UTF8, 0, pwStr, -1, pStr, len, NULL, NULL);    
  31.     return pStr;    
  32. }    
  33.   
  34. CRTSPPlayer::CRTSPPlayer(HWND hWnd, LPRECT lpRect):  
  35. m_hWnd(hWnd),  
  36. m_rcWnd(*lpRect),  
  37. m_hDecodeThread(NULL),  
  38. m_bExitDecodeThread(FALSE),  
  39. m_nFrameWidth(0),  
  40. m_nFrameHeight(0),  
  41. m_pFormatContext(NULL),  
  42. m_pCodecContext(NULL),  
  43. m_pCodec(NULL),  
  44. m_nStreamIndex(-1),  
  45. m_pFrameYUV(NULL),  
  46. m_pFrameRGB(NULL),  
  47. m_pBufRGB(NULL),  
  48. m_nPlayStatus(RTSP_PLAYSTATUS_NONE)  
  49. {  
  50.     memset(m_strFilePath,0,sizeof(m_strFilePath));  
  51. }  
  52.   
  53. CRTSPPlayer::~CRTSPPlayer(void)  
  54. {  
  55.     DecodeUninit();  
  56. }  
  57.   
  58. // 打开媒体文件  
  59. BOOL CRTSPPlayer::OpenMedia(LPCTSTR pFileName)  
  60. {  
  61.     if(pFileName == NULL)  
  62.         return FALSE;  
  63.     DecodeUninit();  
  64.     memcpy(m_strFilePath,pFileName,sizeof(m_strFilePath));  
  65.     DecodeInit(m_strFilePath);  
  66.     return TRUE;  
  67. }  
  68.   
  69. // 播放  
  70. void CRTSPPlayer::Play()  
  71. {   
  72.     if(GetPlayStatus() == RTSP_PLAYSTATUS_STOP)  
  73.     {  
  74.         DecodeInit(m_strFilePath);  
  75.     }  
  76.     BOOL bRet = StartDecodeThread();  
  77.     if(bRet)  
  78.     {  
  79.         SetPlayStatus(RTSP_PLAYSTATUS_PLAYING);  
  80.     }  
  81. }  
  82.   
  83. // 暂停  
  84. void CRTSPPlayer::Pause()  
  85. {  
  86.     StopDecodeThread();  
  87.     SetPlayStatus(RTSP_PLAYSTATUS_PAUSE);  
  88. }  
  89.   
  90. // 停止  
  91. void CRTSPPlayer::Stop()  
  92. {  
  93.     StopDecodeThread();  
  94.     DecodeUninit();  
  95.     SetPlayStatus(RTSP_PLAYSTATUS_STOP);  
  96. }  
  97.   
  98. BOOL CRTSPPlayer::StartDecodeThread()  
  99. {  
  100.     if(m_hDecodeThread == NULL)  
  101.     {  
  102.         m_hDecodeThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadDecodeVideo, this, 0, NULL);  
  103.     }  
  104.     return m_hDecodeThread ? TRUE : FALSE;  
  105. }  
  106.   
  107. void CRTSPPlayer::StopDecodeThread()  
  108. {  
  109.     if(m_hDecodeThread)  
  110.     {  
  111.         m_bExitDecodeThread = TRUE;  
  112.         WaitForSingleObject(m_hDecodeThread,INFINITE);  
  113.         CloseHandle(m_hDecodeThread);  
  114.         m_hDecodeThread = NULL;  
  115.     }  
  116. }  
  117.   
  118. int CRTSPPlayer::ImgConvert(AVPicture * dst, PixelFormat dst_pix_fmt, const AVPicture * src, PixelFormat src_pix_fmt, int src_width, int src_height)  
  119. {  
  120.   
  121.     unsigned char * srcSlice[4];  
  122.     int srcStride[4] = {0};  
  123.   
  124.     unsigned char * dstSlice[4];  
  125.     int dstStride[4] = {0};  
  126.   
  127.   
  128.     for (int i=0; i<4; i++)  
  129.     {  
  130.         srcSlice[i] = src->data[i];  
  131.         srcStride[i] = src->linesize[i];  
  132.   
  133.         dstSlice[i] = dst->data[i];  
  134.         dstStride[i] = dst->linesize[i];  
  135.     }  
  136.   
  137.     SwsContext *pSwsContext = sws_getContext(src_width, src_height, src_pix_fmt, src_width, src_height, dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);  
  138.   
  139.     int nRet = sws_scale(pSwsContext, srcSlice, srcStride, 0, src_height, dstSlice, dstStride);  
  140.   
  141.     if (pSwsContext != NULL)  
  142.     {  
  143.         sws_freeContext(pSwsContext);  
  144.     }  
  145.   
  146.     return nRet;  
  147. }  
  148.   
  149. int WINAPI CRTSPPlayer::ThreadDecodeVideo(LPVOID lpParam)  
  150. {  
  151.     CRTSPPlayer *pPlayer = (CRTSPPlayer*)lpParam;  
  152.   
  153.     pPlayer->BeginDecode();  
  154.   
  155.     return 0;  
  156. }  
  157.   
  158. int CRTSPPlayer::DecodeInit(LPCTSTR pFileName)  
  159. {  
  160.     if(pFileName == NULL)  
  161.     {  
  162.         return -1;  
  163.     }  
  164.   
  165.     av_register_all();  
  166.   
  167. #ifdef  UNICODE     
  168.     const char *filePath = WcharToUtf8(pFileName);   
  169.     // Open video  
  170.     if (av_open_input_file(&m_pFormatContext, filePath, NULL, 0, NULL) != 0)  
  171.     {  
  172.         return -2; // Couldn't open file  
  173.     }  
  174.     delete[] filePath;  
  175. #else  
  176.     // Open video  
  177.     if (av_open_input_file(&m_pFormatContext, pFileName, NULL, 0, NULL) != 0)  
  178.     {  
  179.         return -2; // Couldn't open file  
  180.     }  
  181. #endif  
  182.     // Retrieve stream information  
  183.     if (av_find_stream_info(m_pFormatContext) < 0)  
  184.     {  
  185.         return -3; // Couldn't find stream information  
  186.     }  
  187.   
  188.     // Find the first video stream  
  189.     for (UINT i=0; i<m_pFormatContext->nb_streams; i++)  
  190.     {  
  191.         if (m_pFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)  
  192.         {  
  193.             m_nStreamIndex = i;  
  194.             break;  
  195.         }  
  196.     }  
  197.     if (m_nStreamIndex == -1)  
  198.     {  
  199.         return -4; // Didn't find a video stream  
  200.     }  
  201.   
  202.     // Get a pointer to the codec context for the video stream  
  203.     m_pCodecContext = m_pFormatContext->streams[m_nStreamIndex]->codec;  
  204.   
  205.     // Find the decoder for the video stream  
  206.     m_pCodec = avcodec_find_decoder(m_pCodecContext->codec_id);  
  207.     if (m_pCodec == NULL)  
  208.     {  
  209.         return -5 ; // Codec not found  
  210.     }  
  211.   
  212.     // Inform the codec that we can handle truncated bitstreams -- i.e.,  
  213.     // bitstreams where frame boundaries can fall in the middle of packets  
  214.     if (m_pCodec->capabilities & CODEC_CAP_TRUNCATED)  
  215.     {  
  216.         m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;  // we do not send complete frames  
  217.     }  
  218.   
  219.     // Open codec  
  220.     if (avcodec_open(m_pCodecContext, m_pCodec) < 0)  
  221.     {  
  222.         return -6; // Could not open codec  
  223.     }  
  224.   
  225.     // Allocate video frame  
  226.     m_pFrameYUV = avcodec_alloc_frame();  
  227.   
  228.     // Allocate an AVFrame structure  
  229.     m_pFrameRGB = avcodec_alloc_frame();  
  230.   
  231.     // Determine required buffer size and allocate buffer  
  232.     int numBytes = avpicture_get_size(PIX_FMT_BGR24, m_pCodecContext->width, m_pCodecContext->height);  
  233.     m_pBufRGB = new BYTE [numBytes];  
  234.     memset(m_pBufRGB,0,numBytes);  
  235.     // Assign appropriate parts of buffer to image planes in m_pFrameRGB  
  236.     avpicture_fill((AVPicture *)m_pFrameRGB, m_pBufRGB, PIX_FMT_BGR24, m_pCodecContext->width, m_pCodecContext->height);  
  237.   
  238.     m_nFrameWidth  = m_pCodecContext->width;  
  239.     m_nFrameHeight = m_pCodecContext->height;  
  240.   
  241.     return 0;  
  242. }  
  243.   
  244. void CRTSPPlayer::DecodeUninit()  
  245. {  
  246.     // Close the codec  
  247.     if (m_pCodecContext)  
  248.     {  
  249.         avcodec_close(m_pCodecContext);  
  250.         //av_free(m_pCodec);  
  251.         m_pCodecContext = NULL;  
  252.         m_pCodec = NULL;  
  253.     }  
  254.   
  255.     // Close the video file  
  256.     if (m_pFormatContext)  
  257.     {  
  258.         av_close_input_file(m_pFormatContext);  
  259.         m_pFormatContext = NULL;  
  260.     }  
  261.   
  262.     if (m_pFrameYUV)  
  263.     {  
  264.         av_free(m_pFrameYUV);  
  265.         m_pFrameYUV = NULL;  
  266.     }  
  267.   
  268.     if (m_pFrameRGB)  
  269.     {  
  270.         av_free(m_pFrameRGB);  
  271.         m_pFrameRGB = NULL;  
  272.     }  
  273.   
  274.     if (m_pBufRGB)  
  275.     {  
  276.         delete [] m_pBufRGB;  
  277.         m_pBufRGB = NULL;  
  278.     }  
  279. }  
  280.   
  281. int CRTSPPlayer::BeginDecode()  
  282. {  
  283.     int bytesRemaining = 0, bytesDecoded;  
  284.     BYTE * rawData = NULL;  
  285.   
  286.     int frameFinished = 0;  
  287.   
  288.     m_struPacket.data = NULL;  
  289.     m_struPacket.size = 0;  
  290.   
  291.     m_bExitDecodeThread = FALSE;  
  292.   
  293.     while (!m_bExitDecodeThread && m_pFormatContext)  
  294.     {  
  295.         // Read the next packet, skipping all packets that aren't for this stream  
  296.         do  
  297.         {  
  298.             // Read new packet  
  299.             if (av_read_frame(m_pFormatContext, &m_struPacket) < 0)  
  300.             {  
  301.   
  302.                 return -2;  
  303.             }  
  304.         } while (m_struPacket.stream_index != m_nStreamIndex);  
  305.   
  306.         bytesRemaining = m_struPacket.size;  
  307.         rawData = m_struPacket.data;  
  308.   
  309.         // Work on the current packet until we have decoded all of it  
  310.         while (bytesRemaining > 0)  
  311.         {  
  312.             // Decode the next chunk of data  
  313.             bytesDecoded = avcodec_decode_video(m_pCodecContext, m_pFrameYUV, &frameFinished, rawData, bytesRemaining);  
  314.   
  315.             // Was there an error?  
  316.             if (bytesDecoded < 0)  
  317.             {  
  318.                 return -1;  
  319.             }  
  320.   
  321.             bytesRemaining -= bytesDecoded;  
  322.             rawData += bytesDecoded;  
  323.   
  324.             // Did we finish the current frame? Then we can return  
  325.             if (frameFinished)  
  326.             {  
  327.                 ImgConvert(  
  328.                     (AVPicture *)m_pFrameRGB,  
  329.                     PIX_FMT_BGR24,  
  330.                     (AVPicture *)m_pFrameYUV,  
  331.                     m_pCodecContext->pix_fmt,  
  332.                     m_pCodecContext->width,  
  333.                     m_pCodecContext->height);  
  334.   
  335.                 Display();  
  336.             }  
  337.         }  
  338.     }  
  339.     m_hDecodeThread = NULL;  
  340.     return 0;  
  341. }  
  342.   
  343. void CRTSPPlayer::Display()  
  344. {  
  345.     HDC hdc = GetDC(m_hWnd);  
  346.     // 创建内存DC  
  347.     HDC hMemDc = CreateCompatibleDC(hdc);       
  348.   
  349.     // 创建位图  
  350.     BITMAPINFOHEADER bmpHdr = {0};    
  351.     bmpHdr.biSize = sizeof (BITMAPINFOHEADER);    
  352.     bmpHdr.biWidth = m_nFrameWidth;    
  353.     bmpHdr.biHeight = -m_nFrameHeight;    
  354.     bmpHdr.biPlanes = 1;    
  355.     bmpHdr.biBitCount = 24;    
  356.     bmpHdr.biCompression = BI_RGB;    
  357.   
  358.     BYTE *pData = NULL;     
  359.     HBITMAP hBitmap = CreateDIBSection (NULL, (BITMAPINFO *)&bmpHdr, DIB_RGB_COLORS, (void**)&pData, NULL, 0);    
  360.   
  361.     try  
  362.     {  
  363.         memcpy(pData, m_pBufRGB, m_nFrameWidth * m_nFrameHeight * 3);  
  364.     }  
  365.     catch (CMemoryException* e)  
  366.     {  
  367.           
  368.     }  
  369.   
  370.     HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDc, hBitmap);  
  371.   
  372. #ifdef SHOW_TITLE  
  373.     // 设置字体参数  
  374.     LOGFONT logfont;  
  375.     memset(&logfont, 0, sizeof(LOGFONT));  
  376.     logfont.lfHeight = 40;  
  377.     logfont.lfWidth = 0;      
  378.     logfont.lfEscapement = 0;  
  379.     logfont.lfOrientation = 0;  
  380.     logfont.lfWeight = 30;  
  381.     logfont.lfItalic = 0;  
  382.     logfont.lfUnderline = 0;  
  383.     logfont.lfStrikeOut = 0;  
  384.     logfont.lfCharSet = DEFAULT_CHARSET;     
  385.     logfont.lfOutPrecision= OUT_DEFAULT_PRECIS;     
  386.     logfont.lfClipPrecision= OUT_DEFAULT_PRECIS;     
  387.     logfont.lfQuality = DEFAULT_QUALITY;     
  388.     logfont.lfPitchAndFamily= DEFAULT_PITCH;    
  389.   
  390.     // 创建字体并选入环境  
  391.     HFONT hFont = CreateFontIndirect(&logfont);  
  392.     HFONT hOldFont = (HFONT)SelectObject(hMemDc, hFont);  
  393.   
  394.     // 设置绘图环境  
  395.     SetBkMode(hMemDc, TRANSPARENT);    
  396.     SetTextColor(hMemDc, RGB(255, 255, 0));  
  397.   
  398.     // 绘制文字  
  399.     TextOut(hMemDc,0,0,m_strFilePath,_tcslen(m_strFilePath));  
  400.   
  401.     // 恢复环境释放字体  
  402.     SelectObject(hMemDc, hOldFont);  
  403. #endif  
  404.     StretchBlt(    
  405.         hdc,    
  406.         m_rcWnd.left,     
  407.         m_rcWnd.top,     
  408.         m_rcWnd.right-m_rcWnd.left,     
  409.         m_rcWnd.bottom-m_rcWnd.top,     
  410.         hMemDc,    
  411.         0,     
  412.         0,     
  413.         m_nFrameWidth,     
  414.         m_nFrameHeight,     
  415.         SRCCOPY);    
  416.   
  417.     // 恢复并释放环境      
  418.     SelectObject(hMemDc,hOldBitmap);    
  419.     DeleteObject(hBitmap);    
  420.     DeleteDC(hMemDc);    
  421. }  
  422.   
  423. // 获取播放状态  
  424. RTSP_PLAYSTATUS CRTSPPlayer::GetPlayStatus(void)  
  425. {  
  426.     return m_nPlayStatus;  
  427. }  
  428.   
  429. // 设置播放状态  
  430. void CRTSPPlayer::SetPlayStatus(RTSP_PLAYSTATUS playStatus)  
  431. {  
  432.     m_nPlayStatus = playStatus;  
  433. }  
原创粉丝点击