参考的文章:
100行代码实现最简单的基于FFMPEG+SDL的视频播放器
显示使用的是 SDL ,windows下用 GDI+ 显示数据里的图片,以下为代码 ,
typedef struct tagVideoData
{
tagVideoData()
{
bRunning = TRUE;
hDC = NULL;
}
CString strRTSP;
HWND hWnd;
BOOL bRunning;
HANDLE hProc;
HDC hDC;
CRect rectPre;
} VIDEODATA,*LPVIDEODATA;
DWORD WINAPI ShowVideoProc(LPVOID lpParameter)
{
VIDEODATA *pData = (VIDEODATA *)lpParameter;
if (NULL == pData)
return 1;
while (TRUE)
{
av_register_all();
avformat_network_init();
AVFormatContext *pFormatCtx = avformat_alloc_context();
if(avformat_open_input(&pFormatCtx,pData->strRTSP.GetBuffer(0),NULL,NULL)!=0){
printf("Couldn't open input stream.\n");
break;
}
if(avformat_find_stream_info(pFormatCtx,NULL)<0){
printf("\n 卡在这里的时候关闭容易崩溃,Couldn't find stream information.\n");
break;
}
if (!IsWindow(pData->hWnd))
break;
int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
videoindex = -1;
for(i = 0; i < pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoindex = i;
break;
}
}
if(videoindex == -1)
{
OutputDebugString("Didn't find a video stream.\n");
break;
}
pCodecCtx = pFormatCtx->streams[videoindex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL){
OutputDebugString("Codec not found.\n");
break;
}
if(avcodec_open2(pCodecCtx, pCodec,NULL) < 0)
{
OutputDebugString("Could not open codec.\n");
break;
}
AVFrame *pFrame,*pFrameYUV;
AVPacket *packet;
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
int screen_w = pCodecCtx->width;
int screen_h = pCodecCtx->height;
packet = (AVPacket *)av_malloc(sizeof(AVPacket));
av_dump_format(pFormatCtx,0,pData->strRTSP.GetBuffer(0),0);
struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
int ret = 0;
int got_picture = 0;
while(av_read_frame(pFormatCtx, packet) >=0
&& pData->bRunning
&& IsWindow(pData->hWnd)
)
{
if(packet->stream_index == videoindex)
{
//Decode
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if(ret < 0)
{
OutputDebugString("Decode Error.\n");
break;
}
if(got_picture)
{
pData->hDC = ShowVideoPic(pFrame,pFrameYUV,pCodecCtx,pData->hWnd,pData->hDC,pData->rectPre);
Sleep(10);
}
}
av_free_packet(packet);
}
//FIX: Flush Frames remained in Codec
while (1
&& pData->bRunning
&& IsWindow(pData->hWnd)
)
{
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
if (ret < 0)
break;
if (!got_picture)
break;
pData->hDC = ShowVideoPic(pFrame,pFrameYUV,pCodecCtx,pData->hWnd,pData->hDC,pData->rectPre);
}
sws_freeContext(img_convert_ctx);
//av_free(out_buffer);
av_free(pFrame);
av_free(pFrameYUV);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
break;
}
CloseHandle(pData->hProc);
// if (IsWindow(pData->hWnd))
// {
// SendMessage(pData->hWnd,USER_END_PLAY,(WPARAM)pData,pData->bRunning);
// }
if (NULL != pData)
DeleteDC(pData->hDC);
delete pData;
return 0;
}
HDC ShowVideoPic(AVFrame *pFame,AVFrame *pFrameRGB,AVCodecContext *pContent,HWND hWnd,HDC &hDC,CRect &rectPre)
{
if (NULL == pFame)
return hDC;
if (NULL == pFame)
return hDC;
if (NULL == pContent)
return hDC;
if (NULL == pFame->data)
return hDC;
if (!IsWindow(hWnd))
return hDC;
if (pFame->width != pContent->width
|| pFame->height != pContent->height
)
return hDC;
if (0 == pFame->width
|| 0 == pFame->height
|| !IsWindowVisible(hWnd)
)
return hDC;
CRect rect;
GetClientRect(hWnd,&rect);
if (rect.Width() <= 0
|| rect.Height() <= 0
)
return hDC;
int nWidthRect = rect.Width();
int nHeightRect = rect.Height();
int nWidth = pContent->width;
int nHeight = pContent->height;
//
// if (nWidthRect > nHeightRect)
// {
// nHeightRect = (double)nWidthRect / (double)nWidth * nHeight ;
// }
// else
// {
// nWidthRect = (double) nHeightRect / (double)nHeight * nWidth;
// }
double dScale = (double) nWidthRect / (double)nWidth;
dScale = max(0.1,dScale);
dScale = min(1.0,dScale);
nWidthRect = nWidth * dScale;
nWidthRect -= nWidthRect % 4;
dScale = (double)nWidthRect / (double)nWidth;
nHeightRect = nHeight * dScale;
SwsContext *img_convert_ctx ;
int frame_count = 0;
int nCountT = avpicture_get_size(AV_PIX_FMT_BGR24, nWidthRect,nHeightRect);
uint8_t * pOutBuffer = new uint8_t[nCountT];
if (avpicture_fill((AVPicture *)pFrameRGB, pOutBuffer, AV_PIX_FMT_BGR24, nWidthRect, nHeightRect) > 0 )
{
img_convert_ctx = sws_getCachedContext(NULL,nWidth, nHeight, pContent->pix_fmt, nWidthRect,nHeightRect, AV_PIX_FMT_BGR24,SWS_BILINEAR, NULL, NULL, NULL);
if (NULL != img_convert_ctx)
{
int nHeightOut = sws_scale(img_convert_ctx, (const uint8_t* const*)pFame->data, pFame->linesize, 0, nHeight, pFrameRGB->data, pFrameRGB->linesize);
if (nHeightOut > 0)
{
Bitmap bitmap(nWidthRect,nHeightRect,nWidthRect * 3,PixelFormat24bppRGB,pFrameRGB->data[0]);
if (bitmap.GetLastStatus() == Ok
&& IsWindow(hWnd)
&& IsWindowVisible(hWnd)
)
{
HDC hDCTemp = GetDC(hWnd);
HBITMAP hBmp = NULL;
if (!rectPre.EqualRect(&rect))
{
DeleteDC(hDC);
hDC = CreateCompatibleDC(hDCTemp);
hBmp = CreateCompatibleBitmap(hDCTemp,rect.Width(),rect.Height());
SelectObject(hDC,hBmp);
rectPre = rect;
}
Graphics graphics(hDC);
graphics.DrawImage(&bitmap,Rect(rect.left,rect.top,rect.Width(),rect.Height()),0,0,nWidthRect,nHeightRect,UnitPixel);
StretchBlt(hDCTemp,0,0,rect.Width(),rect.Height(),hDC,0,0,rect.Width(),rect.Height(),SRCCOPY);
ReleaseDC(hWnd,hDCTemp);
if (NULL != hBmp)
DeleteObject(hBmp);
}
}
}
sws_freeContext(img_convert_ctx);
}
delete []pOutBuffer;
return hDC;
}