FFmpeg4.0 实现一个H264视频解码器

     FFmpeg相信做流媒体的都不陌生,这就不累述了。最近在各方资源里we闻到有人说”FFmpeg是做音视频编解码的“,说的太狭隘了,了解FFmpeg的一般也都知道VLC,VLC是一套以FFmpeg为基础的完整流媒体解决方案,行内称:VLC是汽车,FFMpeg就是发动机”,这就很形象的描述了FFmpeg的功能。FFmpeg是集音视频采集、音视频演示数据处理、解复用、编码解码、渲染等完整流媒体框架,内合入ffplay可实现渲染播放。webrtc是功能上与之并驾齐驱的一套架构,它合入一些新的编码标准,如音频的OPUS标准,SIP信令协议等,后续再以webrtc为框架写一些blog。

      不说废话,先上代码。程序中将视频流decode成YUV420P格式,合入SDL2渲染播放。虽然是完整代码,目的为学术交流和技术共享,无意培养伸手党。代码中解决ffmpeg中新老接口对接,其它都是按decode的一般流程解码,如有不妥之处,欢迎指正。技术交流群:479245235,欢迎各界精英论道。

#include "stdio.h"
#include "iostream"
#include "stdlib.h"
#include 
#include 
#include  //C++11时间类标准模板库

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavfilter/avfilter.h"
#include "libavutil/imgutils.h"
#include "libavutil/fifo.h"
#include "libavutil/samplefmt.h"
#include "libavutil/time.h"
#include "libavutil/timestamp.h"
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libswresample/swresample.h"
#include "SDL2\SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include 
#include 
#include 
#include 
#include 
#include 
#ifdef __cplusplus
};
#endif
#endif

using namespace std;

#define  _CRT_SECURE_NO_WARNINGS

int main()
{
	const char *fname;

	char errbuf[256] = { 0 };
	int iRes = 0;
	int vindex = -1;
	AVFormatContext *fctx = NULL;
	AVCodecContext *cctx = NULL;
	AVCodec *c = NULL;
	AVPacket *pkt = NULL;
	AVFrame *fr = NULL;
	AVFrame *yuv = NULL;
	uint8_t *buf = NULL;
	int vsize;
	struct SwsContext *imgCtx = NULL;

	SDL_Window *sw = NULL;
	SDL_Renderer *sr = NULL;
	SDL_Texture *ste = NULL;
	SDL_Rect srect = { 0 };

//	av_register_all();  //ffmpeg 4.0 After no
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		cout << "SDL init failed!" << endl;
		return -1;
	}
		

	fctx = avformat_alloc_context();
	if ((iRes = avformat_open_input(&fctx, fname, NULL, NULL)) != 0)
	{
		cout << "File open failed!" << endl;
		return -1;
	}
		
	if (avformat_find_stream_info(fctx, NULL) < 0)
	{
		cout << "Stream find failed!\n";
		return -1;
	}
	av_dump_format(fctx, -1, fname, NULL);

	for (int i = 0; i < fctx->nb_streams; i++)
	{
		if (fctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
			vindex = i;
	}
	if (vindex == -1)
	{
		cout << "Codec find failed!" << endl;
		return -1;
	}

	cctx = avcodec_alloc_context3(NULL);
	if (avcodec_parameters_to_context(cctx, fctx->streams[vindex]->codecpar) < 0)
	{
		cout << "Copy stream failed!" << endl;
		return -1;
	}
	c = avcodec_find_decoder(cctx->codec_id);
	if (!c) {
		cout << "Find Decoder failed!" << endl;
		return -1;
	}
	if (avcodec_open2(cctx, c, NULL) != 0) {
		cout << "Open codec failed!" << endl;
		return -1;
	}

	sw = SDL_CreateWindow("video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 680, 540, SDL_WINDOW_OPENGL);
	sr = SDL_CreateRenderer(sw, -1, 0);
	ste = SDL_CreateTexture(sr, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, cctx->width, cctx->height);
	if (!sw || !sr || !ste) {
		cout << "Create SDL windows failed!" << endl;
		return -1;
	}
	srect.w = cctx->width;
	srect.h = cctx->height;

	imgCtx = sws_getContext(cctx->width, cctx->height, cctx->pix_fmt, cctx->width, cctx->height, AV_PIX_FMT_YUV420P,
		SWS_BICUBIC, NULL, NULL, NULL);
	if (!imgCtx) {
		cout << "Get swscale context failed!" << endl;
		return -1;
	}
	pkt = av_packet_alloc();
	fr = av_frame_alloc();
	yuv = av_frame_alloc();
	vsize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, cctx->width, cctx->height, 1);
	buf = (uint8_t *)av_malloc(vsize);
	av_image_fill_arrays(yuv->data, yuv->linesize,buf, AV_PIX_FMT_YUV420P, cctx->width, cctx->height, 1);
	while (av_read_frame(fctx, pkt) >= 0) {
		if (pkt->stream_index == vindex) {
			if ((iRes = avcodec_send_packet(cctx, pkt)) != 0)
			{
				cout << "Send video stream packet failed!" << endl;
				av_strerror(iRes, errbuf, 256);
				return -5;
			}
			if ((iRes = avcodec_receive_frame(cctx, fr)) != 0)
			{
				cout << "Receive video frame failed!\n";
				av_strerror(iRes, errbuf, 256);
				return -6;
			}
			sws_scale(imgCtx, fr->data, fr->linesize, 0, cctx->height, yuv->data, yuv->linesize);

			SDL_UpdateTexture(ste, &srect, yuv->data[0], yuv->linesize[0]);
			SDL_RenderClear(sr);
			SDL_RenderCopy(sr, ste, NULL, NULL);
			SDL_RenderPresent(sr);
		}
	}

	av_free(buf);
	av_frame_free(&yuv);
	av_frame_free(&fr);
	av_packet_free(&pkt);
	sws_freeContext(imgCtx);
	SDL_DestroyTexture(ste);
	SDL_DestroyRenderer(sr);
	SDL_DestroyWindow(sw);
	SDL_Quit();
	avcodec_free_context(&cctx);
	avformat_close_input(&fctx);
	avformat_free_context(fctx);

	return 0;
}

本人从事流媒体研发多年,资深流媒体CTO,QQ:2470425326;公司为音视频解决方案供应商,位于上海市浦东新区张江镇张衡路1299号凯信国际广场2号楼,真诚欢迎各界伙伴前来参观和洽谈合作。

你可能感兴趣的:(StreamMedia)