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 구성을 어떻게 구현할 수 있는지에 대해서 이해할 수 있도록 도움이 되었으면 좋겠습니다.

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

Wednesday, September 10, 2014

How to connect Wired Internet on iPad without Wireless

 For few days, I was seeking a way to connect wired-network on iPad Air without wireless router. After several trials and errors, I finally found this fantastic video on Youtube. On the video, even in airplane mode, iPad works on network by wired connection.



The Materials to connect with wired network

  • Apple USB to Ethernet Adapter (Otherwise, iPad doesn't recognize what the peripheral is)
  • Apple Lightning to USB Camera Adapter (Lightning to mini USB Adapter and usb OTG cable doesn't work)
  • Powered USB Hub
Unfortunately, only Apple genuine adapters work, otherwise, iPad showed no response on its screen, or recognize the devices as USBIOdevice.

In sum up, I need $76 (to buy ethernet and usb camera adapters) for wired connection on iPad.

Friday, January 17, 2014

HOW TO ACHIEVE A STATELESS MINDSET (Korean Translation)

Original Article: HOW TO ACHIEVE A STATELESS MINDSET

주의: 역자 나름의 의역이 상당수 있으므로, 원문을 참고하시기 바랍니다.


평온한 사고방식을 추구하는 방법



그냥 이번 일, 그냥 저런 사람, 그냥 이런거, 이순간일 뿐.
매일 하얀 도화지같은 느낌으로 일하는 것을 상상하기


프로그래밍에서는 "statelessness"라고 하는 개념이 있다. 이는 각각의 요청 사항에 대해서 이전 요청 내역들과는 무관하게 새롭게 받아들인 요청으로 처리한다는 의미이다.

어떤 경우에 있어서는 이러한 방식은 매우 제한적이다. 그러나 한편으로는 수많은 요청 사항들을 처리하는 좋은 방법이 된다.

하루에 수많은 고객으로부터 엄청난 요청을 받는 사람이 바로 당신이라고 생각해보자. 수많은 요구를 하는 고객들을 전부 처리해야한다면, 미칠노릇일것이다. 이런 것들을 다 기억한다는 것 자체가 말이 되지 않는다.

이것은 우리의 삶과 비슷하다. 우리는 끊임없이 정보를 얻고, 불만을 듣고, 아이디어를 내고, 긴장감 속에서, 매일 다른 많은 해야할 것들을 다루고 있다. 이메일, 전화 통화, 문자 메시지, 인터넷 브라우징, 다른사람들과의 소통, 업무 등 이런것들을 매일 해야하고, 이 모든 것들은 우리가 나가 떨어질때까지 우리를 괴롭힌다.

그냥 이 바로 이전까지의 요청들은 잊어버렸다고 가정해보자. 그것들을 해야할 필요가 없다고, 그냥 소각된거라고.

그냥 지금 당장 그 많은 것들을 해야할 필요가 없다고 상상해보자.

이것들 모두 그냥 사라졌고, 그냥 하얀 도화지 하나뿐이라고 생각하자.

빈 도화지라면, 무슨 생각이 드는가?

가벼운 마음으로, 아무런 압박감없이, 처리할 다음 업무, 다음 사람과 할 이야기, 다음 공간으로 이동한다고 하면 무슨 생각이 드는가? 그냥 마음속에 짐이 없다고 생각한다면?

그냥 당장의 업무, 앞에 있는 사람, 하고 있던 것, 이순간이라면?

이것 밖에 없다고. 그냥 이 황량한 우주에 이것만 있단 말이다.

그러면 평온해지지 않겠는가?

이런 식이라면, 다음 순간에는 이 남은 모든 것이 있을 것이지만, 곧 또한 사라지지 않겠는가?

이것이 "stateless"이다.

그냥 이전 순간은 그것으로 놔두는 것이다. 현재의 것만 전부라고 하자. 이전의 요청사항이나 아이디어들이 당신을 괴롭히려고 한다면, 그냥 그대로 두자.

이것은 "stateless"에 대한 연습이고, 아마도 실패할 텐데, 그것도 그냥 두자.

아무것도 없었다라고 하고 그냥 다시 시작하면?

Wednesday, January 15, 2014

GREAT WORKPLACE!

 It's joyful to work in a huge manufacturer. In CES 2014, LG showed Web OS Smart TV of which I am in charge. Some colleagues said to me that the atmosphere of CES looked like that LG can upstage the competitors with Web OS. Really? Unfortunately, although I expected a handsome compliment review or article in the Internet, I got just reviews. Here's one of them. I think the review is very polite as well as dry.



 Of course, I hope my company's new and big challenge is accomplished so that my incomes also grow up. In my case, gstreamer becomes a kind of motivation to concentrate my effort into one point. I mean, I could enjoy my role in WebOS. However, the problem is one group of senior citizens in the company.

 I am very curious about their decision tree inside of their brain. Someone who can make major decision seems to conclude that the more time to hold software engineers by force, the more successful. Very thankfully, I can be one of the targets. It could be ok for me because here's Great Korea for workaholics. My puppy becomes only victim of the ridiculous decision, she is waiting for me during I am at the office.

Notwithstanding, I want to suggest one thing for my lovely old folks. Please read any article in the Internet by googling with "great workplace", there are lots of good stuffs more than you thought, your majesty.