Gstreamer基础教程8: 缩短管道

1. Goal

用GStreamer构造的pipeline不需要完全关闭。 可以通过各种方式随时将数据注入pipeline并从中提取数据。 本教程显示:

  • 如何将外部数据注入一般的GStreamer pipeline
  • 如何从通用GStreamer pipeline中提取数据
  • 如何访问和处理此数据

2. Introductin

应用程序可以几种方式与流经GStreamer pipeline的数据进行交互。 本教程描述了最简单的教程,因为它使用了仅为此目的而创建的元素。
用于将应用程序数据注入GStreamer pipeline的元素是appsrc,用于将GStreamer数据提取回应用程序的元素是appsink。 为了避免混淆名称,请从GStreamer的角度考虑:appsrc只是一个常规source,它提供从天而降的数据(实际上是由应用程序提供)。 appsink是一个常规sink,流经GStreamer pipeline的数据将消失(实际上是由应用程序恢复的)。
appsrc和appsink用途广泛,它们提供了自己的API(请参阅其文档appsrc, appsink),可以通过与gstreamer-app库链接来访问它们。 但是,在本教程中,我们将使用更简单的方法并通过信号对其进行控制。
appsrc可以在多种模式下工作:在PULL模式下,它每次需要时都从应用程序请求数据。 在PUSH模式下,应用程序以自己的速度推送数据。 此外,在PUSH模式下,当已经提供了足够的数据时,应用程序可以选择在推送功能中被阻止,或者可以侦听足够数据和需求数据信号以控制流量。 本示例实现了后一种方法。 有关其他方法的信息可以在appsrc文档中找到。

2.1 Buffer

数据以称为缓冲区的块形式通过GStreamer pipeline传输。 由于此示例产生并使用数据,因此我们需要了解GstBuffers
Source Pad产生缓冲区,该缓冲区由Sink Pad消耗; GStreamer获取这些缓冲区,并将它们从一个元素传递到另一个元素。
缓冲区只是代表一个数据单元,不要假设所有缓冲区都具有相同的大小或代表相同的时间量。 您也不应该假设如果单个缓冲区输入一个元素,那么就会出现单个缓冲区。 元素可以随意处理接收到的缓冲区。 GstBuffers也可能包含多个实际内存缓冲区。 实际的内存缓冲区是使用GstMemory对象提取的,一个GstBuffer可以包含多个GstMemory对象。
每个缓冲区都有附加的时间戳和持续时间,这些时间戳和持续时间描述应在何时解码,呈现或显示缓冲区的内容。 时间戳记是一个非常复杂而微妙的主题,但是目前这种简化的视图已经足够了。
例如,filesrc(读取文件的GStreamer元素)将生成带有ANY caps且没有时间戳信息的缓冲区。 在解复用之后(请参见基本教程3:动态管道),缓冲区可以具有一些特定的caps,例如"video / x-h264"。 解码后,每个缓冲区将包含带有原始caps的单个视频帧(例如,“video / x-raw-yuv”)和非常精确的时间戳,指示何时应显示该帧。

2.2 This tutorial

本教程以两种方式扩展了基础教程7。首先,用将生成音频数据的appsrc代替audiotestsrc。 其次,将一个新的分支添加到tee区域,以便数据进入音频接收器,并且波形显示也复制到appsink。 appsink将信息上传回应用程序,然后通知用户已接收到数据,但显然可以执行更复杂的任务。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PEKMjqjk-1623031571717)(:/f6e2ff7461364af7a8d9b48c4f4c45e1)]

3. Implement

3.1 Compile

gcc basic-tutorial-8.c -o basic-tutorial-8 `pkg-config --cflags --libs gstreamer-1.0 gstreamer-audio-1.0`

3.2 Code

// a crude waveform generator
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include <string.h>

#define CHUNK_SIZE 1024   /* Amount of bytes we are sending in each buffer */
#define SAMPLE_RATE 44100 /* Samples per second we are sending */

/* Structure to contain all our information, so we can pass it to callbacks */
typedef struct _CustomData {
   
  GstElement *pipeline, *app_source, *tee, *audio_queue, *audio_convert1, *audio_resample, *audio_sink;
  GstElement *video_queue, *audio_convert2, *visual, *video_convert, *video_sink;
  GstElement *app_queue, *app_sink;

  guint64 num_samples;   /* Number of samples generated so far (for timestamp generation) */
  gfloat a, b, c, d;     /* For waveform generation */

  guint sourceid;        /* To control the GSource */

  GMainLoop *main_loop;  /* GLib's Main Loop */
} CustomData;

/* This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc.
 * The idle handler is added to the mainloop when appsrc requests us to start sending data (need-data signal)
 * and is removed when appsrc has enough data (enough-data signal).
 */
static gboolean push_data (CustomData *data) {
   
  GstBuffer *buffer;
  GstFlowReturn ret;
  int i;
  GstMapInfo map;
  gint16 *raw;
  gint num_samples = CHUNK_SIZE / 2; /* Because each sample is 16 bits */
  gfloat freq;

  /* Create a new empty buffer */
  buffer = gst_buffer_new_and_alloc (CHUNK_SIZE);

  /* Set its timestamp and duration */
  GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (data->num_samples, GST_SECOND, SAMPLE_RATE);
  GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (num_samples, GST_SECOND, SAMPLE_RATE);

  /* Generate some psychodelic waveforms */
  gst_buffer_map (buffer, &map, GST_MAP_WRITE);
  raw = (gint16 *)map.data;
  data->c += data->d;
  data->d -= data->c / 1000;
  freq = 1100 + 1000 * data->d;
  for (i = 0; i < num_samples; i++) {
   
    data->a += data->b;
    data->b -= data->a / freq;
    raw[i] = (gint16)(500 * data->a);
  }
  gst_buffer_unmap (buffer, &map);
  data->num_samples += num_samples;

  /* Push the buffer into the appsrc */
  g_signal_emit_by_name (data->app_source, "push-buffer", buffer, &ret);

  /* Free the buffer now that we are done with it */
  gst_buffer_unref (buffer);

  if (ret != GST_FLOW_OK) {
   
    /* We got some error, stop sending data */
    return FALSE;
  }

  return TRUE;
}

/* This signal callback triggers when appsrc needs data. Here, we add an idle handler
 * to the mainloop to start pushing data into the appsrc */
static void start_feed (GstElement *source, guint size, CustomData *data) {
   
  if (data->sourceid == 0) {
   
    g_print ("Start feeding\n");
    data->sourceid = g_idle_add ((GSourceFunc) push_data, data);
  }
}

/* This callback triggers when appsrc has enough data and we can stop sending.
 * We remove the idle handler from the mainloop */
static void stop_feed 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值