文档章节

dtplayer中关于sdl的集成

p
 peter_future
发布于 2014/04/23 09:20
字数 1698
阅读 490
收藏 0
点赞 0
评论 0

目录

1 概述

2 AVpicture的介绍

2 sdl的集成

3 sdl2的集成


1 概述


在原生的ffmpeg提供的播放器的例子ffplay中,audio和video的输出是依靠sdl或者sdl2来完成的,具体代码如下(来自ffplay.c):

static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, int64_t pos)

{

    VideoPicture *vp;

    int dst_pix_fmt;

    vp = &is->pictq[is->pictq_windex];


    /** alloc or resize hardware picture buffer */

    if (!vp->bmp ||

        vp->width != is->video_st->codec->width ||

        vp->height != is->video_st->codec->height) {


    /** if the frame is not skipped, then display it */

    if (vp->bmp) {

        AVPicture pict;


        /** get a pointer on the bitmap */

        SDL_LockYUVOverlay (vp->bmp);


        dst_pix_fmt = PIX_FMT_YUV420P;

        memset(&pict,0,sizeof(AVPicture));

        pict.data[0] = vp->bmp->pixels[0];

        pict.data[1] = vp->bmp->pixels[2];

        pict.data[2] = vp->bmp->pixels[1];


        pict.linesize[0] = vp->bmp->pitches[0];

        pict.linesize[1] = vp->bmp->pitches[2];

        pict.linesize[2] = vp->bmp->pitches[1];


        sws_flags = av_get_int(sws_opts, "sws_flags", NULL);

        is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,

            vp->width, vp->height, vp->pix_fmt, vp->width, vp->height,

            dst_pix_fmt, sws_flags, NULL, NULL, NULL);

        if (is->img_convert_ctx == NULL) {

            fprintf(stderr, "Cannot initialize the conversion context\n");

            exit(1);

        }

        sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,

                  0, vp->height, pict.data, pict.linesize);


        /** update the bitmap content */

        SDL_UnlockYUVOverlay(vp->bmp);


        vp->pts = pts;

        vp->pos = pos;

    return 0;

}

这里只摘取了部分重要的代码,其中vp->bmp为SDL_Overlay,也就是输出缓冲区,读者可以认为将yuv数据拷贝到此缓冲区

就可以显示了,对于ffplay来讲是通过sws_scale来完成的


但很多用户希望直接通过将src_frame中对应的数据直接拷贝到SDL_Overlay来达到目的,

其中原因是多方面的,对于dtplayer来说就是在decoder的时候已经通过调用sws_scale转换好了,此处再转换一次本就属于浪费

更重要的是:若将sws_scale放在sdl输出中,那么就必须强制的依赖ffmpeg,这也是无法接受的。

下面就介绍dtplayer中是如何直接操作src_frame来实现video帧的显示


2 AVpicture的介绍


想要正确的显示YUV数据,需要对AVPicture数据结构有比较透彻的了解

特别是其data【4】和linesize【4】这两个成员数组

对于audio来讲,只用了data[0]和linesize【0】,比较简单,这里只介绍video部分

AVPicture里面有data[4]和linesize[4]其中data是一个指向指针的指针(二级、二维指针),也就是指向视频数据缓冲区的首地址

在实际的数据排列中,yuv是连续存放的,data数组中的成员可以认为是指向的是数据中的位移,具体如下图

data -->xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
             ^                          ^                            ^
              |                           |                              |
          data[0]                 data[1]                   data[2]

比如说,当pix_fmt=PIX_FMT_YUV420P时,data中的数据是按照YUV的格式存储的

也就是:

data -->YYYYYYYYYYYYYYUUUUUUUUUUUUUVVVVVVVVVVVV
             ^                          ^                               ^
              |                           |                                 |
          data[0]                 data[1]                     data[2]

linesize是指对应于每一行的大小,为什么需要这个变量,是因为在YUV格式和RGB格式时,每行的大小不一定等于图像的宽度。

       linesize = width + padding size(16+16) for YUV
       linesize = width*pixel_size  for RGB


padding is needed during Motion Estimation and Motion Compensation for Optimizing MV serach and  P/B frame reconstruction

for RGB only one channel is available
so RGB24 : data[0] = packet rgbrgbrgbrgb......
           linesize[0] = width*3
data[1],data[2],data[3],linesize[1],linesize[2],linesize[2] have no any means for RGB

 

测试如下:(原始的320×182视频)
如果pix_fmt=PIX_FMT_RGBA32
linesize 的只分别为:1280  0    0     0

如果pix_fmt=PIX_FMT_RGB24
linesize 的只分别为:960   0    0     0

如果pix_fmt=PIX_FMT_YUV420P
linesize 的只分别为:352   176  176   0

【注】以上内容参考:

http://blog.csdn.net/liaozc/article/details/6110474

http://bbs.chinavideo.org/viewthread.php?tid=119&extra=page%3D1%26filter%3Ddigest&page=1



2 sdl的集成


对于sdl version1.0来说

这里对于如何在dtplayer框架中添加vo不做介绍,感兴趣的自己读代码好了,本身逻辑也非常简单

直接贴出render的代码


static int vo_sdl_render (vo_wrapper_t *wrapper, AVPicture_t * pict){    dt_lock (&vo_mutex);    SDL_Rect rect;    SDL_LockYUVOverlay (overlay);    memcpy (overlay->pixels[0], pict->data[0], dw * dh);    memcpy (overlay->pixels[1], pict->data[2], dw * dh / 4);    memcpy (overlay->pixels[2], pict->data[1], dw * dh / 4);    SDL_UnlockYUVOverlay (overlay);    rect.x = dx;    rect.y = dy;    rect.w = dw;    rect.h = dh;    SDL_DisplayYUVOverlay (overlay, &rect);    dt_unlock (&vo_mutex);    return 0;}

可以看出对于AVpicture_t是封装的ffmpeg的AVPicture的结构,可以认为是没有区别的

操作就是将AVPicture的YUV缓冲区分别拷贝到 overlay的YUV缓冲区中,

需要注意的是这里拷贝的长度并非是AVpicture中的linesize【0】  linesize【1】  linesize【2】 

这里的原因解释下:之所以不能能直接使用linesize数组,是因为linesize【0】linesize【1】 linesize【2】

代表的并不是YUV数据的长度,而是每行多少像素个数+padding(参考上面第2小节),也就是说

linesize[0] = dw + 32

linesize[1] = dw/2

linesize[1] = dw/2

但data中保存的却是正确的yuv数据,因此我们只需要正确的设置要拷贝的数据量,就可以正确的显示视频了


3 sdl2的集成


sdl2与sdl1的接口差别很大,看下sdl2的代码

static int vo_sdl2_render (vo_wrapper_t *wrapper, AVPicture_t * pict)

{

    int ret = 0;

    sdl2_ctx_t *ctx = (sdl2_ctx_t *)wrapper->handle;

    

    if(!ctx->sdl_inited)

    {

        ret = sdl2_pre_init(ctx);

        ctx->sdl_inited = !ret;

    }

    

ctx->mux_vo.lock();

    SDL_Rect dst;

    dst.x = ctx->dx;

    dst.y = ctx->dy;

    dst.w = ctx->dw;

    dst.h = ctx->dh;

    if(ctx->ren == nullptr)

        ctx->ren = SDL_CreateRenderer(ctx->win,-1,0);

    if(ctx->tex == nullptr)

ctx->tex = SDL_CreateTexture(ctx->ren,SDL_PIXELFORMAT_YV12,SDL_TEXTUREACCESS_STREAMING,ctx->dw,ctx->dh);

    //ctx->tex = SDL_CreateTexture(ctx->ren,SDL_PIXELFORMAT_YV12,SDL_TEXTUREACCESS_STATIC,ctx->dw,ctx->dh);

    SDL_UpdateYUVTexture(ctx->tex,NULL, pict->data[0], pict->linesize[0],  pict->data[1], pict->linesize[1],  pict->data[2], pict->linesize[2]);

    //SDL_UpdateTexture(ctx->tex, &dst, pict->data[0], pict->linesize[0]);

    SDL_RenderClear(ctx->ren);

    SDL_RenderCopy(ctx->ren,ctx->tex,&dst,&dst);

    SDL_RenderPresent(ctx->ren);

    ctx->mux_vo.unlock();

    return 0;

}


sdl2的代码可以直接使用linesize数据的大小,是由于SDL_UpdateYUVTexture或者SDL_UpdateTexture本身直接需要的就是AVPicture中linesize的参数,看下接口说明

int SDL_UpdateYUVTexture(SDL_Texture*    texture,                         const SDL_Rect* rect,                         const Uint8 *   Yplane,                         int             Ypitch,                         const Uint8*    Uplane,                         int             Upitch,                         const Uint8*    Vplane,                         int             Vpitch)

Function Parameters

texture

the texture to update

rect

a pointer to the rectangle of pixels to update, or NULL to update the entire texture

Yplane

the raw pixel data for the Y plane

Ypitch

the number of bytes between rows of pixel data for the Y plane

Uplane

the raw pixel data for the U plane

Upitch

the number of bytes between rows of pixel data for the U plane

Vplane

the raw pixel data for the V plane

Vpitch

the number of bytes between rows of pixel data for the V plane


由于参数匹配,所以直接使用就可以了。



这里在使用SDL2的时候还有个地方需要注意:sdl2 是通过SDL_Window  SDL_Renderer  SDL_Texture三者协同作用来工作的

SDL_Window  ==窗口

SDL_Renderer ==画布

SDL_Texture    ==内容

这里窗口的创建必须在主线程中,至少要在显示输出的线程中创建,否则通过SDL_RenderPresent显示video的时候是不会刷新的

可以参考之前dtplayer的实现,由于后面将sdl2提前到player层面作为界面,因此可reset到之前版本,具体步骤如下:

git clone https://github.com/peterfuture/dtplayer.git

git reset   bcda0659a25f43f9f3e8eec9bb25d1b6c532281c

直接参考dtvideo/video_out/vo_sdl2.c就可以了 


github:https://github.com/avplayer/dtplayer   # C++

github:https://github.com/peterfuture/dtplayer # C

bug report: peter_future@outlook.com

blog: http://blog.csdn.net/dtplayer

bbs: http://avboost.com/

wiki: http://wiki.avplayer.org/Dtplayer


由于后面随着开发的进行文章会进行细节的更新,因此为了保证读者随时读到最新的内容,文章禁止转载,多谢大家支持!


© 著作权归作者所有

共有 人打赏支持
p
粉丝 2
博文 3
码字总数 1928
作品 1
程序员
多媒体播放器--dtplayer

dtplayer是基于ffmpeg开发的多媒体播放器,具备令人发指的扩展能力。 c语言开发,目前仅支持linux平台。 github: https://github.com/peterfuture/dtplayer 交流:peter_future@outlook.com...

peter_future ⋅ 2014/03/21 ⋅ 0

初探Security Development Lifecycle (SDL)

这个东西是什么: Security Development Lifecycle (SDL)中文名称软件安全开发周期 来自哪里: Microsoft,2004 有什么意义:    它是一个逐渐完善的体系,并将软件安全的考虑与实施方法集成...

303Donatello ⋅ 2017/05/19 ⋅ 0

dttv-android 项目

dttv-android是基于dtplayer的android版本的多媒体播放器 audio通过audiotrack输出 video通过opengl输出 后续会添加 opensl es 输出音频解决android兼容性问题 暂时支持android 4.4 项目地址...

peter_future ⋅ 2014/08/22 ⋅ 0

3.SDL游戏开发:把代码写长一点(二)

看问题想本质,读USB驱动源码时,要读至threadrun才到精彩处,那么对于上层的应用来说,那种至高境界估计是到不了,但是还是接着把代码上面代码理解下,从整个代码来看,里面增加的SDL函数就...

一一无念 ⋅ 2012/11/05 ⋅ 1

1.SDL游戏开发:环境搭建与测试

SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个...

一一无念 ⋅ 2012/11/05 ⋅ 4

6.SDL游戏开发:玩玩文字的游戏reading the fuck source code

TTF(TrueTypeFont)是一种字库名称。TTF(TrueTypeFont)是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。首先我们先看下win...

一一无念 ⋅ 2012/11/06 ⋅ 1

[转]关于游戏开放式源代码项目组成引擎核心部分简介

Axiom – 渲染引擎 关于Axiom 高性能,交叉平台的Axiom(公数)3D渲染引擎是应用.NET的C Sharp语言开发的OGRE引擎C Sharp版。 Axiom 3D引擎项目是完全针对3D图形引擎开发,并利用C Sharp语言...

WANGYANG ⋅ 2011/08/11 ⋅ 0

使用SDL动态显示鼠标的位置信息(四)

博主这两天看动漫看晕了,有点懈怠啊...嘿嘿,动漫的名字叫做《我的妹妹不可能那么可爱》,二季看完之后我突然觉得我有个妹妹该多好啊,嘿嘿... 不过更为恼火的是,博主搭建了SDL2.0的环境,...

夲仒無道 ⋅ 2013/10/04 ⋅ 0

8.SDL游戏开发:事件(二)

没上班日子无聊,没得上班又没钱的日子便是痛苦,在上海又换了个地,生活不容易,新地方还不错,上网用无线,下午准备接着写SDL系列,没想到的是B450上fedora12 无线网卡驱动没整上,然后我在...

一一无念 ⋅ 2012/11/08 ⋅ 0

2.SDL游戏开发:把代码写长一点(一)

接着上一篇讲,里面有几个值得研究的函数,尽管理API里已经说得很清楚了,调用SDL_Init()动态的加载和初始化SDL库。 该函数带有一组标记来表示哪部分需要激活: SDLINITAUDIOSDLINITVIDEOSD...

一一无念 ⋅ 2012/11/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用ZBLOG2.3博客写读书笔记网站能创造今日头条的辉煌吗?

最近两年,著名的自媒体网站今日头条可以说是火得一塌糊涂,虽然从目前来看也遇到了一点瓶颈,毕竟发展到了一定的规模,继续增长就更加难了,但如今的今日头条规模和流量已经非常大了。 我们...

原创小博客 ⋅ 19分钟前 ⋅ 0

MyBatis四大核心概念

本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper)。 MyBatis 作为互联网数据库映射工具界的“上古神器”,训有四大“神兽”,谓之:Sql...

waylau ⋅ 39分钟前 ⋅ 0

以太坊java开发包web3j简介

web3j(org.web3j)是Java版本的以太坊JSON RPC接口协议封装实现,如果需要将你的Java应用或安卓应用接入以太坊,或者希望用java开发一个钱包应用,那么用web3j就对了。 web3j的功能相当完整...

汇智网教程 ⋅ 52分钟前 ⋅ 0

2个线程交替打印100以内的数字

重点提示: 线程的本质上只是一个壳子,真正的逻辑其实在“竞态条件”中。 举个例子,比如本题中的打印,那么在竞态条件中,我只需要一个方法即可; 假如我的需求是2个线程,一个+1,一个-1,...

Germmy ⋅ 今天 ⋅ 0

Springboot2 之 Spring Data Redis 实现消息队列——发布/订阅模式

一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式,这里利用redis消息“发布/订阅”来简单实现订阅者模式。 实现之前先过过 redis 发布订阅的一些基础概念和操...

Simonton ⋅ 今天 ⋅ 0

error:Could not find gradle

一.更新Android Studio后打开Project,报如下错误: Error: Could not find com.android.tools.build:gradle:2.2.1. Searched in the following locations: file:/D:/software/android/andro......

Yao--靠自己 ⋅ 昨天 ⋅ 0

Spring boot 项目打包及引入本地jar包

Spring Boot 项目打包以及引入本地Jar包 [TOC] 上篇文章提到 Maven 项目添加本地jar包的三种方式 ,本篇文章记录下在实际项目中的应用。 spring boot 打包方式 我们知道,传统应用可以将程序...

Os_yxguang ⋅ 昨天 ⋅ 0

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 昨天 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 昨天 ⋅ 0

eclipse酷炫大法之设置主题、皮肤

eclipse酷炫大法 目前两款不错的eclipse 1.系统设置 Window->Preferences->General->Appearance 2.Eclipse Marketplace下载【推荐】 Help->Eclipse Marketplace->搜索‘theme’进行安装 比如......

anlve ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部