ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

FFMpeg学习——4 SDL

2021-07-17 09:34:22  阅读:155  来源: 互联网

标签:FFMpeg screen len 学习 renderer SDL audio event


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;
}

标签:FFMpeg,screen,len,学习,renderer,SDL,audio,event
来源: https://blog.csdn.net/chen06130/article/details/118823160

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有