FFmpeg 视频解码,窗口显示


#ifndef __DECODE_STREAM_FROM_CAMERA__
#define __DECODE_STREAM_FROM_CAMERA__


extern "C"{
#include "libavcodec/avcodec.h"   
#include "libavformat/avformat.h"  
#include "libavdevice/avdevice.h"  
#include "libavfilter/avfilter.h"  
#include "libswscale/swscale.h"  
#include "libswresample/swresample.h"  
#include "libavutil/avutil.h"
}

#pragma warning(disable:4996)

class DecodeStream
{
public:
	DecodeStream();
	BOOL OpenStream(const char* url);
	BOOL FindStream();
	BOOL ReadStream(HWND hVideoWnd = NULL, int DlgItemID = 0);
	BOOL CloseStream();
	~DecodeStream();
private:
	void ShowRGBToWnd(HWND hWnd, BYTE* data, int width, int height);
private:
	AVFormatContext *m_pFormatCtx;
	unsigned int m_videoStream;
	AVCodecContext  *m_pCodecCtx;
	AVCodec         *m_pCodec;
	AVFrame *m_pFrame, *m_pFrameRGB;
	
	struct SwsContext *m_pSwsCtx;
	int m_frameFinished;
	int m_PictureSize;
	uint8_t *m_buf;
	int m_open;
	BYTE *m_bitBuffer;
};



#endif //__DECODE_STREAM_FROM_CAMERA__


#include "DecodeStream.h"

DecodeStream::DecodeStream()
{
	m_pFormatCtx = avformat_alloc_context();

	av_register_all();
	avformat_network_init();
	avdevice_register_all();

	m_pFrame = av_frame_alloc();
	m_pFrameRGB = av_frame_alloc();

	m_videoStream = -1;
	m_bitBuffer = NULL;
}

BOOL DecodeStream::OpenStream(const char* url)
{
	AVDictionary* opts = NULL;
	av_dict_set(&opts, "stimeout", "5000000", 0);
	AVInputFormat *ifmt = av_find_input_format("vfw");
	if (avformat_open_input(&m_pFormatCtx, url, ifmt, &opts) != 0)
	{
		return FALSE;
	}
	m_open = 1;
	return TRUE;
}

BOOL DecodeStream::FindStream()
{
	if (avformat_find_stream_info(m_pFormatCtx, NULL) < 0)
	{
		avformat_close_input(&m_pFormatCtx);
		return FALSE;
	}
	for (size_t i = 0; i < m_pFormatCtx->nb_streams; i++)
		if (m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			m_videoStream = i;
		}
	if (m_videoStream == -1)
	{
		avformat_close_input(&m_pFormatCtx);
		return FALSE;
	}
	m_pCodecCtx = m_pFormatCtx->streams[m_videoStream]->codec;
	m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);
	if (m_pCodec == NULL)
	{
		avformat_close_input(&m_pFormatCtx);
		return FALSE;
	}
	if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0)
	{
		avformat_close_input(&m_pFormatCtx);
		return FALSE;
	}
	m_PictureSize = avpicture_get_size(AV_PIX_FMT_BGR24, m_pCodecCtx->width, m_pCodecCtx->height);
	m_buf = (uint8_t*)av_malloc(m_PictureSize);
	if (m_buf == NULL)
	{
		avformat_close_input(&m_pFormatCtx);
		avcodec_close(m_pCodecCtx);
		return FALSE;
	}
	avpicture_fill((AVPicture *)m_pFrameRGB, m_buf, AV_PIX_FMT_BGR24, m_pCodecCtx->width, m_pCodecCtx->height);
	m_pSwsCtx = sws_getContext(m_pCodecCtx->width, m_pCodecCtx->height, m_pCodecCtx->pix_fmt, m_pCodecCtx->width, m_pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
	return TRUE;
}

BOOL DecodeStream::ReadStream(HWND hVideoWnd /* = NULL */, int DlgItemID/* = 0*/)
{
	AVPacket* packet = av_packet_alloc();
	while (av_read_frame(m_pFormatCtx, packet) >= 0 && m_open == 1){
		if (packet->stream_index == m_videoStream){
			//真正的解码    
			avcodec_decode_video2(m_pCodecCtx, m_pFrame, &m_frameFinished, packet);
			if (m_frameFinished){

				//转换图像格式,将解压出来的YUV420P的图像转换为BRG24的图像    
				sws_scale(m_pSwsCtx, m_pFrame->data, m_pFrame->linesize, 0, m_pCodecCtx->height, m_pFrameRGB->data, m_pFrameRGB->linesize);
				if (hVideoWnd != NULL && ItemID != 0)
					showRGBToWnd(hVideo, m_pFrameRGB->data[0], m_pCodecCtx->width, m_pCodecCtx->height);
			}
		}
		av_free_packet(packet);
	}
	avformat_close_input(&m_pFormatCtx);
	av_packet_free(&packet);
	sws_freeContext(m_pSwsCtx);
	avcodec_close(m_pCodecCtx);
	return TRUE;
}

BOOL DecodeStream::CloseStream()
{
	m_open = 0;
	return TRUE;
}

void DecodeStream::ShowRGBToWnd(HWND hWnd, BYTE* data, int width, int height)
{
	if (data == NULL)
		return;

	static BITMAPINFO *bitMapinfo = NULL;
	static bool First = TRUE;

	if (First)
	{
		m_bitBuffer = new BYTE[40 + 4 * 256];//开辟一个内存区域

		if (m_bitBuffer == NULL)
		{
			return;
		}
		First = FALSE;
		memset(m_bitBuffer, 0, 40 + 4 * 256);
		bitMapinfo = (BITMAPINFO *)m_bitBuffer;
		bitMapinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		bitMapinfo->bmiHeader.biPlanes = 1;
		for (int i = 0; i < 256; i++)
		{ //颜色的取值范围 (0-255)
			bitMapinfo->bmiColors[i].rgbBlue = bitMapinfo->bmiColors[i].rgbGreen = bitMapinfo->bmiColors[i].rgbRed = (BYTE)i;
		}
	}
	bitMapinfo->bmiHeader.biHeight = -height;
	bitMapinfo->bmiHeader.biWidth = width;
	bitMapinfo->bmiHeader.biBitCount = 3 * 8;
	CRect drect;
	GetClientRect(hWnd, drect);    //pWnd指向CWnd类的一个指针 
	HDC hDC = GetDC(hWnd);     //HDC是Windows的一种数据类型,是设备描述句柄;
	SetStretchBltMode(hDC, COLORONCOLOR);
	StretchDIBits(hDC,
		0,
		0,
		drect.right,   //显示窗口宽度
		drect.bottom,  //显示窗口高度
		0,
		0,
		width,      //图像宽度
		height,      //图像高度
		data,
		bitMapinfo,
		DIB_RGB_COLORS,
		SRCCOPY
		);
	ReleaseDC(hWnd, hDC);
}

DecodeStream::~DecodeStream()
{
	if (m_pFrame != NULL && m_pFrameRGB != NULL){
		av_free(m_pFrame);
		av_free(m_pFrameRGB);
	}
	if(m_bitBuffer != NULL)
		delete[] m_bitBuffer;
}



猜你喜欢

转载自blog.csdn.net/HHCOO/article/details/76208979
今日推荐