ffmpeg 实现视频播放

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/u012748494/article/details/98207579

感谢 https://www.cnblogs.com/wenjingu/p/3990301.html

1、  库

sdl2.dll    sdlmain2.dll

ffmpeg-20190722-817235b-win64-dev

ffmpeg-20190722-817235b-win64-shared

2、错误

  main 未定义入口,  改成 int SDL_main(int argc, char *argv[])
//int _tmain(int argc, char *argv[])   原因不明 ,  反正可以跑起来

//#include "stdafx.h"

#ifdef __cplusplus
extern "C" {
#endif

#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavutil/avutil.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>

#include <SDL.h>
#include <SDL_main.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#ifdef __cplusplus
}
#endif

//#pragma comment(lib, ".\\sdl\\SDL2-2.0.9-vc\\lib\\x64\\SDL2.lib")

//#pragma comment(lib, ".\\sdl\\SDL2-2.0.9-vc\\lib\\x64\\SDLmain2.lib")
//#define main SDL_main
/*
#ifdef __MINGW32__    //  必须定义入口点, 说这个方法, 好像不行的
#undef main // Prevents SDL from overriding main().
#endif
*/
int ffplayer()
{
	AVFormatContext    *pFormatCtx;
	AVCodecContext  *pFormatCtx__;
	int                i, videoindex;
	AVCodecContext    *pCodecCtx = NULL;
	AVCodec            *pCodec = NULL;
	int  res = 0;
	char rtspUrl[] = "D:\\code\\ffmpeg\\ffmpeg_sdl_001\\test_masaike.mp4";
	//char rtspUrl[] = "rtsp://admin:[email protected]:554";
	//av_register_all();//注册组件
	avformat_network_init();//支持网络流
	pFormatCtx = avformat_alloc_context();//初始化AVFormatContext
	//pFormatCtx = avcodec_alloc_context3(NULL);
	if (avformat_open_input(&pFormatCtx,/*filepath*/rtspUrl, NULL, NULL) != 0) {//打开文件或网络流
		printf("无法打开文件\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++) //获取视频流ID
	{	
		if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
			//if (pFormatCtx->streams[i]/*视音频流*/->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)//查找音频
		{
				videoindex = i;
			//	break;
		}
	}
	if (videoindex == -1)
	{
		printf("Didn't find a video stream.\n");
		return -1;
	}
	//s
	//pCodecCtx = pFormatCtx->streams[videoindex]->codecpar;
	pCodec = avcodec_find_decoder(pFormatCtx->streams[videoindex]->codecpar->codec_id);//查找解码器
	//codec_id

	pCodecCtx = avcodec_alloc_context3(pCodec);
	avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoindex]->codecpar);

	if (pCodec == NULL)
	{
		printf("Codec not found.\n");
		return -1;
	}
	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)//打开解码器
	{
		printf("Could not open codec.\n");
		return -1;
	}
	AVFrame    *pFrame, *pFrameYUV;
	pFrame = av_frame_alloc();//存储解码后AVFrame
	pFrameYUV = av_frame_alloc();//存储转换后AVFrame
	uint8_t *out_buffer;
	const int bufLen = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
	out_buffer = new uint8_t[bufLen];//分配AVFrame所需内存

	//out_buffer = new uint8_t[avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];//分配AVFrame所需内存
	//avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);//填充AVFrame

	//avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

	res = av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);

	//------------SDL初始化--------
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}
	SDL_Window *screen = SDL_CreateWindow("RTSP Client Demo",
		SDL_WINDOWPOS_UNDEFINED,
		SDL_WINDOWPOS_UNDEFINED,
		pCodecCtx->width, pCodecCtx->height,
		SDL_WINDOW_RESIZABLE/* SDL_WINDOW_HIDDEN*/ | SDL_WINDOW_OPENGL);
	if (!screen) {
		printf("SDL: could not set video mode - exiting\n");
		return -1;
	}
	SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
	SDL_Texture* sdlTexture = SDL_CreateTexture(
		sdlRenderer,
		SDL_PIXELFORMAT_YV12,
		SDL_TEXTUREACCESS_STREAMING,
		pCodecCtx->width,
		pCodecCtx->height);

	SDL_Rect rect;
	//-----------------------------
	int ret, got_picture = 0;
	static struct SwsContext *img_convert_ctx;
	int y_size = pCodecCtx->width * pCodecCtx->height;

	SDL_Event event;
	AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));//存储解码前数据包AVPacket
	av_new_packet(packet, y_size);
	//输出一下信息-----------------------------
	printf("文件信息-----------------------------------------\n");
	//av_dump_format(pFormatCtx,0,filepath,0);
	printf("-------------------------------------------------\n");
	//------------------------------
	while (av_read_frame(pFormatCtx, packet) >= 0)//循环获取压缩数据包AVPacket
	{
		if (packet->stream_index == videoindex)
		{
			//ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);//解码。输入为AVPacket,输出为AVFrame
			ret = avcodec_send_packet(pCodecCtx, packet);
			if (ret < 0)
			{
				printf("解码错误\n");
				return -1;
			}
			ret = avcodec_receive_frame(pCodecCtx, pFrame);
			got_picture = 9;
			if (got_picture)
			{
				//像素格式转换。pFrame转换为pFrameYUV。
				img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
				sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
				sws_freeContext(img_convert_ctx);
				//------------SDL显示--------
				rect.x = 0;
				rect.y = 0;
				rect.w = pCodecCtx->width;
				rect.h = pCodecCtx->height;

				SDL_UpdateTexture(sdlTexture, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0]);
				SDL_RenderClear(sdlRenderer);
				SDL_RenderCopy(sdlRenderer, sdlTexture, &rect, &rect);
				SDL_RenderPresent(sdlRenderer);
				//延时20ms
				SDL_Delay(20);
				//------------SDL-----------
			}
		}
		//	av_free_packet(packet);
		av_packet_unref(packet);
		SDL_PollEvent(&event);
		switch (event.type) {
		case SDL_QUIT:
			SDL_Quit();
			exit(0);
			break;
		default:
			break;
		}
	}

	SDL_DestroyTexture(sdlTexture);
	delete[] out_buffer;
	av_free(pFrameYUV);
	avcodec_close(pCodecCtx);
	avformat_close_input(&pFormatCtx);

	getchar();
	return 0;
}

int SDL_main(int argc, char *argv[])  用main 会报错

{
    ffplayer();

扫描二维码关注公众号,回复: 7592618 查看本文章

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u012748494/article/details/98207579