• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

GStreamer插件实列rockchipmpp

武飞扬头像
专注&突破
帮助1

尽管这些年arm发展取得了不少的进步,不过对于音视频的编解码仍然心有余力不足,好在芯片厂家在SOC里面提供了硬件加速能力。善于发挥出芯片的能力,才能打造出完美的应用.今天我们一起来探索一下rk3568上的为我们提供的多媒体加速能力-MPP,然后一起分析一下rk的gstreamer插件。

MPP

概述

瑞芯微提供的媒体处理软件平台( Media Process Platform ,简称 MPP )是适用于瑞芯微芯片系列的 通用媒体处理软件平台。该平台对应用软件屏蔽了芯片相关的复杂底层处理,其目的是为了屏蔽不 同芯片的差异,为使用者提供统一的视频媒体处理接口(Media Process Interface ,缩写 MPI )。 MPP 提供的功能包括:
  • 视频解码
                 H.265 / H.264 / H.263 / VP9 / VP8 / MPEG-4 / MPEG-2 / MPEG-1 / VC1 / MJPEG
  •  视频编码
                 H.264 / VP8 / MJPEG
  • 视频处理
                 视频拷贝,缩放,色彩空间转换,场视频解交织(Deinterlace

系统架构

MPP 平台在系统架构的层次图如下图:
学新通
  • 硬件层 Hardware
        硬件层是瑞芯微系列芯片平台的视频编解码硬件加速模块,包括 VPU rkvdec rkvenc 等不同类型,不同功能的硬件加速器。
  • 内核驱动层 Kernel driver
        Linux 内核的编码器硬件设备驱动,以及相关的 mmu ,内存,时钟,电源管理模块等。
  • 操作系统层
        MPP 用户态的运行平台,如 Android 以及 Debian Linux 发行版
  • 应用层
        MPP 层通过 MPI 对接各种中间件软件,如 OpenMax ffmpeg gstreamer ,或者直接对接客户的上 层应用。

MPI

由于视频编解码与视频处理过程需要处理大量的数据交互,包括码流数据,图像数据以及内存数据, 同时还要处理与上层应用以及内核驱动的交叉关系,所以 MPP 设计了 MPI 接口,用于与上层交互。 本章节说明了 MPI 接口使用的数据结构,以及设计思路。
学新通
MppMem C malloc 内存的封装。
MppBuffer 为硬件用的 dmabuf 内存的封装。
MppPacket 为一维缓存封装,可以从 MppMem MppBuffer 生成,主要用于表示码流数据。
MppFrame 为二维帧数据封装,可以从 MppMem MppBuffer 生成,主要用于表示图像数据。
使用 MppPacket MppFrame 就可以简单有效的完成一般的视频编解码工作。
以视频解码为例,码流输入端把地址和大小赋值给 MppPacket ,通过 put_packet 接口输入,在输出 端通过 get_frame 接口得到输入图像 MppFrame ,即可完成最简单的视频解码过程。
学新通
MPI Media Process Interface )是 MPP 提供给用户的接口,用于提供硬件编解码功能,以及一些必 要的相关功能。MPI 是通过 C 结构里的函数指针方式提供给用户,用户可以通过 MPP 上下文结构 MppCtx 与 MPI 接口结构 MppApi 组合使用来实现解码器与编码器的功能。

 学新通

如上图所示, mpp_create mpp_init mpp_destroy 是操作 MppCtx 接口的过程,其中 mpp_create 接 口也获取到了 MPI 接口结构体 MppApi ,真正的编码与解码过程是通过调用 MppApi 结构体里内的函数指针来实现,也就是上图中红框内的部分。红框内的函数调用分为编解码流程接口put/get_packet/frame 和相关的 control reset 接口。下文先描述编解码器接口,再对编解码器工作中的一些要点进行说明。

rk gstreamer 插件

rockchipmpp是rk公司开发的一个在gstreamer插件,主要把自己的MPP和GStreamer,结合起来,我们在使用是可以直接把相关代码放到gstreamer源码中编译即可。

如下为它的源码

  1.  
    ├── gstmppallocator.c
  2.  
    ├── gstmppallocator.h
  3.  
    ├── gstmppalphadecodebin.c
  4.  
    ├── gstmppalphadecodebin.h
  5.  
    ├── gstmpp.c
  6.  
    ├── gstmppdec.c
  7.  
    ├── gstmppdec.h
  8.  
    ├── gstmppenc.c
  9.  
    ├── gstmppenc.h
  10.  
    ├── gstmpp.h
  11.  
    ├── gstmpph264enc.c
  12.  
    ├── gstmpph264enc.h
  13.  
    ├── gstmpph265enc.c
  14.  
    ├── gstmpph265enc.h
  15.  
    ├── gstmppjpegdec.c
  16.  
    ├── gstmppjpegdec.h
  17.  
    ├── gstmppjpegenc.c
  18.  
    ├── gstmppjpegenc.h
  19.  
    ├── gstmppvideodec.c
  20.  
    ├── gstmppvideodec.h
  21.  
    ├── gstmppvp8enc.c
  22.  
    ├── gstmppvp8enc.h
  23.  
    ├── gstmppvpxalphadecodebin.c
  24.  
    ├── gstmppvpxalphadecodebin.h
学新通

 gstmpp.c为统一的入口文件,在它里面注册其他插件,gstmppjpegdec.c为jpeg的解码文件,我们能以他们为例子分析一下这个rockchip的mpp插件

gstreamer rkmpp 插件定义

如下为rkmpp的定义

  1.  
    GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
  2.  
    GST_VERSION_MINOR,
  3.  
    rkmpp,
  4.  
    "Rockchip Mpp Video Plugin",
  5.  
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

这个功能相当于面向对象语言的模板功能,由于C语言不支持模板功能,需要使用宏定义,来模拟模板功能,下面我们一起展开一下;

  1.  
     
  2.  
    #ifdef __cplusplus
  3.  
    #define G_BEGIN_DECLS extern "C" {
  4.  
    #define G_END_DECLS }
  5.  
    #else
  6.  
    #define G_BEGIN_DECLS
  7.  
    #define G_END_DECLS
  8.  
    #endif
  9.  
     
  10.  
    #if (0 || defined(_MSC_VER)) && !defined(GST_STATIC_COMPILATION)
  11.  
    # define GST_PLUGIN_EXPORT __declspec(dllexport)
  12.  
    # ifdef GST_EXPORTS
  13.  
    # define GST_EXPORT __declspec(dllexport)
  14.  
    # else
  15.  
    # define GST_EXPORT __declspec(dllimport) extern
  16.  
    # endif
  17.  
    #else
  18.  
    # if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
  19.  
    # define GST_PLUGIN_EXPORT __attribute__ ((visibility ("default")))
  20.  
    # define GST_EXPORT extern __attribute__ ((visibility ("default")))
  21.  
    # else
  22.  
    # define GST_PLUGIN_EXPORT
  23.  
    # define GST_EXPORT extern
  24.  
    # endif
  25.  
    #endif
  26.  
    #define G_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2
  27.  
    #define G_PASTE(identifier1,identifier2) G_PASTE_ARGS (identifier1, identifier2)
  28.  
     
  29.  
     
  30.  
    #define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
  31.  
    G_BEGIN_DECLS \
  32.  
    GST_PLUGIN_EXPORT const GstPluginDesc * G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void); \
  33.  
    GST_PLUGIN_EXPORT void G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void); \
  34.  
    \
  35.  
    static const GstPluginDesc gst_plugin_desc = { \
  36.  
    major, \
  37.  
    minor, \
  38.  
    G_STRINGIFY(name), \
  39.  
    (gchar *) description, \
  40.  
    init, \
  41.  
    version, \
  42.  
    license, \
  43.  
    PACKAGE, \
  44.  
    package, \
  45.  
    origin, \
  46.  
    __GST_PACKAGE_RELEASE_DATETIME, \
  47.  
    GST_PADDING_INIT \
  48.  
    }; \
  49.  
    \
  50.  
    const GstPluginDesc * \
  51.  
    G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void) \
  52.  
    { \
  53.  
    return &gst_plugin_desc; \
  54.  
    } \
  55.  
    \
  56.  
    void \
  57.  
    G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void) \
  58.  
    { \
  59.  
    gst_plugin_register_static (major, minor, G_STRINGIFY(name), \
  60.  
    description, init, version, license, \
  61.  
    PACKAGE, package, origin); \
  62.  
    } \
  63.  
    G_END_DECLS
学新通

这个宏定义主要生成gst_plugin_desc结构和gst_plugin_rkmpp_get_desc,gst_plugin_rkmpp_register,来的分析,把部分宏找出来直接用gcc命令生产:

gcc  -E -P gst-define.c > gst-define_m.c

 大致代码如下

  1.  
    __attribute__ ((visibility ("default"))) const GstPluginDesc * gst_plugin_rkmpp_get_desc (void);
  2.  
    __attribute__ ((visibility ("default"))) void gst_plugin_rkmpp_register (void);
  3.  
    static const GstPluginDesc gst_plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, G_STRINGIFY(rkmpp), (gchar *) "Rockchip Mpp Video Plugin", plugin_init, VERSION, GST_LICENSE, PACKAGE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN, __GST_PACKAGE_RELEASE_DATETIME, GST_PADDING_INIT };
  4.  
    const GstPluginDesc * gst_plugin_rkmpp_get_desc (void)
  5.  
    { return &gst_plugin_desc; }
  6.  
    void gst_plugin_rkmpp_register (void)
  7.  
    { gst_plugin_register_static (GST_VERSION_MAJOR, GST_VERSION_MINOR, G_STRINGIFY(rkmpp), "Rockchip Mpp Video Plugin",
  8.  
    plugin_init, VERSION, GST_LICENSE, PACKAGE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
  9.  
    }

插件初始化

前奏

  1.  
    void
  2.  
    gst_init (int *argc, char **argv[])
  3.  
    {
  4.  
    GError *err = NULL;
  5.  
     
  6.  
    if (!gst_init_check (argc, argv, &err)) {
  7.  
    g_print ("Could not initialize GStreamer: %s\n",
  8.  
    err ? err->message : "unknown error occurred");
  9.  
    if (err) {
  10.  
    g_error_free (err);
  11.  
    }
  12.  
    exit (1);
  13.  
    }
  14.  
    }

它的主要功能,

  • 初始化GStreamer库
  • 注册内部element
  • 加载插件列表,扫描列表中及相应路径下的插件
  • 解析并执行命令行参数

我们下面简单跟踪它的代码,重点看看怎么一步步加载插件的

gst_init  主要调用gst_init_check,这个函数如下所示

  1.  
    gboolean
  2.  
    gst_init_check (int *argc, char **argv[], GError ** err)
  3.  
    {
  4.  
    static GMutex init_lock;
  5.  
    #ifndef GST_DISABLE_OPTION_PARSING
  6.  
    GOptionGroup *group;
  7.  
    GOptionContext *ctx;
  8.  
    #endif
  9.  
    gboolean res;
  10.  
     
  11.  
    g_mutex_lock (&init_lock);
  12.  
     
  13.  
    if (gst_initialized) {
  14.  
    GST_DEBUG ("already initialized gst");
  15.  
    g_mutex_unlock (&init_lock);
  16.  
    return TRUE;
  17.  
    }
  18.  
    #ifndef GST_DISABLE_OPTION_PARSING
  19.  
    ctx = g_option_context_new ("- GStreamer initialization");
  20.  
    g_option_context_set_ignore_unknown_options (ctx, TRUE);
  21.  
    g_option_context_set_help_enabled (ctx, FALSE);
  22.  
    group = gst_init_get_option_group ();
  23.  
    g_option_context_add_group (ctx, group);
  24.  
    res = g_option_context_parse (ctx, argc, argv, err);
  25.  
    g_option_context_free (ctx);
  26.  
    #else
  27.  
    init_pre (NULL, NULL, NULL, NULL);
  28.  
    init_post (NULL, NULL, NULL, NULL);
  29.  
    res = TRUE;
  30.  
    #endif
  31.  
     
  32.  
    gst_initialized = res;
  33.  
     
  34.  
    g_mutex_unlock (&init_lock);
  35.  
     
  36.  
    return res;
  37.  
    }
学新通

这个函数主要是先看看有没有初始化,没有的话,进行初始化。在初始化的时候也可以使用GOption来指定参数,之前已经提过,GOption数组来定义你的命令行选项将表与由gst_init_get_option_group函数返回的选项组一同传给GLib初始化函数。通过使用GOption表来初始化GSreamer,你的程序还可以解析除标准GStreamer选项以外的命令行选项。

这里重点是

  1.  
    group->pre_parse_func = pre_parse_func; init_pre
  2.  
    group->post_parse_func = post_parse_func; ///init_post

主要的工作是在init_post中完成,这里不准备详细介绍,着重说几点:

  • 插件的加载并不是普通的动态库加载那样,而是形成一个plugin registry,这个registry主要记载插件的详细信息,在使用的时候方便调用
  • 插件的加载使用父子进程方式,父进程收集和记录信息,子进程执行加载过程

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhiafgkg
系列文章
更多 icon
同类精品
更多 icon
继续加载