【FFmpeg】SDL 音视频开发 ② ( SDL 视频显示函数 | 设置渲染器目标纹理 | 设置渲染器颜色 | 清除渲染器 | 渲染器绘制矩形 | 纹理拷贝 | 窗口中显示渲染纹理 )

博客源码下载 : https://download.csdn.net/download/han1202012/89421317

SDL 代码执行效果如下 :

在这里插入图片描述





一、SDL 视频显示函数




1、SDL 的 渲染器 和 纹理 之间的关系


渲染器 SDL_Renderer 负责将 图像数据 绘制到 渲染目标 上 , 渲染目标通常是

  • 窗口 SDL_Window : 就是 SDL 中创建的 Windows 窗口 或 对话框 ;
  • 纹理 SDL_Texture : 下面详细解释 ;

纹理 SDL_Texture 是 SDL 中用于 存储图像数据 的 结构体类型 , 该结构体对象存储的是 图像的描述信息 , 不是具体的像素数据 ;

  • 如 : 纹理的背景颜色是白色 , 纹理图像的绝对地址是 “D:/image.png” , 纹理中在 (100, 100) 位置绘制了一个 100 x100 大小的矩形 , 这是描述信息 ,
    • 不会存储具体的像素 如 : 第一行第一列是白色像素点 , 第一行第二列是白色像素点 ;

渲染器 SDL_Renderer 工作流程 : 一般情况下 , 渲染器会 先将 绘制内容 渲染到 纹理 SDL_Texture 中 , 在 纹理背景颜色 或 背景图片 的基础上 , 绘制 文字 / 形状 / 图片 等内容 , 然后再将 渲染好的 纹理 SDL_Texture 绘制到窗口中 ;

可以这么理解 , 先在内存中的一张虚拟画布上作画 , 然后将画好的内容一次性绘制到窗口中 ;


2、SDL_SetRenderTarget 函数 - 设置渲染器目标纹理


SDL_SetRenderTarget 函数 的 作用是 设置 SDL_Renderer 渲染器 的 渲染目标纹理 , 渲染就是绘图 , 向目标纹理中渲染就是在 SDL_Texture 纹理中绘图 ;

SDL_SetRenderTarget 函数原型如下 :

int SDL_SetRenderTarget(SDL_Renderer* renderer, SDL_Texture* texture);
  • renderer 参数 : 指向 SDL_Renderer 渲染器对象的指针 , 这个渲染器就是要在 SDL_Texture 纹理中绘图的主体 ;
  • texture 参数 : 指向 SDL_Texture 纹理对象的指针 , 在该纹理中进行绘图 ; 如果要在渲染器关联的窗口中绘图 , 传递 NULL 即可 ;
  • 返回值 : 如果 为 SDL_Renderer 渲染器 设置 要渲染的 目标纹理 SDL_Texture 成功 , 返回 0 ; 如果设置过程中发生错误 , 则返回 -1 ; 使用 SDL_GetError 函数可获取报错信息 ;

代码示例 : 先创建 SDL_Window 窗口对象 , 然后根据 窗口对象 创建 SDL_Renderer 渲染器对象 , 最后 根据渲染对象 创建 SDL_Texture 纹理对象 ;

创建了渲染器对象 和 纹理对象后 , 再为 渲染器 设置要渲染的 目标纹理 , 在最后 调用 SDL_SetRenderTarget 为 渲染器设置 目标纹理 ;

    // 创建 SDL Window 窗口对象
    SDL_Window *window = SDL_CreateWindow("SDL窗口",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              800,
                              600,
                              SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
                              
    // 创建 SDL_Renderer 渲染器对象
    SDL_Renderer *renderer = SDL_CreateRenderer(
                window, -1, 0);

    // 创建 SDL_Texture 纹理对象
    SDL_Texture* texture = SDL_CreateTexture(
                renderer,
                SDL_PIXELFORMAT_RGBA8888,
                SDL_TEXTUREACCESS_TARGET,
                800, 600);
                
    // 为 渲染器 设置 纹理
    SDL_SetRenderTarget(renderer, texture);

3、SDL_SetRenderDrawColor 函数 - 设置渲染器颜色


SDL_SetRenderDrawColor 函数 用于设置 使用渲染器 进行绘图时 , 要绘制的 颜色 , 设置了该颜色后 , 之后渲染器绘制 线条 / 矩形 / 多边形 / 文字 时 , 使用该颜色作为默认绘图的颜色 ;

SDL_SetRenderDrawColor 函数原型 :

int SDL_SetRenderDrawColor(SDL_Renderer* renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
  • renderer 参数 : 指向 SDL_Renderer 渲染器对象 的指针 , 这是要使用指定颜色值进行绘图的渲染器 ;
  • r 参数 : 三原色中的红色 Red 分量的值 , 取值范围 0 ~ 255 ;
  • g 参数 : 三原色中的绿色 Green 分量的值 , 取值范围 0 ~ 255 ;
  • b 参数 : 三原色中的蓝色 Blue 分量的值 , 取值范围 0 ~ 255 ;
  • a 参数 : 透明度分量的值取值范围 0 ~ 255 , 0 表示完全透明 , 255 完全不透明 ;
  • 返回值 : 如果 为 SDL_Renderer 渲染器 设置 RGBA 颜色 成功 , 返回 0 ; 如果设置过程中发生错误 , 则返回 -1 ; 使用 SDL_GetError 函数可获取报错信息 ;

代码示例 : 该函数是为 SDL_Renderer 渲染器设置颜色值 , 只要 渲染器对象 创建之后 , 就可以设置 , 也可以多次设置修改颜色值 ;

    // 创建 SDL_Renderer 渲染器对象
    SDL_Renderer *renderer = SDL_CreateRenderer(
                window, -1, 0);
                
    // 设置红色背景, 后面四个参数分别是 RGBA
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);

4、SDL_RenderClear 函数 - 清除渲染器


SDL_RenderClear 函数 的 作用是 清除 与 渲染器 的 目标纹理 内容 , 使用指定颜色值渲染 目标纹理 ;

在之前调用 SDL_SetRenderDrawColor 函数为渲染器设置了一个颜色值 , 调用 SDL_RenderClear 函数 清除渲染器时 , 就会使用该颜色值 铺满 SDL_Texture 纹理画面 ;


SDL_RenderClear 函数原型 :

int SDL_RenderClear(SDL_Renderer* renderer);
  • renderer 参数 : 指向 SDL_Renderer 渲染器对象 的指针 , 这是要清除该渲染器对象 渲染绘制 的 SDL_Texture 纹理画面 ;
  • 返回值 : 如果 为 SDL_Renderer 渲染器 清除纹理画面内容 成功 , 返回 0 ; 如果设置过程中发生错误 , 则返回 -1 , 使用 SDL_GetError 函数可获取报错信息 ;

代码示例 : 下面的代码中提前为渲染器设置了 不透明红色 颜色值 , 在清除渲染器时就会使用红色铺满 该渲染器 渲染的 目标纹理对象 ;

        // 为 渲染器 设置 纹理
        SDL_SetRenderTarget(renderer, texture);
        // 设置红色背景, 后面四个参数分别是 RGBA
        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        // 清除屏幕
        SDL_RenderClear(renderer);

5、SDL_RenderDrawRect 函数 - 渲染器绘制矩形


SDL_RenderDrawRect 函数 用于在 目标纹理对象 上绘制一个矩形边框 , 注意 : 只绘制边缘 , 不填充颜色 ;

SDL_RenderDrawRect 函数原型 :

int SDL_RenderDrawRect(SDL_Renderer* renderer, const SDL_Rect* rect);
  • renderer 参数 : 指向 SDL_Renderer 渲染器对象 的指针 , 该渲染器对象 被设置了 渲染绘制 的 SDL_Texture 纹理画面 , 矩形就在该纹理上进行绘制 ;
  • rect 参数 : 指向 SDL_Rect 结构的指针 , 该结构体中封装了 矩形的 左上角坐标位置 和 宽高 , 单位都是像素 ;
  • 返回值 : 如果 为 SDL_Renderer 渲染器 绘制矩形 成功 , 返回 0 ; 如果设置过程中发生错误 , 则返回 -1 , 使用 SDL_GetError 函数可获取报错信息 ;

SDL_Rect 是矩形结构 , 该结构体内容如下 : int x, y 是 矩形左上角的 x 和 y 坐标 , int w, h 是 矩形的宽度和高度 , 单位都是像素 ;

typedef struct SDL_Rect {  
    int x, y;          // 矩形左上角的 x 和 y 坐标  
    int w, h;          // 矩形的宽度和高度  
} SDL_Rect;

代码示例 : 下面的代码中 , 为 renderer 渲染器 设置目标纹理为 texture 纹理 , 绘制的内容在 texture 纹理上 , 在该纹理上绘制一个红色矩形 , 矩形的左上角坐标位置是 (100, 100) , 矩形的宽高大小为 100x100 像素大小 , 最后调用 SDL_RenderDrawRect 函数 , 将 红色矩形 绘制到 渲染器渲染 的 目标纹理 中 ;

	// 为 渲染器 设置 纹理
	SDL_SetRenderTarget(renderer, texture);
	// 设置渲染器颜色值为红色, 后面四个参数分别是 RGBA
	SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        
    // 在 (100, 100) 位置绘制 100x100 像素大小的矩形
    SDL_Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.w = 100;
    rect.h = 100;

    // 渲染器绘制矩形
    SDL_RenderDrawRect(renderer, &rect);

6、SDL_RenderCopy 函数 - 纹理拷贝


SDL_RenderCopy 函数 的 作用是 将 SDL_Texture 纹理画面 ( 被复制 ) 复制到 SDL_Renderer 渲染器 的 SDL_Texture 目标纹理 ( 被赋值 ) 中 ;

SDL_RenderCopy 函数原型 :

int SDL_RenderCopy(
	SDL_Renderer* renderer, 
	SDL_Texture* texture, 
	const SDL_Rect* srcrect, 
	const SDL_Rect* dstrect);
  • renderer 参数 : 指向 SDL_Renderer 渲染器对象 的指针 , 这是目标渲染器 , 渲染器是用于绘制到窗口或表面的上下文 ;
  • texture 参数 : 指向 SDL_Texture 纹理对象的指针 , 这是要复制的纹理 , 纹理中是对图像的描述数据 , 不是像素数据 ;
  • srcrect 参数 : 指向 SDL_Rect 矩形对象的指针 , 源矩形 , 被复制的 SDL_Texture* texture 参数中的纹理画面上 , 要复制哪些区域 , 使用该矩形指定 ; 如果该参数为 NULL , 则复制整个 SDL_Texture 纹理对象 ;
  • dstrect 参数 : 指向 SDL_Rect 矩形对象的指针 , 目标矩形 , 要绘制到的 SDL_Renderer* renderer 参数 绑定的 渲染目标纹理 上的位置和大小 ;

代码示例 : 下面的代码中 , 现在 texture 纹理中 , 绘制了一个矩形 , 然后将 渲染器 的 渲染目标纹理 设置为窗口 , 最后将 绘制了矩形的 纹理对象 拷贝到 渲染窗口纹理的 渲染器中 ;

	// 为 渲染器 设置 纹理
	SDL_SetRenderTarget(renderer, texture);
	// 设置渲染器颜色值为红色, 后面四个参数分别是 RGBA
	SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        
    // 在 (100, 100) 位置绘制 100x100 像素大小的矩形
    SDL_Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.w = 100;
    rect.h = 100;

    // 渲染器绘制矩形
    SDL_RenderDrawRect(renderer, &rect);

	// 设置渲染目标为窗口
	SDL_SetRenderTarget(renderer, NULL);
	// 拷贝纹理到 目标纹理 为 窗口 的 渲染器 中
	// 这个渲染器 就是 原来绘制 被拷贝纹理的渲染器
	SDL_RenderCopy(renderer, texture, NULL, NULL);

7、SDL_RenderPresent 函数 - 窗口中显示渲染纹理


SDL_RenderPresent 函数 的 作用是 将渲染器上 渲染绘制 的图像 显示到 窗口 中 ;

调用该函数前 , 务必确认 , 渲染器的目标纹理就是窗口 , 已经调用了 SDL_SetRenderTarget(renderer, NULL); 方法 , 第二个参数设置 NULL , 就是将目标纹理设置为窗口 ;


SDL_RenderPresent 函数原型 :

void SDL_RenderPresent(SDL_Renderer* renderer);
  • renderer 参数 : 指向 SDL_Renderer 渲染器对象 的指针 , 这是与窗口绑定的 SDL_Renderer 渲染器 , 并将目标 渲染纹理 设置为了 NULL , 也就是在窗口中渲染 ;
  • 该函数没有返回值 ;

代码示例 : 前两行代码就是上一个章节复制纹理的代码 , 将另外一个纹理复制到渲染器的目标纹理中 , 渲染器的目标纹理 就是窗口 , 再调用 SDL_RenderPresent 函数 , 将窗口中渲染的图像绘制出来 ;

	// 设置渲染目标为窗口
	SDL_SetRenderTarget(renderer, NULL);
	// 拷贝纹理到 目标纹理 为 窗口 的 渲染器 中
	// 这个渲染器 就是 原来绘制 被拷贝纹理的渲染器
	SDL_RenderCopy(renderer, texture, NULL, NULL);
	// 输出渲染器渲染内容
    SDL_RenderPresent(renderer);




二、代码示例 - 移动元素绘制




1、完整代码示例


博客源码下载 : https://download.csdn.net/download/han1202012/89421317 , 完整代码可以在这里下载 ;

完整代码示例 :

#include <stdio.h>

#include <SDL.h>

#undef main
int main(int argc, char* argv[])
{
    printf("Hello World!\n");

    // 创建 SDL 窗口对象
    SDL_Window *window = NULL;

    // 初始化 SDL 环境 , 用于播放视频
    SDL_Init(SDL_INIT_VIDEO);

    // 创建 SDL Window 窗口对象
    window = SDL_CreateWindow("SDL窗口",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              800,
                              600,
                              SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);


    // 创建 SDL_Renderer 渲染器对象
    SDL_Renderer *renderer = SDL_CreateRenderer(
                window, -1, 0);

    // 创建 SDL_Texture 纹理对象
    SDL_Texture* texture = SDL_CreateTexture(
                renderer,
                SDL_PIXELFORMAT_RGBA8888,
                SDL_TEXTUREACCESS_TARGET,
                800, 600);


    // 在 (100, 100) 位置绘制 100x100 像素大小的矩形
    SDL_Rect rect;
    rect.x = 100;
    rect.y = 100;
    rect.w = 100;
    rect.h = 100;

    int count = 0;

    while (count <= 100) {
        // 为 渲染器 设置 纹理
        SDL_SetRenderTarget(renderer, texture);
        // 设置红色背景, 后面四个参数分别是 RGBA
        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        // 清除屏幕
        SDL_RenderClear(renderer);

        // 渲染矩形数据计算
        rect.x += count;
        if(rect.x >= 700) {
            rect.x = 0;
        }
        /*rect.y += count;
        if(rect.y >= 500) {
            rect.y = 0;
        }*/


        // 渲染器绘制矩形
        SDL_RenderDrawRect(renderer, &rect);
        // 设置绘制矩形颜色为白色 最后四位参数是 RGBA
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
        // 设置矩形为颜色填充
        SDL_RenderFillRect(renderer, &rect);

        // 设置渲染目标为窗口
        SDL_SetRenderTarget(renderer, NULL);
        // 拷贝纹理到 CPU 中
        SDL_RenderCopy(renderer, texture, NULL, NULL);

        // 输出渲染器渲染内容
        SDL_RenderPresent(renderer);

        // 延迟 0.05 秒
        SDL_Delay(50);

        // 循环次数自增 1
        count++;
    }

    // 销毁纹理
    SDL_DestroyTexture(texture);
    // 销毁渲染器
    SDL_DestroyRenderer(renderer);
    // 销毁窗口
    SDL_DestroyWindow(window);

    // 释放系统资源
    SDL_Quit();

    return 0;
}

2、执行结果


执行结果 : 执行后 , 在 窗口 中绘制了 SDL_Rect 矩形 , 该矩形移动时 , 出现了

在这里插入图片描述

  • 64
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
#include <SDL2/SDL.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h>int main() { AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame = NULL; AVPacket packet; int videoStream; SDL_Window *screen; SDL_Renderer *renderer; SDL_Texture *texture; int i, numBytes; uint8_t *buffer = NULL; // 首先打开视频文件 if(avformat_open_input(&pFormatCtx, "test.mp4", NULL, NULL) != 0) { printf("Couldn't open the file"); return -1; } // 找到视频流 if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Couldn't find stream info"); return -1; } // 查找视频流索引 videoStream = -1; for(i=0; i<pFormatCtx->nb_streams; i++) { if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; break; } } if(videoStream == -1) { printf("Couldn't find a video stream"); return -1; } // 初始化SDL if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { printf("Couldn't initialize SDL: %s", SDL_GetError()); return -1; } // 创建窗口 screen = SDL_CreateWindow("FFmpeg Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pFormatCtx->streams[videoStream]->codec->width, pFormatCtx->streams[videoStream]->codec->height, SDL_WINDOW_OPENGL); if(!screen) { printf("SDL: could not create window - exiting: %s", SDL_GetError()); return -1; } // 创建渲染器 renderer = SDL_CreateRenderer(screen, -1, 0); if(!renderer) { printf("SDL: could not create renderer - exiting: %s", SDL_GetError()); return -1; } // 创建纹理 texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, pFormatCtx->streams[videoStream]->codec->width, pFormatCtx->streams[videoStream]->codec->height); if(!texture) { printf("SDL: could not create texture - exiting: %s", SDL_GetError()); return -1; } // 获取解码器 pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if(pCodec == NULL) { printf("Unsupported codec"); return -1; } // 打开解码器 if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("Could not open codec"); return -1; } // 分配视频帧 pFrame = av_frame_alloc(); // 申请缓冲区 numBytes = avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); // 将缓冲区放入视频 avpicture_fill((AVPicture *)pFrame, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); // 开始解码 while(av_read_frame(pFormatCtx, &packet) >= 0) { if(packet.stream_index == videoStream) { int frameFinished; // 解码视频帧 avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); // 如果解码完成 if(frameFinished) { SDL_UpdateYUVTexture(texture, NULL, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1], pFrame->data[2], pFrame->linesize[2]); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); } } // 释放packet av_free_packet(&packet); } // 释放资源 av_free(buffer); av_free(pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 0; }答案:使用FFmpeg采集视频数据,然后通过SDL渲染,可以使用如下代码例程:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值