草庐IT

GStreamer插件实列rockchipmpp

专注&突破 2023-05-05 原文

尽管这些年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源码中编译即可。

如下为它的源码

├── gstmppallocator.c
├── gstmppallocator.h
├── gstmppalphadecodebin.c
├── gstmppalphadecodebin.h
├── gstmpp.c
├── gstmppdec.c
├── gstmppdec.h
├── gstmppenc.c
├── gstmppenc.h
├── gstmpp.h
├── gstmpph264enc.c
├── gstmpph264enc.h
├── gstmpph265enc.c
├── gstmpph265enc.h
├── gstmppjpegdec.c
├── gstmppjpegdec.h
├── gstmppjpegenc.c
├── gstmppjpegenc.h
├── gstmppvideodec.c
├── gstmppvideodec.h
├── gstmppvp8enc.c
├── gstmppvp8enc.h
├── gstmppvpxalphadecodebin.c
├── gstmppvpxalphadecodebin.h

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

gstreamer rkmpp 插件定义

如下为rkmpp的定义

GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    rkmpp,
    "Rockchip Mpp Video Plugin",
    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

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


#ifdef  __cplusplus
#define G_BEGIN_DECLS  extern "C" {
#define G_END_DECLS    }
#else
#define G_BEGIN_DECLS
#define G_END_DECLS
#endif

#if (0 || defined(_MSC_VER)) && !defined(GST_STATIC_COMPILATION)
# define GST_PLUGIN_EXPORT __declspec(dllexport)
# ifdef GST_EXPORTS
#  define GST_EXPORT __declspec(dllexport)
# else
#  define GST_EXPORT __declspec(dllimport) extern
# endif
#else
# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
#  define GST_PLUGIN_EXPORT __attribute__ ((visibility ("default")))
#  define GST_EXPORT extern __attribute__ ((visibility ("default")))
# else
#  define GST_PLUGIN_EXPORT
#  define GST_EXPORT extern
# endif
#endif
#define G_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2
#define G_PASTE(identifier1,identifier2)      G_PASTE_ARGS (identifier1, identifier2)


#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
G_BEGIN_DECLS \
GST_PLUGIN_EXPORT const GstPluginDesc * G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void); \
GST_PLUGIN_EXPORT void G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void); \
\
static const GstPluginDesc gst_plugin_desc = { \
  major, \
  minor, \
  G_STRINGIFY(name), \
  (gchar *) description, \
  init, \
  version, \
  license, \
  PACKAGE, \
  package, \
  origin, \
  __GST_PACKAGE_RELEASE_DATETIME, \
  GST_PADDING_INIT \
};                                       \
\
const GstPluginDesc * \
G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void) \
{ \
    return &gst_plugin_desc; \
} \
\
void \
G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void) \
{ \
  gst_plugin_register_static (major, minor, G_STRINGIFY(name), \
      description, init, version, license, \
      PACKAGE, package, origin); \
} \
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

 大致代码如下

 __attribute__ ((visibility ("default"))) const GstPluginDesc * gst_plugin_rkmpp_get_desc (void);
 __attribute__ ((visibility ("default"))) void gst_plugin_rkmpp_register (void); 
 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 };
 const GstPluginDesc * gst_plugin_rkmpp_get_desc (void) 
 	{ return &gst_plugin_desc; } 
 void gst_plugin_rkmpp_register (void) 
 	{ gst_plugin_register_static (GST_VERSION_MAJOR, GST_VERSION_MINOR, G_STRINGIFY(rkmpp), "Rockchip Mpp Video Plugin", 
 	plugin_init, VERSION, GST_LICENSE, PACKAGE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
 }

插件初始化

我们在编写一个GStreamer应用_专注&突破的博客-CSDN博客开始的时候说过编写gstreamer应用首先使用gst_init 初始化

前奏

void
gst_init (int *argc, char **argv[])
{
  GError *err = NULL;

  if (!gst_init_check (argc, argv, &err)) {
    g_print ("Could not initialize GStreamer: %s\n",
        err ? err->message : "unknown error occurred");
    if (err) {
      g_error_free (err);
    }
    exit (1);
  }
}

它的主要功能,

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

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

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

gboolean
gst_init_check (int *argc, char **argv[], GError ** err)
{
  static GMutex init_lock;
#ifndef GST_DISABLE_OPTION_PARSING
  GOptionGroup *group;
  GOptionContext *ctx;
#endif
  gboolean res;

  g_mutex_lock (&init_lock);

  if (gst_initialized) {
    GST_DEBUG ("already initialized gst");
    g_mutex_unlock (&init_lock);
    return TRUE;
  }
#ifndef GST_DISABLE_OPTION_PARSING
  ctx = g_option_context_new ("- GStreamer initialization");
  g_option_context_set_ignore_unknown_options (ctx, TRUE);
  g_option_context_set_help_enabled (ctx, FALSE);
  group = gst_init_get_option_group ();
  g_option_context_add_group (ctx, group);
  res = g_option_context_parse (ctx, argc, argv, err);
  g_option_context_free (ctx);
#else
  init_pre (NULL, NULL, NULL, NULL);
  init_post (NULL, NULL, NULL, NULL);
  res = TRUE;
#endif

  gst_initialized = res;

  g_mutex_unlock (&init_lock);

  return res;
}

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

这里重点是

  group->pre_parse_func = pre_parse_func; init_pre
  group->post_parse_func = post_parse_func; ///init_post

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

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

有关GStreamer插件实列rockchipmpp的更多相关文章

  1. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  2. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  3. ruby-on-rails - 您希望看到哪些 Rails 插件? - 2

    您认为可以作为插件很好地存在于您的Rails应用程序中必须实现的哪些行为?您过去曾搜索过哪些插件功能但找不到?哪些现有的Rails插件可以改进或扩展,如何改进或扩展? 最佳答案 我希望在管理界面中看到一个引擎插件,它提供了应用程序中所有模型的仪表板摘要,以及可配置的事件图表。 关于ruby-on-rails-您希望看到哪些Rails插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questio

  4. ruby - vagrant 从 github 安装插件 - 2

    我们正在使用Vagrant进行部署,我们最终希望将此集群部署在Rackspace上。vagrant-rackspace插件是一个自然的选择,但它有一些错误,这些错误未包含在最新的0.1.1版本中(notablythatvagrantprovisiondoesn'twork)。我已经在我的personalfork中解决了这个问题通过合并其他人的工作来对存储库进行改造。是否可以从github安装vagrant插件?显而易见的事情没有奏效:[unix]$vagrantplugininstallvagrant-rackspace--plugin-sourcehttps://github.com

  5. IDEA使用LeetCode插件 - 2

    前言我们习惯用idea编写、调试代码,在LeetCode上刷题时,如果能够在IDEA编写代码,并且做好代码管理,是一件事半功倍的事情。对于后续复习题目,做笔记也会非常便利。本文目的在于介绍LeetCodeEditor的使用,以及配置工具类,最终目录结构如下:note:放置笔记src:放置代码leetcode.editor.cn:插件LeetCodeEditor自动生成utils:自定义的工具包,可用于自动化输入测试用例,定义题目需要的类(结构体)out:运行测试时自动生成LeetCodeEditorGitHub:https://github.com/shuzijun/leetcode-edit

  6. regex - Ruby 是否有类似于 Perl 6 语法的插件? - 2

    多年来,Perl一直是我首选的编程语言工具之一。Perl6语法看起来像是一个很棒的语言特性。我想知道是否有人开始为Ruby做这样的事情。 最佳答案 如果您想在Ruby中使用实际的Perl6语法,最好的选择是Cardinal,Parrot上的ruby​​编译器。它目前尚未完成并且非常缓慢,但我非常希望它最终成为一个可行的ruby​​实现。它目前大部分处于非事件状态,等待Parrot中的一些基础架构更改以支持改进的解析速度和其他功能。 关于regex-Ruby是否有类似于Perl6语法的插件

  7. ruby-on-rails - 你为 Rails 推荐哪个状态机插件? - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭9年前。Improvethisquestion我正在为Rails3/ActiveRecord项目寻找一个相对简单的状态机插件。我做了一些研究并提出了以下插件:转换:https://github.com/qoobaa/transitions从旧的ActiveRecord状态机库中提取

  8. ruby-on-rails - 使用模块扩展带有 "has_many"的插件中的模型 - 2

    我在引擎样式插件中有一些代码,其中包含一些模型。在我的应用程序中,我想扩展其中一个模型。通过在初始值设定项中包含一个模块,我已经设法将实例和类方法添加到相关模型中。但是我似乎无法添加关联、回调等。我收到“找不到方法”错误。/libs/qwerty/core.rbmoduleQwertymoduleCoremoduleExtensionsmoduleUser#InstanceMethodsGoHere#ClassMethodsmoduleClassMethodshas_many:hits,:uniq=>true#nomethodfoundbefore_validation_on_crea

  9. ruby - 用于 CSS3 跨浏览器兼容性的 SASS 插件? - 2

    是否有一个SASS扩展可以采用SASS样式表,找到中性属性(例如border-radius)并为其输出所有特定于供应商的属性(例如-webkit-border-radius等)自动?我真的不想手动创建所有混入,也不想手动编写代码。我确定一定有这样的扩展名,但我找不到它。帮忙? 最佳答案 有一个非常好的gem可以满足您的需求。它叫做Bourbon它不会用特定于供应商的css替换您的css,因为它可以像SASS一样工作。它基本上是一个正确生成跨浏览器css的mixin集合。 关于ruby-用

  10. ruby - vim 使用 AutoComplPop 插件崩溃 - 2

    我使用vim编辑ruby​​文件,但是当我输入“.”时它崩溃了。我发现它是由AutoComplPop插件引起的。我该怎么办? 最佳答案 我找到了一种使用autocomplpop和filetype=ruby来防止vim崩溃的方法。将以下行放入您的.vimrcletg:acp_behaviorRubyOmniMethodLength=-1这将防止在您键入“.”时触发autocomplpop。(期间)这不是解决办法。(我不是vim插件程序员)祝你好运! 关于ruby-vim使用AutoComp

随机推荐