SDL2 播放 YUV 原始视频数据

124 篇文章 0 订阅
113 篇文章 1 订阅
//#define SDL_MAIN_HANDLED
#include<SDL.h>
#include<iostream>
using namespace std;


int main(int argc, char* argv[]) {
	//very important and serious about YUV format
	//cif 352*288 , otherwise fail to play!!!
	const int width = 352, height = 288;
	//QCIF:176*144
	//const int width = 176, height = 144;
	const int bpp=12;//bits per pixel 像素深度
	byte buffer[width*height*bpp/8];

	if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) == -1) {
		cout << "sdl init error" << endl;
		return -1;
	}
	cout << "sdl init OK" << endl;

	//atexit(SDL_Quit);

	SDL_Window* screen = SDL_CreateWindow("SDL Demo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 
						 SDL_WINDOW_RESIZABLE);

	if (!screen) {
		cout << "SDL create window failed" << endl;
		return -2;
	}

	SDL_Renderer* renderer = SDL_CreateRenderer(screen, -1, 0);


	//IYUV: Y+U+V
	//YU12: Y+V+U
	Uint32 pixformat = SDL_PIXELFORMAT_IYUV;

	SDL_Texture* texture = SDL_CreateTexture(renderer, pixformat, SDL_TEXTUREACCESS_STREAMING, width, height);


	FILE* file;
	fopen_s(&file,"C:/Users/Dell/Desktop/BigBuckBunny_CIF_24fps.yuv", "rb+");
	//fopen_s(&file,"C:/Users/Dell/Desktop/akiyo_qcif.yuv", "rb+");
	


	if (file == NULL) {
		cout << "cannot open this file\n" << endl;
		return -5;
	}

	SDL_Rect rect;

	while (1) {
		if (fread(buffer, 1, width * height * bpp / 8, file) != width * height * bpp / 8) {
			// Loop
			fseek(file, 0, SEEK_SET);
			fread(buffer, 1, width * height * bpp / 8, file);
			SDL_Delay(40);
		}
		
		//cout << SDL_GetError() << endl;

		SDL_UpdateTexture(texture, NULL, buffer, width);

		rect.x = 0;
		rect.y = 0;
		rect.w = width;
		rect.h = height;

		SDL_RenderClear(renderer);
		SDL_RenderCopy(renderer, texture, NULL, &rect);
		SDL_RenderPresent(renderer);
		//Delay 40ms
		SDL_Delay(40);

	}










	SDL_Quit();

	cout << "sdl quit" << endl;

	cout << "Hello World" << endl;



	return 0;
}

1.YUV 播放文件的 宽度和高度 要 适配 否则,播放有问题,满屏花色。
2.main 函数要有标准参数,否则编译错误。
3.静态编译的时候请加上这些库文件
SDL2-staticd.lib
SDL2_test.lib
Winmm.lib
Version.lib
Imm32.lib
Setupapi.lib
SDL2maind.lib
,
否则,光报错。
5.播放存在文件,不是调试模式下运行一会就会卡住,不能播放,且鼠标失灵,估计是主线渲染画面的问题。启用多线线程该如何解决?

 

 

 

使用SDL2在Linux上播放视频,需要先安装SDL2库和FFmpeg库。接下来,需要用FFmpeg将视频解码成yuv像素数据,再使用SDL2将像素数据渲染到屏幕上。 以下是基本的步骤: 1. 引入SDL2和FFmpeg库,定义相关变量和函数。 ```c #include <SDL2/SDL.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> AVCodecContext *codec_ctx; AVFormatContext *format_ctx; AVCodec *codec; SDL_Renderer* renderer; SDL_Texture* texture; SDL_Window *window; SDL_Rect rect; unsigned char *output_buffer; int pitch; struct SwsContext *sws_ctx; ``` 2. 初始化SDL2和FFmpeg库。 ```c if(SDL_Init(SDL_INIT_VIDEO) != 0) { printf("SDL_Init Error: %s", SDL_GetError()); return -1; } av_register_all(); avformat_network_init(); format_ctx = avformat_alloc_context(); if(avformat_open_input(&format_ctx, file_path, NULL, NULL) != 0) { return -1; } if(avformat_find_stream_info(format_ctx, NULL) < 0) { return -1; } int video_stream_index = -1; for(int i=0; i < format_ctx->nb_streams; i++) { if(format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; break; } } if(video_stream_index == -1) { return -1; } codec_ctx = format_ctx->streams[video_stream_index]->codec; codec = avcodec_find_decoder(codec_ctx->codec_id); if(codec == NULL) { return -1; } if(avcodec_open2(codec_ctx, codec, NULL) < 0) { return -1; } ``` 3. 配置SDL2窗口、渲染器和纹理。 ```c window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, codec_ctx->width, codec_ctx->height, SDL_WINDOW_OPENGL); renderer = SDL_CreateRenderer(window, -1, 0); texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, codec_ctx->width, codec_ctx->height); rect.w = codec_ctx->width; rect.h = codec_ctx->height; ``` 4. 读取视频流、解码和渲染。 ```c AVPacket packet; int frame_finished; AVFrame* frame = av_frame_alloc(); while(av_read_frame(format_ctx, &packet) >= 0) { if(packet.stream_index == video_stream_index) { if(avcodec_send_packet(codec_ctx, &packet) == 0) { while(avcodec_receive_frame(codec_ctx, frame) == 0) { sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL); sws_scale(sws_ctx, (const uint8_t * const*)frame->data, frame->linesize, 0, codec_ctx->height, (uint8_t * const *)output_buffer, &pitch); SDL_UpdateYUVTexture(texture, NULL, output_buffer, codec_ctx->width, output_buffer+codec_ctx->width*codec_ctx->height, codec_ctx->width/2, output_buffer+codec_ctx->width*codec_ctx->height*5/4, codec_ctx->width/2); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); sws_freeContext(sws_ctx); } } } av_packet_unref(&packet); } ``` 5. 释放资源。 ```c avformat_close_input(&format_ctx); avcodec_free_context(&codec_ctx); SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); ``` 总体上来说,使用SDL2播放视频需要对FFmpeg库有一定的了解,掌握基本的视频解码、像素转换和纹理渲染等技巧。对于初学者来说,需要仔细研究相关文档和示例程序,并多做实践。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值