Multimedia/GStreamer

GStreamer pwg: ch 12

Roien 2021. 12. 22.
반응형

 

12.     Reqeust and Sometimes pads

 

Ÿ   sometimes pads

    n  어떤 경우에 생성되는 pads

Ÿ   request pads

    n  application에서 요청 시 생성되는 pads

 

Ÿ   availability

    n  pad availability pad's template에 보임

 

 

12.1.     sometimes pads

 

특정 조건 하에서만 생성되는 pads

Ÿ   보통 stream content에 의존하여 생성됨

    n  demuxer가 stream header를 parsing 후 elementary stream(audio, video, 자막 등)이 뭔지 파악

    n  각 elementary stream 처리를 위한 (하나 이상의) pad를 생성

Ÿ   제약

    n  pad unique name을 지녀야 함

Ÿ   dispose 시점

    n  stream data dispose될 때 함께 dispose 

        s   i.e., from PAUSED to the READY state

        s   EOS 시점에서는 dispose 해서는 안 됨 (seek으로 re-activate 할 수 있음)

 

 

text file parsing하는 example code 

3 numbers
0: foo source pad number
1: bar  
0: boo  
2: bye  

 

typedef struct _GstMyFilter {
[..]
  gboolean firstrun;
  GList *srcpadlist;
} GstMyFilter;
 
static GstStaticPadTemplate src_factory =
GST_STATIC_PAD_TEMPLATE (
  "src_%u",
  GST_PAD_SRC,
  GST_PAD_SOMETIMES,
  GST_STATIC_CAPS ("ANY")
);
 
static void
gst_my_filter_class_init (GstMyFilterClass *klass) {
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
  gst_element_class_add_pad_template (element_class,
    gst_static_pad_template_get (&src_factory));
[..]
}
 
static void
gst_my_filter_init (GstMyFilter *filter) {
[..]
  filter->firstrun = TRUE;
  filter->srcpadlist = NULL;
}
 
/*
 * Get one line of data - without newline.
 */
static GstBuffer *
gst_my_filter_getline (GstMyFilter *filter) {
  guint8 *data;
  gint n, num;
 
  /* max. line length is 512 characters - for safety */
  for (n = 0; n < 512; n++) {
    num = gst_bytestream_peek_bytes (filter->bs, &data, n + 1);
    if (num != n + 1)
      return NULL;
 
    /* newline? */
    if (data[n] == '\n') {
      GstBuffer *buf = gst_buffer_new_allocate (NULL, n + 1, NULL);
 
      gst_bytestream_peek_bytes (filter->bs, &data, n);
      gst_buffer_fill (buf, 0, data, n);
      gst_buffer_memset (buf, n, '\0', 1);
      gst_bytestream_flush_fast (filter->bs, n + 1);
 
      return buf;
    }
  }
}
 
static void
gst_my_filter_loopfunc (GstElement *element) {
  GstMyFilter *filter = GST_MY_FILTER (element);
  GstBuffer *buf;
  GstPad *pad;
  GstMapInfo map;
  gint num, n;
 
  /* parse header */
  if (filter->firstrun) {
    gchar *padname;
    guint8 id;
 
    if (!(buf = gst_my_filter_getline (filter))) {
      gst_element_error (element, STREAM, READ, (NULL),
             ("Stream contains no header"));
      return;
    }
    gst_buffer_extract (buf, 0, &id, 1);
    num = atoi (id);
    gst_buffer_unref (buf);
 
    /* for each of the streams, create a pad */
    for (n = 0; n < num; n++) {
      padname = g_strdup_printf ("src_%u", n);
      pad = gst_pad_new_from_static_template (src_factory, padname);
      g_free (padname);
 
      /* here, you would set _event () and _query () functions */
 
      /* need to activate the pad before adding */
      gst_pad_set_active (pad, TRUE);
 
      gst_element_add_pad (element, pad);
      filter->srcpadlist = g_list_append (filter->srcpadlist, pad);
    }
  }
 
  /* and now, simply parse each line and push over */
  if (!(buf = gst_my_filter_getline (filter))) {
    GstEvent *event = gst_event_new (GST_EVENT_EOS);
    GList *padlist;
 
    for (padlist = srcpadlist;
         padlist != NULL; padlist = g_list_next (padlist)) {
      pad = GST_PAD (padlist->data);
      gst_pad_push_event (pad, gst_event_ref (event));
    }
    gst_event_unref (event);
    /* pause the task here */
    return;
  }
 
  /* parse stream number and go beyond the ':' in the data */
  gst_buffer_map (buf, &map, GST_MAP_READ);
  num = atoi (map.data[0]);
  if (num >= 0 && num < g_list_length (filter->srcpadlist)) {
    pad = GST_PAD (g_list_nth_data (filter->srcpadlist, num);
 
    /* magic buffer parsing foo */
    for (n = 0; map.data[n] != ':' &&
                map.data[n] != '\0'; n++) ;
    if (map.data[n] != '\0') {
      GstBuffer *sub;
 
      /* create region copy that starts right past the space. The reason
       * that we don't just forward the data pointer is because the
       * pointer is no longer the start of an allocated block of memory,
       * but just a pointer to a position somewhere in the middle of it.
       * That cannot be freed upon disposal, so we'd either crash or have
       * a memleak. Creating a region copy is a simple way to solve that. */
      sub = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
          n + 1, map.size - n - 1);
      gst_pad_push (pad, sub);
    }
  }

  gst_buffer_unmap (buf, &map);
  gst_buffer_unref (buf);
}

 

Ÿ   file이 깨져있던가, 혹은 악의적인 file content에 대해 valid 여부를 check

    n  i.e., buffer overflow

 

 

12.2.     Request pads

sometimes pads와 유사함

차이는 request On-demand 시점에서 생성됨

 

muxer에서 보통 사용됨

output system stream 내에 위치하는 각각의 elementary stream에 대해

하나의 sink pad가 요청될 수 있음

 

Ÿ   가변 input/output pads를 지닌 element에서 사용될 수 있음

    n  i.e. tee, input-selector(multi-input) elements

 

pad template GST_PAD_REQUEST로 제공해서 구현할 수 있음

GstElement request_new_pad virtual method를 구현해야함

 

Ÿ   request_new_pad

Ÿ   release_pad

    n  clean up에 사용

 

static GstPad * gst_my_filter_request_new_pad (GstElement     *element,
                         GstPadTemplate *templ,
                                                 const gchar    *name,
                                                 const GstCaps  *caps);
 
static void gst_my_filter_release_pad (GstElement *element,
                                       GstPad *pad);
 
static GstStaticPadTemplate sink_factory =
GST_STATIC_PAD_TEMPLATE (
  "sink_%u",
  GST_PAD_SINK,
  GST_PAD_REQUEST,
  GST_STATIC_CAPS ("ANY")
);
 
static void
gst_my_filter_class_init (GstMyFilterClass *klass) {
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
[..]
  gst_element_class_add_pad_template (klass,
    gst_static_pad_template_get (&sink_factory));
[..]
  element_class->request_new_pad = gst_my_filter_request_new_pad;
  element_class->release_pad = gst_my_filter_release_pad;
}
 
static GstPad *
gst_my_filter_request_new_pad (GstElement     *element,
                   GstPadTemplate *templ,
                   const gchar    *name,
                               const GstCaps  *caps) {
  GstPad *pad;
  GstMyFilterInputContext *context;
 
  context = g_new0 (GstMyFilterInputContext, 1);
  pad = gst_pad_new_from_template (templ, name);
  gst_pad_set_element_private (pad, context);
 
/* normally, you would set _chain () and _event () functions here */
// set _chain or _event for the created pad
 
  gst_element_add_pad (element, pad);
 
  return pad;
}
 
static void
gst_my_filter_release_pad (GstElement *element,
                           GstPad *pad) {
  GstMyFilterInputContext *context;
 
  context = gst_pad_get_element_private (pad);
  g_free (context);
 
  gst_element_remove_pad (element, pad);
}

 

반응형

'Multimedia > GStreamer' 카테고리의 다른 글

GStreamer pwg ch 7 ~ 9  (0) 2021.12.22
GStreamer pwg ch 11  (0) 2021.12.22
GStreamer pwg: ch 13  (0) 2021.12.22
GStreamer pwg: ch. 13 part 1  (0) 2021.12.22
GStreamer pwg: ch 13 part 2  (0) 2021.12.22

댓글