GStreamer pwg: ch. 15
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, ¶ms); /* 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, ¶ms); 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는 각 buffer를copy하고 요구사항에 맞게 적용해야 함
'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 |
댓글