视音频技术零基础学习笔记(四)及解码程序添加注释

SDL视频显示

作用:把解码得到的YUV数据显示出来

视频显示知识

视频显示的流程

  • 视频显示的流程,就是将像素数据“画”在屏幕上的过程。
  • 例如显示YUV,就是将YUV“画”在系统的窗口中。

SDL简介

作用

  • SDL(Simple DirectMedia Layer)库的作用说白了就是封装了复杂的视音频底层交互工作,简化了视音频处理的难度。
  • SDL除了视音频这部分,更多用在游戏上。本课程中只涉及到SDL库的一小部分——视频显示部分。

特点

  • 跨平台
  • 开源

结构

SDL结构

  • SDL会根据当前系统选择调用什么底层库

VC下SDL开发环境搭建

和FFmpeg开发类似,这里只记录不同点。

  • lib库包含:“SDL2.lib;SDL2main.lib”
  • 头文件
//注:
我用的VS2013编译就是如下include能编译成功,而雷老师原来#include "SDL2/SDL.h"在VS2010下貌似可以编译
//c语言
#include "sdl/SDL.h"
//c++
extern "C"
{
    #include "sdl/SDL.h"
}
  • 测试程序
int main(int argc, char* argv[]){
    //调用初始化函数
    if(SDL_Init(SDL_INIT_VIDEO)) {
        printf( "Could not initialize SDL - %s\n", SDL_GetError());
    } 
    else{
        printf("Success init SDL");
    }
    return 0;
}

SDL视频显示的函数

显示流程

SDL视频显示流程

SDL视频显示函数简介

  • SDL_Init():初始化SDL系统
  • SDL_CreateWindow():创建窗口SDL_Window(数据结构)
  • SDL_CreateRenderer():创建渲染器SDL_Renderer(数据结构)
  • SDL_CreateTexture():创建纹理SDL_Texture(数据结构),实际上我们使用的时候就操作Texture这个对象即可
  • SDL_UpdateTexture():设置纹理的数据
  • SDL_RenderCopy():将纹理的数据拷贝给渲染器
  • SDL_RenderPresent():显示
  • SDL_Delay():工具函数,用于延时。控制视频按正常速率显示,一般每秒25帧。
  • SDL_Quit():退出SDL系统

SDL视频显示的数据结构

显示结构

显示结构

  • 最底层是Window
  • SDL_Rect标明Texture显示在屏幕的位置和区域大小
  • 一个Textrue对应一个YUV数据

SDL数据结构简介

  • SDL_Window: 代表了一个“窗口”
  • SDL_Renderer: 代表了一个“渲染器”
  • SDL_Texture: 代表了一个“纹理”
  • SDL_Rect: 一个简单的矩形结构

SDL中时间和多线程

SDL多线程

  • 函数: SDL_CreateThread() //创建一个线程
  • 数据结构: SDL_Thread //线程的句柄

SDL事件

函数
  • SDL_WaitEvent(): 等待一个事件
  • SDL_PushEvent(): 发送一个事件
数据结构
  • SDL_Event:代表一个事件

多线程在本程序中的作用

  • 若不用多线程,那么SDL打开的Window无法响应任何消息,包括窗口移动、窗口缩放以及窗口关闭等。这是由于单线程只有精力完成显示这一项工作,没有监听消息。
  • 这里用类似Win32程序的方法,就是main函数开一个消息循环,不停的监听消息,根据不同的消息类型选择不同的处理方式。
  • 延时也作为一个消息,那么时间一到发消息,main函数监听到这个消息并响应,播放下一帧画面。

代码分析

注:这里只分析多线程的那个程序

#include <stdio.h>

extern "C"
{
#include "sdl/SDL.h"
};

const int bpp=12;

int screen_w=500,screen_h=500;
const int pixel_w=320,pixel_h=180;

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


//这里定义了新的消息
//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)
//Break
#define BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit=0;

int refresh_video(void *opaque){
    thread_exit=0;
    while (thread_exit==0) {
        SDL_Event event;
        //发送刷新消息
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event);
        SDL_Delay(40);
    }
    //thread_exit=0;
    //Break
    SDL_Event event;
    //发送结束消息
    event.type = BREAK_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("test_yuv420p_320x180.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){
        //监听消息,等待中
        SDL_WaitEvent(&event);
        if(event.type==REFRESH_EVENT){
            //这里表示如果读不到足够的内容,应该是读完了文件,因此为了循环播放重新置位fp
            //bpp表示存一个YUV像素点所需的二进制位数
            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);
            }

            //用buffer设置纹理
            SDL_UpdateTexture( sdlTexture, NULL, buffer, pixel_w);  

            //FIX: If window is resize
            //sdlRect.x表示矩形区域和sdlwindow的相对坐标位置
            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){
            //获取当前窗口的宽和高
            SDL_GetWindowSize(screen,&screen_w,&screen_h);
        }else if(event.type==SDL_QUIT){
            thread_exit=1;
        }else if(event.type==BREAK_EVENT){
            break;
        }
    }
    SDL_Quit();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值