GStreamer pwg: ch. 14
14. Caps negotiation
Caps negotiation
n 다룰 element 간에 media format(GstCaps)을 찾기
n pipeline 구성을 위해 optimal solution을 찾는 과정
14.1. Caps negotiation basics
negotiation rules
downstream element
n 자신의 sinkpad에 대한 format을 제안함
n 이 제안을 sink pad 상에 이뤄진 CAPS query의 result로 전달
upstream element
n format에 대해 결정
n 선택한 media format을 CAPS event를 가지고 source pad 상의 downstream으로 전달
downstream element는
n upstream에게 RECONFIGURE event를 upstream으로 보내서 새로운 format을 제안함을 알림
n RECONFIGURE event는
s upstream element에게 negotiation phase를 다시 시작할 것을 지시함
s RECONFIGURE event를 전달한 element는 다른 format을 젱안함
CAPS와 RECONFIGURE event와 CAPS query에 더불어
특정 caps가 어떤 element에 의해 채택 되었는지를 check하는 ACCEPT_CAPS query가 있음
14.2. Caps negotiation use cases
push-mode scheduling의 경우
sink pad만이 format을 제안하고 source pad는 이를 채택할지 말지 결정
n 즉, 대부분의 복잡한 작업은 모두 source pad에서 수행됨
source pad 상의 3가지의 caps negotiation use cases
fixed negotiation
n element가 한가지 format만 출력할 수 있음
transform negotiation (새롭게 맞춤 caps를 생성)
n input과 output format이 fixed transformation이 존재
n output caps를 input caps의 값을 가지고 생성함
n element가 만드는 caps는 upstream cpas와 채택한 element의 downstream caps에 의존
dynamic negotiation (downstream 즉, src pad의 caps 중 가능한 것을 fixiate하여 사용)
n element가 많은 format을 출력할 수 있음
n 입력 caps에 맞는 (channel, sample rate 등) caps를 만들어 사용
n sinkpad로 전달된 caps에 대해서 passthrough로 동작할 것이 아니면
downstream caps중 transform가능한 첫 번째 caps를 output caps로 설정
이를 fixed caps로 만들어야 함(fixiate)
14.2.1. Fixed negotiation
source pad
n fixed format을 생성
보통 이 format은 media 내부에서 encode 됨
다른 format을 요청하는 downstream element는 없음
source pad가 renegotiation하는 경우는 자기 스스로 caps를 변경하고자 할 때 뿐임
fixed caps
모든 element가 renegotiable하지 않은 경우에 사용
ex.
n typefinder
s typefinder는 byte stream을 보고 type을 알아낸 후,
s CAPS event를 보내고 해당 type의 buffer를 push
n 거의 모든 demuxers
s 포함된 elementary stream은 file header에 정의되어 있기에, not negotiable
n 어떤 decoders
s format이 data이 embedded
s peercaps의 일부가 아님
s decoder 스스로는 reconfigurable 하지 않음
n fixed format을 생성하는 몇몇 source들
gst_pad_use_fixed_caps()
를 fixed caps를 가지고 source pad상에서 사용함
pad가 negotiable하지 않은 한, default CAPS query는 padtemplate에 존재한 caps를 리턴
pad가 negotiable하다면, 이 CAPS query는 negotiated된 caps를 리턴
fixed cpas source pads 관련 code
[..] pad = gst_pad_new_from_static_template (..); gst_pad_use_fixed_caps (pad); [..] |
fixed caps는 gst_pad_set_caps를 통해서 pad에 설정됨
[..] caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_AUDIO_NE(F32), "rate", G_TYPE_INT, <samplerate>, "channels", G_TYPE_INT, <num-channels>, NULL); if (!gst_pad_set_caps (pad, caps)) { GST_ELEMENT_ERROR (element, CORE, NEGOTIATION, (NULL), ("Some debug information here")); return GST_FLOW_ERROR; } [..] |
input caps는 output caps로 만들어지는 정보를 포함하지 않음
format에 대해 configure가 필요한 element들은 full caps negotiation을 구현해야만 함
14.2.2. transform negotiation
element input caps와 output caps간의 고정 변환
n 이 변환은 element의 property 설정에 의해 설정될 수 있음 (content에 의하지 않음)
downstream caps에 의해 element가 채택 할 수 있는 caps가 결정됨
element가 생성할 caps는 upstream caps의 고정 변환에 의해 결정됨
element의 type은 CAPS event를 받을 시 sink pad의 _event 함수에서 caps를 source pad에 설정
즉, caps 변환 함수는 고정된 caps를 다른 고정된 caps로 변환함
ex.
Videobox
n object property에 따라 video frame에 설정가능한 border를 추가함
Identity element
n 모든 element가 data의 format을 변경하지 않음
n ex. video와 audio effect, 혹은 stream inspector
Some decoders and encoders
n output format은 input format에 의해 결정됨
n ex. mulawdec이나 mulawenc
n 이런 decoder들은 header가 없음
negotiation steps of a typical transform element
[...] static gboolean gst_my_filter_setcaps (GstMyFilter *filter, GstCaps *caps) { GstStructure *structure; int rate, channels; gboolean ret; GstCaps *outcaps; structure = gst_caps_get_structure (caps, 0); ret = gst_structure_get_int (structure, "rate", &rate); ret = ret && gst_structure_get_int (structure, "channels", &channels); if (!ret) return FALSE; outcaps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_AUDIO_NE(S16), "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); ret = gst_pad_set_caps (filter->srcpad, outcaps); // sink의 caps로 source의 caps를 생성 gst_caps_unref (outcaps); return ret; } static gboolean gst_my_filter_sink_event (GstPad *pad, GstObject *parent, GstEvent *event) { gboolean ret; GstMyFilter *filter = GST_MY_FILTER (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_my_filter_setcaps (filter, caps); break; } default: ret = gst_pad_event_default (pad, parent, event); break; } return ret; } [...] |
14.2.3. dynamic negotiation
가장 복잡하고 powerful
fixed caps à unfixed (multiple) formats
source pad가 가능한 것들 중 downstream이 받아들일 수 있는 format을 선택
sinkpad로 전달된 caps에 대해서 passthrough로 동작할 것이 아니면
downstream caps중 transform가능한 첫 번째 caps를 output caps로 설정
이를 fixed caps로 만들어야 함(fixiate)
typical flow
sink pad에서 caps를 받음
element가 passthrough mode로 동작하길 선호하면,
n downstream이 ACCEPT_CAPS query를 지닌 caps를 채택하는지 check
n 채택한다면 negotiation 완료하고 passthrough mode로 동작
source pad에서 가능한 caps를 계산
downstream peer pad에 가능한 caps를 문의
downstream list 중 transform 가능한 첫 번째 caps를 선택
n 이를 output cpas로 설정
n fixed caps를 만들기 위해 reasonable deafult로 caps를 fixiate 해야함
examples
converter elements
n videoconverter, audioconverter, audiosampler, videoscale, …
source elements
n audiotestsrc, videotestsrc, v4l2src, pulsesrc, …
static gboolean gst_my_filter_setcaps (GstMyFilter *filter, GstCaps *caps) { if (gst_pad_set_caps (filter->srcpad, caps)) { filter->passthrough = TRUE; } else { GstCaps *othercaps, *newcaps; GstStructure *s = gst_caps_get_structure (caps, 0), *others; /* no passthrough, setup internal conversion */ gst_structure_get_int (s, "channels", &filter->channels); othercaps = gst_pad_get_allowed_caps (filter->srcpad); others = gst_caps_get_structure (othercaps, 0); gst_structure_set (others, "channels", G_TYPE_INT, filter->channels, NULL); /* now, the samplerate value can optionally have multiple values, so * we "fixate" it, which means that one fixed value is chosen */ newcaps = gst_caps_copy_nth (othercaps, 0); gst_caps_unref (othercaps); gst_pad_fixate_caps (filter->srcpad, newcaps); if (!gst_pad_set_caps (filter->srcpad, newcaps)) return FALSE; /* we are now set up, configure internally */ filter->passthrough = FALSE; gst_structure_get_int (s, "rate", &filter->from_samplerate); others = gst_caps_get_structure (newcaps, 0); gst_structure_get_int (others, "rate", &filter->to_samplerate); } return TRUE; } static gboolean gst_my_filter_sink_event (GstPad *pad, GstObject *parent, GstEvent *event) { gboolean ret; GstMyFilter *filter = GST_MY_FILTER (parent); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); ret = gst_my_filter_setcaps (filter, caps); break; } default: ret = gst_pad_event_default (pad, parent, event); break; } return ret; } static GstFlowReturn gst_my_filter_chain (GstPad *pad, GstObject *parent, GstBuffer *buf) { GstMyFilter *filter = GST_MY_FILTER (parent); GstBuffer *out; /* push on if in passthrough mode */ if (filter->passthrough) return gst_pad_push (filter->srcpad, buf); /* convert, push */ out = gst_my_filter_convert (filter, buf); gst_buffer_unref (buf); return gst_pad_push (filter->srcpad, out); |
14.3. upstream caps (re)negotiation
upstream negotiation
n 이미 negotiate 된 pipeline을 새로운 format으로 renegotiate 하는것이 주 목적
ex.
n video window가 변경되어 여러 video size를 선택하는 경우
n video output이 rescaling 할 수 없는 경우
n audio channel 구성이 변경되는 경우
GST_EVENT_RECONFIGURE event
renegotiation 요청 event
upstream element에 caps를 reconfigure 하기를 지시하여 새로운 caps를 선택
RECONFIGURE event를 보내는 element는 GST_QUERY_CAPS query function을 통해 새로운 선호되는 caps를 리턴함으로서 새로운 caps의 선택에 영향을 줌
RECONFIGURE event는
n 이 event가 통과하는 모든 pad 상에 GST_PAD_FLAG_NEED_RECONFIGURE를 설정
여러 다른 element들은 서로 다른 역할을 지님
new format을 upstream으로 propose 하는 element
n 새로운 caps가 upstream에서 받아 들일 수 있을지를 ACCEPT_CAPS query로 확인
n 이후 RECONFIGURE event를 보내고 선호되는 새 format으로 CAPS query에 응답할 준비를 함
n renegotiate하고자 하는 upstream element가 없는 경우, element는 현재 format을 처리해야 함
transform negotiation 을 하고자 RECONFIGURE event를 upstream으로 전달한 element
n format에 맞게 새로운 caps를 '생성' 하는 하고자 하는 경우
n upstream caps에 기반한 fixed transform이기에 event를 upstream으로 보내서 새로운 format을 선택
fixed negotiation을 하고자 RECONFIGURE event를 버린 element (fixed negotiation 경우)
n 이런 element는 reconfigure 될 수 없음
n 이들의 output caps는 upstream caps에 의존하지 않기에 event는 버려짐
NEED_RECONFIGURE flag를 check 하여 source pad 상에서 reconfigure될 수 있는 element들
n gst_pad_check_reconfigure()로 NEED_RECONFIGURE flag를 check함
s 이 함수가 true 리턴 시 renegotiation을 진행 해야 함
14.4. implementing a CAPS query function
GST_QUERY_CAPS query type을 지닌 _query() 함수는 peer element가 이 pad에 대해 어떤 format을 지원하는지 알고자 할 때 혹은 preference 순서가 무엇인지 알고자 할 때 호출됨
downstream 혹은 upstream에 대한 peer element의 제약을 고려한 해당 element가 지원하는 모든 format들을 리턴함 (preference의 순서 혹은 highest preference 순서대로 sorted)
static gboolean gst_my_filter_query (GstPad *pad, GstObject * parent, GstQuery * query) { gboolean ret; GstMyFilter *filter = GST_MY_FILTER (parent); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS { GstPad *otherpad; GstCaps *temp, *caps, *filt, *tcaps; gint i; otherpad = (pad == filter->srcpad) ? filter->sinkpad : filter->srcpad; caps = gst_pad_get_allowed_caps (otherpad); gst_query_parse_caps (query, &filt); /* We support *any* samplerate, indifferent from the samplerate * supported by the linked elements on both sides. */ for (i = 0; i < gst_caps_get_size (caps); i++) { GstStructure *structure = gst_caps_get_structure (caps, i); gst_structure_remove_field (structure, "rate"); } /* make sure we only return results that intersect our * padtemplate */ tcaps = gst_pad_get_pad_template_caps (pad); if (tcaps) { temp = gst_caps_intersect (caps, tcaps); gst_caps_unref (caps); gst_caps_unref (tcaps); caps = temp; } /* filter against the query filter when needed */ if (filt) { temp = gst_caps_intersect (caps, filt); gst_caps_unref (caps); caps = temp; } gst_query_set_caps_result (query, caps); gst_caps_unref (caps); ret = TRUE; break; } default: ret = gst_pad_query_default (pad, parent, query); break; } return ret; } |
14.5. pull-mode Caps negotiation
'Multimedia > GStreamer' 카테고리의 다른 글
GStreamer pwg: ch. 13 part 1 (0) | 2021.12.22 |
---|---|
GStreamer pwg: ch 13 part 2 (0) | 2021.12.22 |
GStreamer pwg: ch. 15 (0) | 2021.12.22 |
GStreamer pwg: ch. 16 (0) | 2021.12.22 |
GStreamer pwg: ch. 17 (0) | 2021.12.22 |
댓글