GStreamer User Book #2

본 연재는 SK Telecom의 후원으로 진행하는 “책책책 책을 만듭시다!” 프로그램으로 기획되었으며, 연재 종료 후 도서로 출간될 예정입니다. 연재 내용 중에 저자의 주관적 의견이 노출되는 경우, 해당 의견은 SK Telecom의 의견이 아님을 미리 밝힙니다.

GStreamer 구동 환경

실제로 GStreamer는 멀티 플랫폼을 지향하는 미디어 프레임워크이다. 대부분의 리눅스 배포본에 기본적으로 탑재해있으며, Android와 iOS와 같은 모바일 플랫폼을 위한 SDK를 제공하고 있다. 또한 MacOS X와 Windows에서도 사용이 가능하다.

하지만 이러한 멀티 플랫폼 지원은 GStreamer보다는 뒤에 논의할 GLib에서 각 OS의 의존적인 부분을 추상화하여 제공하기 때문에 가능한 것이고, 이러한 특성 때문에 태생적으로 리눅스에서 가장 편리하게 사용할수 있다. 유닉스 기반의 운영체제인 MacOS X도 리눅스와 유사하게 혹은 리눅스 환경 대비 큰 노력을 들이지 않고도 편리하게 사용할 수있다.

Windows에서는 MinGW(Minialist GNU for Windows)를 이용하여 리눅스에서 사용하던 GNU 도구와 컴파일러를 기반으로 빌드한 SDK를 사용하였으나, GStreamer 버전 1.16부터는 MSVC 기반으로 빌드한 SDK도 같이 제공하고 있다. 하지만 이는 GStreamer SDK이전에 MinGW나 MSVC에 대해 먼저 익숙하다는 전제가 필요하고, 그렇기 때문에 GStreamer를 이용하는 애플리케이션 작성법을 익히기 위한 출발점으로 Windows 환경은 권장하지 않는다. 그렇지만 GStreamer를 구동하는 환경을 정확히 제어하고, GStreamer가 제공하는 라이브러리와 플러그인을 어떻게 애플리케이션과 연결할 것인지를 이해하고 있다면, Windows 환경에서 GStreamer를 이용하는 것 자체가 어려운 일은 아닐 것이다.

본 서적에서는 리눅스 혹은 MacOS X를 사용하는 것을 가정하고 예제를 작성하고 있다.

Release version과 ABI version

리눅스를 연습하기 위한 환경으로 선택했다면, 리눅스 배포본에서 제공하는 패키지 명칭 때문에 GStreamer의 버전 체계에 의문이 생길 수 있다. gstreamer0.10 혹은 gstreamer1.0으로 명명된 패키지들을 볼 수 있는데, 이때 사용하는 숫자는 ABI(Application Binary Interface)에 대한 호환성을 표기하는 버전 체계이다. ABI 버전이 같은 경우에는, 라이브러리와 바이너리에 대한 하위 호환성을 유지한다는 뜻이며, 같은 ABI 버전 내에서 릴리즈 버전을 운영하는 형태로 진행된다. 즉, 현재 릴리즈 버전이 1.16.x이라면, 1.14.x 버전에서 빌드된 플러그인을 새롭게 빌드하지 않고도 사용이 가능하도록 하지만, 0.10.x 버전의 바이너리는 사용하지 못한다. 이러한 호환성을 강조하기 위하여 GStreamer는 각 라이브러리, 플러그인, CLI 도구들에 ABI 버전을 명시하는 정책을 사용하고 있다.

GStreamer 설치하기

최신 동향이나 논의되고 있는 기능들을 활용하고자 한다면 git 저장소에서 소스 코드를 가져와서 빌드하는 것이 맞겠지만, 개발 중인 코드들은 가끔씩 사용자를 당황하게 할때까 있다. 최근에는 CI(Continuous Integration)의 발달로 인해서 master 브랜치에 제출된 코드에 대한 검사를 철저히 하기는 하지만, 어디까지나 빌드와 단위 기능에 대한 테스트까지 수행될 뿐 논리적인 혹은 런타임 오류까지 확인하지 못하기에 특별한 이유가 없다면 Pre-built 패키지를 사용하는 것을 권장한다.

권장 환경

  • GStreamer 1.10 버전 이상
  • Linux
    • 우분투의 경우 18.04 이후
    • 데비안의 경우 stretch
    • CenOS 7 이후
  • Mac OS X (HomeBrew 사용 권장)

Linux

대표적으로 많이 사용되는 우분투, 데비안 같은 경우에는 gstreamer1.0 이라는 패키지 명칭으로 제공되고 있다. 다만 주의 할점은 헤더와 디버깅 심볼들은 별도의 패키지로 제공되기 때문에 GStreamer 기반 사용자 애플리케이션을 작성하기 위해서는 반드시 개발용 패키지를 설치해야한다. 편의상 우분투 패키지 명칭을 통해서 살펴본다면 다음과 같은 패키지들이 필수이다.

  • 런타임 라이브러리 및 실행 파일
    • libgstreamer1.0-0
    • libgstreamer-plugins-base1.0-0
    • libgstreamer-plugins-bad1.0-0
    • gstreamer1.0-plugins-base
    • gstreamer1.0-plugins-base-apps
    • gstreamer1.0-plugins-good
    • gstreamer1.0-plugins-ugly
    • gstreamer1.0-plugins-bad
    • gstreamer1.0-libav
    • gstreamer1.0-tools
  • 개발용 헤더 파일
    • libgstreamer1.0-dev
    • libgstreamer-plugins-base1.0-dev
    • libgstreamer-plugins-good1.0-dev
    • libgstreamer-plugins-bad1.0-dev
  • 디버깅용 심볼 파일
    • libgstreamer1.0-0-dbg
    • gstreamer1.0-plugins-base-dbg
    • gstreamer1.0-plugins-good-dbg
    • gstreamer1.0-plugins-ugly-dbg
    • gstreamer1.0-plugins-bad-dbg
    • gstreamer1.0-libav-dbg

특히 이름이 -dbg로 끝나는 패키지들은 사용자 애플리케이션을 작성하는 도중 gdb와 같은 디버깅 도구로 내부 스택을 추적할 때 반드시 필요하기 때문에 Pre-built 패키지로 개발 환경을 구축할 때에는 반드시 함께 설치해야한다. 런타임, 개발, 디버깅이라는 용도에 따른 패키지를 구분하는 규칙은 다른 리눅스 배포본에서도 유사하다.

MacOS X

MacOS X는 HomeBrew(https://brew.sh/)라는 도구를 통해서 GStreamer를 설치할 수 있다.

$ brew install \
    gstreamer \
    gst-plugins-base \
    gst-plugins-good \
    gst-plugins-ubly \
    gst-plugins-bad \
    gst-libav

GStreamer CLIs

GStreamer가 기본적으로 제공하는 CLI 도구들은 애플리케이션을 작성하기 전에 사용 환경을 점검하고 사용하고자 하는 GStreamer Pipeline 구조를 시뮬레이션 하기 위한 용도로 사용할 수 있다.

gst-inspect-1.0

GStreamer의 상태를 점검하고 개별 플러그인과 Element에 대한 정보를 알려주는 역할을 수행한다.

$ gst-inspect-1.0
osxaudio:  osxaudiodeviceprovider (GstDeviceProviderFactory)
osxaudio:  osxaudiosrc: Audio Source (OSX)
osxaudio:  osxaudiosink: Audio Sink (OSX)
replaygain:  rgvolume: ReplayGain volume
replaygain:  rglimiter: ReplayGain limiter
... (중략) ...

아무런 인자없이 수행을 하게 되면, 현재 환경에서 사용할 수 있는 플러그인 목록을 출력한다. 개별 플러그인을 살펴보고 싶다면, 단순히 해당 플러그인의 이름을 인자로 사용하면 플러그인을 구성하고 있는 Element 리스트를 출력한다.

다음은 coreelements라는 이름의 플러그인 정보를 살펴본 예이다.

$ gst-inspect-1.0 coreelements
Plugin Details:
  Name                     coreelements
  Description              GStreamer core elements
  Filename                 /usr/local/lib/gstreamer-1.0/libgstcoreelements.so
  Version                  1.16.0
  License                  LGPL
  Source module            gstreamer
  Source release date      2019-04-19
  Binary package           GStreamer source release
  Origin URL               Unknown package origin

  capsfilter: CapsFilter
  concat: Concat
  dataurisrc: data: URI source element
  downloadbuffer: DownloadBuffer
  fakesrc: Fake Source
  fakesink: Fake Sink
  fdsrc: Filedescriptor Source
  fdsink: Filedescriptor Sink
  filesrc: File Source
  funnel: Funnel pipe fitting
  identity: Identity
  input-selector: Input selector
  output-selector: Output selector
  queue: Queue
  queue2: Queue 2
  filesink: File Sink
  tee: Tee pipe fitting
  typefind: TypeFind
  multiqueue: MultiQueue
  valve: Valve element
  streamiddemux: Streamid Demux

  21 features:
  +-- 21 elements

플러그인의 이름이 인자로 주어진 경우에는 부수적인 정보들을 확인할 수 있다. 여기서 개발자에게 중요한 것은 절대 경로로 표시된 해당 플러그인의 위치(Filename)와 버전 정보, 그리고 이 플러그인이 속한 모듈의 이름(Binary package)이다. 플러그인의 경로를 통해서 해당 플러그만 삭제하거나 업데이트를 하는 용도로도 사용할 수 있으며, 소속 모듈의 이름을 통해서 레퍼런스를 찾아보기가 쉽기 때문이다.

또한 하단에는 이 플러그인이 가지고 있는 최종 Element 들에 대한 정보를 가지고 있는데, coreelements의 경우에는 21개의 Element를 가지고 있음을 알수 있다. 각 개별 Element의 정보를 확인하기 위해서는 플러그인의 경우와 동일하게 해당 Element의 이름을 인자로 사용하면 된다.

다음은 identity Element에 대한 정보를 확인한 결과이다. 해당 Element의 속성을 표시해주는 것을 확인할 수 있는데, Element에 대한 설명외에도 개발자를 위한 직접적인 정보를 구성하고 있다. 이번 장에서는 각 항목들이 어떻게 구분되고 있는지 살펴보고 생략된 항목들은 이후 챕터에서 상세하게 다룰 예정이다.

$ gst-inspect-1.0 identity
Factory Details:
  Rank                     none (0)
  Long-name                Identity
  Klass                    Generic
  Description              Pass data without modification
  Author                   Erik Walthinsen <omega@cse.ogi.edu>

Plugin Details:
  Name                     coreelements
  Description              GStreamer core elements
  Filename                 /usr/local/lib/gstreamer-1.0/libgstcoreelements.so
  Version                  1.16.0
  License                  LGPL
  Source module            gstreamer
  Source release date      2019-04-19
  Binary package           GStreamer source release
  Origin URL               Unknown package origin

GObject
 +----GInitiallyUnowned
       +----GstObject
             +----GstElement
                   +----GstBaseTransform
                         +----GstIdentity

Pad Templates:
...(중략)...

Pads:
...(중략)...

Element Properties:
...(중략)...

Element Signals:
...(중략)...

GObject를 최상위 부모로 표현한 트리는 해당 Element가 어떠한 역할을 하는지 유추할 수 있게 하는 가장 간단한 정보 중에 하나이다. identity의 경우 GstBaseTransform을 상속하고 있음을 알수 있고, 이는 입력과 출력이 있다는 것으로 해석할 수 있다.

Pad Templates는 이 Element가 생성하는 Pad들이 어떤 스키마를 가지고 생성하는지 알려주는 역할을 하며, Pads 항목은 Pad를 생성할때 사용하는 이름 규칙과 어떠한 Pad template과 관련이 있는지를 알려주는 역할을 한다. 이 정보를 이용하여 Element 간 연결이 가능한지를 확인할 수 있고 gst-launch-1.0을 이용하여 Pipeline을 어떻게 구성할시 시뮬레이션을 할수 있다.

Element Properties는 Element가 가지고 있는 속성 값을 표현하며, 해당 속성의 타입, 읽기/쓰기 여부, 사용할 수 있는 값의 범위 등을 별도의 API를 사용하지 않고도 알수 있게 한다.

Element Signals는 Element에서 외부로 어떠한 이벤트를 보내는지 혹은 외부에서 어떻게 Element 내부의 함수를 호출할 수 있는지를 기술하고 있으며, Signal의 경우 제공하지 않는 Element도 많이 존재한다.

gst-inspect-1.0의 또 다른 숨겨진 기능 중에 하나는 플러그인 파일을 직접 분석하는 기능이다. 예를들어 coreelements는 위 정보에 따르면 /usr/local/lib/gstreamer-1.0/libgstcoreelements.so 파일로 제공되고 있는데, 해당 파일을 직접 읽어서 정보를 출력해주는 역할을 한다.

$ gst-inspect-1.0 /usr/local/lib/gstreamer-1.0/libgstcoreelements.so

위 명령의 결과는 gst-inspect-1.0 corelements를 사용했을 때와 동일한데, 내부적으로는 플러그인 파일 자체를 읽어서 정보를 표시해주는 것이기 때문에, 다른 경로에 설치된 동일한 이름의 플러그인을 제거한다던가, 실수로 동일한 이름으로 정의된 Element를 찾아야 하는 경우에 유용하게 사용할 수 있다.

또한 gst-inspect-1.0은 제공된 파일이 GStreamer 플러그인이 아닌지를 판별하는데 사용할수도 있다.

$ gst-inspect-1.0 /usr/local/lib/libgstreamer-1.0.0.dylib
Could not load plugin file: File "/usr/local/lib/libgstreamer-1.0.0.dylib" is not a GStreamer plugin

의외로 GStreamer를 이용한 애플리케이션 개발 프로젝트가 길어지는 경우에 이런 문제는 자주 발생하게 된다. 주요 원인 중에 하나는 이전 버전의 플러그인과 현재 버전의 플러그인의 동작성을 테스트하면서 Pre-built 패키지들이 설치된 공간을 편의상 패키지 관리자가 아닌 수동으로 교체하고 복원하는 것을 잊어버리는 경우인데, 그런 경우 대게 시스템이 꼬였다라고 하며 OS부터 다시 설치하는 것으로 마무리 짖곤 한다. 물론 이러한 문제는 GStreamer 환경 변수를 정교하게 조작하여 애초부터 방지할수는 있겠지만, 이미 문제가 발생한 경우, 단순한 플러그인 파일 중복이나 버전 호환성 문제 때문이라면 gst-inspect-1.0 도구로 해결할 확률이 매우 높다.

gst-launch-1.0

GStreamer는 Pipeline 구조를 통해서 데이터를 전달하고 가공하는 역할을 수행한다. 애플리케이션을 제작하기 위해서는 Pipeline 내에 적절한 Element를 배치하는 작업을 먼저 수행하게 되는데, 구상한 전체 Pipeline을 테스트하거나, Pipeline 내의 일부 구간에 대해서 동작을 확인하는 용도로 사용할 수 있는 도구이다.

다음은 gst-launch-1.0으로 w3.org에서 제공하는 영상을 playbin을 통해서 재생하는 명령이다. playbin은 GStreamer에서 Playback을 지원하기 위하여 작성한 Element로 내부에서는 소스 타입부터 화면출력까지 현재 시스템에서 사용할 수 있는 최적의 Element를 찾아 Pipeline을 구성하는 기능을 수행한다.

$ gst-launch-1.0 playbin uri=https://media.w3.org/2010/05/sintel/trailer.mp4
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Got context from element 'source': gst.soup.session=context, session=(SoupSession)NULL, force=(boolean)false;
Got context from element 'sink': gst.gl.GLDisplay=context, gst.gl.GLDisplay=(GstGLDisplay)"\(GstGLDisplayCocoa\)\ gldisplaycocoa0";
Redistribute latency...
Got context from element 'playsink': gst.gl.GLDisplay=context, gst.gl.GLDisplay=(GstGLDisplay)"\(GstGLDisplayCocoa\)\ gldisplaycocoa0";
Redistribute latency...
Prerolled, waiting for buffering to finish...
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstAudioSinkClock

playbin 재생 화면 캡쳐

playbin은 GStreamer에서 제공하는 Element 중에도 State of the Art로 여겨질만큼 많은 노력의 결정체이다. 실제로 위에 주어진 미디어를 재생하기 위하여 다음과 같이 복잡한 Pipeline을 자동으로 생성하고있다.

playbin dot graph

gst-launch-1.0의 막강한 기능은 Element를 임의로 나열할 수 있다는 것이다. 다음은 테스트용 비디오 소스를 통해서 화면으로 출력하는 간단한 Pipeline이다.

$ gst-launch-1.0 videotestsrc ! autovideosink

위 Pipeline에 약간의 기능을 추가하여, 화면 크기를 조절하고, 재생 시간 정보를 표시하려면 다음과 같은 Pipeline을 사용할 수 있다.

$ gst-launch-1.0 \
    videotestsrc ! video/x-raw,width=320,height=240 ! \
    timeoverlay halignment=center valignment=center font-desc="Sans, 32" ! \
    autovideosink

위의 예제를 변형하여 화면 출력과 동시에 레코딩을 수행한다면 tee Element를 이용하여 스트림을 분기할 수 있다.

gst-launch-1.0 \
     videotestsrc ! video/x-raw,width=320,height=240 ! \
     timeoverlay halignment=center valignment=center font-desc="Sans, 32" ! \
     tee name=t \
     t. ! queue ! autovideosink \
     t. ! queue ! theoraenc bitrate=256 ! oggmux ! filesink location=test.ogg

위 Pipeline을 구동하면, 윈도우에 보이는 화면그대로 test.ogg 파일로 저장되어있음을 알 수 있고, 또다시 gst-launch-1.0 playbin uri=file://<절대경로>/test.ogg 를 이용하여 재생이 가능함을 확인할 수 있다.

gst-typefind-1.0

미디어 정보를 처리하는데 있어서 가장 어려운 부분중에 하나는 다양한 코덱과 다양한 포맷의 파일들을 다룰 수 있어야 한다는 것이다. GStreamer는 파일의 헤더 혹은 바이트 패턴을 분석해서 주어진 파일의 포맷을 추측하는 기능을 제공하는데, gst-typefind-1.0을 이용하여 해당 기능을 사용해볼 수 있다.

도구 자체로는 특별한 입력이 필요없기 때문에, 로컬에 준비된 미디어 파일을 인자로 사용하여 테스트 해볼 수 있다. 본 예제에서는 앞서 소개했던 w3c의 HTML5 Video Events and API 테스트 페이지에서 사용하고 있는 컨텐츠를 미리 다운로드 하여 사용하는 것으로 가정하였다.

$ wget https://media.w3.org/2010/05/sintel/trailer.mp4

gst-typefind-1.0에 파일 경로를 입력하여 실행하면 다음과 같이 주어진 파일의 포맷과 속성을 결과로 얻을 수 있다.

$ gst-typefind-1.0 ./trailer.mp4
./trailer.mp4 - video/quicktime, variant=(string)iso

파일의 확장자(여기서는 .mp4)를 이용하여 파일 포맷을 추정하는 것이 가장 간단하겠지만, GStreamer는 앞서 기술한 것처럼 내부 바이트 패턴을 분석하기 때문에 파일의 이름을 변경한다하더라도 동일한 결과를 얻을 수 있다.

$ mv trailer.mp4 dummy
$ gst-typefind-1.0 ./dummy
./dummy - video/quicktime, variant=(string)iso

사실 gst-typefind-1.0core 모듈의 typefind Element를 활용한 아주 간단한 Pipeline을 활용한 도구이기 때문에, 동일한 정보를 앞서 기술한 gst-launch-1.0의 디버깅 메시지를 통하여 얻을 수 있다. 타입 정보는 typefind Element 내부에 디버그 메시지 레벨 4에서 출력하기 때문에 --gst-debug=typefind:4를 인자로 주어 메시지를 확인할 수 있다.

$ gst-launch-1.0 \
    filesink location=./dummy ! typefind ! fakesink \
    --gst-debug=typefind:4
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
0:00:00.042075000 18827 0x7f9c40019b70 INFO                typefind gsttypefindelement.c:850:gst_type_find_get_extension:<typefindelement0> could not find uri extension in file:///Users/justinkim/git/gst-build/dummy
0:00:00.048977000 18827 0x7f9c40019b70 INFO                typefind gsttypefindelement.c:181:gst_type_find_element_have_type:<typefindelement0> found caps video/quicktime, variant=(string)iso, probability=100
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 0:00:00.004914000
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...

그렇다면, typefind Element가 인식할 수 있는 파일 타입은 얼마나 될까? 엄밀히 말하자면, 사용자가 원하는 모든 포맷을 인식할 수 있다. 내부적으로는 typefind Element는 GstTypeFindFactory의 정의에 맞게 구현된 함수를 등록하여 호출하는 방식을 취하고 있기 때문에 현재 GStreamer가 인식하지 못하는 패턴일지라도 GStreamer 모듈을 수정하지 않고도 사용자 애플리케이션에서 몇몇 함수를 정의하고 등록하는 것만으로 typefind가 사용자가 정의한 파일을 인식할 수 있게 된다. 이에 대해서는 이후 GStreamer 애플리케이션을 작성하는 예제에서 상세하게 다룰 예정이다.

gst-discoverer-1.0

gst-typefind-1.0은 해당 파일의 포맷을 분석하는 역할에 그쳤다면, gst-discoverer-1.0은 미디어 정보를 추출하는 역할을 한다. 내부적으로 Pipeline을 구성하여 정보를 추출하고 있으며, 비디오와 오디오 그리고 부수적인 데이터 정보까지 분석하기 때문에, uridecodebin을 사용하고 있다. 이 때문에 gst-plugins-base 모듈에서 구현하고 있고, gst-typefind-1.0과 다르게 URI를 통해서 소스를 제공할 수 있다.

$ gst-discoverer-1.0 https://media.w3.org/2010/05/sintel/trailer.mp4
Analyzing https://media.w3.org/2010/05/sintel/trailer.mp4
Done discovering https://media.w3.org/2010/05/sintel/trailer.mp4

Topology:
  container: Quicktime
    audio: MPEG-4 AAC
    video: H.264 (High Profile)

Properties:
  Duration: 0:00:52.209000000
  Seekable: yes
  Live: no
  Tags:
      audio codec: MPEG-4 AAC audio
      maximum bitrate: 128000
      datetime: 1970-01-01T00:00:00Z
      title: Sintel Trailer
      artist: Durian Open Movie Team
      copyright: (c) copyright Blender Foundation | durian.blender.org
      description: Trailer for the Sintel open movie project
      encoder: Lavf52.62.0
      container format: ISO MP4/M4A
      video codec: H.264 / AVC
      bitrate: 535929

또한 미디어 파일의 정보를 추출하기 위해서 gst-discoverer-1.0은 재생이 가능한 온전한 Pipeline을 사용한다. Demuxer와 Decoder를 모두 사용하게 되며, 미디어 파일에 얻을 수 있는 메타데이터들을 수집하여 출력하고 있다. 다만 영상과 음성 출력을 목적으로 하는 것이 아니기 때문에 디코딩을 수행한 이후 발생한 데이터를 fakesink를 이용하여 버리게 된다.

다음은 실제로 위에 사용한 영상 파일을 분석하는데 사용한 Pipeline을 캡쳐한 이미지이다.

discoverer dot graph

Pipeline 내부에서 사용하는 정보들을 추출하는 것이기 때문에, gst-launch-1.0을 이용해서도 동일한 정보들을 추출할 수 있다. -t 옵션을 사용하게 되면 메타데이터를 출력하게 되는데, gst-discoverer-1.0이 출력하는 정보와 동일함을 알수 있다. 아래의 예제는 gst-discoverer-1.0이 사용하는 동일한 Pipeline을 이용하여 gst-launch-1.0에서 실행한 경우이다.

아래 예제에서 볼 수 있듯이 메타데이터(tag)는 중복해서 나타날 수 있고, gst-launch-1.0 명령 자체에는 동적으로 트랙을 구성하는 기능이 없기 때문에, 미디어 파일의 트랙 정보를 알고 있는 경우에만 Pipeline을 구성할 수 있다.

$ gst-launch-1.0 -t \
    uridecodebin uri=https://media.w3.org/2010/05/sintel/trailer.mp4 name=u \
    u. ! queue ! fakesink \
    u. ! queue ! fakesink
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Got context from element 'source': gst.soup.session=context, session=(SoupSession)NULL, force=(boolean)false;
Redistribute latency...
FOUND TAG      : found by element "fakesink1".
     audio codec: MPEG-4 AAC audio
 maximum bitrate: 128000
FOUND TAG      : found by element "fakesink1".
        datetime: 1970-01-01 00:00:00 (UTC)
           title: Sintel Trailer
          artist: Durian Open Movie Team
       copyright: (c) copyright Blender Foundation | durian.blender.org
     description: Trailer for the Sintel open movie project
         encoder: Lavf52.62.0
container format: ISO MP4/M4A
FOUND TAG      : found by element "fakesink1".
     audio codec: MPEG-4 AAC audio
 maximum bitrate: 128000
 ... (중략) ...