GStreamer pwg: ch. 13 part 1
13. Different Scheduling Modes
live streaming
n PUSH 선호
on-demand로 display 를 하는 경우
n PULL 선호
n ex. video player
1. 모두 push mode인 경우
A. 첫 번째 element가 자신의 src pad로 data를 push하여 다음 element의 sink pad에 전달
B. 두 번째 element의 sink pad에 _chain() 함수로 전달 받은 buffer를 처리
i. _chain()은 자신의 src pad의 gst_pad_push를 호출하여 다음 element의 sink pad로 전달
2. sink pad는 pull, src pad는 push (현재 element가 pipeline의 flow control을 담당)
A. sink pad가 pull mode로 활성화 시 GstTask를 시작
i. 스레드는 gst_pad_pull_range를 호출하여 upstream element의 src pad에 _get_range를 호출
B. upstream element의 _get_range는
i. random access하여 buffer를 채움
C. 전달 받은 buffer를 source pad에 push
3. 한 element 내 모든 pad가 pull mode
A. sink와 src가 모두 pull mode이면, 동작이 다음 element에도 의존
B. 이말은 나의 src가 먼저 뒤의 element의 pull에 slave로 깨어나 get_range를 수행하고,
C. 여기서 나의 sink pad에 pull_range를 호출함을 의미
i. 즉, GstTask thread가 안 돌아도 됨 (내가 flow control을 담당하지 않음)
pad는 push 혹은 pull mode로 동작할 수 있음
push mode
n _chain() operating elements
s sink pad혹은 source pad 상의 chain-function을 지님
n sink pad 상에 chain-function을 지닌 element는 data를 source로 push함
n peer element의 srcpad 상의 gst_pad_push를 사용하면 (앞의 element가 push 하면)
s 이것이 현재 element의 _chain() 을 호출하게 함
s 이때 element는 buffer를 source pad로 push
n dataflow의 시작을 push out을 통해 수행
s 이후 모든 downstream element들은 _chain함수가 호출됨
pull mode
13.1. The pad activation stage
READY -> PAUSED로 상태 변경 시 pad가 activated
source pad부터 활성화 되고 sink pad가 활성화 됨
_activate()
n pad의 _activate() 함수가 호출됨
n 기본으로 "push-mode"로 활성화 됨
s gst_pad_activate_mode()가 호출됨 with GST_PAD_MODE_PUSH scheduling mode
n _activate()는 override 가능함
n 다른 scheduling mode로 결정할 수 있음
_activate_mode()
n pad가 어떤 mode로 활성화 되었는지 알려줌
element의 pad들은 서로 다른 mode로 동작 가능
모든 pad가 push-mode로 활성화 된 경우
n element는 전체적으로 push-mode로 동작함
n source element
s source pad로 buffer를 push하여 downstream element가 buffer를 받음
s 즉, source pad가 동작을 시작
s downstream element는 upstream element가 보낸 buffer를 sinkpads의 _chain() 함수를 사용해 받음
- _chain() 함수는 source pad 상으로 buffer를 push out
n push-mode로 동작하려면,
s 각 sinkpad에 chain-function이 설정 되어야 함
- gst_pad_set_chain_function으로 설정
s 모든 downstream element는 동일 mode로 동작해야 함
pull + push
n source pad가 push-mode로 동작하는 동안, sinkpad가 driving force로 동작
n sink pad는 pipeline 뒤에서 driving force(추진력, 원동력)가 됨
n driving force가 되려면, pad는 활성화 될 시 GstTask(thread)를 시작해야 함
s thread는 gst_pad_pull_range을 호출하여 data를 access하고, 이를 source pad에 push
n 즉, 이 element가 pipeline에서 data flow를 제어함을 의미
n 이렇게 동작하려면,
s 모든 downstream element들은 push mode여야 함
s 모든 upstream element는 pull-mode 여야 함
n GST_PAD_MODE_PULL인 경우 (GST_QUERY_SCHEDULING query의 결과가)
s source pad들은 downstream element에 의해 PULL mode로 활성화
s source pad에 getrange 함수가 설정 되어 있어야 이 mode로 동작 가능
- gst_pad_set_getrange_function
한 element 내 모든 pad가 PULL mode
n task를 시작하는걸 의미하지는 않음
n downstream element에서의 pull slave를 의미함
s downstream element가 "주도적"으로 pull 할 것 임
n _get_range 함수로 data에 random access
s gst_pad_set_getrange_function으로 설정
n element가 sinkpad를 지닌다면,
s 이 pad들과 peer pad들은 PULL access mode로 동작해야함
n sink element가 pull mode면,
s task를 시작해서 sink pad 상의 get_pad_pull_range를 호출해야만 함
s upstream SCHEDULING query가 GST_PAD_MODE_PULL scheduling mode인 경우에만 가능
13.2. pads driving the pipeline
sink pad가 pull mode + src pad는 push mode
n task를 시작하여 pipeline의 data flow를 시작함
n sink pad에서 data에 대해 random access 하여 src로 data를 push
n 유용한 경우
s demuxers, parsers 혹은 특정 decoders
- data가 parsing 되지 않은 상태로 전달 되는 경우
n ex. MPEG-audio or video stream
- 이 경우 byte 단위의 정확한 access가 필요함
- 이런 element들은 push mode로도 동작할 수 있어야 함
s 특정 audio outputs
- input data flow에 대해 control이 필요한 경우
- ex. Jack sound server
PULL이 유용한 경우는
n data에 대한 "주도권"을 가져야 하는 경우임
s 내가 원하는 시점에 parsing을 적절한 방법으로 할 수 있어야 하는 경우 등
1) upstream element가 pull mode를 지원하는지 확인
2) 위가 pull mode면 나의 sink pad를 pull mode로 활성화
activate_mode 함수
#include "filter.h" #include <string.h> static gboolean gst_my_filter_activate (GstPad * pad, GstObject * parent); static gboolean gst_my_filter_activate_mode (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active); static void gst_my_filter_loop (GstMyFilter * filter); G_DEFINE_TYPE (GstMyFilter, gst_my_filter, GST_TYPE_ELEMENT); GST_ELEMENT_REGISTER_DEFINE(my_filter, "my-filter", GST_RANK_NONE, GST_TYPE_MY_FILTER); static void gst_my_filter_init (GstMyFilter * filter) { [..] gst_pad_set_activate_function (filter->sinkpad, gst_my_filter_activate); gst_pad_set_activatemode_function (filter->sinkpad, gst_my_filter_activate_mode); [..] } [..] static gboolean gst_my_filter_activate (GstPad * pad, GstObject * parent) { GstQuery *query; gboolean pull_mode; /* first check what upstream scheduling is supported */ query = gst_query_new_scheduling (); if (!gst_pad_peer_query (pad, query)) { gst_query_unref (query); goto activate_push; } /* see if pull-mode is supported */ pull_mode = gst_query_has_scheduling_mode_with_flags (query, GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE); gst_query_unref (query); if (!pull_mode) goto activate_push; /* now we can activate in pull-mode. GStreamer will also * activate the upstream peer in pull-mode */ return gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE); activate_push: { /* something not right, we fallback to push-mode */ return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE); } } static gboolean gst_my_filter_activate_pull (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { gboolean res; GstMyFilter *filter = GST_MY_FILTER (parent); switch (mode) { case GST_PAD_MODE_PUSH: res = TRUE; break; case GST_PAD_MODE_PULL: if (active) { filter->offset = 0; res = gst_pad_start_task (pad, (GstTaskFunction) gst_my_filter_loop, filter, NULL); } else { res = gst_pad_stop_task (pad); } break; default: /* unknown scheduling mode */ res = FALSE; break; } return res; } |
#define BLOCKSIZE 2048 static void gst_my_filter_loop (GstMyFilter * filter) { GstFlowReturn ret; guint64 len; GstBuffer *buf = NULL; if (!gst_pad_query_duration (filter->sinkpad, GST_FORMAT_BYTES, &len)) { GST_DEBUG_OBJECT (filter, "failed to query duration, pausing"); goto stop; } if (filter->offset >= len) { GST_DEBUG_OBJECT (filter, "at end of input, sending EOS, pausing"); gst_pad_push_event (filter->srcpad, gst_event_new_eos ()); goto stop; } /* now, read BLOCKSIZE bytes from byte offset filter->offset */ ret = gst_pad_pull_range (filter->sinkpad, filter->offset, BLOCKSIZE, &buf); if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (filter, "pull_range failed: %s", gst_flow_get_name (ret)); goto stop; } /* now push buffer downstream */ ret = gst_pad_push (filter->srcpad, buf); buf = NULL; /* gst_pad_push() took ownership of buffer */ if (ret != GST_FLOW_OK) { GST_DEBUG_OBJECT (filter, "pad_push failed: %s", gst_flow_get_name (ret)); goto stop; } /* everything is fine, increase offset and wait for us to be called again */ filter->offset += BLOCKSIZE; return; stop: GST_DEBUG_OBJECT (filter, "pausing task"); gst_pad_pause_task (filter->sinkpad); } |
pull sink pad의 task는 input과 output에 대한 제어를 수행
n input을 읽고 이를 source pad에 'PUSH'
예전 push mode 보다는 유연함을 제공함
'Multimedia > GStreamer' 카테고리의 다른 글
GStreamer pwg: ch 12 (0) | 2021.12.22 |
---|---|
GStreamer pwg: ch 13 (0) | 2021.12.22 |
GStreamer pwg: ch 13 part 2 (0) | 2021.12.22 |
GStreamer pwg: ch. 14 (0) | 2021.12.22 |
GStreamer pwg: ch. 15 (0) | 2021.12.22 |
댓글