FFMpeg学习——4 SDL

1 简介

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。

2 显示流程

在这里插入图片描述
(1)SDL视频显示函数
SDL_Init():初始化SDL系统
SDL_CreateWindow():创建窗口SDL_Window
SDL_CreateRenderer():创建渲染器SDL_Renderer
SDL_CreateTexture():创建纹理SDL_Texture
SDL_UpdateTexture():设置纹理的数据
SDL_RenderCopy():将纹理的数据拷贝给渲染器
SDL_RenderPresent():显示
SDL_Delay():工具函数,用于延时。
SDL_Quit():退出SDL系统

(2)SDL多线程
SDL_CreateThread():创建一个线程
(3)SDL事件
SDL_WaitEvent()等待一个事件
SDL_PushEvent()发送一个事件

3 渲染

(1)原理
在这里插入图片描述
SDL数据结构简介
SDL_Window:代表了一个“窗口”
SDL_Renderer:代表了一个“渲染器”
SDL_Texture:代表了一个“纹理”
SDL_Rect:一个简单的矩形结构
对Render操作时实际上分为两个阶段:

  • 渲染阶段。在该阶段,用户可以画各种图形渲染到SDL_Surface或SDL_Texture 中;
  • 显示阶段。以SDL_Texture为数据,将 SDL_Surfce或SDL_Texture中的数据输出到显示器上。
SDL_SetRenderTarget(renderer, texture) // 渲染到纹理
SDL_SetRenderTarget(renderer, NULL) // 渲染到屏幕

(2)测试
在窗体中,绘制随机出现的方块


#include <iostream>

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

int screen_w = 800, screen_h = 600;

int main(int argc, char* argv[]) {
	int quit = 1;
	SDL_Event event;
	SDL_Texture* texture;
	SDL_Rect rect;
	if (SDL_Init(SDL_INIT_VIDEO)) {
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}

	SDL_Window* screen;
	//SDL 2.0 Support for multiple windows
	screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (!screen) {
		printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
		return -1;
	}
	SDL_Renderer* renderer = SDL_CreateRenderer(screen, -1, 0);
	if (!renderer) {
		goto _DWINDOW;
	}

	SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
	SDL_RenderClear(renderer);
	SDL_RenderPresent(renderer); //显示

	texture = SDL_CreateTexture(renderer,
		SDL_PIXELFORMAT_RGBA8888,
		SDL_TEXTUREACCESS_TARGET,
		screen_w,
		screen_h
	);

	rect.w = 50;
	rect.h = 50;

	do {

		SDL_PollEvent(&event);
		switch (event.type) {
		case SDL_QUIT:
			quit = 0;
			break;
		default:
			break;
		}
		rect.x = rand() % 600;
		rect.y = rand() % 450;

		SDL_SetRenderTarget(renderer, texture);
		SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
		SDL_RenderClear(renderer);

		SDL_RenderDrawRect(renderer, &rect);
		SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0x00);
		SDL_RenderFillRect(renderer, &rect);

		SDL_SetRenderTarget(renderer, NULL);
		SDL_RenderCopy(renderer, texture, NULL, NULL);
		SDL_RenderPresent(renderer);
	} while (quit);

	SDL_DestroyTexture(texture);
	SDL_DestroyRenderer(renderer);

_DWINDOW:
	SDL_DestroyWindow(screen);

_EXIT:
	SDL_Quit();
	return 0;
}

4 实例

4.1 yuv播放器

主要yuv视频格式要提前知道,并具体设置

#include <iostream>

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

//Bit per Pixel
const int bpp = 12;

int screen_w = 600, screen_h = 600;
const int pixel_w = 640, pixel_h = 360;

unsigned char buffer[pixel_w * pixel_h * bpp / 8];

// Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
#define QUIT_EVENT  (SDL_USEREVENT + 2)

int thread_exit = 0;

int refresh_video(void* opaque) {
	while (thread_exit == 0) {
		SDL_Event event;
		event.type = REFRESH_EVENT;
		SDL_PushEvent(&event);
		SDL_Delay(40);
	}

	thread_exit = 0;

	//push quit event
	SDL_Event event;
	event.type = QUIT_EVENT;
	SDL_PushEvent(&event);

	return 0;
}

int main(int argc, char* argv[])
{
	if (SDL_Init(SDL_INIT_VIDEO)) {
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}

	SDL_Window* screen;
	//SDL 2.0 Support for multiple windows
	screen = SDL_CreateWindow("Simplest Video Play SDL2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (!screen) {
		printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
		return -1;
	}
	SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);

	Uint32 pixformat = 0;

	//IYUV: Y + U + V  (3 planes)
	//YV12: Y + V + U  (3 planes)
	pixformat = SDL_PIXELFORMAT_IYUV;


	SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, pixel_w, pixel_h);

	FILE* fp = NULL;

	fp = fopen("1.yuv", "rb+");

	if (fp == NULL) {
		printf("cannot open this file\n");
		return -1;
	}

	SDL_Rect sdlRect;

	SDL_Thread* refresh_thread = SDL_CreateThread(refresh_video, NULL, NULL);
	SDL_Event event;
	while (1) {
		//Wait
		SDL_WaitEvent(&event);
		if (event.type == REFRESH_EVENT) {
			if (fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp) != pixel_w * pixel_h * bpp / 8) {
				// Loop
				fseek(fp, 0, SEEK_SET);
				fread(buffer, 1, pixel_w * pixel_h * bpp / 8, fp);
			}


			SDL_UpdateTexture(sdlTexture, NULL, buffer, pixel_w);

			//FIX: If window is resize
			sdlRect.x = 0;
			sdlRect.y = 0;
			sdlRect.w = screen_w;
			sdlRect.h = screen_h;

			SDL_RenderClear(sdlRenderer);
			SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &sdlRect);
			SDL_RenderPresent(sdlRenderer);

		}
		else if (event.type == SDL_WINDOWEVENT) {
			//If Resize
			SDL_GetWindowSize(screen, &screen_w, &screen_h);
		}
		else if (event.type == SDL_QUIT) {
			thread_exit = 1;
		}
		else if (event.type == QUIT_EVENT) {
			break;
		}
	}

	return 0;
}

4.2 pcm播放器

注意:声卡通过回调函数要数据,而不是用户主动推数据

#define BLOCK_SIZE 4096000
static Uint8 *audio_buf = NULL;
static Uint8 *audio_pos = NULL;
static size_t buffer_len = 0;

//callback function for audio devcie
void read_audio_data(void *udata, Uint8 *stream, int len){

	if (buffer_len == 0){
		return;
	}

	SDL_memset(stream, 0, len);

	len = (len < buffer_len) ? len : buffer_len;
	SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);

	audio_pos += len;
	buffer_len -= len;
}

int main(int argc, char* argv[])
{

	
	if (SDL_Init(SDL_INIT_AUDIO)) {
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}
	char *path = "1.pcm";
	FILE *audio_fd = fopen(path, "rb+");
	if (!audio_fd){
		SDL_Log("Failed to open");
		goto __FAIL;
	}
	audio_buf = (Uint8*)malloc(BLOCK_SIZE);
	if (!audio_buf){
		SDL_Log("Failed to malloc");
		goto __FAIL;
	}

	SDL_AudioSpec spec;
	spec.freq = 44100;
	spec.channels = 2;
	spec.format = AUDIO_S16SYS;
	spec.silence = 0;
	spec.samples = 2048;
	spec.callback = read_audio_data;
	spec.userdata = NULL;

	if (SDL_OpenAudio(&spec, NULL)){
		SDL_Log("Failed to malloc");
		goto __FAIL;
	}

	SDL_PauseAudio(0);

	while (1){
		buffer_len = fread(audio_buf, 1, BLOCK_SIZE, audio_fd);
		if (buffer_len == 0) {
			break;
		}
		audio_pos = audio_buf;
		while (audio_pos < (audio_buf + buffer_len)) {
			SDL_Delay(1);
		}
	}
	
	SDL_CloseAudio();

__FAIL:
	if (audio_buf){
		free(audio_buf);
	}
	if (audio_fd){
		fclose(audio_fd);
	}
	SDL_Quit();

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值