C++基于FFmpeg直播(推流)之二

C++编程FFMpeg实时直播推流实战–提取码:nh21

我们先实现用SDL播放YUV数据
先来了解一下基本概念

SDL基本函数:
[初始化]

  • SDL_Init(): 初始化SDL。
  • SDL_CreateWindow(): 创建窗口(Window)。
  • SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。
  • SDL_CreateTexture(): 创建纹理(Texture)。

[循环渲染数据]

  • SDL_UpdateTexture(): 设置纹理的数据。
  • SDL_RenderCopy(): 纹理复制给渲染器。
  • SDL_RenderPresent(): 显示。

C中的fseek函数
int fseek( FILE *stream, long offset, int origin );
第一个参数stream为文件指针
第二个参数offset为偏移量,整数表示正向偏移,负数表示负向偏移
第三个参数origin设定从文件的哪里开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
SEEK_SET: 文件开头
SEEK_CUR: 当前位置
SEEK_END: 文件结尾
其中SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2.
简言之:
fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;
fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;
fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。

下面看一下运行效果:
C++基于FFmpeg直播(推流)之二_第1张图片
下面看源代码 注释很详细

#include 

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

const int bpp=12;

int screen_w=500,screen_h=500;
const int pixel_w=1920,pixel_h=1080;

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


//Refresh Event
#define REFRESH_EVENT  (SDL_USEREVENT + 1)

#define BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit=0;

int refresh_video(void *opaque){
    thread_exit=0;
    while (!thread_exit) {
        SDL_Event event;
        event.type = REFRESH_EVENT;
        SDL_PushEvent(&event); //发送事件 即handler
        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)) {  //初始化SDL系统
        printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
        return -1;
    } 

    SDL_Window *screen; 
    //SDL 2.0  创建窗口(Window)。
    screen = SDL_CreateWindow("WS 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;
    }
    //创建基于窗口创建渲染器(Render)
    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;  
    //创建纹理(Texture)
    SDL_Texture* sdlTexture = SDL_CreateTexture(sdlRenderer,pixformat, SDL_TEXTUREACCESS_STREAMING,pixel_w,pixel_h);

    FILE *fp=NULL;
    //用我们上篇博客解码出来的yuv文件
    fp=fopen("output.yuv","rb+");

    if(fp==NULL){
        printf("cannot open this file\n");
        return -1;
    }
    //window 视频显示框
    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_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;
}

转自:https://blog.csdn.net/King1425/article/details/71160339

你可能感兴趣的:(C++基于FFmpeg直播(推流)之二)