Multimedia/GStreamer

GStreamer pwg: ch. 14

Roien 2021. 12. 22.
반응형

 

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

댓글