FFmpeg+SDL2实现视频流播放

作者: MzDavid | 来源:发表于2019-04-22 16:59 被阅读3次

    SDL2文章列表

    SDL2入门

    SDL2事件处理

    SDL2纹理渲染

    SDL2音频播放

    本篇博客使用FFmpeg+SDL2完成播放视频流Demo(仅播放视频),所有相关知识在之前的博客中都有提到,稍作整理完成。

    流程图:

    FFmpeg解码视频流:

    SDL2显示YUV数据:

    源码

    #include <stdio.h>
    #include <SDL.h>
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    
    int WinMain(int argc, char *argv[]) {
        int ret = -1;
        char *file = "C:\\Users\\lenovo\\Desktop\\fengjing.mp4";
        
        AVFormatContext *pFormatCtx = NULL; 
        int i, videoStream;
        AVCodecParameters *pCodecParameters = NULL; 
        AVCodecContext *pCodecCtx = NULL;
        AVCodec *pCodec = NULL;
        AVFrame *pFrame = NULL;
        AVPacket packet;
    
        SDL_Rect rect;
        Uint32 pixformat;
        SDL_Window *win = NULL;
        SDL_Renderer *renderer = NULL;
        SDL_Texture *texture = NULL;
        
        //默认窗口大小
        int w_width = 640;
        int w_height = 480;
        
        //SDL初始化
        if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL - %s\n", SDL_GetError());
            return ret;
        }
    
    
        // 打开输入文件
        if (avformat_open_input(&pFormatCtx, file, NULL, NULL) != 0) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open  video file!");
            goto __FAIL; 
        }
    
        //找到视频流
        videoStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
        if (videoStream == -1) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Din't find a video stream!");
            goto __FAIL;// Didn't find a video stream
        }
    
        // 流参数
        pCodecParameters = pFormatCtx->streams[videoStream]->codecpar;
    
        //获取解码器
        pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
        if (pCodec == NULL) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unsupported codec!\n");
            goto __FAIL; // Codec not found
        }
    
        // 初始化一个编解码上下文
        pCodecCtx = avcodec_alloc_context3(pCodec);
        if (avcodec_parameters_to_context(pCodecCtx, pCodecParameters) != 0) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't copy codec context");
            goto __FAIL;// Error copying codec context
        }
    
        // 打开解码器
        if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open decoder!\n");
            goto __FAIL; // Could not open codec
        }
    
        // Allocate video frame
        pFrame = av_frame_alloc();
    
        w_width = pCodecCtx->width;
        w_height = pCodecCtx->height;
    
        //创建窗口
        win = SDL_CreateWindow("Media Player",
                               SDL_WINDOWPOS_UNDEFINED,
                               SDL_WINDOWPOS_UNDEFINED,
                               w_width, w_height,
                               SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
        if (!win) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window by SDL");
            goto __FAIL;
        }
    
        //创建渲染器
        renderer = SDL_CreateRenderer(win, -1, 0);
        if (!renderer) {
            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Renderer by SDL");
            goto __FAIL;
        }
    
        pixformat = SDL_PIXELFORMAT_IYUV;//YUV格式
        // 创建纹理
        texture = SDL_CreateTexture(renderer,
                                    pixformat,
                                    SDL_TEXTUREACCESS_STREAMING,
                                    w_width,
                                    w_height);
    
    
        //读取数据
        while (av_read_frame(pFormatCtx, &packet) >= 0) {
            if (packet.stream_index == videoStream) {
                //解码
                avcodec_send_packet(pCodecCtx, &packet);
                while (avcodec_receive_frame(pCodecCtx, pFrame) == 0) {
    
                    SDL_UpdateYUVTexture(texture, NULL,
                                         pFrame->data[0], pFrame->linesize[0],
                                         pFrame->data[1], pFrame->linesize[1],
                                         pFrame->data[2], pFrame->linesize[2]);
    
                    // Set Size of Window
                    rect.x = 0;
                    rect.y = 0;
                    rect.w = pCodecCtx->width;
                    rect.h = pCodecCtx->height;
    
                    //展示
                    SDL_RenderClear(renderer);
                    SDL_RenderCopy(renderer, texture, NULL, &rect);
                    SDL_RenderPresent(renderer);
                }
            }
    
            av_packet_unref(&packet);
    
            // 事件处理
            SDL_Event event;
            SDL_PollEvent(&event);
            switch (event.type) {
                case SDL_QUIT:
                    goto __QUIT;
                default:
                    break;
            }
    
    
        }
    
        __QUIT:
        ret = 0;
    
        __FAIL:
        // Free the YUV frame
        if (pFrame) {
            av_frame_free(&pFrame);
        }
    
        // Close the codec
        if (pCodecCtx) {
            avcodec_close(pCodecCtx);
        }
    
        if (pCodecParameters) {
            avcodec_parameters_free(&pCodecParameters);
        }
    
        // Close the video file
        if (pFormatCtx) {
            avformat_close_input(&pFormatCtx);
        }
    
        if (win) {
            SDL_DestroyWindow(win);
        }
    
        if (renderer) {
            SDL_DestroyRenderer(renderer);
        }
    
        if (texture) {
            SDL_DestroyTexture(texture);
        }
    
        SDL_Quit();
    
        return ret;
    }
    
    

    这个Demo目前只是通过一个while循环将视频播放出来,所以可以播放视频但是速度不正常,并且没有声音,这些问题会在后面一一解决,最后完成一个简易的播放器。

    相关文章

      网友评论

        本文标题:FFmpeg+SDL2实现视频流播放

        本文链接:https://www.haomeiwen.com/subject/unlugqtx.html