Tuesday, May 22, 2018

Open source software technology seminar at TUIT

From 15th, May to 17th, May, a seminar sponsored by NIPA was held at TUIT, Uzbekistan.  This seminar was the 3rd follow-up action of Korean-Uzbekistan government MOU for the invigorating open source activity and I presented for the last day with "GStreamer & IoT". In my session, I introduced the basic concept of IoT and some use cases of GStreamer in IoT domain, and also I didn't forget to say what Open source software developer does.



Most of the attendees were students or government officials who are willing to be involved in open source project in a direct or indirect way. Usually, they seemed to be interested in developing Uzbekistan industry through the international exchange like this seminar. Especially, according to a professor at TUIT, they started a long-term plan to develop agriculture with IoT technology so they need advisors around the world.


After the session was over, we had extra time for QnA. Although I could give them answers properly, there's one unanswered question,  "How can open source software developer help the developing world?".  It is because I haven't thought of this serious question except for donating. It might be a big homework for me.

I'd like to thank my sponsors; Collabora for time, NIPA for flight and accommodation.

Monday, February 19, 2018

SRT, typical examples

Following last week's blog post announcing SRT in GStreamer, I'd like to briefly discuss another way to use an SRT stream: with VLC 3.0!

Released earlier this month, the latest version of the free & open source multimedia player (which also uses the GStreamer framework) now contains SRT modules which had been in development in VLC's master branch. Let's take a look at what VLC says.

$ vlc --list | grep srt
VLC media player 3.0.0 Vetinari (revision 3.0.0-3-g7821ebf808)
  access_output_srt      SRT stream output
  access_srt             SRT input

These modules can be seen in VLC’s preferences menu if “Show All” is checked in the preferences window.

As we can infer from the name, VLC has input/output SRT modules. The basic usage isn’t different from the case when using UDP or TCP-based stream. From Olivier's article, we got a typical example to stream via SRT, then let's create SRT stream.

gst-launch-1.0 v4l2src ! video/x-raw, height=1080, width=1920 \
    ! videoconvert ! x264enc tune=zerolatency ! video/x-h264, profile=high \
    ! mpegtsmux ! srtserversink uri=srt://:8888/


Then, now, VLC can play the SRT stream with the URL, "srt://ip_address:8888/".



Limitations

Yes, The current SRT modules in VLC is able to work as an SRT player and an SRT stream generator. However, there are some limitations because VLC released version took a part of SRT module patch set.

 - Stream Encryption

To encrypt and decrypt SRT stream, a passphrase is required. The passphrase property patches have already been merged into VLC master, but not yet released. We are looking forward that next version of VLC has this feature.

 - Connection modes

We have created 4 different elements for GStreamer, but the current VLC modules only support client mode. That means the current version of VLC can play only if an SRT stream generator runs in listener(server) mode. Supporting all modes in SRT modules of VLC would be next challenge for us.

Conclusion

Hopefully, SRT modules in VLC, also GStreamer SRT plugins will have helped you to build SRT applications. Let's discuss the details of SRT with VLC and GStreamer!

Wednesday, January 17, 2018

Windows 10을 위한 GStreamer 이미지 빌드

다른 방법: GStreamer 릴리즈 버전을 Windows 10에서 사용하는 방법

GStreamer 최신 버전은 릴리즈 버전과 다르게 새로운 기능들을 많이 포함하고 있어 기능을 테스트 해보기에는 좋으나  Windows 10에서 빌드는 생각보다 쉽지 않아 Docker를 통해 빌드 하는 방법을 포스팅합니다.

주의점:
  • 테스트 목적으로 사용할 것을 권고
  • 실행 시점의 GStreamer master 브랜치를 사용하기 때문에 항상 다른 결과물을 얻게됨

Docker 이미지 빌드


아이러니하게도 현재 가능한 방법 중 가장 쉬운 빌드 방법은 리눅스를 이용하여 크로스 컴파일 하는 것입니다. 크로스 컴파일 환경 구성부터 사용자 별로 다를 수 있기 때문에 테스트 가능한 환경을 Dockerfile로 작성해보았습니다.

  $ curl -o Dockerfile \
    https://gist.github.com/justinjoy/df218013356815ad6e3d0211458a4214
  $ docker build  -t joykim/cerbero-build .

Docker 이미지 실행


위 명령으로 생성된 Docker 이미지를 손쉽게 사용하기 위한 docker-compose.yml은 다음과 같습니다.

version: '3'
services:
  cerbero-build:
    image: joykim/cerbero-build:latest
    hostname: cerbero-build
    volumes:
      - ./work:/work

혹은 다음 명령으로 다운로드 할 수 있습니다.

  $ curl -o docker-compose.yml \
    https://gist.github.com/justinjoy/1641cd0d65f7ea285e144e3b615f3431

Docker 이미지에서 bash를 실행하여 빌드가 가능한 쉘을 실행하도록 합니다.

  $ docker-compose run cerbero-build bash

cerbero 빌드

Docker 내부에 cerbero를 가져와서 빌드를 시작합니다.
  worker@cerbero-build:~$ git clone git://anongit.freedesktop.org/gstreamer/cerbero
  worker@cerbero-build:~$ cd cerbero
  worker@cerbero-build:~/cerbero$ ./cerbero-uninstalled -c config/cross-win64.cbc bootstrap
  worker@cerbero-build:~/cerbero$ ./cerbero-uninstalled -c config/cross-win64.cbc package gstreamer-1.0

빌드가 성공적으로 끝나면, 생성된 두 파일을 Windows 10 으로 복사하여 사용할 수 있습니다.

  • gstreamer-1.0-windows-x86_64-1.13.0.1-devel.tar.bz2 (헤더와 정적 라이브러리)
  • gstreamer-1.0-windows-x86_64-1.13.0.1.tar.bz2 (동적 라이브러리)

Monday, October 9, 2017

Gstreamer Camera 2 Source for Android

I'm very happy to send a new camera source element patch to support Android Camera 2 API.  This implementation is a part of R&D work which is sponsored by Collabora, Ltd.

Not much later since the previous element, ahcsrc, has been merged into 'gst-plugins-bad', Android N announced their public native level APIs. This news brought me another R&D opportunity to implement same featured, but more stable and little bit faster element to handle Camera Devices on Android.

I named the new element as 'ahc2src' because the previous one is just 'ahcsrc' and the fundamental API is Android Camera 2 NDK API. That means JNI is no longer required to access Camera devices. To understand why 'ahc2src' is better, here's comparison chart.




ahcsrc
ahc2src
Supported Android version
> Lollipop (android-19)
> Nougat (android-24)
API
Camera API
Camera 2 NDK API
Device control
Java API through JNI
Native
Supported Image Format
YV12, YUY2, NV16, NV21, RGB16
NV12 (YUV_420_888)
Memory Copy
Java to GstBuffer
None (AImageReader inside)

Regarding memory copy, I'm not sure whether it doesn't perform inside of Android. However, ahc2src itself just passes image pointers to source pad and manage the reference counts.

How to get this new element?

Until merged and released gstreamer images which are built for Android Nougat, my personal repository will be continuously maintained to provide 'ahc2src' element. If you want to build from scratch, it might be annoying because of some issues which come from Android NDK.

See the details in the below links;

Build from Cerbero

In my personal repository, the patches are ready to build. It will fetch 'gst-plugins-bad' from here.

  $ git clone https://gitlab.collabora.com/joykim/cerbero.git
  $ git checkout wip/ahc2

Note that 'wip/ahc2' branch is potentially or frequently overwritten by forced push.

  $ ./cebero-uninstalled -c config/cross-android-nougat-arm64.cbc bootstrap
  $ ./cebero-uninstalled -c config/cross-android-nougat-arm64.cbc package gstreamer-1.0

Then, the generated SDK image should be extracted to a proper path. (e.g /Users/justin/Library/Android/gstreamer/devel/arm64)

Gstreamer Android Camera Example Application

From the point of Android application view, there's not much different from when using 'ahcsrc'. In theory, it might be enough to replace 'ahcsrc' with 'ahc2src'.

  $ git clone https://gitlab.collabora.com/joykim/gst-android-camera.git
  $ git checkout wip/ahc2

Then, you should modify 'gradle.properties' to set a proper gstreamer SDK path. (e.g, gstAndroidRoot=/Users/justin/Library/Android/gstreamer/devel)

  $ gradle installDebug

If there's no error, the example application will be installed successfully.

Enjoy your Gstreamer with Android Camera 2 source!

Saturday, February 25, 2017

Embedded Linux Conference & Open IoT Summit 2017

A couple of months ago, I was hesitating to go to somewhere in North America because it is so far, and above all, topics of the conference are little different from my official domain. However, my curiosity about new area upstaged many obstacles so I could attend this time.

It was held in Portland, Oregon. The city looks like full-grid which I've built in SimCity and very quite and not crowded place.


Gustavo Padovan from Collabora has talked Unifying Android and Mainline Kernel Graphic Stack, but unfortunately, my another interesting session was opened at the same time so I missed his session. I will check some other sessions including his session later when the recording is registered to Youtube.

As for myself, I tended to take the sessions in Open IoT Summit, especially regarding RTOS and OTA matters. A year ago, Zephyr was introduced, but now, it wants to be a LINUX for end-devices.

Another RTOS, RIOT-OS, was showed in this conference. RIOT-OS supports more architectures than Zephyr because it has developed since 2013. However, most of people in the session worried about its license. It is a free open source software under LGPL 2.1. However, due to the characteristic of industry who potentially uses RTOS, the license policy would be an unsolved problem. In the case of Zephyr, it is developing under Apache License so it is relatively less restricted for the industry.

The other outstanding topic was OTA. I could see practical demonstrations to update software with less threatened methods. The traditional strategy for updating firmware is to have doubled space as a preserved area so substantial amount of flash is wasted even after produced, but one session proved that ostree is already available for providing enterprise level service.

Most of topics were very informative so I eagerly look forward to the recordings which will be uploaded soon.

I'd like to thank my employer, Collabora,  for sponsoring my flight, accommodation, and even time.



Friday, September 18, 2015

Gstreamer Camera Source for Android

Note: This article is outdated. The source element for android camera has been merged already. 


Using Android Camera via Gstreamer is not easy. There are two unofficial implementations; one is OpenWebRTC, another is android hardware camera source which is what I’d like to introduce here.

Actually, a source element for Android Hardware Camera has been developed already in Gstreamer 0.10. However, due to license problem and the other issues which I don’t know, the latest implementation was opened recently. Almost of Gstreamer developers might want to port this work from 0.10 to 1.0, but it’s not easy to fill the time gap between them. Perhaps, it’s not about level of difficulty, but rather it is about time consuming.

To use Android Camera with Gstreamer 1.0, we need to get few patches from my personal repository because review on my proposed patches are in progress.



No one recommend building gst-plugins-bad for Android platform as it is. It requires a bit annoying tasks like setting environment variables, copying files into specific directories and typing hundreds of commands. Simply, we can use cerbero to get Gstreamer SDK image, but it’s not the scope of this article. :)

Here’s an url for pre-built SDK to make all thing simple.


This image should be extracted in a proper directory, in here, ~/Android/gstreamer I used.

$ mkdir ~/Android/gstreamer
$ cd ~/Android/gstreamer
$ tar jxvf /somewhere/gstreamer-1.0-android-armv7-1.5.90.tar.bz2

Then, GSTREAMER_ROOT_ANDROID is reuqired.

$ export GSTREAMER_ROOT_ANDROID=~/Android/gstreamer

Before compiling gst-camera-app, we need to set PATH variable with Android SDK as well as NDK. For SDK, tools and platform-tools directories should be in PATH. Regarding to NDK, the path as itself is sufficient to use ‘ndk-build’ command.

Now, we can clone gst-camera-app.


In the directory of test application, Android project properties should be updated.

$ android update project -p .

Then, this application is ready to compile by just a command, ndk-build.

$ ndk-build 

However, if you want to get debug image, use this command instead.

$ ndk-build NDK_DEBUG=1

The test application uses glimagesink element. It causes a problem with android emulator so we need a real android device to test this application. Regarding to this issue, please refer to https://bugzilla.gnome.org/show_bug.cgi?id=753905

The command, ndk-build, generates all of c objects to connect gstreamer with Java. Now, we can build Java classes and install Android package into a real device.

$ ant debug && ant installd

Or


$ ant release && ant installr


Now, enjoy the camera.


Thursday, July 23, 2015

GStreamer Dynamic Pipelines | coaxion.net – slomo's blog (Korean Translation)

본 문서는 지극히 개인적인 목적에 의해서 번역을 해본 내용이며,내용에 대한 저작권은 원저작자에게 있음을밝힙니다.

This article is a Korean translated version of this. All right reserved to original author.

Gstreamer Dynamic Pipelines


오랜 기간 동안 다루어지고 있는 또다른 Gstreamer 관련 주제 중 하나는 Application에서 어떻게 pipeline을 동적으로 구성할 수 있느냐는 것입니다.
이 내용은 pipeline을 중지 하지 않고 playing 상태에서 pipeline 내의 각 element이 재연결을 실행하는 것을 말합니다.
이러한 동작을 어떻게 할 수 있는지 설명해보도록 하겠습니다. 그렇다고 해서 여기서 기본적이거나 단순하 경우만 살펴보려고 하는 것은 아닙니다.
demuxer나 decodebin에서 state가 PLAYING으로 설정되었을때 pad를 생성하고 연결하는 방법과 같은 것은 제 예제 코드도 이야기를 하고 있습니다만, 이러한 것을 설명하는 문서들은 이미 충분히 많이 있습니다.
또한 여기의 두 예제는 몇 버그 사항 때문에 Gstreamer 1.2.3 혹은 그 이상에서만 동작이 가능합니다.


The Theory


pipeline을 동적 구성하는 것에 대해서 어려운 점은 무엇일까요? 왜 pipeline이 동작하고 있지 않을때처럼 각 element와 그 pad들을 아무때나 재연결할 수는 없는 것일까요?
여러분의 집에 있는 배수관을 하나의 예로 생각해보세요. 배수로중에 무언가를 변경하려고 한다면, 관로를 따라 아무것도 흐르지 않을 때 하는 것이 좋을 것입니다. 그렇지 않으면 큰 문제가 생기겠죠.

Pad Probes


Gstreamer는 이 문제를 pad probe를 통해서 다루고 있습니다. Pad Probe는 특정 조건을 만나면 호출되는 callback을 등록할 수 있게 되어있습니다.
이러한 조건들은 flag type으로 표현되어 있습니다.
  • GST_PAD_PROBE_TYPE_BUFFER: buffer가 도착했을 때
  • GST_PAD_PROBE_TYPE_QUERY_UPSTREAM: upstream query를 만났을 때
추가적으로 scheduling 타입과 blocking 타입을 지정할 수 있습니다.
  • GST_PAD_PROBE_TYPE_IDLE
  • GST_PAD_PROBE_TYPE_BLOCK
gst_pad_add_probe() 함수는 probe를 추가하고 id를 리턴하고 있으며, 이 id는 gst_pad_remove_probe() 함수로 probe를 제거하는데 사용할 수 있습니다.

 

The callback


probe callback은 특정 조건을 만났을 때 호출이 됩니다. callback이 호출 되었을 때 어떠한 조건이었는가, 어떠한 데이터가 있었는가는 전달된 information structure를 통해서 알 수 있습니다. 이 information structure에는 buffer, event, query 등이 들어있게 됩니다.
callback에서 얻은 데이터들은 단순히 읽을 수 있는 것 뿐이아니라, 변경하는 것도 가능합니다.
callback 안에서 무언가 작업을 완료했다면, 그에 맞는 리턴 타입으로 돌려줘야합니다.
데이터가 전달될 필요가 있다면 GST_PAD_PROBE_PASS, drop 해야하는 경우라면 GST_PAD_PROBE_DROP, 데이터를 전달하면서 probe를 제거하려면 GST_PAD_PROBE_REMOVE, 기본값으로는 GST_PAD_PROBE_OK를 사용할 수 있으며, 추후에 더 확장될 예정입니다.
callback은 임의의 thread로부터 호출 될 수 있다는 것에 주의해야합니다. 이를 호출한 thread가 main application thread라는 것을 보장하지는 않습니다.
모든 serialized event, buffer, query는 이와 관련된 streaming thread로 부터 호출 될 것입니다.
또한 callback은 여러번 호출 될 수 있다는 것을 명심해야합니다. GST_PAD_PROBE_REMOVE를 리턴하려고할때에도 다른 thread에 의해서 해당 callback이 호 출 될 수도 있습니다.

 

Blocking Types


blocking 타입에 대한 조건은 매우 흥미로운 주제입니다. blocking 타입을 사용하지 않으면 probe callback은 단순 알람의 기능으로 사용할 수 있지만, 이 글의 주제와는 맞지 않습니다.
blocking 타입으로 지정되어 호출된 probe는 pad를 block 상태로 만듭니다. 이는 probe가 제거되거나 GST_PAD_PROBE_PSS가 리턴되지 않는 한 probe 조건과 맞는 데이터가 더이상 통과하지 못한다는 것을 의미합니다. 이는 조건에 맞지 않는 데이터들은 callback을 아무런 조작없이 통과할 수 있다는 것을 의미합니다
특히 GST_PAD_PROBE_TYPE_DATA_BOTH가 지정된경우에는 데이터의 흐름이 차단되며, downstream 방향의 pad는 안전하게 재 연결작업을 할 수 있다는 의미가 됩니다. pipeline의 한 부분에 대해 연결을 재설정할 수 있기 위해서는 해당 포인트의 데이터흐름이 더이상 없다는 것을 확신할 수 있어야 합니다.

GST_PAD_PROBE_TYPE_IDLE 의 경우에는 pad가 idle이 되는 상태에서 호출 됩니다. 즉 현재 아무런 데이터가 흐르지 않는다는 것이됩니다. 이는 gst_pad_add_probe가 호출 되는 즉시 발생할 수 있고, gst_pad_add_probe를 호출한 thread로 부터 바로 불리게 됩니다. 또는 다음번에 도착하는 buffer, event, query들이 처리된 이후에 호출 될 수도 있습니다.
GST_PAD_PROBE_TYPE_BLOCK은 데이터를 전송하기 전에 pad를 block하고 호출 됩니다. 이는 pad의 기능을 pending하고 block하고 있는 동안에 buffer, event, query를 조작할 수 있는 기능을 제공합니다.

GST_PAD_PROBE_TYPE_BLOCK의 주요 기능은 현재 pending된 data를 가져올 수 있다는 것이고, GST_PAD_PROBE_TYPE_IDLE의 경우는 즉시 호출이 보장된다는 점이 주요 기능입니다. (이후 데이터가 도착하는지 여부와는 관계없이 호출됩니다) gs t_pad_add_probe를 호출한 thread로부터 직접 불리게 된다는 점이 단점이기도 합니다.
사용하는 방법에 따라서 이 두가지는 적절하게 선택되어야 합니다.
이제 예제코드를 보도록하겠습니다.

 

Example 1: Inserting & removing a filter


이 예제에서는 decodebin과 navseek element와 연결된 videosink를 이용할 것입니다. 이는 커서 키를 이용해서 지원되는 비디오 파일을 보고 seek을 수행할 수 있도록 도와줄 것입니다.
매 5초 간격으로 video effect filter가 sink 앞에 추가 되었다가 제거될 것입니다. 이 작업은 playback을 멈추거나 seek 때문에 화면이 정지하거나 하는 상황없이 진행됩니다.

 

setting up everything


main 함수에서 pipeline을 만들고 모든 부분을 연결했습니다. 그리고 GstElement::pad-added 시그널도 연결해둔뒤에 mainloop을 실행했습니다.
pad-added callback에서는 decodebin 이 생성한 첫번재 video pad를 converter와 video sink 에 연결합니다. 또한 매 5초마다 filter를 추가 혹은 제거하기 위한 timout callback을 등록했습니다.
이 시점 이후부터 pipeline은 PLAYING으로 전환되고 비디오가 출력될 것입니다.

 

The insertion/removal of the filter


timeout callback은 매우 심심한 함수 입니다. gst_pad_add_probe를 호출하여 IDLE probe를 연결하는 일밖에는 하지 않습니다. 그리고 동시 호출로 부터 보호하기 위해서 여기에 몇가지 변수를 초기화해 두었습니다.
IDLE probe를 사용한 이유는 callback이 불렸을 때 데이터에는 관심이 없고, callback이 가능하면 즉시 호출되기를 원하기 때문입니다.
이제 실질적인 filter의 추가와 제거는 probe callback에서 수행됩니다. 이부분이 사실상 우리가 관심있어하는 부분입니다.
이제 atomic operation으로 이전에 호출된적이 있는지 먼저 검사를 하고, 추가와 제거를 실행합니다. 두 가지 경우 모두, 모든 element가 각자의 pad 연결이 잘되어있고 적절한 state로 전이 되어있음을 확실히 해두어야 합니다.
또한 filter 앞쪽에 video convert를 넣어두어서 decoder의 출력물을 filter가 잘 사용할 수 있게 해주어야 합니다.
이것이 알고자하는 모든 경우였습니다. 조금 더 복잡한 경우는 gst-plugins-base에 있습니다.
주요 차이점은 BLOCK probe를 사용한 것이고, 교체를 하기 전에 EOS event를 비워 냈다(drain)는 점입니다.
filter 앞에 추가된 BLOCK probe에 의해서 EOS event가 filter에 전송되었고, 뒤쪽에 있는 다른 callback에 의해서 처리되고 있음을 알 수 있습니다.
probe 에는 EOS event가 수신될때까지 모든 데이터가 전송되며, EOS event를 수신하였을 때 filter만 제거하면 됩니다.
이렇게 하는 경우는 filter 내부에 버퍼를 가지고 있는 경우도 있기 때문입니다.
IDLE 대신에 BLOCK probe를 여기서 사용하는 이유는 잠재적으로 application의 main thread로 부터 EOS event를 받은 것처럼 되고, 이는 EOS event가 다른 probe에 도달하여 filter를 제거할 수 있을 때까지 block 되기 때문입니다.

 

Example 2: Adding & removing sinks

두번째 예제는 decodebin을 통해서 video를 재생하되, 매 3초마다 무작위로 video sink를 추가하거나 제거하는 것입니다.
이는 tee element를 통해서 video stream을 복제하는 과정이 들어있습니다.

 

Setting up everything


main 함수에서 pipline을 설정하고 모든 부분을 이미 연결해 두었습니다. 그리고 GstElement::pad-added 시그널을 decodebin에 등록하고 mainloop을 실행 합니다. 이는 이전 예제와 동일하며, 아직은 sink를 여기에 추가하지는 않았습니다.
pad-added callback 에서 decodebin과 tee element를 연결하고 첫번째 srcpad를 tee로 부터 가져옵니다. 그리고나서 첫번째 sink 에 연결합니다.
첫번째 sink는 fakesink(sync=TRUE) element로 이는 항상 사용될 것입니다.
이는 화면상에 현재 보여지는 것이 없다고 하더라도 비디오 재생은 항상 진행된다는 것을 보장해줍니다. 최종적으로 3초마다 호출되는 타이머 callback을 등록합니다.

 

Addition of sinks


timout callback 에서 random number를 발생해서 sink를 연결할지 제거할지를 결정하게 됩니다.
timeout callback을 통해 새로운 sink를 추가하는 것으로 모든 작업은 진행됩니다. 현재 데이터가 흐르고 있지 않기 때문에 pad probe 없이 main thread로 부터 이작업은 완료됩니다.
새로운 tee의 srcpad는 여기서 만들어지고, 만약 tee가 어떠한 데이터를 새로 만들어진 pad로 전송한다면 해당 데이터는 drop 될 것입니다.
새로운 sink를 추가 하기 위해서 tee에서 srcpad를 요청했고 이것을 queue, video converter, sink에 연결합니다. 그리고 모든 state를 동기화 하게 됩니 다. 여기에서 추가한 sink를 잊지 말아야 합니다.
모든 tee srcpad 뒤에 있는 queue element는 필수입니다. 만약 queue가 없다면 tee는 lockup 될 것입니다. (tee의 srcpad는 단일 thread로 부터 동작되기 때문입니다)

 

Removal of sinks

sink의 제거는 조금 복잡합니다. 데이터가 흐르고 있는 상태이기 때문에 관련된 pad를 block 해야합니다.이렇게 하기 위해서 IDLE probe를 추가하고, callback에서 unlink와 sink의 detroy를 수행하게 됩니다.

또 다시 callback이 다른 thread를 통해서 여러번 호출 되는 상황으로 부터 보호가기 위해, sink info structure를 통해 실제 제거하려고 하는 sink의 정 보를 가져오게 됩니다.
여기서 g_free를 gst_pad_add_probe의 detroy notify를 통해 전달하는 것에 주의하세요. 그리고 callback안에서 직접 memory free를 수행하면 안됩니다. 이것은 매우 필수적인 것으로 callback은 여전히 sink를 release 한 이후에도 호출될 수 있기 때문입니다. 그렇게 되면 이미 free된 영역에 접근하는 형태 가 되어버립니다.


이 내용이 동적인 pipeline 구성을 어떻게 구현할 수 있는지에 대해서 이해할 수 있도록 도움이 되었으면 좋겠습니다.

제공된 예제를 통해서 쉽게 확장할 수 있고, 실제 그리고 더 복잡한 유즈 케이스에도 적용할 수 있을 것입니다. 이러한 컨셉은 모든 경우에 있어서 동일 합니다.