流媒体

Gstreamer使用说明

2021-09-18  本文已影响0人  Mr_Michael

一、简介

Application Development Manual

Gstreamer是一个支持Windows,Linux,Android, iOS的跨平台的多媒体框架,应用程序可以通过管道(Pipeline)的方式,将多媒体处理的各个步骤串联起来,达到预期的效果。每个步骤通过元素(Element)基于GObject对象系统通过插件(plugins)的方式实现,方便了各项功能的扩展。

GStreamer 的核心功能是为插件、数据流和媒体类型处理/协商提供框架。它还提供了一个 API 来使用各种插件编写应用程序。

GStreamer 提供

1.Gstreamer框架

1.png

Gstreamer框架根据各个模块的成熟度以及所使用的开源协议,将core及plugins置于不同的源码包中:

2.Gstreamer基础概念

1)Element

Element是Gstreamer中最重要的对象类型之一。一个element实现一个功能(读取文件,解码,输出等),程序需要创建多个element,并按顺序将其串连起来(使用管道 !),构成一个完整的pipeline。

官方Elements与Plugins Lists

# Print all elements
gst-inspect-1.0 -a

# List the plugin contents
gst-inspect-1.0 --plugin

# 查看某个element
gst-inspect-1.0 videotestsrc

element主要有三种:

Visualisation of a source element Visualisation of a sink element 过滤器元件的可视化 具有多个输出垫的过滤器元件的可视化

2)Pad

pads 是元素与外界的接口,有两个属性定义:方向和可用性。两个element必须通过pad才能连接起来,在element通过pad连接成功后,数据会从上一个element的src pad传到下一个element的sink pad然后进行处理。一个element可以同时拥有多个相同的pad。

3)Bin和Pipeline

bin 是一个容器元素,用于管理多个element。由于 bin 本身就是一个元素,因此可以以与任何其他元素相同的方式处理 bin。改变bin的状态时,bin会自动去修改所包含的element的状态,也会转发所收到的消息。如果没有bin,我们需要依次操作我们所使用的element。通过bin降低了应用的复杂度。

包含一些元素的 bin 的可视化

Pipeline继承自bin,为程序提供一个bus用于传输消息,并且对所有子element进行同步。当将pipeline的状态设置为PLAYING时,pipeline会在一个/多个新的线程中通过element处理数据。

示例:通过下面的命令播放文件时,会创建如下pipeline:

gst-launch-1.0 filesrc location=sintel_trailer-480p.ogv ! oggdemux name=demux ! queue ! vorbisdec ! autoaudiosink demux. ! queue ! theoradec ! videoconvert ! autovideosink
2.png

这个pipeline由8个element构成,每个element都实现各自的功能:

filesrc读取文件,oggdemux解析文件,分别提取audio,video数据,queue缓存数据,vorbisdec解码audio,autoaudiosink自动选择音频设备并输出;theoradec解码video,videoconvert转换video数据格式,autovideosink自动选择显示设备并输出。

3.Gstreamer通信机制

3.png

二、安装Gstreamer

参考Installing on Linux

# Install GStreamer on Ubuntu or Debian
sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio

三、Gstreamer命令行使用

# 从usb video抓一次图
gst-launch-1.0 v4l2src device=/dev/video0 num-buffers=1 ! "image/jpeg,width=1920,height=1080" ! filesink location=capture.jpg

# 从usb video定期抓图
gst-launch-1.0 --gst-debug-level=3 v4l2src device=/dev/video0 ! \
        "image/jpeg,width=1920,height=1080,framerate=30/1" ! \
        multifilesink location=/data/tmpfs/capture1.jpg max-files=1 post-messages=true
        
# 从usb video定期抓图并进行rtmp推流
gst-launch-1.0 -v v4l2src device=/dev/video0 ! 'video/x-h264, width=1920, height=1080, framerate=20/1' ! queue !  h264parse ! flvmux ! rtmpsink location='rtmp://10.53.3.61:1935/live/camera0'

gst-launch-1.0 -v v4l2src device=/dev/video0 ! 'video/x-raw, width=1024, height=768, framerate=30/1' ! queue  ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://10.53.3.61:1935/live/camera0'
    # omxh264enc是第三方的h264enc插件,如果omxh264enc不支持video/x-raw,videoconvert自动将视频转换为视频接收器可以理解的格式

# 从RTSP流中定期抓图,分别进行图片保存、推流和视频保存
gst-launch-1.0 -e --gst-debug-level=3 rtspsrc location=rtsp://192.168.1.19:554/mpeg4 ! rtph264depay ! h264parse ! tee name=t \
    t. ! queue ! avdec_h264 ! queue flush-on-eos=true ! videorate ! "video/x-raw,framerate=5/1" ! jpegenc ! multifilesink post-messages=true location=/data/tmpfs/camera/capture.jpg max-files=1 \  # capture
    t. ! queue ! flvmux streamable=true ! rtmpsink sync=false location=rtmp://172.17.0.1/live/camera0 \ # stream
    t. ! queue ! splitmuxsink max-size-time=600000000000 location=/data/tmpfs/camera/video/%06d.mp4 # video

四、Gstreamer API与程序开发

API reference

示例应用helloworld.c

The "hello world" pipeline
#include <gst/gst.h>
#include <glib.h>

static gboolean bus_call (GstBus     *bus, GstMessage *msg, gpointer    data)
{
  GMainLoop *loop = (GMainLoop *) data;

  switch (GST_MESSAGE_TYPE (msg)) {

    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;

    case GST_MESSAGE_ERROR: {
      gchar  *debug;
      GError *error;

      gst_message_parse_error (msg, &error, &debug);
      g_free (debug);

      g_printerr ("Error: %s\n", error->message);
      g_error_free (error);

      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }

  return TRUE;
}

static void on_pad_added (GstElement *element, GstPad     *pad, gpointer    data)
{
  GstPad *sinkpad;
  GstElement *decoder = (GstElement *) data;

  /* We can now link this pad with the vorbis-decoder sink pad */
  g_print ("Dynamic pad created, linking demuxer/decoder\n");

  sinkpad = gst_element_get_static_pad (decoder, "sink");
  gst_pad_link (pad, sinkpad);
  gst_object_unref (sinkpad);
}

int main (int   argc, char *argv[])
{
  GMainLoop *loop;

  GstElement *pipeline, *source, *demuxer, *decoder, *conv, *sink;
  GstBus *bus;
  guint bus_watch_id;

  /*init GStreamer */
  gst_init (&argc, &argv);

  loop = g_main_loop_new (NULL, FALSE);

  /* Check input arguments */
  if (argc != 2) {
    g_printerr ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]);
    return -1;
  }

  /* Create gstreamer elements */
  pipeline = gst_pipeline_new ("audio-player");
  source   = gst_element_factory_make ("filesrc",       "file-source");
  demuxer  = gst_element_factory_make ("oggdemux",      "ogg-demuxer");
  decoder  = gst_element_factory_make ("vorbisdec",     "vorbis-decoder");
  conv     = gst_element_factory_make ("audioconvert",  "converter");
  sink     = gst_element_factory_make ("autoaudiosink", "audio-output");

  if (!pipeline || !source || !demuxer || !decoder || !conv || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  /* Set up the pipeline */

  /* we set the input filename to the source element */
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);

  /* we add a message handler */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  /* we add all elements into the pipeline */
  /* file-source | ogg-demuxer | vorbis-decoder | converter | alsa-output */
  gst_bin_add_many (GST_BIN (pipeline),
                    source, demuxer, decoder, conv, sink, NULL);

  /* we link the elements together */
  /* file-source -> ogg-demuxer ~> vorbis-decoder -> converter -> alsa-output */
  gst_element_link (source, demuxer);
  gst_element_link_many (decoder, conv, sink, NULL);
  g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), decoder);

  /* note that the demuxer will be linked to the decoder dynamically.
     The reason is that Ogg may contain various streams (for example
     audio and video). The source pad(s) will be created at run time,
     by the demuxer when it detects the amount and nature of streams.
     Therefore we connect a callback function which will be executed
     when the "pad-added" is emitted.*/

  /* Set the pipeline to "playing" state*/
  g_print ("Now playing: %s\n", argv[1]);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Iterate */
  g_print ("Running...\n");
  g_main_loop_run (loop);

  /* Out of the main loop, clean up nicely */
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);

  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));
  g_source_remove (bus_watch_id);
  g_main_loop_unref (loop);

  return 0;
}

编译应用

# 利用pkg-config获取编译此应用程序所需的编译器和链接器标志
gcc -Wall helloworld.c -o helloworld $(pkg-config --cflags --libs gstreamer-1.0)
上一篇 下一篇

猜你喜欢

热点阅读