利用ffmpeg实现最简单的视频播放功能

本例子实现的视频播放功能100行代码左右。根据ffmpeg官方的指导来写的。对于新手可以研究下。

还是直接上代码:

/*
*author tongli
*mail:2074929378@qq.com
*/
#include <stdio.h>

extern "C"{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "SDL.h"
#include "SDL_thread.h"
}

int main(int argc, char* argv[])
{
	AVFormatContext	*pFormatCtx;
	int				i, videoindex;
	AVCodecContext	*pCodecCtx;
	AVCodec			*pCodec;
	SDL_Event event;
	int got_picture;
	struct SwsContext *img_convert_ctx;
	AVPacket packet;
	AVFrame	*pFrame;
	SDL_Rect rect;
	AVPicture pict;
	char *filename = "nihao.avi";
	av_register_all();//注册全部的编解码器,协议等。本质上是初始化几个static的链表
	avformat_network_init();
	pFormatCtx = avformat_alloc_context();//此处必须进行初始化。

	if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0){//根据文件名进行视频编码格式的判断
		printf("Couldn't open input stream.\n");
		return -1;
	}
	if (avformat_find_stream_info(pFormatCtx, NULL) < 0)//获取流的一些信息
	{
		printf("Couldn't find stream information.\n");
		return -1;
	}
	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)
	{
		printf("Didn't find a video stream.\n");
		return -1;
	}
	pCodecCtx = pFormatCtx->streams[videoindex]->codec;
	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//找到解码器
	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)//打开解码器
	{
		printf("Could not open codec.\n");
		return -1;
	}
	
	pFrame = av_frame_alloc();

	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);//初始化SDL
	SDL_Surface *screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
	
	SDL_Overlay *bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);

	int y_size = pCodecCtx->width * pCodecCtx->height;
	//以前的函数形式是img_convet(...),现在由sws_getContexst(...)与sws_scale(...)共同来实现功能。就是将获取到的视频帧转换为目标图像格式
	img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
	
	while (av_read_frame(pFormatCtx, &packet) >= 0)//获得数据包
	{
		if (packet.stream_index == videoindex)//检测数据包是不是视频包
		{
			avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet);//所有的视频包是不是能组成一帧视频图像
			if (got_picture)//如果能合成一帧视频图像
			{
				SDL_LockYUVOverlay(bmp);
				
				pict.data[0] = bmp->pixels[0];
				pict.data[1] = bmp->pixels[2];
				pict.data[2] = bmp->pixels[1];

				pict.linesize[0] = bmp->pitches[0];
				pict.linesize[1] = bmp->pitches[2];
				pict.linesize[2] = bmp->pitches[1];
				sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, 
					pCodecCtx->height,pict.data, pict.linesize);
				SDL_UnlockYUVOverlay(bmp);
				rect.x = 0;
				rect.y = 0;
				rect.w = pCodecCtx->width;
				rect.h = pCodecCtx->height;
				SDL_DisplayYUVOverlay(bmp, &rect);

				SDL_Delay(40);//延迟40ms
			}
		}
		//SDL事件循环
		av_free_packet(&packet);
		SDL_PollEvent(&event);
		switch (event.type){
		case SDL_QUIT:
			SDL_Quit();
			exit(0);
			break;
		default:
			break;
		}
		
	}
	sws_freeContext(img_convert_ctx);
	avcodec_close(pCodecCtx);
	avformat_close_input(&pFormatCtx);
	return 0;
}


源代码下载:100行左右的视频播放源码


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值