文档章节

dtplayer中关于sdl的集成

p
 peter_future
发布于 2014/04/23 09:20
字数 1698
阅读 490
收藏 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


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


© 著作权归作者所有

共有 人打赏支持
上一篇: dttv-android 项目
下一篇: 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
862
0
3.SDL游戏开发:把代码写长一点(二)

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

一一无念
2012/11/05
0
1
dttv-android 项目

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

peter_future
2014/08/22
0
0
初探Security Development Lifecycle (SDL)

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

303Donatello
2017/05/19
0
0
1.SDL游戏开发:环境搭建与测试

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

一一无念
2012/11/05
0
4

没有更多内容

加载失败,请刷新页面

加载更多

验证码

response生成验证码 验证码的作用:防止恶意注册、攻击等 网站上看到的验证码,实际上都是一些图片,而这些图片都是程序(Servlet)生成的! package day19.test; import java.awt.Color; i...

码农屌丝
47分钟前
0
0
day147-2018-11-14-英语流利阅读-待学习

《毒液》刚刚上映,创造漫威宇宙的人却走了 雪梨 2018-11-14 1.今日导读 中国的金庸创造了侠义英雄和江湖传奇,而大洋彼岸的斯坦·李也同样创造了一个绚烂璀璨的漫威宇宙,他构思的每个超级英...

飞鱼说编程
49分钟前
3
0
CentOS 安装PHP5和PHP7

安装PHP5 下载解压二进制包 [root@test-a src]# cd /usr/local/src/[root@test-a src]# wget http://cn2.php.net/distributions/php-5.6.32.tar.bz2[root@test-a src]# tar jxvf php-5.6......

野雪球
今天
4
0
修改jfinal默认的redis序列化方式

jfinal 越来越流行, jfinal的redis插件默认的序列化方式是fst。 但是系统中其他项目中用的是spring data redis中的StringRedisTemplate,所有的value都是通过gson转化成String放进去的。 直接...

采蘑菇的大叔
今天
1
2
windows上类似dnsmasq的软件Dual DHCP DNS Server

官网地址:http://dhcp-dns-server.sourceforge.net/官网定向的下载地址:https://sourceforge.net/projects/dhcp-dns-server/files/ 设置参考地址:http://blog.51cto.com/zhukeqiang/18264......

xueyuse0012
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部