音视频-SDL的简单使用

简介: 音视频-SDL的简单使用

使用SDL进行音视频的播放


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


SDL的下载地址: https://www.libsdl.org/


现在较为新的版本在main函数中需要添加#define SDL_MAIN_HANDLED定义, 初步代码如下:

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define SDL_MAIN_HANDLED
#include <SDL.h>
//自定义消息类型
#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件
#define QUIT_EVENT      (SDL_USEREVENT + 2)     // 退出事件
//定义分辨率
// YUV像素分辨率
#define YUV_WIDTH   320
#define YUV_HEIGHT  240
//定义YUV格式
#define YUV_FORMAT  SDL_PIXELFORMAT_IYUV
int s_thread_exit = 0;  // 退出标志 = 1则退出
int refresh_video_timer(void *data)
{
    while (!s_thread_exit)
    {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }
    s_thread_exit = 0;
    //push quit event
    SDL_Event event;
    event.type = QUIT_EVENT;
    SDL_PushEvent(&event);
    return 0;
}
int main()
{
    if (SDL_Init(SDL_INIT_VIDEO)) {
        fprintf(stderr, "Can't not initialize SDL, err: %s\n", SDL_GetError());
    }
    SDL_Event event;                    // 事件
    SDL_Rect rect;                      // 矩形
    SDL_Window *window = NULL;          // 窗口
    SDL_Renderer *renderer = NULL;      // 渲染
    SDL_Texture *texture = NULL;        // 纹理
    SDL_Thread *timer_thread = NULL;    // 请求刷新线程
    uint32_t pixformat = YUV_FORMAT;    // YUV420P,即是SDL_PIXELFORMAT_IYUV
    // 分辨率
    // 1. YUV的分辨率
    int video_width = YUV_WIDTH;
    int video_height = YUV_HEIGHT;
    // 2.显示窗口的分辨率
    int win_width = YUV_WIDTH;
    int win_height = YUV_WIDTH;
    // YUV文件句柄
    FILE *video_fd = NULL;
    const char *yuv_path = "yuv420p_320x240.yuv";
    size_t video_buff_len = 0;
    uint8_t *video_buf = NULL; //读取数据后先把放到buffer里面
    // 我们测试的文件是YUV420P格式
    uint32_t y_frame_len = video_width * video_height;
    uint32_t u_frame_len = video_width * video_height / 4; // 420p是4个y对应一个u
    uint32_t v_frame_len = video_width * video_height / 4; // 420p是4个y对应一个v
    uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;
    window = SDL_CreateWindow("Simplest YUV Player",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              video_width, video_height,
                              SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if (!window) {
        printf("Can't create window, err: %s\n", SDL_GetError());
        goto _FAIL;
    }
    // 基于窗口创建渲染器
    renderer = SDL_CreateRenderer(window, -1, 0);
    // 基于渲染器创建纹理
    texture = SDL_CreateTexture(renderer,
                                pixformat,
                                SDL_TEXTUREACCESS_STREAMING,
                                video_width,
                                video_height);
    // 分配空间
    video_buf = (uint8_t*)malloc(yuv_frame_len);
    if (!video_buf) {
        fprintf(stderr, "Failed to alloce yuv frame space!\n");
        goto _FAIL;
    }
    // 打开YUV文件
    video_fd = fopen(yuv_path, "rb");
    if (!video_fd) {
        fprintf(stderr, "Failed to open yuv file\n");
        goto _FAIL;
    }
    // 创建请求刷新线程
    timer_thread = SDL_CreateThread(refresh_video_timer, NULL, NULL);
    while (1) {
        SDL_WaitEvent(&event);
        if (event.type == REFRESH_EVENT) {
            video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd);
            if (video_buff_len <= 0) {
                fprintf(stderr, "Failed to read data from yuv file!\n");
                goto _FAIL;
            }
            // 设置纹理的数据
            SDL_UpdateTexture(texture, NULL, video_buf, video_width);
            // 显示区域, 可以通过修改w和h进行缩放
            rect.x = 0;
            rect.y = 0;
            float w_ratio = win_width * 1.0 / video_width;
            float h_ratio = win_height * 1.0 / video_height;
            rect.w = video_width * w_ratio;
            rect.h = video_height * h_ratio;
            // 清屏
            SDL_RenderClear(renderer);
            // 将纹理的数据拷贝给渲染器
            SDL_RenderCopy(renderer, texture, NULL, &rect);
            // 显示
            SDL_RenderPresent(renderer);
        } else if (event.type == SDL_WINDOWEVENT) {
            SDL_GetWindowSize(window, &win_width, &win_height);
            printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n", win_width, win_height);
        } else if (event.type == SDL_QUIT) {
            s_thread_exit = 1;
        } else if (event.type == QUIT_EVENT) {
            break;
        }
    }
_FAIL:
    s_thread_exit = 1;
    // 释放资源
    if(timer_thread)
        SDL_WaitThread(timer_thread, NULL); // 等待线程退出
    if(video_buf)
        free(video_buf);
    if(video_fd)
        fclose(video_fd);
    if(texture)
        SDL_DestroyTexture(texture);
    if(renderer)
        SDL_DestroyRenderer(renderer);
    if(window)
        SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}
相关文章
|
存储 Cloud Native Linux
音视频 SDL vs2017配置
音视频 SDL vs2017配置
|
存储 编解码 Linux
FFmpeg+SDL播放器开发实践:解析、解码、渲染全流程详解
FFmpeg+SDL播放器开发实践:解析、解码、渲染全流程详解
[笔记]音视频学习之SDL篇《十四》简单的动画
[笔记]音视频学习之SDL篇《十四》简单的动画
|
6月前
|
人机交互 C++
QT + FFmpeg 5.x + x264 + x265 + SDL2 音视频播放器
QT + FFmpeg 5.x + x264 + x265 + SDL2 音视频播放器
220 0
|
存储 Cloud Native Linux
音视频 SDL简介
音视频 SDL简介
[笔记]音视频学习之SDL篇《七》用类封装SDL
[笔记]音视频学习之SDL篇《七》用类封装SDL
[笔记]音视频学习之SDL篇《九》 渲染yuv数据
[笔记]音视频学习之SDL篇《九》 渲染yuv数据
[笔记]音视频学习之SDL篇《一》 渲染图片
[笔记]音视频学习之SDL篇《一》 渲染图片
实战--ffmpeg与sdl实现最简单的视频播放器
实战--ffmpeg与sdl实现最简单的视频播放器
99 0