Multimedia/GStreamer

GStreamer pwg: ch. 15

Roien 2021. 12. 22.
반응형

 

15.     Memory allocation

 

Ÿ   GstMemory object

    n  memory 조각의 access를 관리

Ÿ   GstBuffer

    n  plugin data 교환에 사용됨

    n  GstMemory를 사용

Ÿ   GstBufferPool

    n  동일 size memory를 효율적으로 사용하기 위함

 

GST_QUERY_ALLOCATION query

Ÿ   element memory negotiation을 위해 사용되는 query

 

 

15.1.     GstMemory

 

GstMemroy

    Ÿ   maxsize memory 영역을 point

        n  offset으로 area  start 위치를 지정

            s   객체 생성 후 offset은 변경 가능, maxsize는 변경 불가능

        n  size offset 부터 크기를 지정

 

GstAllocator

    Ÿ   GstMemroy를 생성

    Ÿ   대부분의 allocator gst_allocator_alloc를 구현

    Ÿ   다른 method를 구현해야 하는 allocator

        n  추가적인 parameter가 필요한 경우

 

    Ÿ   여러 다른 allocator가 존재할 수 있음

        n  system memory, shared memory, DMA buf file descriptor back memory 

        n  새로운 memory type의 지원을 위해서는 새로운 allocator를 구현해야 함

 

 

15.1.1.        GstMemroy API example

GstMemory wrapping  memory에 대한 access

    Ÿ   gst_memory_map gst_memory_unmap으로 보호됨

    Ÿ   access mode (read/write) memory mapping 시 주어짐

    Ÿ   map function

        n  요청된 access mode로 접근 가능한 valid memory region pointer를 리턴

 

gst_memory_map을 사용하셔 memory region access하는 GstMemroy object를 만드는 example

[...]
 
  GstMemory *mem;
  GstMapInfo info;
  gint i;
 
  /* allocate 100 bytes */
  mem = gst_allocator_alloc (NULL, 100, NULL);
 
  /* get access to the memory in write mode */
  gst_memory_map (mem, &info, GST_MAP_WRITE);
 
  /* fill with pattern */
  for (i = 0; i < info.size; i++)
    info.data[i] = i;
 
  /* release memory */
  gst_memory_unmap (mem, &info);
 
[...]

 

 

15.1.2.        Implementing a GstAllocator

 

 

15.2.     GstBuffer

Ÿ   memory metadata를 지님

Ÿ   downstream으로 push/pull로서 전달될 content를 표현

Ÿ   하나 이상의 GstMemory를 포함

 

Metadata 구성

Ÿ   DTS, PTS timestamp

    n  DTS: decoding time stamp

    n  PTS: presentation timestamp

    n  정의되지 않던가, 알려지지 않은 경우 둘 다 GST_CLOCK_TIME_NONE 일 수 있음

Ÿ   duration

    n  역시 모르는 경우, 정의되지 않은 경우에는 GST_CLOCK_TIME_NONE

Ÿ   offset, offset_end

    n  video의 경우 stream  frame number

    n  audio의 경우  sample number

Ÿ   arbitrary structures

    n  via GstMeta

 

 

15.2.1.        GstBuffer writability

 

usage

    Ÿ   buffer 생성과 memory 추가를 별도 수행

        n  gst_buffer_new()

            s   buffer 생성

        n  memory 객체 추가

    Ÿ   buffer 생성과 memory 추가를 한번에 수행

        n  gst_buffer_new_allocate()

            s   buffer의 할당과 memory combine을 동시에 수행

        n  gst_buffer_new_wrapped_full

            s   buffer의 할당과 existing memory wrapping

            s   free 함수를 함께 줄 수 있음

 

memory에 대한 access

    Ÿ   GstMemory 객체를 얻고 mapping하여 access

    Ÿ   혹은 gst_buffer_map을 사용해서 access

        n  모든 memory를 하나의 big block으로 merge

 

[...]
  GstBuffer *buffer;
  GstMemory *mem;
  GstMapInfo info;
 
  /* make empty buffer */
  buffer = gst_buffer_new ();
 
  /* make memory holding 100 bytes */
  mem = gst_allocator_alloc (NULL, 100, NULL);
 
  /* add the buffer */
  gst_buffer_append_memory (buffer, mem);
 
[...]
 
  /* get WRITE access to the memory and fill with 0xff */
  gst_buffer_map (buffer, &info, GST_MAP_WRITE);
  memset (info.data, 0xff, info.size);
  gst_buffer_unmap (buffer, &info);
 
[...]
 
  /* free the buffer */
  gst_buffer_unref (buffer);
 
[...]

 

 

15.3.     GstMeta

 

GstMeta로 임의의(arbitrary) 구조체를 추가할 수 있음

    Ÿ   extra property를 지닌 arbitrary structure를 추가

        n  cropping, stride, region of interest 등의 정보를 지님

 

    Ÿ   metadata system API spec과 구현을 분리

        n  API와 실제로 어떻게 동작하는지를 분리

        n  서로 다른 구현을 사용할 수 있게 함

 

 

15.3.1.        GstMeta API example

 새로운 buffer를 할당한 후, metadata specific API metadata buffer에 추가할 수 있음

metadata가 정의된 header file link해서 해당 API를 사용할 수 있음

 

FooBar라는 이름의 metadata API는 두 개의 method를 제공

    Ÿ   gst_buffer_add_foo_bar_meta()

    Ÿ   gst_buffer_gst_foo_bar_meta()

        n  _add_*_meta()

            s   metadata 설정을 위한 추가적인 parameter를 가질 수 있음

 

video frame에서 cropping region을 명시하기 위해서 metadata가 사용되는 예

#include <gst/video/gstvideometa.h>
 
[...]
  GstVideoCropMeta *meta;
 
  /* buffer points to a video frame, add some cropping metadata */
  meta = gst_buffer_add_video_crop_meta (buffer);
 
  /* configure the cropping metadata */
  meta->x = 8;
  meta->y = 8;
  meta->width = 120;
  meta->height = 80;
[...]

 

frame rendering 할 때 buffer 상의 metadata를 사용할 수 있음

#include <gst/video/gstvideometa.h>
 
[...]
  GstVideoCropMeta *meta;
 
  /* buffer points to a video frame, get the cropping metadata */
  meta = gst_buffer_get_video_crop_meta (buffer);
 
  if (meta) {
    /* render frame with cropping */
    _render_frame_cropped (buffer, meta->x, meta->y, meta->width, meta->height);
  } else {
    /* render frame */
    _render_frame (buffer);
  }
[...]

 

 

15.3.2.        implementing new GstMeta

 

 

15.3.2.1.      define the metadata API

 

element가 어떤 종류의 metadata를 교환할지를 negotiation할 때 metadata API 정의가 사용됨

API 정의는 임의의 metadata를 포함

buffer pipeline을 통해 전달 될 때 metadata가 어떻게 저장되는지가 중요함

 

존재하는 API의 신규 구현 시, 이 부분은 건너 띄어도 됨

 

일단, my-example-meta.h를 생성

API의 정의를 지니고 있음

 

#include <gst/gst.h>
 
typedef struct _MyExampleMeta MyExampleMeta;
 
struct _MyExampleMeta {
  GstMeta       meta;
 
  gint          age;
  gchar        *name;
};
 
GType my_example_meta_api_get_type (void);
#define MY_EXAMPLE_META_API_TYPE (my_example_meta_api_get_type())
 
#define gst_buffer_get_my_example_meta(b) \
  ((MyExampleMeta*)gst_buffer_get_meta((b),MY_EXAMPLE_META_API_TYPE))

 

정의하는 Meta data 구조체의 첫 번째 field는 늘 항상 GstMeta 여야 함

 

Ÿ   my_example_meta-api_get_type

    n  meta API definition을 등록

Ÿ   gst_buffer_get_my_example_meta()

    n  metadata를 리턴하는 새로 정의된 API

 

#include "my-example-meta.h"
 
GType
my_example_meta_api_get_type (void) {
  static GType type;
  static const gchar *tags[] = { "foo", "bar", NULL };
 
  if (g_once_init_enter (&type)) {
    GType _type = gst_meta_api_type_register ("MyExampleMetaAPI", tags);
    g_once_init_leave (&type, _type);
  }
  return type;
}

 

gst_meta_api_type_register를 사용하여 api tag에 대한 이름을 등록

새롭게 등록된 API을 정의하는 GType pointer를 리턴

 

 

15.3.2.2.      Implementing a metadata API

 

등록된 metadata API GType에 대한 구현을 해야 함

 

GstMetaInfo

    Ÿ   구현에서는 이 구조체를 유지

    Ÿ   이는 my_example_meta_get_info를 통해 사용될 수 있음

GstBuffer metadata 구현을 추가하는 함수도 만들어야 함

 

[...]
 
/* implementation */
const GstMetaInfo *my_example_meta_get_info (void);
#define MY_EXAMPLE_META_INFO (my_example_meta_get_info())
 
MyExampleMeta * gst_buffer_add_my_example_meta (GstBuffer      *buffer,
                                                gint            age,
                                                const gchar    *name);

 

구현 부분

[...]
 
static gboolean
my_example_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer) {
  MyExampleMeta *emeta = (MyExampleMeta *) meta;
 
  emeta->age = 0;
  emeta->name = NULL;
 
  return TRUE;
}
 
static gboolean
my_example_meta_transform (GstBuffer * transbuf, GstMeta * meta,
    GstBuffer * buffer, GQuark type, gpointer data) {
  MyExampleMeta *emeta = (MyExampleMeta *) meta;
 
  /* we always copy no matter what transform */
  gst_buffer_add_my_example_meta (transbuf, emeta->age, emeta->name);
 
  return TRUE;
}
 
static void
my_example_meta_free (GstMeta * meta, GstBuffer * buffer) {
  MyExampleMeta *emeta = (MyExampleMeta *) meta;
 
  g_free (emeta->name);
  emeta->name = NULL;
}
 
const GstMetaInfo *
my_example_meta_get_info (void) {
  static const GstMetaInfo *meta_info = NULL;
 
  if (g_once_init_enter (&meta_info)) {
    const GstMetaInfo *mi = gst_meta_register (
MY_EXAMPLE_META_API_TYPE,    // my_example_meta_api_get_type()
        "MyExampleMeta",
        sizeof (MyExampleMeta),
        my_example_meta_init,
        my_example_meta_free,
        my_example_meta_transform);
    g_once_init_leave (&meta_info, mi);
  }
  return meta_info;
}
 
MyExampleMeta *
gst_buffer_add_my_example_meta (GstBuffer   *buffer,
                                gint         age,
                                const gchar *name)
{
  MyExampleMeta *meta;
 
  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
 
  meta = (MyExampleMeta *) gst_buffer_add_meta (buffer,
 my_example_meta_get_info(), NULL);
 
  meta->age = age;
  meta->name = g_strdup (name);
 
  return meta;
}

 

Ÿ   gst_meta_register

    n  구현한 API들을 등록

Ÿ   transform function

    n  buffer 상에서 특정 transformation 시 호출됨

Ÿ   gst_buffer_add_*_meta

    n  metadata 구현을 buffer에 추가

 

15.4.     GstBufferPool

재사용 가능한 buffer들의 list 관리 방법을 제공함

모든 buffer들은 동일 property를 지녀야 함 (ex. size, padding, metadata, alignment, etc)

 

bufferpool 객체

    Ÿ   최소, 최대 buffer의 량을 설정

    Ÿ   특정 GstAllocator를 사용해서 설정될 수 있음

        n  buffer memory

    Ÿ   bufferpool 특정 options on/off 할 수 있음

        n  ex. GstMeta pool  buffer에 추가

        n  ex. 특정 padding buffer  memory에 활성화

    Ÿ   bufferpool activation

        n  inactive strate

            s   pool 설정 가능

        n  active state

            s   설정 불가

            s   pool에서 buffer acquire  release 가능

 

 

15.4.1.        GstBufferPool API ex

Ÿ   GstBufferPool의 여러 derived 구현이 존재함

    n  buffer access

        s   직접 bufferpool을 생성한 경우 혹은

        s   ALLOCATION query를 통해 전달 받은 경우

 

Ÿ   초기 상태

    n  inactive state이므로 설정 가능함

    n  설정이 안된 bufferpool activate 하면 fail

 

GstStructure *config;
 
[...]
 
  /* get config structure */
  config = gst_buffer_pool_get_config (pool);
 
  /* set caps, size, minimum and maximum buffers in the pool */
  gst_buffer_pool_config_set_params (config, caps, size, min, max);
 
  /* configure allocator and parameters */
  gst_buffer_pool_config_set_allocator (config, allocator, &params);
 
  /* store the updated configuration again */
  gst_buffer_pool_set_config (pool, config);
 
[...]

 

bufferpool 설정

    Ÿ   설정은 GstStructure에 유지됨

        n  gst_buffer_pool_get_config()로 획득되는 객체임

    Ÿ   해당 structure update 한 후에, 현재 설정을 다시 bufferpol에 설정

        n  gst_buffer_pool_set_config() 로 설정

 

bufferpoool로 설정 가능한 options

    Ÿ   caps의 할당

    Ÿ   buffer size

        n  pool  buffer들의 size

        n  pool padding을 위해 더 큰 buffer를 할당할지 결정해야 함

    Ÿ   pool 내 최대/최소 buffer 

        n  1 이상

        n  buffer들은 pre-allocated

        n  최대가 0이 아니면, 최대 amount까지 할당함

    Ÿ   allocator 및 사용할 parameter

        n  어떤 bufferpool allocator를 무시하고 내부 것을 사용함

    Ÿ   여러 string으로 식별되는 임의의 options

        n  gst_buffer_pool_get_options()

            s   지원하는 option들을 리턴

        n  gst_buffer_pool_has_option()

            s   지원하는지 ask

        n  gst_buffer_pool_config_add_option()

            s   설정 structure를 추가하여 option을 활성화

            s   pool metadata buffer 상에 설정할지, padding을 수행할지 등에 대한 허가 등을 활성화

 

    Ÿ   활성화

       n  gst_buffer_pool_set_active

        n  bufferpool에 설정이 된 이후에, pool gst_buffer_pool_set_active로 활성화 됨

    Ÿ   pool에서 buffer 찾아오기

        n  gst_buffer_pool_acquire_buffer()

 

[...]
 
  GstFlowReturn ret;
  GstBuffer *buffer;
 
  ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
  if (G_UNLIKELY (ret != GST_FLOW_OK))
    goto pool_failed;
 
  [...]

 

15.5.     GST_QUERY_ALLOCATION

 

Ÿ   ALLOCATION query

    n  element GstMeta, GstBufferPool, GstAllocator negotiate하는데 사용되는 query

Ÿ   allocation 전략의 negotiation

    n  format negotiation 한 이후에 allocation 전략의 협상은 srcpad에 의해서 시작되고 결정됨

Ÿ   sink pad allocation 전략을 제안할 수 있으나,

    n  궁극적으로 source pad downstream sink pad의 제안을 가지고 결정함

 

Ÿ   source pad

    n  협상된 caps parameter로 가지고 GST_QUERY_ALLOCATION를 수행

    n  이로서 downstream element가 어떤 media type이 다뤄지는지 알 수 있음

    n  downstream sink pad allocation query에 대해 다음과 같은 응답을 할 수 있음

        s   size, min/mas amount등의 정보를 지닌 가능한 GstBufferPool 제안에 대한 list

        s   GstAllocator 객체의 list

            -       제안된 allocation parameter(flags, prefix, alignment, padding)을 지님

            -       이런 allocator들은 bufferpool에 의해 지원 될 시 bufferpool 내에서 설정될 수 있음

        s   지원되는 GstMeta 구현의 list

            -       metadata specific parameter들을 지님

            -       upstream element downstream이 어떤 metadata 종류를 지원하는지 아는 것이 중요함

    n  buffer 상에 metadata가 올라가기 전에

 

GST_QUERY_ALLOCATION가 리턴될 때,

Ÿ   source pad는 가용한 bufferpools, allocators, metadata를 선택

 

 

15.5.1.        ALLOCATION query ex. 

#include <gst/video/video.h>
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>
 
  GstCaps *caps;
  GstQuery *query;
  GstStructure *structure;
  GstBufferPool *pool;
  GstStructure *config;
  guint size, min, max;
 
[...]
 
  /* find a pool for the negotiated caps now */
  query = gst_query_new_allocation (caps, TRUE);
 
  if (!gst_pad_peer_query (scope->srcpad, query)) {
    /* query failed, not a problem, we use the query defaults */
  }
 
  if (gst_query_get_n_allocation_pools (query) > 0) {
    /* we got configuration from our peer, parse them */
    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
  } else {
    pool = NULL;
    size = 0;
    min = max = 0;
  }
 
  if (pool == NULL) {
    /* we did not get a pool, make one ourselves then */
    pool = gst_video_buffer_pool_new ();
  }
 
  config = gst_buffer_pool_get_config (pool);
  gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
  gst_buffer_pool_config_set_params (config, caps, size, min, max);
  gst_buffer_pool_set_config (pool, config);
 
  /* and activate */
  gst_buffer_pool_set_active (pool, TRUE);
 
[...]

allocation query를 src pad 상에서 수행

query의 결과로 얻은 가용한 pool 중 적절한 것을 사용

 

 

특정 구현은 video buffer 할당에 특화된 GstVideoBufferPool 객체를 만듦

 

Ÿ   gst_buffer_pool_config_add_option(config, GST_BUFFER_POOL_OPTION_VIDEO_META)

n  pool buffer 상의 GstVideoMeta metadata를넣을 수 있도록 활성화

 

 

15.5.2.        The ALLOCATION query in base classes

 

allocation strategy에 영향을 주는 virtual methods

    Ÿ   propose_allocation

        n  upstream element allcation parameter를 제안

    Ÿ   decide_allocation

        n  downstream으로부터 받은 제안으로부터 allocation parameter를 결정

 

 method의 구현자에서는 pool allocation option들을 갱신하여 GstQuery 객체를 수정해야함

 

 

15.6.     Negotiating the exact layout of video buffers

hardware element input buffer layout에 제약이 있을 수 있음

planes vertical/horizontal padding이 필요할 수 있음

 

producer가 이런 요구를 만족하는 buffer를 생성한다면, buffer 생성 전 설정을 통해 zero-copy를 확실히 할 수 있음

 

Ÿ   dmabuf

    n  Linux에서의 설정은 보통 dmabuf

    n  producer consumer buffer export 하던가 import 

 

consumer producer에게 import/export를 위해 예상되는 buffer layout을 알리기

 

Ÿ   v4l2src (the producer)

    n  feeding buffers

Ÿ   omxvideoenc (the consumer)

    n  encoding

 

 

15.6.1.        v4l2src importing buffers from omxvideoenc

 

Ÿ   omxvideoenc

    n  hardware에 요구사항을 query 하고 GstVidoAlignment를 생성

Ÿ   buffer pool alloc_buffer 구현 내의 omxvideoenc

    n  gst_buffer_add_video_meta_full을 호출하고 반환된 meta에 대해 gst_video_meta_set_alignment를 호출하여 요구되는 alignment를 설정

    n  alighment meta에 추가될 것 임

    n  buffer import 전에 v4l2src가 설정되게 함

 

meta = gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
          GST_VIDEO_INFO_FORMAT (&pool->video_info),
          GST_VIDEO_INFO_WIDTH (&pool->video_info),
          GST_VIDEO_INFO_HEIGHT (&pool->video_info),
          GST_VIDEO_INFO_N_PLANES (&pool->video_info), offset, stride);
 
      if (gst_omx_video_get_port_padding (pool->port, &pool->video_info,
              &align))
        gst_video_meta_set_alignment (meta, align);
 

 

Ÿ   omxvideoenc ALLOCATION query에 대한 응답 시 pool producer를 제안함

Ÿ   v4l2src

    n  ALLOCATION query로부터의 응답을 받을 시 제안된 pool에서 하나의 buffer를 획득하고 GstVideoMeta.stride gst_video_meta_get_plane_height를 사용하여 layout을 획득

Ÿ   v4l2src

    n  가능하면 buffer import 시 이런 요구사항에 맞는 data를 생성하도록 driver에 설정

    n  불가능하면, v4l2src omxvideoenc로부터 import 할 수 없음

        s   (요구사항에 맞게 copy 하려고 할) omxvideoenc로 소유한 buffer의 전달을 fallback

 

 

15.6.2.        v4l2src exporting buffers to omxvideoenc

 

Ÿ   omxvideoenc

    n  hardware에 요구사항을 query 한 후 이에 맞는 GstVideoAlighment를 생성

    n  alighment를 직렬화 한 video-meta라는 이름으로 GstStructure를 생성

 

params = gst_structure_new ("video-meta",
    "padding-top", G_TYPE_UINT, align.padding_top,
    "padding-bottom", G_TYPE_UINT, align.padding_bottom,
    "padding-left", G_TYPE_UINT, align.padding_left,
    "padding-right", G_TYPE_UINT, align.padding_right,
    NULL);

 

Ÿ   omxvideoenc

    n  ALLOCATION query (propose_allocation)를 처리할 시,

        s   GST_VIDEO_META_API_TYP meta를 추가할 때 이 structure parameter로 넘김

 

gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, params);

 

Ÿ   v4l2src

    n  ALLOCATION query(decide_allocation)에 대한 응답을 받을 시

        s   GST_VIDEO_META_API_TYPE parameter를 찾아 예상되는 buffer layout을 계산

 

guint video_idx;
GstStructure *params;
 
if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, &video_idx)) {
  gst_query_parse_nth_allocation_meta (query, video_idx, &params);
 
  if (params) {
    GstVideoAlignment align;
    GstVideoInfo info;
    gsize plane_size[GST_VIDEO_MAX_PLANES];
 
    gst_video_alignment_reset (&align);
 
    gst_structure_get_uint (s, "padding-top", &align.padding_top);
    gst_structure_get_uint (s, "padding-bottom", &align.padding_bottom);
    gst_structure_get_uint (s, "padding-left", &align.padding_left);
    gst_structure_get_uint (s, "padding-right", &align.padding_right);
 
    gst_video_info_from_caps (&info, caps);
 
    gst_video_info_align_full (&info, align, plane_size);
  }
}

 

Ÿ   v4l2src

    n  GstVideoInfo.stride GST_VIDEO_INFO_PLANE_HEIGHT()로 요구된 buffer layout을 찾음

    n  가능할 시 driver에 이 요구사항에 맞는 data를 생성하도록 설정

    n  안되면, driver는 자신의 layout으로 buffer를 생성

        s   omxvideoenc는 각 buffercopy하고 요구사항에 맞게 적용해야 함

 

반응형

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

GStreamer pwg: ch 13 part 2  (0) 2021.12.22
GStreamer pwg: ch. 14  (0) 2021.12.22
GStreamer pwg: ch. 16  (0) 2021.12.22
GStreamer pwg: ch. 17  (0) 2021.12.22
GStreamer pwg: ch. 18 clock  (0) 2021.12.22

댓글