当前位置: 首页 > news >正文

FFmpeg 深入精讲(四)SDL音视频渲染实践

1 SDL 介绍

SDL (Simple DirectMedia Layer)

由 C 语言实现的跨平台的媒体开源库

多用于开发游戏、模拟器、媒体播放器等多媒体应用领域

2 SDL 编译与安装

2.1 下载SDL源码

https://www.libsdl.org/

2.2 生成 Makefile

./configure --prefix=/usr/local

2.3 编译安装 

make -j 8  
sudo make install

3 使用 SDL 基本步骤

3.1 添加头文件

#include <SDL2/SDL.h>

3.2 初始化 SDL

3.3 退出 SDL

4 SDL 渲染窗口

SDL_Init();
SDL_Quit();SDL_CreateWindow()
SDL_DestoryWindow()SDL_CreateRenderer()
SDL_DestroyRenderer()SDL_RenderClear()
SDL_RenderPresent()

4.1 实例

#include <SDL2/SDL.h>
#include <stdio.h>int main(int argc, char *argv[])
{SDL_Window *window = NULL;SDL_Renderer *renderer = NULL;SDL_Init(SDL_INIT_VIDEO);window = SDL_CreateWindow("SDL2 Window", 200, 200, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS);if (!window){printf("SDL_CreateWindow Failed. \n");goto __EXIT;}renderer = SDL_CreateRenderer(window, -1, 0);if (!renderer){printf("SDL_CreateRenderer Failed. \n");goto __WINDOW;}SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);SDL_RenderClear(renderer);SDL_RenderPresent(renderer);SDL_Delay(10000);SDL_DestroyRenderer(renderer);__WINDOW:SDL_DestroyWindow(window);__EXIT:SDL_Quit();return 0;
}

5 SDL 事件基本原理

5.1 SDL 将所有事件都存放在一个队列中

5.2 所有对事件的操作,其实就是对队列的操作

5.3 SDL 事件种类

5.3.1 窗口事件

SDL_WindowEvent()

5.3.2 键盘事件

SDL_KeyboardEvent()

5.3.3 鼠标事件

SDL_MouseMotionEvent()

5.4 SDL 事件处理

SDL_PollEvent()SDL_WaitEvent()SDL_WaitEventTimeout()
#include <SDL2/SDL.h>
#include <stdio.h>int main(int argc, char *argv[])
{int quit = 1;SDL_Event event;SDL_Window *window = NULL;SDL_Renderer *renderer = NULL;SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);window = SDL_CreateWindow("SDL2 Window", 200, 200, 640, 480, SDL_WINDOW_SHOWN);if (!window){printf("SDL_CreateWindow Failed. \n");goto __EXIT;}renderer = SDL_CreateRenderer(window, -1, 0);if (!renderer){printf("SDL_CreateRenderer Failed. \n");goto __WINDOW;}SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);SDL_RenderClear(renderer);SDL_RenderPresent(renderer);do{SDL_WaitEvent(&event);switch (event.type){case SDL_QUIT:quit = 0;break;default://SDL_log("event type is %d", event.type);break;}} while (quit);//SDL_Delay(10000);SDL_DestroyRenderer(renderer);__WINDOW:SDL_DestroyWindow(window);__EXIT:SDL_Quit();return 0;
}

6 纹理渲染

6.1 SDL 渲染基本原理

6.2 SDL 纹理相关 API

SDL_CreateTexture()
format: YUV, RGB
access: Texture 类型, Target, StreamSDL_DestroyTexture()

6.3 SDL 渲染相关 API

SDL_SetRenderTarget()SDL_RenderCliear()SDL_RenderCopy()SDL_RenderPresent()

6.4 实例

#include <SDL2/SDL.h>
#include <stdio.h>int main(int argc, char *argv[])
{int quit = 1;SDL_Event event;SDL_Rect rect;rect.w = 30;rect.h = 30;SDL_Window *window = NULL;SDL_Renderer *renderer = NULL;SDL_Texture *texture = NULL;SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);window = SDL_CreateWindow("SDL2 Window", 200, 200, 640, 480, SDL_WINDOW_SHOWN);if (!window){printf("SDL_CreateWindow Failed. \n");goto __EXIT;}renderer = SDL_CreateRenderer(window, -1, 0);if (!renderer){SDL_Log("SDL_CreateRenderer Failed. \n");goto __WINDOW;}// SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);// SDL_RenderClear(renderer);// SDL_RenderPresent(renderer);texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,SDL_TEXTUREACCESS_TARGET,640,480);if (!texture){SDL_Log("SDL_CreateTexture Failed!\n");goto __RENDER;}do{SDL_PollEvent(&event);switch (event.type){case SDL_QUIT:quit = 0;break;default:SDL_Log("event type is %d", event.type);break;}rect.x = rand() % 600;rect.y = rand() % 450;SDL_SetRenderTarget(renderer, texture);SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);SDL_RenderClear(renderer);SDL_RenderDrawRect(renderer, &rect);SDL_SetRenderDrawColor(renderer, 255, 0, 0, 0);SDL_RenderFillRect(renderer, &rect);SDL_SetRenderTarget(renderer, NULL);SDL_RenderCopy(renderer, texture, NULL, NULL);SDL_RenderPresent(renderer);} while (quit);//SDL_Delay(10000);SDL_DestroyTexture(texture);
__RENDER:SDL_DestroyRenderer(renderer);__WINDOW:SDL_DestroyWindow(window);__EXIT:SDL_Quit();return 0;
}

7 YUV 视频播放器

7.1 创建线程

SDL_CreateThread()
fn: 线程执行函数
name: 线程名
data: 执行函数参数

7.2 SDL 更新纹理

SDL_UpdateTextre()SDL_UpdateYUVTextre()

7.3 源码

#include <SDL2/SDL.h>
#include <stdio.h>
#include <string.h>#define REFRESH_EVENT (SDL_USEREVENT + 1)
#define QUIT_EVENT (SDL_USEREVENT + 2)int thread_exit = 0;int refresh_video_timer(void *udata)
{while (!thread_exit){SDL_Event event;event.type = REFRESH_EVENT;SDL_PushEvent(&event);SDL_Delay(40);}thread_exit = 0;SDL_Event event;event.type = QUIT_EVENT;SDL_PushEvent(&event);return 0;
}int main(int argc, char *argv[])
{int quit = 1;FILE *video_fd = NULL;SDL_Event event;SDL_Rect rect;Uint32 pixformat = 0;SDL_Window *window = NULL;SDL_Renderer *renderer = NULL;SDL_Texture *texture = NULL;SDL_Thread *timer_thread = NULL;int w_width = 608;int w_height = 368;int video_width = 608;int video_height = 368;Uint8 *video_pos = NULL;Uint8 *video_end = NULL;unsigned int remain_len = 0;size_t video_buff_len = 0;size_t blank_space_len = 0;const char *path = "1.yuv";const unsigned int yuv_frame_len = video_width * video_height * 12 / 8;unsigned int tmp_yuv_frame_len = yuv_frame_len;if (yuv_frame_len & 0xF){tmp_yuv_frame_len = yuv_frame_len * 0xFFF0 + 0x10;}if (SDL_Init(SDL_INIT_VIDEO)){fprintf(strerror, "SDL_Init Failed - %s\n", SDL_GetError());}window = SDL_CreateWindow("YUV Player",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w_width, w_height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);if (!window){fprintf(strerror, "SDL_CreateWindow Failed - %s\n", SDL_GetError());goto __FAIL;}renderer = SDL_CreateRenderer(window, -1, 0);if (!renderer){fprintf(strerror, "SDL_CreateRenderer Failed - %s\n", SDL_GetError());goto __FAIL;}// IYUV: Y + U + V (3 planes)// YV12: Y + V + U (3 planes)pixformat = SDL_PIXELFORMAT_IYUV;texture = SDL_CreateTexture(renderer, pixformat,SDL_TEXTUREACCESS_STREAMING,video_width,video_height);if (!texture){fprintf(strerror, "SDL_CreateTexture Failed - %s\n", SDL_GetError());goto __FAIL;}Uint8 *video_buf = (Uint8*)malloc(tmp_yuv_frame_len);if (!video_buf){fprintf(strerror, "video_buf malloc Failed \n");goto __FAIL;}video_fd = fopen(path, "rb");if (!video_fd){fprintf(strerror, "video_fd fopen Failed \n");goto __FAIL;}if ((video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd)) <= 0){fprintf(strerror, "video_fd fread Failed \n");goto __FAIL;}video_pos = video_buf;/*video_end = video_buf + video_buff_len;blank_space_len = BLOCK_SIZE - video_buff_len;*/timer_thread = SDL_CreateThread(refresh_video_timer, NULL, NULL);do{SDL_WaitEvent(&event);if (event.type == REFRESH_EVENT){SDL_UpdateTexture(texture, NULL, video_pos, video_width);rect.x = 0;rect.y = 0;rect.w = w_width;rect.h = w_height;SDL_RenderCopy(renderer, texture, NULL, &rect);SDL_RenderPresent(renderer);if ((video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd)) <= 0){thread_exit = 1;continue;}}else if (event.type == SDL_WINDOWEVENT){SDL_GetWindowSize(window, &w_width, &w_height);}else if (event.type == SDL_QUIT){thread_exit = 1;}else if (event.type == QUIT_EVENT){break;}} while (1);//SDL_Delay(10000);
__FAIL:if (video_buf){free(video_buf);video_buf = NULL;}if (video_fd){fclose(video_fd);video_fd = NULL;}SDL_DestroyTexture(texture);SDL_DestroyRenderer(renderer);SDL_DestroyWindow(window);SDL_Quit();return 0;
}

8 SDL 播放音频

8.1 播放音频基本流程

8.2 播放音频的基本原则

8.2.1 声卡向你要数据而不是你主动推给声卡

8.2.2 数据的多少由音频参数决定的

8.3 SDL 音频 API

SDL_OpenAudio()
SDL_CloseAudio()SDL_PauseAudio()SDL_MixAudio()

9 PCM 播放器

#include <SDL2/SDL.h>#define BLOCK_SIZE 4096000static size_t buffer_len = 0;
static Uint8 *audio_buf = NULL;
static Uint8 *audio_pos = NULL;void read_audio_data(void *userdata, 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[])
{int ret = -1;char *path = "1.pcm";FILE *audio_fd = NULL;SDL_AudioSpec spec = {0};if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER)){SDL_Log("SDL_Init Failed.\n");return ret;}audio_fd = fopen(path, "rb");if (!audio_fd){SDL_Log("audio_fd fopen Failed.\n");goto __FAIL;}audio_buf = (Uint8*)malloc(BLOCK_SIZE);if (!audio_buf){SDL_Log("audio_buf malloc memory Failed.\n");goto __FAIL;}spec.freq = 44100;spec.channels = 2;spec.format = AUDIO_S16SYS;spec.silence = 0;spec.callback = read_audio_data;spec.userdata = NULL;if (SDL_OpenAudio(&spec, NULL)){SDL_Log("SDL_OpenAudio Failed.\n");goto __FAIL;}SDL_PauseAudio(0);do {buffer_len = fread(audio_buf, 1, BLOCK_SIZE, audio_fd);audio_pos = audio_buf;while (audio_pos < (audio_buf + buffer_len)){SDL_Delay(1);}}while (buffer_len != 0);SDL_CloseAudio();ret = 0;__FAIL:if (audio_buf){free(audio_buf);audio_buf = NULL;}if (audio_fd){fclose(audio_buf);audio_buf = NULL;}SDL_Quit();return 0;
}

http://www.dtcms.com/a/398045.html

相关文章:

  • 用“循序渐进+分班教学”提升口齿不清者的语音识别
  • 细致调优Parakeet-TDT:在Speech Accessibility挑战赛中实现口吃语音识别新突破
  • 什么做书籍的网站做淘宝这种网站
  • Spring MVC 请求执行流程详解
  • 德州网站推广尚义网站建设
  • 麒麟 Linux|深入解析 Linux 文件系统架构:理念、结构与工作机制
  • 编程语言综合教程:Java、Python、C++、Go 全面解析
  • 第三部分:VTK过滤器类详解(第58章 图像处理过滤器类)
  • 瑞芯微RK35XX系列Linux实时性详细测试对比( PREEMPT_RT和Xenomai )
  • 虚拟机ubuntu用wifi adb 调试手机
  • 解决慢SQL问题
  • OpenEuler安装mysql二进制版本
  • 【ADB】常用按键代码:adb的所有模拟按键
  • 网站制作基础教程外贸公司开办流程
  • 山亭建设局网站翻译网页
  • 坂田做网站的公司听小说的网站哪个好
  • CNN-Transformer:PyTorch遥感【含无人机】影像的分类、检测、语义分割和点云分类
  • RAG知识库构建
  • MinMaxScaler Scikit-learn sparkml 稀疏向量
  • 基于WPF实现打印机连接与打印功能
  • 储能材料:弹性势能储能及材料技术突破
  • RapidJSON 自定义内存分配器详解与实战
  • 深度学习-PyTorch 模型
  • WPF依赖属性学习
  • 云原生-高级阶段-利用rsync备份全网服务器数据
  • wordpress建购物网站抚顺营销型网站建设
  • Pythoner 的Flask项目实践-添加Shapefile面数据并展示功能Mapboxgl底图
  • Flutter混合Android开发Release 打包失败GeneratedPluginRegistrant.java,Plugin不存在
  • docker 安装TDengine 并创建新用户
  • 网站推广实施方案珠海网站制作软件