Recently, we need to create an RTSP Streaming Media Player. After studying it, we encapsulate an RTSP playing class crtspplayer, and the decoding library uses FFMPEG. Due to the simple requirement and limited time, only the following basic interfaces are available: Play, stop, and pause. The following is a simple RTSP Player Based on the crtspplayer class.
Currently, only videos in h264 format are tested. Videos in other formats are not tested yet. The player also supports playing a local video directly, but the frame rate and the bit rate of the original video are not synchronized. We do not know how to deal with this issue yet. I hope you can understand this question.
In addition, an open-source library VLC can also be used to develop streaming media players. It supports multiple streaming media protocols, such as RTP and RTSP, codeproject has been built on vlclib to encapsulate a more accessible library vlcwrapper (Address: http://www.codeproject.com/Articles/38952/VLCWrapper-A-Little-C-wrapper-Around-libvlc ). It allows you to easily develop video players.
The complete code for crtspplayer is as follows:
Header file:
/*************************************** * **************************** Filename: crtspplayer. h created: 2013-03-25 Author: firehood purpose: RTSP Video Player ************************************* implemented by FFMPEG Library ********************************* * **********************************/# pragma once # include "windows. H "extern" C "{# include" libavformat \ avformat. H "# include" libavcodec \ avcodec. H "# include" libswscale \ swscale. H "}; // playback status Enum rtsp_playstatus {RTS P_playstatus_none, // unknown status (not played) rtsp_playstatus_playing, // playing paused, // rtsp_playstatus_stop paused, // stopped}; Class crtspplayer {public: crtspplayer (hwnd, lprect );~ Crtspplayer (void); Public: // open the media file bool openmedia (lpctstr pfilename); // play void play (); // pause void pause (); // stop void stop (); // obtain the playing status rtsp_playstatus getplaystatus (void); Private: // decodes initialization int decodeinit (lpctstr pfilename); // uninstall void decodeuninit (); // start the decoding thread bool startdecodethread (); // stop the decoding thread void stopdecodethread (); // The decoding thread static int winapi threaddecodevideo (lpvoid lpparam ); // start the decoding task int begindecode (); // display void display (); // image conversion int imgconvert (avpicture * DST, pixelformat dstformt, const avpicture * SRC, pixelformat srcformt, int src_width, int src_height); // sets the playback status void setplaystatus (rtsp_playstatus playstatus); Private: handle m_hdecodethread; bool finished; 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 * handle; // decoded RGB data rtsp_playstatus m_nplaystatus; hwnd m_hwnd; rect m_rcwnd ;};
Source file:
/*************************************** * **************************** Filename: CRTSPPlayer. cpp created: 2013-03-25 author: firehood purpose: RTSP Video Player ************************************* implemented by ffmpeg Library ********************************* * **********************************/# 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_TITLEconst 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_rcW Nd (* 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 () ;}// open the media file BOOL CRTSPPlayer: OpenMedia (LPCTSTR pFileName) {if (pFileName = NULL) return FALSE; DecodeUninit (); memcpy (m_strFilePath, pFileName, sizeof (m_strFilePath); DecodeInit (m_strFilePath); return TRUE ;}// Play void CRTSPPlayer: Play () {if (GetPlayStatus () = RTSP_PLAYSTATUS_STOP) {DecodeInit (m_strFilePath);} BOOL bRet = StartDecodeThread (); if (bRet) {SetPlayStatus (RTSP_PLAYSTA TUS_PLAYING) ;}}// Pause void CRTSPPlayer: Pause () {StopDecodeThread (); SetPlayStatus (RTSP_PLAYSTATUS_PAUSE);} // Stop void CRTSPPlayer: Stop () {StopDecodeThread (); DecodeUninit (); SetPlayStatus (RTSP_PLAYSTATUS_STOP);} BOOL CRTSPPlayer: StartDecodeThread () {if (Bytes = NULL) {bytes = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) ThreadDecodeVideo, this, 0, NULL);} return m_hDecodeThread? TRUE: FALSE;} void CRTSPPlayer: StopDecodeThread () {if (response) {response = TRUE; WaitForSingleObject (response, INFINITE); CloseHandle (m_hDecodeThread); m_hDecodeThread = NULL ;}} int CRTSPPlayer: ImgConvert (AVPicture * dst, PixelFormat convert, const AVPicture * src, PixelFormat src_pix_fmt, int src_width, int src_height) {unsigned char * srcSlice [4]; int srcStride [4] = {0}; un Signed 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, distance, SWS_BICUBIC, NULL, NULL, NULL); int nRet = sws_scale (pSwsContext, srcSlice, srcStride, 0, src_he Ight, 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 videoif (av_open_input_file (& m_pFormatContext, FilePath, NULL, 0, NULL )! = 0) {return-2; // Couldn't open file} delete [] filePath; # else // Open videoif (av_open_input_file (& m_pFormatContext, pFileName, NULL, 0, NULL )! = 0) {return-2; // Couldn't open file} # endif // Retrieve stream informationif (av_find_stream_info (m_pFormatContext) <0) {return-3; // Couldn't find stream information} // Find the first video streamfor (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 streamm_pCodecContext = m_pFormatContext-> streams [m_nStreamIndex]-> codec; // Find the decoder for the video streamm_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 ca N fall in the middle of packetsif (m_pCodec-> capabilities & CODEC_CAP_TRUNCATED) {m_pCodecContext-> flags | = CODEC_FLAG_TRUNCATED; // we do not send complete frames} // Open codecif (avcodec_open (m_pCodecContext, m_pCodec) <0) {return-6; // cocould not open codec} // Allocate video framem_pFrameYUV = avcodec_alloc_frame (); // Allocate an AVFrame structurem_pFrameRGB = avcodec_alloc_frame (); // Determine Required buffer size and allocate bufferint numBytes = bytes (bytes, 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 blocks (AVPicture *) m_pFrameRGB, m_pBufRGB, blocks, m_pCodecContext-> width, m_pCodecContext-> height); m_nFrameWidth = m _ PCodecContext-> width; m_nFrameHeight = m_pCodecContext-> height; return 0;} void CRTSPPlayer: DecodeUninit () {// Close the codecif (m_pCodecContext) {avcodec_close (m_pCodecContext ); // av_free (m_pCodec); m_pCodecContext = NULL; m_pCodec = NULL;} // Close the video fileif (m_pFormatContext) {convert (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 (bytes) {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 streamdo {// Read new packetif (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 itwhile (bytesRemaining> 0) {// Decode the next chunk of databytesDecoded = 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 returnif (frameFinished) {ImgConvert (AVPicture *) convert, convert, (AVPicture *) convert, m_pCodecContext-> pix_fmt, m_pCodecContext-> width, m_pCodecContext-> height ); display () ;}}m_hdecodethread = NULL; return 0;} void CRTSPPlayer: Display () {HDC hdc = GetDC (m_hWnd ); // create a memory dc hdc hMemDc = CreateCompatibleDC (hdc); // create a bitmap 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 // set the font parameter 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; // create a font and select the environment HFONT hFont = CreateFontIndirect (& logfont); HFONT hOldFont = (HFONT) SelectObject (hMemDc, hFont ); // set the drawing environment SetBkMode (hMemDc, TRANSPARENT); SetTextColor (hMemDc, RGB (255,255, 0); // draw text TextOut (hMemDc, m_strFilePath, _ tcslen (m_strFilePath); // restore environment release font SelectObject (hMemDc, hOldFont); # reset (hdc, m_rcWnd.left, m_rcWnd.top, m_rcWnd.right-m_rcWnd.left, m_rcWnd.bottom-m_rcWnd.top, hMemDc, 0, 0, 0, m_nFrameWidth, m_nFrameHeight, SRCCOPY); // restore and release the environment SelectObject (hMemDc, hOldBitmap); DeleteObject (hBitmap); DeleteDC (hMemDc);} // obtain the playback status RTSP_PLAYSTATUS CRTSPPlayer :: getPlayStatus (void) {return m_nPlayStatus;} // sets the playback status void CRTSPPlayer: SetPlayStatus (RTSP_PLAYSTATUS playStatus) {m_nPlayStatus = playStatus ;}