前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FFmpeg4.0+SDL2.0笔记02:Outputting to the Screen

FFmpeg4.0+SDL2.0笔记02:Outputting to the Screen

原创
作者头像
非一
修改2021-04-14 10:08:03
4960
修改2021-04-14 10:08:03
举报
文章被收录于专栏:非一非一

环境

背景:在系统性学习FFmpeg时,发现官方推荐教程还是15年的,不少接口已经弃用,大版本也升了一级,所以在这里记录下FFmpeg4.0+SDL2.0的学习过程。

win10,VS2019,FFmpeg4.3.2,SDL2.0.14

原文地址:http://dranger.com/ffmpeg/tutorial02.html

SDL与Video

为了播放视频,我们将使用SDL库。SDL即Simple Direct Layer,它是非常优秀且跨平台的多媒体库,不少项目都有所使用。

SDL可以渲染多种图像格式,其中包括YUV格式。粗略讲一下YUV,与RGB类似,YUV是储存原始图像的一种格式,Y是亮度(luma),UV是色度。

SDL2.0现在支持7种YUV格式,包括ffmpeg解码出的YUV420P格式。420表示图像按4:2:0的比例采样,也就是每4个亮度样本(Y)对应1个色度样本(UV),总共6字节,相比RGB24需要4*3=12字节,YUV节省了一半带宽,并且人眼感知不到其中的差别。P表示YUV数据按planar格式存储——即Y,U,V分别存放在3个数组里。

首先来看看如何使用SDL库。第一步,初始化,注意main函数必须写成SDL库要求的形式int main(int argc, char* argv[]),否则编译不通过。另外SDL1.0里不少接口和组件已被弃用,参考:https://wiki.libsdl.org/MigrationGuide#SDL_1.2_to_2.0_Migration_Guide

代码语言:javascript
复制
extern "C" {
#include <SDL.h>
#include <SDL_thread.h>
}

int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        cout << "SDL_Init failed: " << SDL_GetError() << endl;
        return -1;
    }
}

创建窗口

SDL1.0里的SDL_SetVideoMode已被弃用,这里我们使用SDL_Window,SDL_Renderer和SDL_Texture,SDL_CreateWindow会创建对应宽高的窗口,SDL_CreateRenderer创建该窗口的渲染器,SDL_CreateTexture创建渲染器的Texture好让我们放置YUV数据。

代码语言:javascript
复制
        SDL_Window* pScreen;
        SDL_Renderer* pRenderer;
        SDL_Texture* pTexture;
	    
	    //创建窗口
        pScreen = SDL_CreateWindow("SDLPlayer",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            pVideoCodecCtx->width,
            pVideoCodecCtx->height,
            0);
        if (pScreen == nullptr) {
            cout << "SDL_CreateWindow failed:" << SDL_GetError() << endl;
            return -1;
        }

        //创建渲染Context
        pRenderer = SDL_CreateRenderer(pScreen, -1, 0);
        if (pRenderer == nullptr) {
            cout << "SDL_CreateRenderer failed:" << SDL_GetError() << endl;
            return -1;
        }

        //初始化成白色
        SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
        SDL_RenderClear(pRenderer);
        SDL_RenderPresent(pRenderer);

        //创建Render所需的Texture,用于放置YUV数据
        pTexture = SDL_CreateTexture(pRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pVideoCodecCtx->width, pVideoCodecCtx->height);
        if (pTexture == nullptr) {
            cout << "SDL_CreateTexture failed:" << SDL_GetError() << endl;
            return -1;
        }

渲染图像

渲染图像只需把YUV数据送给SDL_Texture,再送给SDL_Renderer,调用SDL_RenderPresent就行了。

代码语言:javascript
复制
    int count = 0;
    //读取视频包并解码,转换,保存文件
    while (av_read_frame(pFormatCtx, &packet) >= 0) {
        if (packet.stream_index == iVideoStream) {
            avcodec_send_packet(pVideoCodecCtx, &packet);
            if (avcodec_receive_frame(pVideoCodecCtx, pFrame) == 0) {

                //将YUV更新至texture,然后渲染
                SDL_UpdateYUVTexture(pTexture, NULL,
                    pFrame->data[0], pFrame->linesize[0],      //Y
                    pFrame->data[1], pFrame->linesize[1],      //U
                    pFrame->data[2], pFrame->linesize[2]);     //V
                SDL_RenderClear(pRenderer);
                SDL_RenderCopy(pRenderer, pTexture, NULL, NULL);
                SDL_RenderPresent(pRenderer);
                cout << "presented frame" << ++count << endl;
            }
            //取消packet引用的内存,原先的av_free_packet弃用
            av_packet_unref(&packet);
        }
    }

运行程序便看到视频开始播放了!但是有个问题,整个视频像开了超级加速一样,没两下就播完了,后面我们会解决视频同步问题。

代码:https://github.com/onlyandonly/ffmpeg_sdl_player

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境
  • SDL与Video
  • 创建窗口
  • 渲染图像
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档