嵌入式 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完整的代码:
头文件:
- /********************************************************************
- filename: CRTSPPlayer.h
- created: 2013-03-25
- author: firehood
- purpose: ffmpeg库实现的RTSP视频播放器
- *********************************************************************/
- #pragma once
- #include "windows.h"
- extern "C"
- {
- #include "libavformat\avformat.h"
- #include "libavcodec\avcodec.h"
- #include "libswscale\swscale.h"
- };
- // 播放状态
- enum RTSP_PLAYSTATUS
- {
- RTSP_PLAYSTATUS_NONE, // 未知状态(未播放)
- RTSP_PLAYSTATUS_PLAYING, // 正在播放
- RTSP_PLAYSTATUS_PAUSE, // 已暂停
- RTSP_PLAYSTATUS_STOP, // 已停止
- };
- class CRTSPPlayer
- {
- public:
- CRTSPPlayer(HWND hWnd, LPRECT lpRect);
- ~CRTSPPlayer(void);
- public:
- // 打开媒体文件
- BOOL OpenMedia(LPCTSTR pFileName);
- // 播放
- void Play();
- // 暂停
- void Pause();
- // 停止
- void Stop();
- // 获取播放状态
- RTSP_PLAYSTATUS GetPlayStatus(void);
- private:
- // 解码初始化
- int DecodeInit(LPCTSTR pFileName);
- // 卸载
- void DecodeUninit();
- // 开始解码线程
- BOOL StartDecodeThread();
- // 停止解码线程
- void StopDecodeThread();
- // 解码线程
- static int WINAPI ThreadDecodeVideo(LPVOID lpParam);
- // 开始解码任务
- int BeginDecode();
- // 显示
- void Display();
- // 图像转换
- int ImgConvert(AVPicture * dst, PixelFormat dstFormt, const AVPicture * src, PixelFormat srcFormt, int src_width, int src_height);
- // 设置播放状态
- void SetPlayStatus(RTSP_PLAYSTATUS playStatus);
- private:
- HANDLE m_hDecodeThread;
- BOOL m_bExitDecodeThread;
- TCHAR m_strFilePath[MAX_PATH];
- AVFormatContext* m_pFormatContext;
- AVCodecContext* m_pCodecContext;
- AVCodec* m_pCodec;
- AVPacket m_struPacket;
- int m_nStreamIndex;
- AVFrame* m_pFrameYUV;
- AVFrame* m_pFrameRGB;
- int m_nFrameWidth;
- int m_nFrameHeight;
- BYTE* m_pBufRGB; // 解码后的RGB数据
- RTSP_PLAYSTATUS m_nPlayStatus;
- HWND m_hWnd;
- RECT m_rcWnd;
- };
源文件:
- /********************************************************************
- filename: CRTSPPlayer.cpp
- created: 2013-03-25
- author: firehood
- purpose: ffmpeg库实现的RTSP视频播放器
- *********************************************************************/
- #include "StdAfx.h"
- #include "RTSPPlayer.h"
- #pragma comment(lib, "avformat.lib")
- #pragma comment(lib, "avcodec.lib")
- #pragma comment(lib, "swscale.lib")
- #pragma comment(lib, "avutil.lib")
- #define SHOW_TITLE
- const char* WcharToUtf8(const wchar_t *pwStr)
- {
- if (pwStr == NULL)
- {
- return NULL;
- }
- int len = WideCharToMultiByte(CP_UTF8, 0, pwStr, -1, NULL, 0, NULL, NULL);
- if (len <= 0)
- {
- return NULL;
- }
- char *pStr = new char[len];
- WideCharToMultiByte(CP_UTF8, 0, pwStr, -1, pStr, len, NULL, NULL);
- return pStr;
- }
- CRTSPPlayer::CRTSPPlayer(HWND hWnd, LPRECT lpRect):
- m_hWnd(hWnd),
- m_rcWnd(*lpRect),
- m_hDecodeThread(NULL),
- m_bExitDecodeThread(FALSE),
- m_nFrameWidth(0),
- m_nFrameHeight(0),
- m_pFormatContext(NULL),
- m_pCodecContext(NULL),
- m_pCodec(NULL),
- m_nStreamIndex(-1),
- m_pFrameYUV(NULL),
- m_pFrameRGB(NULL),
- m_pBufRGB(NULL),
- m_nPlayStatus(RTSP_PLAYSTATUS_NONE)
- {
- memset(m_strFilePath,0,sizeof(m_strFilePath));
- }
- CRTSPPlayer::~CRTSPPlayer(void)
- {
- DecodeUninit();
- }
- // 打开媒体文件
- BOOL CRTSPPlayer::OpenMedia(LPCTSTR pFileName)
- {
- if(pFileName == NULL)
- return FALSE;
- DecodeUninit();
- memcpy(m_strFilePath,pFileName,sizeof(m_strFilePath));
- DecodeInit(m_strFilePath);
- return TRUE;
- }
- // 播放
- void CRTSPPlayer::Play()
- {
- if(GetPlayStatus() == RTSP_PLAYSTATUS_STOP)
- {
- DecodeInit(m_strFilePath);
- }
- BOOL bRet = StartDecodeThread();
- if(bRet)
- {
- SetPlayStatus(RTSP_PLAYSTATUS_PLAYING);
- }
- }
- // 暂停
- void CRTSPPlayer::Pause()
- {
- StopDecodeThread();
- SetPlayStatus(RTSP_PLAYSTATUS_PAUSE);
- }
- // 停止
- void CRTSPPlayer::Stop()
- {
- StopDecodeThread();
- DecodeUninit();
- SetPlayStatus(RTSP_PLAYSTATUS_STOP);
- }
- BOOL CRTSPPlayer::StartDecodeThread()
- {
- if(m_hDecodeThread == NULL)
- {
- m_hDecodeThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadDecodeVideo, this, 0, NULL);
- }
- return m_hDecodeThread ? TRUE : FALSE;
- }
- void CRTSPPlayer::StopDecodeThread()
- {
- if(m_hDecodeThread)
- {
- m_bExitDecodeThread = TRUE;
- WaitForSingleObject(m_hDecodeThread,INFINITE);
- CloseHandle(m_hDecodeThread);
- m_hDecodeThread = NULL;
- }
- }
- int CRTSPPlayer::ImgConvert(AVPicture * dst, PixelFormat dst_pix_fmt, const AVPicture * src, PixelFormat src_pix_fmt, int src_width, int src_height)
- {
- unsigned char * srcSlice[4];
- int srcStride[4] = {0};
- unsigned char * dstSlice[4];
- int dstStride[4] = {0};
- for (int i=0; i<4; i++)
- {
- srcSlice[i] = src->data[i];
- srcStride[i] = src->linesize[i];
- dstSlice[i] = dst->data[i];
- dstStride[i] = dst->linesize[i];
- }
- SwsContext *pSwsContext = sws_getContext(src_width, src_height, src_pix_fmt, src_width, src_height, dst_pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
- int nRet = sws_scale(pSwsContext, srcSlice, srcStride, 0, src_height, dstSlice, dstStride);
- if (pSwsContext != NULL)
- {
- sws_freeContext(pSwsContext);
- }
- return nRet;
- }
- int WINAPI CRTSPPlayer::ThreadDecodeVideo(LPVOID lpParam)
- {
- CRTSPPlayer *pPlayer = (CRTSPPlayer*)lpParam;
- pPlayer->BeginDecode();
- return 0;
- }
- int CRTSPPlayer::DecodeInit(LPCTSTR pFileName)
- {
- if(pFileName == NULL)
- {
- return -1;
- }
- av_register_all();
- #ifdef UNICODE
- const char *filePath = WcharToUtf8(pFileName);
- // Open video
- if (av_open_input_file(&m_pFormatContext, filePath, NULL, 0, NULL) != 0)
- {
- return -2; // Couldn't open file
- }
- delete[] filePath;
- #else
- // Open video
- if (av_open_input_file(&m_pFormatContext, pFileName, NULL, 0, NULL) != 0)
- {
- return -2; // Couldn't open file
- }
- #endif
- // Retrieve stream information
- if (av_find_stream_info(m_pFormatContext) < 0)
- {
- return -3; // Couldn't find stream information
- }
- // Find the first video stream
- for (UINT i=0; i<m_pFormatContext->nb_streams; i++)
- {
- if (m_pFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
- {
- m_nStreamIndex = i;
- break;
- }
- }
- if (m_nStreamIndex == -1)
- {
- return -4; // Didn't find a video stream
- }
- // Get a pointer to the codec context for the video stream
- m_pCodecContext = m_pFormatContext->streams[m_nStreamIndex]->codec;
- // Find the decoder for the video stream
- m_pCodec = avcodec_find_decoder(m_pCodecContext->codec_id);
- if (m_pCodec == NULL)
- {
- return -5 ; // Codec not found
- }
- // Inform the codec that we can handle truncated bitstreams -- i.e.,
- // bitstreams where frame boundaries can fall in the middle of packets
- if (m_pCodec->capabilities & CODEC_CAP_TRUNCATED)
- {
- m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED; // we do not send complete frames
- }
- // Open codec
- if (avcodec_open(m_pCodecContext, m_pCodec) < 0)
- {
- return -6; // Could not open codec
- }
- // Allocate video frame
- m_pFrameYUV = avcodec_alloc_frame();
- // Allocate an AVFrame structure
- m_pFrameRGB = avcodec_alloc_frame();
- // Determine required buffer size and allocate buffer
- int numBytes = avpicture_get_size(PIX_FMT_BGR24, m_pCodecContext->width, m_pCodecContext->height);
- m_pBufRGB = new BYTE [numBytes];
- memset(m_pBufRGB,0,numBytes);
- // Assign appropriate parts of buffer to image planes in m_pFrameRGB
- avpicture_fill((AVPicture *)m_pFrameRGB, m_pBufRGB, PIX_FMT_BGR24, m_pCodecContext->width, m_pCodecContext->height);
- m_nFrameWidth = m_pCodecContext->width;
- m_nFrameHeight = m_pCodecContext->height;
- return 0;
- }
- void CRTSPPlayer::DecodeUninit()
- {
- // Close the codec
- if (m_pCodecContext)
- {
- avcodec_close(m_pCodecContext);
- //av_free(m_pCodec);
- m_pCodecContext = NULL;
- m_pCodec = NULL;
- }
- // Close the video file
- if (m_pFormatContext)
- {
- av_close_input_file(m_pFormatContext);
- m_pFormatContext = NULL;
- }
- if (m_pFrameYUV)
- {
- av_free(m_pFrameYUV);
- m_pFrameYUV = NULL;
- }
- if (m_pFrameRGB)
- {
- av_free(m_pFrameRGB);
- m_pFrameRGB = NULL;
- }
- if (m_pBufRGB)
- {
- delete [] m_pBufRGB;
- m_pBufRGB = NULL;
- }
- }
- int CRTSPPlayer::BeginDecode()
- {
- int bytesRemaining = 0, bytesDecoded;
- BYTE * rawData = NULL;
- int frameFinished = 0;
- m_struPacket.data = NULL;
- m_struPacket.size = 0;
- m_bExitDecodeThread = FALSE;
- while (!m_bExitDecodeThread && m_pFormatContext)
- {
- // Read the next packet, skipping all packets that aren't for this stream
- do
- {
- // Read new packet
- if (av_read_frame(m_pFormatContext, &m_struPacket) < 0)
- {
- return -2;
- }
- } while (m_struPacket.stream_index != m_nStreamIndex);
- bytesRemaining = m_struPacket.size;
- rawData = m_struPacket.data;
- // Work on the current packet until we have decoded all of it
- while (bytesRemaining > 0)
- {
- // Decode the next chunk of data
- bytesDecoded = avcodec_decode_video(m_pCodecContext, m_pFrameYUV, &frameFinished, rawData, bytesRemaining);
- // Was there an error?
- if (bytesDecoded < 0)
- {
- return -1;
- }
- bytesRemaining -= bytesDecoded;
- rawData += bytesDecoded;
- // Did we finish the current frame? Then we can return
- if (frameFinished)
- {
- ImgConvert(
- (AVPicture *)m_pFrameRGB,
- PIX_FMT_BGR24,
- (AVPicture *)m_pFrameYUV,
- m_pCodecContext->pix_fmt,
- m_pCodecContext->width,
- m_pCodecContext->height);
- Display();
- }
- }
- }
- m_hDecodeThread = NULL;
- return 0;
- }
- void CRTSPPlayer::Display()
- {
- HDC hdc = GetDC(m_hWnd);
- // 创建内存DC
- HDC hMemDc = CreateCompatibleDC(hdc);
- // 创建位图
- BITMAPINFOHEADER bmpHdr = {0};
- bmpHdr.biSize = sizeof (BITMAPINFOHEADER);
- bmpHdr.biWidth = m_nFrameWidth;
- bmpHdr.biHeight = -m_nFrameHeight;
- bmpHdr.biPlanes = 1;
- bmpHdr.biBitCount = 24;
- bmpHdr.biCompression = BI_RGB;
- BYTE *pData = NULL;
- HBITMAP hBitmap = CreateDIBSection (NULL, (BITMAPINFO *)&bmpHdr, DIB_RGB_COLORS, (void**)&pData, NULL, 0);
- try
- {
- memcpy(pData, m_pBufRGB, m_nFrameWidth * m_nFrameHeight * 3);
- }
- catch (CMemoryException* e)
- {
- }
- HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDc, hBitmap);
- #ifdef SHOW_TITLE
- // 设置字体参数
- LOGFONT logfont;
- memset(&logfont, 0, sizeof(LOGFONT));
- logfont.lfHeight = 40;
- logfont.lfWidth = 0;
- logfont.lfEscapement = 0;
- logfont.lfOrientation = 0;
- logfont.lfWeight = 30;
- logfont.lfItalic = 0;
- logfont.lfUnderline = 0;
- logfont.lfStrikeOut = 0;
- logfont.lfCharSet = DEFAULT_CHARSET;
- logfont.lfOutPrecision= OUT_DEFAULT_PRECIS;
- logfont.lfClipPrecision= OUT_DEFAULT_PRECIS;
- logfont.lfQuality = DEFAULT_QUALITY;
- logfont.lfPitchAndFamily= DEFAULT_PITCH;
- // 创建字体并选入环境
- HFONT hFont = CreateFontIndirect(&logfont);
- HFONT hOldFont = (HFONT)SelectObject(hMemDc, hFont);
- // 设置绘图环境
- SetBkMode(hMemDc, TRANSPARENT);
- SetTextColor(hMemDc, RGB(255, 255, 0));
- // 绘制文字
- TextOut(hMemDc,0,0,m_strFilePath,_tcslen(m_strFilePath));
- // 恢复环境释放字体
- SelectObject(hMemDc, hOldFont);
- #endif
- StretchBlt(
- hdc,
- m_rcWnd.left,
- m_rcWnd.top,
- m_rcWnd.right-m_rcWnd.left,
- m_rcWnd.bottom-m_rcWnd.top,
- hMemDc,
- 0,
- 0,
- m_nFrameWidth,
- m_nFrameHeight,
- SRCCOPY);
- // 恢复并释放环境
- SelectObject(hMemDc,hOldBitmap);
- DeleteObject(hBitmap);
- DeleteDC(hMemDc);
- }
- // 获取播放状态
- RTSP_PLAYSTATUS CRTSPPlayer::GetPlayStatus(void)
- {
- return m_nPlayStatus;
- }
- // 设置播放状态
- void CRTSPPlayer::SetPlayStatus(RTSP_PLAYSTATUS playStatus)
- {
- m_nPlayStatus = playStatus;
- }
嵌入式 RTSP流媒体播放器实现的更多相关文章
- EasyPlayerPro Windows流媒体播放器(RTSP/RTMP/HTTP/HLS/File/TCP/RTP/UDP都能播)发布啦
EasyPlayerPro简介 EasyPlayerPro是一款全功能的流媒体播放器,支持RTSP.RTMP.HTTP.HLS.UDP.RTP.File等多种流媒体协议播放.支持本地文件播放,支持本地 ...
- RTSP/RTMP/HLS/HTTP流媒体播放器EasyPlayer
EasyPlayer播放器系列项目 EasyPlayer是由EasyDarwin开源团队开发和维护的一个流媒体播放器系列项目,随着多年不断的发展和迭代,不断基于成功的实践经验,发展出包括有: Easy ...
- 基于Live555,ffmpeg的RTSP播放器直播与点播
基于Live555,ffmpeg的RTSP播放器直播与点播 多路RTSP高清视频播放器下载地址:http://download.csdn.net/detail/u011352914/6604437多路 ...
- EasyPlayer RTSP播放器运行出现: Unable to load DLL 找不到指定的模块。exception from HRESULT 0x8007007E 解决方案
最近有EasyPlayer RTSP播放器的开发者反馈,在一台新装的Windows Server 2008的操作系统上运行EasyPlayer RTSP播放器出现"Unable to loa ...
- EasyPlayer RTSP播放器OCX RegSvr32注册报错,DllRegisterServer调用失败,错误代码为0x80040200 解决方法
问题描述 模块"EasyPlayer-RTSPWebActiveX.ocx" 已加载,但对DLLRegisterServer调用失败,错误代码为0x80040200. 解决方法 是 ...
- EasyPlayer windows RTSP播放器OCX插件使用说明
鉴于大家对于EasyPlayer插件的使用还不太熟悉,特此写一篇插件的使用文档,供大家参考:EasyPlayer插件有两种,一种是基于IE的ActiveX控件,一种是基于FireFox(也支持多浏览器 ...
- EasyPlayer RTSP播放器对RTSP播放地址url的通用兼容修改意见
问题反馈 最近在线上遇到一位老朋友咨询关于EasyPlayer播放器的事情,大概现象就是分别用EasyPlayer和vlc播放大华摄像机的RTSP流,流地址是:rtsp://admin:admin12 ...
- EasyPlayerPro(Windows)流媒体播放器开发之框架讲解
EasyPlayerPro for Windows是基于ffmpeg进行开发的全功能播放器,开发过程中参考了很多开源的播放器,诸如vlc和ffplay等,其中最强大的莫过于vlc,但是鉴于vlc框架过 ...
- EasyPlayerPro(Windows)流媒体播放器开发之跨语言调用
下面我们来讲解一下关于EasyPlayerPro接口的调用,主要分为C++和C#两种语言,C++也可以基于VC和QT进行开发,C++以VC MFC框架为例进行讲解,C#以Winform框架为例进行讲解 ...
随机推荐
- lintcode :单词搜索
题目 单词搜索 给出一个二维的字母板和一个单词,寻找字母板网格中是否存在这个单词. 单词可以由按顺序的相邻单元的字母组成,其中相邻单元指的是水平或者垂直方向相邻.每个单元中的字母最多只能使用一次. 样 ...
- CF 353A Domino
#include<stdio.h> #include<math.h> int main() { int i,n; int x,y; int m1,m2,m3,m4; while ...
- DIV CSS设计时IE6、IE7、FF 与兼容性有关的特性(转载的)
在网站设计的时候,应该注意css样式兼容不同浏览器问题,特别是对完全使用DIV CSS设计的网,就应该更注意IE6 IE7 FF对CSS样式的兼容,不然,你的网乱可能出去不想出现的效果! 所有浏览器 ...
- Qt通过UDP传图片,实现自定义分包和组包
一.包头结构体 //包头 struct PackageHeader { //包头大小(sizeof(PackageHeader)) unsigned int uTransPackageHdrSize; ...
- mysql代码里面有中文注释导致语法错误
一个简单的创建表的代码 DROP database IF exists reg_login; CREATE database reg_login; use reg_login --用户表 create ...
- Git忽略文件方法【转】
转自:http://www.cnblogs.com/shangdawei/archive/2012/09/08/2676669.html http://cwind.iteye.com/blog/166 ...
- [原]HDU-1598-find the most comfortable road(暴力枚举+Kruskal最小生成树)
题意: 给出一个图,然后Q个询问,每次询问从一个节点到另一个节点,联通图中的“最大边和最小边之差”的最小值,但如果节点之间不连通,则输出-1. 思路:由于询问Q < 11,m < 1000 ...
- ACdream 1726 A Math game (dfs+二分)
http://acdream.info/problem?pid=1726 官方题解:http://acdream.info/topic?tid=4246 求n个数里面能不能选一些数出来让它们的和等于k ...
- linux 查看程序是否运行
命令格式:ps -ax|grep program_name 如查看包含python的程序是否运行: ps -ax|grep python ? Sl : python ToServer.py pts/ ...
- Linux Kernel CMPXCHG函数分析
原文地址:http://blog.csdn.net/penngrove/article/details/44175387 最近看到Linux Kernel cmpxchg的代码,对实现很不理解.上网查 ...