tag:blogger.com,1999:blog-700239343735884172024-03-14T08:08:06.049+09:00Hello Library Worldyashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-70023934373588417.post-52631086145855634552022-02-20T04:43:00.011+09:002023-06-03T19:09:18.978+09:00JuliaMono and face-font-rescale-alist on Emacs<p>
I have been a happy user of <a href="https://en.wikipedia.org/wiki/Inconsolata">Inconsolata</a> font for a long time. But
since I started to use <a href="https://julialang.org/">Julia</a>,I've switched to <a href="https://juliamono.netlify.app/">JuliaMono</a> font.
Whenever I change the fonts on my Emacs, Org Mode's <a href="https://orgmode.org/org.html#Agenda-Views">Agenda Views</a> (with
<a href="https://orgmode.org/org.html#Tracking-your-habits">Habits tracker</a>) starts to break.
</p>
<p>
This is because each glyph has its own "Holizontal Advance" for the
given size, shown in the image from freetype.org:
</p>
<div class="separator" style="clear: both;"><a href="https://freetype.org/freetype2/docs/tutorial/glyph-metrics-3.svg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="253" data-original-width="388" src="https://freetype.org/freetype2/docs/tutorial/glyph-metrics-3.svg"/></a></div>
<p>
A font usually doesn't have all glyphs for all Unicode scripts, but
has only subsets of it. I use Emacs for writing code as well as
writing Japanese and English documents. Thus, I need both a good
programming font and decent Japanese fonts. But they tend to disagree
with pixel width against each font size.
</p>
<p>
Here is a list of Holizontal Advance in pixel, taken from each font for
each size. This is generated by <a href="https://gist.github.com/yashi/7f440d808539738686d26dd29aab42c6">this gist</a>.
</p>
<pre class="example" id="org52f2387">
font size: 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Inconsolata.otf
U+0061: 7 7 8 9 9 10 11 11 12 13 13 14 15 15 16 17 17 18 19 19 20
U+3042: (not found)
JetBrainsMono-Regular.ttf
U+0061: 8 9 10 10 11 12 13 14 14 15 16 17 17 19 19 20 21 22 22 23 24
U+3042: (not found)
JuliaMono-Regular.ttf
U+0061: 8 9 10 10 11 12 13 14 14 15 16 17 18 18 19 20 21 22 22 23 24
U+3042: (not found)
DejaVuSans.ttf
U+0061: 8 9 10 10 12 12 13 14 15 15 17 17 18 19 20 20 21 22 23 24 25
U+3042: (not found)
Vera.ttf
U+0061: 8 9 10 10 12 12 13 14 15 15 17 17 18 19 20 20 21 22 23 24 25
U+3042: (not found)
NotoMono-Regular.ttf
U+0061: 8 9 10 10 11 12 13 14 14 15 16 17 17 19 19 20 21 22 22 23 24
U+3042: (not found)
RobotoCondensed-Regular.ttf
U+0061: 7 7 7 8 9 9 10 11 11 12 12 14 15 15 15 16 16 17 18 19 19
U+3042: (not found)
NotoSansCJK-Regular.ttc
U+0061: 8 8 9 10 11 11 12 13 14 14 15 16 17 17 18 19 20 20 21 22 23
U+3042: 13 15 16 17 19 20 21 23 24 25 27 28 29 31 32 33 35 36 37 39 40
hiragino-kaku-gothic-pron-w3.otf
U+0061: 8 8 9 10 11 12 12 13 14 15 15 16 17 18 18 19 20 21 21 22 23
U+3042: 13 15 16 17 19 20 21 23 24 25 27 28 29 31 32 33 35 36 37 39 40
hiragino-min-pron-w3.otf
U+0061: 7 8 9 9 10 11 12 12 13 14 15 15 16 17 17 18 19 20 20 21 22
U+3042: 13 15 16 17 19 20 21 23 24 25 27 28 29 31 32 33 35 36 37 39 40
</pre>
<p>
To match font width, Emacs can scale fonts. You have to tell Emacs
which font you want to scale and how much. To do this, you set
<code>face-font-rescale-alist</code>.
</p>
<div class="org-src-container">
<pre class="src src-elisp">(<span style="color: #1c86ee;">let*</span> ((default-font <span style="color: #8b7355;">"JuliaMono-15"</span>) <span style="color: #7f7f7f;">; </span><span style="color: #7f7f7f;">or "Inconsolata-18"</span>
(scale (<span style="color: #1c86ee;">cond</span> ((string-prefix-p <span style="color: #8b7355;">"inconsolata"</span> default-font t) 1.05)
((string-prefix-p <span style="color: #8b7355;">"juliamono"</span> default-font t) 1.20)))
(spec (font-spec <span style="color: #cd6600;">:family</span> <span style="color: #8b7355;">"Hiragino Kaku Gothic ProN W3"</span>)))
(set-face-attribute 'default nil <span style="color: #cd6600;">:font</span> default-font)
(set-face-attribute 'fixed-pitch nil <span style="color: #cd6600;">:font</span> default-font)
(set-fontset-font t 'japanese-jisx0208 spec)
(set-fontset-font t 'greek (font-spec <span style="color: #cd6600;">:family</span> default-font))
(add-to-list 'face-font-rescale-alist `(<span style="color: #8b7355;">".*Hiragino.*"</span> . ,scale)))
</pre>
</div>
<p>
In the above code, I also set the default fontset for two scripts,
<code>'japanese-jisx0208</code> and <code>'greek</code>. This is because
<code>'japanese-jisx0208</code> also includes Greek script. Thus, we must explicitly
set <code>'greek</code> back to the default font.
</p>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-17868999009654249632017-01-02T02:21:00.000+09:002017-01-02T02:21:09.462+09:00OAuth2 and oauth2.el<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orgf8d2760">1. はじめに</a></li>
<li><a href="#orgf46a1b0">2. Native アプリで利用する場合の基本</a></li>
<li><a href="#org23a4ec1">3. まずは概念的に説明してみる</a>
<ul>
<li><a href="#orge66ef4c">3.1. Authorization Code を貰う</a></li>
<li><a href="#orgb043c5c">3.2. Access Token を貰う</a></li>
</ul>
</li>
<li><a href="#org455cbcc">4. COLUMN: なぜ世の中のドキュメントは、ややこしいのか?</a></li>
<li><a href="#org60e4f8a">5. こんどは oauth2.el で説明してみる</a>
<ul>
<li><a href="#org19d051c">5.1. 抽象度の高い関数だと、分りづらかった</a></li>
<li><a href="#org31c95e1">5.2. Authorization Code を貰う</a></li>
<li><a href="#org87bbc31">5.3. Access Token を貰う</a></li>
<li><a href="#org4a7e1cb">5.4. Token Structure</a></li>
<li><a href="#orgd8cb4cd">5.5. Refresh Token</a></li>
</ul>
</li>
<li><a href="#org7e7ee7a">6. Authz Server から事前に貰うもの</a></li>
<li><a href="#orgf3f4ffb">7. おわりに</a></li>
<li><a href="#orgaff8490">8. ref</a></li>
</ul>
</div>
</div>
<div id="outline-container-orgf8d2760" class="outline-2">
<h2 id="orgf8d2760"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
いろいろ調べても、なんだか複雑な OAuth2。 RFC、Google、Github などでちょっとづつ説明や言葉使い、サポートしている物が違うので、基本を理解していないと頭の中でまとまりませでした。また、OAuth2はいろいろな種類のアプリに対応しているので、OAuth2を理解していないと自分のアプリ用にどれを使えば良いのか判断すらできませんでした。
</p>
<p>
毎回使う時になると、以前にどうやって使っていたのか忘れているので、きっといつも全然理解せずに使っていたのだろうと思います。今回は RFC を読んで、少しは理解したような気がするので、将来の自分の為に書いてみようと思います。
</p>
</div>
</div>
<div id="outline-container-orgf46a1b0" class="outline-2">
<h2 id="orgf46a1b0"><span class="section-number-2">2</span> Native アプリで利用する場合の基本</h2>
<div class="outline-text-2" id="text-2">
<p>
OAuth2 を Native アプリで利用する場合、基本は2つしかない (と言いきってみる)
</p>
<ul class="org-ul">
<li>Authorization Code を貰う</li>
<li>Authorization Code を使って Access Token を貰う</li>
</ul>
<p>
Access Token さえ手に入れば、API に投げつけて使える。これだけ。たったこれだけなのに、なんで世の中こんなにややこしく書いてんだ?!?という気分です。
</p>
<p>
ちなみに、 Github の Personal access token は、その名の通り 個人用の Access Token です。なので、 Authrization Code を貰ってから Access Token を貰うという手順をふまなくても、いきなり API に投げてやることができます。とても便利なんだけど、漏れたら悪用されちゃうので、危険です。
</p>
</div>
</div>
<div id="outline-container-org23a4ec1" class="outline-2">
<h2 id="org23a4ec1"><span class="section-number-2">3</span> まずは概念的に説明してみる</h2>
<div class="outline-text-2" id="text-3">
</div><div id="outline-container-orge66ef4c" class="outline-3">
<h3 id="orge66ef4c"><span class="section-number-3">3.1</span> Authorization Code を貰う</h3>
<div class="outline-text-3" id="text-3-1">
<p>
Authorization Code (Authz Code とも書く<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>) を貰うには
</p>
<ul class="org-ul">
<li>貰う場所 (Authz Endpoint)</li>
<li>ID (Client ID)</li>
<li>使いたい場所 (Scope)</li>
</ul>
<p>
が必要。
</p>
<dl class="org-dl">
<dt>貰う場所</dt><dd><p>
Authz code を貰う場所 (Authz Endpoint) を URL で指定します。
</p>
<ul class="org-ul">
<li>Google なら <a href="https://accounts.google.com/o/oauth2/v2/auth">https://accounts.google.com/o/oauth2/v2/auth</a></li>
<li>Github なら <a href="https://github.com/login/oauth/authorize">https://github.com/login/oauth/authorize</a></li>
<li>Facebook なら <a href="https://www.facebook.com/dialog/oauth">https://www.facebook.com/dialog/oauth</a></li>
</ul>
<p>
という具合です。
</p></dd>
<dt>ID</dt><dd><p>
Client の ID を指定します。これは事前に Authz Server に Client を登録して、IDを発行してもらわなければなりません。これは OAuth2 のルールです。
</p>
<p>
App を登録する Authz Server はサービスによって異なります。
</p>
<ul class="org-ul">
<li>google なら <a href="https://console.developers.google.com/">Google API Console</a></li>
<li>github なら <a href="https://github.com/settings/profile">Profile Setting</a> の OAuth applications</li>
<li>facebook なら <a href="https://developers.facebook.com/apps/">Apps</a></li>
</ul>
<p>
という感じです。
</p></dd>
<dt>使いたい場所</dt><dd><p>
OAuth2 がステキなのは、どの部分の利用だけを許すかという Scope を決めれる部分です。
</p>
<ul class="org-ul">
<li>google なら <a href="https://developers.google.com/identity/protocols/googlescopes">https://developers.google.com/identity/protocols/googlescopes</a></li>
<li>github なら <a href="https://developer.github.com/v3/oauth/#scopes">https://developer.github.com/v3/oauth/#scopes</a></li>
<li>facebook なら <a href="https://developers.facebook.com/docs/facebook-login/permissions/">https://developers.facebook.com/docs/facebook-login/permissions/</a></li>
</ul>
<p>
が参考になります。
</p></dd>
</dl>
</div>
</div>
<div id="outline-container-orgb043c5c" class="outline-3">
<h3 id="orgb043c5c"><span class="section-number-3">3.2</span> Access Token を貰う</h3>
<div class="outline-text-3" id="text-3-2">
<p>
Authz Code を貰ったら、次は Access Token を貰います。 Access Token を貰う為に必要な情報は
</p>
<ul class="org-ul">
<li>貰う場所 (Token Endpoint)</li>
<li>ID (client id)</li>
<li>Secret (client secret)</li>
<li>Grant Type (今回は authz code)</li>
<li>Authz Code (上で貰ったやつ)</li>
</ul>
<p>
です。
</p>
<dl class="org-dl">
<dt>貰う場所</dt><dd>これは、良いですよね。 Authz Code でも貰う場所の指定がありました。どこで貰うのか分らないと、どうにもならないです。 今回は Access Token を貰うので、 Token Endpoint を指定します
<ul class="org-ul">
<li>google の場合は <a href="https://www.googleapis.com/oauth2/v4/token">https://www.googleapis.com/oauth2/v4/token</a></li>
<li>github の場合は <a href="https://github.com/login/oauth/access_token">https://github.com/login/oauth/access_token</a></li>
<li>facebook の場合は <a href="https://graph.facebook.com/oauth/access_token">https://graph.facebook.com/oauth/access_token</a></li>
<li>twitter の場合は access token に対応しておらず Client Credentials だけに対応です</li>
</ul></dd>
</dl>
<dl class="org-dl">
<dt>Client ID</dt><dd>Authz Code を貰う時と同じです</dd>
<dt>Client Secret</dt><dd>これは、今回始めて出てきました。 Client Secret は Client のパスワードみたいなもので、 Client ID と一緒に使うことで Client 自体の認証を行います。 Authz Server に Client を登録する時に ID と一緒に貰えます</dd>
<dt>Grant Type</dt><dd>今回は Authz Code を使いたいので authorization_code と指定します。</dd>
<dt>Authz Code</dt><dd>最後に先程 Authz Endpoint から貰った Authz Code を渡します。</dd>
</dl>
<p>
これで、Access Token と呼ばれる文字列を Token Endpoint から貰えます。
</p>
</div>
</div>
</div>
<div id="outline-container-org455cbcc" class="outline-2">
<h2 id="org455cbcc"><span class="section-number-2">4</span> COLUMN: なぜ世の中のドキュメントは、ややこしいのか?</h2>
<div class="outline-text-2" id="text-4">
<p>
きっとややこしいのは、 Authz Code 以外にも implicit, password credencial, client credencial とか、色んな方法があるからじゃないだろうか? しかも、まだ理解できていない最初のうちに、どれかの選択を迫られる。今回は Native App に限定したので Authz code に特化して書くことができたが、他の種類のアプリを作っている人にはまるで参考にならない文書になってしまっている。
</p>
<p>
それともう一つ、Google の oauth2 のページには、手順が 3つで書いてある。これ、ぜんぜん嘘ではない。
</p>
<ol class="org-ol">
<li>Obtain OAuth 2.0 credentials from the Google API Console.</li>
<li>Obtain an access token from the Google Authorization Server.</li>
<li>Send the access token to an API.</li>
</ol>
<p>
1番で事前の処理、2番で Access Token を貰うまでの方法、そして 3で実際の API 発行となっているので、本当に間違っていない。だけど、2番の部分が
</p>
<ul class="org-ul">
<li>2.1 authz code を貰う</li>
<li>2.2 access token を貰う</li>
</ul>
<p>
って書いてあったら、もっと簡単に理解できたような気がする。
</p>
<p>
ただ、先にも書いた通り Authz Code を使わない方法もあるので、このレイヤーでは、そう書けない。これが最初に読んだ時には分かりづらかった原因ではないだろうか?
</p>
<p>
この文書では、Google 手順の 2番について主に記載している。1番については、後半の「事前に貰うもの」で、3番については API を発行するだけの簡単な話なので割愛している。
</p>
</div>
</div>
<div id="outline-container-org60e4f8a" class="outline-2">
<h2 id="org60e4f8a"><span class="section-number-2">5</span> こんどは oauth2.el で説明してみる</h2>
<div class="outline-text-2" id="text-5">
</div><div id="outline-container-org19d051c" class="outline-3">
<h3 id="org19d051c"><span class="section-number-3">5.1</span> 抽象度の高い関数だと、分りづらかった</h3>
<div class="outline-text-3" id="text-5-1">
<p>
やっと Emacs の話。 Emacs では <code>oauth2.el</code> というパッケージが ELPA から入手可能です。このパッケージの Commentary には、こう書いてあります。
</p>
<blockquote>
<p>
The main entry point is `oauth2-auth-and-store' which will return a
token structure. This token structure can be then used with
`oauth2-url-retrieve-synchronously' or `oauth2-url-retrieve' to
retrieve any data that need OAuth authentication to be accessed.
</p>
</blockquote>
<p>
つまり、
</p>
<blockquote>
<p>
メインで使う関数は oauth2-auth-and-store で、 token structure を戻しま
す。戻ってきた token structure を oauth2-url-retrieve-synchronously や
oauth2-url-retrieve と一緒に使うことで、データーが取れますよ
</p>
</blockquote>
<p>
と。
</p>
<p>
これが、上で説明した2つの手順と繋がらなくて、自分は苦労しました。 oauth2-auth-and-store は、上記 2つの手順を一気に実施してくれて、さらに pstore に token を保存してくれる関数だと最初は理解できなかった。つまり Google 手順の 2番をまるっとやってくれる関数なんです。今思えば Google の手順とはぴったり合っているじゃないですか。
</p>
<p>
oauth2-auth-and-store は全部やってくれて、とても便利な関数になっているんだけど、初めて oauth する時は、まったく意味がわからなかった。特に code を取得し、access token を取得するという 2つの手順が見えていないと、全然使えなかった。
</p>
<div class="org-src-container">
<pre class="src src-elisp">oauth2-auth (auth-url token-url client-id client-secret <span style="color: #8cc4ff;">&optional</span> scope state redirect-uri)
</pre>
</div>
<p>
関数も、↑ずらーっと引数が並んでいるので、なにをどこに指定すれば良いのか、最初はまるで分かりませんでした。 ここまで読んで OAuth2 を理解できていれば、全然簡単なのですが…。
</p>
<dl class="org-dl">
<dt>auth-url</dt><dd>Authz Endpoint</dd>
<dt>token-url</dt><dd>Token Endpoint</dd>
<dt>client-id</dt><dd>Client ID</dd>
<dt>client-secret</dt><dd>Client Secret</dd>
</dl>
<p>
と、ここまでが必須
</p>
<dl class="org-dl">
<dt>scope</dt><dd>ほぼ必須じゃないのかな。サービスの中でアクセスできる部分を指定するもの。今回は blogger サービスへのアクセスを例にしているので …. を指定する</dd>
<dt>state</dt><dd>今回は、使っていない。client の実装で、どこからコールしたのか分るようにするための文字列らしい。redirect されてくるときに、そのまま返してくれるらしい</dd>
<dt>redirect-uri</dt><dd>今回は、使っていない。そのうち <a href="http://localhost%3Aport">http://localhost:port</a> に対応したい</dd>
</dl>
<p>
一度 OAuth2 を理解してしまえば、とても簡単なのですが。自分には抽象度が高すぎだったのと RFC や Google のドキュメントとのずれによって、理解するのに苦しみました。
</p>
</div>
</div>
<div id="outline-container-org31c95e1" class="outline-3">
<h3 id="org31c95e1"><span class="section-number-3">5.2</span> Authorization Code を貰う</h3>
<div class="outline-text-3" id="text-5-2">
<p>
oauth2.el で Authz Code を貰う関数は、 <code>oauth2-request-authorization</code> です。
</p>
<div class="org-src-container">
<pre class="src src-elisp">oauth2-request-authorization (auth-url client-id <span style="color: #8cc4ff;">&optional</span> scope state redirect-uri)
</pre>
</div>
<dl class="org-dl">
<dt>auth-url</dt><dd>Authz Endpoint</dd>
<dt>client-id</dt><dd>Client ID</dd>
<dt>scope</dt><dd>スコープ</dd>
</dl>
<p>
という感じに、変数の名前の通りで、先の説明と一対一に整合が取れます。この関数を実行すると、 <code>"4/mMf2ADq_XXXXXXXXXXXXXXXXXXXXXX"</code> といった文字列を貰えます。これが Authz Code です。
</p>
</div>
</div>
<div id="outline-container-org87bbc31" class="outline-3">
<h3 id="org87bbc31"><span class="section-number-3">5.3</span> Access Token を貰う</h3>
<div class="outline-text-3" id="text-5-3">
<p>
oauth2.el で Access Token を貰う関数は <code>oauth2-make-access-request</code> です。
</p>
<div class="org-src-container">
<pre class="src src-elisp">oauth2-make-access-request (url data)
</pre>
</div>
<dl class="org-dl">
<dt>url</dt><dd>Token Endpoint</dd>
<dt>data</dt><dd>POST で投げる時に body に入れる文字列</dd>
</dl>
<p>
この関数を実行すると <code>Content-Type: application/x-www-form-urlencoded</code> で POST してくれて、alist で情報が戻ってくるようになっています。
</p>
<p>
data と書いてありますが、中身は URL で使うような文字列を指定します。
</p>
<ul class="org-ul">
<li><code>client_id=</code> に、Authz Server から貰った Client ID を繋いで</li>
<li><code>client_secret=</code> にも、 Authz Server から貰った Client Secret を指定します</li>
<li><code>gran_type=authorization_code</code> は、上でも説明した通り code を使っているので、この通りしてします</li>
<li><code>code=</code> には <code>oauth2-request-authorization</code> で、貰った文字列を追記</li>
</ul>
<p>
という感じで、こちらも先の説明と一対一に紐付けることができます。
</p>
</div>
</div>
<div id="outline-container-org4a7e1cb" class="outline-3">
<h3 id="org4a7e1cb"><span class="section-number-3">5.4</span> Token Structure</h3>
<div class="outline-text-3" id="text-5-4">
<p>
RFC でも <code>token</code> が出てきますが oauth2.el でも <code>token structure</code> なるものが出てきます。これ、なんのことはない、 Access Token や Token Endpoint などをまとめてくれている structure です。
</p>
<p>
<code>defstruct oauth2-token</code> しているので <code>make-oauth2-token</code> という コンストラクターが定義されていて、 <code>oauth2-request-access</code> の中で使われていたり <code>oauth2-token-client-id</code> や <code>oauth2-token-client-secret</code> というアクセッサーも自動で定義されてます。
</p>
</div>
</div>
<div id="outline-container-orgd8cb4cd" class="outline-3">
<h3 id="orgd8cb4cd"><span class="section-number-3">5.5</span> Refresh Token</h3>
<div class="outline-text-3" id="text-5-5">
<p>
Access Token を取得するまでに話を絞っていたので、 Refresh Token の話をしていませんでした。 Access Token を貰うときに、一緒に Refresh Token なるものも貰えます。これ、Access Token が expire した時にもう一度 Access Token を貰うための Token です。
</p>
<p>
Refresh Token を使って Access Token を貰うのは、最初に Access Token を 貰う Endpoint と同じ Token Endpoint で貰えます。 <code>grant_type</code> を <code>code</code> から <code>refresh_token</code> に変更します。
</p>
<p>
oauth2.el では自動で refresh してくれるようになっているので、気にしなくても問題ありません。
</p>
</div>
</div>
</div>
<div id="outline-container-org7e7ee7a" class="outline-2">
<h2 id="org7e7ee7a"><span class="section-number-2">6</span> Authz Server から事前に貰うもの</h2>
<div class="outline-text-2" id="text-6">
<p>
Client ID も Client Secret も Authz Server から先に貰わないといけません。 先に Authz Server に Client を登録しないと ID すら発行してもらえないというのは OAuth2 の約束事です。Google 手順の一番目について簡単に説明しておきます。
</p>
<p>
Google の場合は Google API Console の Credentials から create credentials → OAuth client ID を選択します。 Application type を選択させられるので、作成しているアプリに合わせて適切なものを選ぶ必要があります。 Native アプリケーション や Emacs から使う場合には other を選べば良いです。名前を付けて、作成完了です。
</p>
<p>
Github の場合は Personal Setting の中の Developer settings の下に OAuth applications があります。ここで、Register a new application を押せば OK です。 Authorization callback URL は、ちゃんと設定してあげないと動作しなくなるので注意してください。他は、まぁ、適当でもなんとかなるはずです。
</p>
<p>
どちらもスクリーンショットを付けた方が分りやすくて良いと思いますが、サイトの見た目が変ると使えなくなるので、やめておきます。 OAuth2 について調べている時、古いスクリーンショットが数多く出てきて、まるで役に立たなかったので。 Client ID と Client Secret が必要で OAuth の Client を API Console で登録/作成する必要があると理解できていれば、 Google API Console の使い方は難しくないはずです。逆に Google API Console でなにをすれば良いのか理解していないと、スクリーンショットの通りにしか作業しかできず、ちょっと Google API Console の UI が変更になっただけで、このページ自体が無意味な物になってしまうと思います。
</p>
<p>
ところで、OAuth2 の client_id は OAuth1 では consumer key と呼ばれていました。まだ、たまに OAuth2 と言いながら consumer key と書かれている場所もあるようです。
</p>
</div>
</div>
<div id="outline-container-orgf3f4ffb" class="outline-2">
<h2 id="orgf3f4ffb"><span class="section-number-2">7</span> おわりに</h2>
<div class="outline-text-2" id="text-7">
<p>
Clinet ID や Client Secret がないと Access Token が貰えないのはこの文章を読んでもらえれば分ると思います。
</p>
<p>
ところが、<a href="https://developers.google.com/terms/#b-confidential-matters">Google では Open Source のアプリには Client ID や Client Secret を入れてはいけない</a>と記載されています。つまり、Open Source Application のユーザーは、みんな Client ID と Client Secret を自分で取得しないといけないということです。なぜでしょう?
</p>
<p>
Client ID と Client Secret は Client / Application を特定するために使う ID とパスワードみたいなものというのは先にも説明した通りです。そのため、Open Source のように簡単にソースを読めてしまう場合には、悪い人に ID と Secret を取られてしまう <b>可能性が高い</b> からというのが Google 側の理由です。 もちろんバイナリー配布のアプリから ID や Secret を抜き出すことも多分可能です。しかし、ソースコードから抜き出すよりは敷居が高いと Google は判断しているようです。ID が悪用されて困るのは Client / Application の開発者なので、開発者自身を守るためにも ID や Secret をコード内に入れないで欲しいということでしょう。
</p>
<p>
この問題を解決するために OAuth 2.0 Dynamic Client Registration という RFC も進んでいるので、期待しています。
</p>
<p>
Github の personal access token は、使い方を間違えば危険だが、 API を使わせるという意味では Open Source Application User にも便利なような気がしますね。
</p>
</div>
</div>
<div id="outline-container-orgaff8490" class="outline-2">
<h2 id="orgaff8490"><span class="section-number-2">8</span> ref</h2>
<div class="outline-text-2" id="text-8">
<ul class="org-ul">
<li><a href="https://tools.ietf.org/html/rfc6749">RFC 6749</a></li>
<li><a href="https://developers.google.com/identity/protocols/OAuth2InstalledApp">Using OAuth 2.0 for Mobile and Desktop Applications</a></li>
<li><a href="http://stackoverflow.com/questions/27585412/can-i-really-not-ship-open-source-with-client-id">client_id と client_secret は、 open source では embed できない</a></li>
<li><a href="https://github.com/emacsmirror/oauth2/blob/master/oauth2.el">oauth2.el</a>
<ul class="org-ul">
<li>two main function
<ul class="org-ul">
<li>oauth2-request-authorization => authorization code</li>
<li>oauth2-make-access-request => access token</li>
</ul></li>
<li>Those functions are wrapped
<ul class="org-ul">
<li>oauth2-auth
<ul class="org-ul">
<li>oauth2-request-authorization => authorization code</li>
<li>oauth2-request-access => token struct
<ul class="org-ul">
<li>oauth2-make-access-request => access token</li>
<li>make-oauth2-token => token struct
<ul class="org-ul">
<li>access-token</li>
<li>refresh-token</li>
<li>access-response (raw response)</li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">
<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1">1</a></sup> <div class="footpara">authentification の authn と区別するんだよ</div></div>
</div>
</div>yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-212707956993750032016-12-29T21:58:00.001+09:002016-12-30T17:38:03.756+09:00GStreamer でプログラミング 8 (Log)<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orge9769ee">1. はじめに</a></li>
<li><a href="#orgd64bc13">2. すべてのログは <code>gst_debug_log()</code> に通ず</a></li>
<li><a href="#orgc6bd1e6">3. 便利なマクロ達</a></li>
<li><a href="#org74db4a2">4. カテゴリーの作り方</a></li>
<li><a href="#org91c5ad0">5. おわりに</a></li>
</ul>
</div>
</div>
<div id="outline-container-orge9769ee" class="outline-2">
<h2 id="orge9769ee"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
デバッグは、プログラムを書く上で避けては通れない作業の1つです。今回は、デバッグ時に役に立つ logger についてです。
</p>
</div>
</div>
<div id="outline-container-orgd64bc13" class="outline-2">
<h2 id="orgd64bc13"><span class="section-number-2">2</span> すべてのログは <code>gst_debug_log()</code> に通ず</h2>
<div class="outline-text-2" id="text-2">
<p>
GStreamer のログは、どのマクロを使っても最終的には <code>gst_debug_log()</code> に展開されます。なので、この関数が使えるようになればどのマクロでも使いこなせます。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_debug_log</span> (<span style="color: #228b22;">GstDebugCategory</span> *<span style="color: #a0522d;">category</span>,
<span style="color: #228b22;">GstDebugLevel</span> <span style="color: #a0522d;">level</span>,
<span style="color: #a020f0;">const</span> <span style="color: #228b22;">gchar</span> *<span style="color: #a0522d;">file</span>,
<span style="color: #a020f0;">const</span> <span style="color: #228b22;">gchar</span> *<span style="color: #a0522d;">function</span>,
<span style="color: #228b22;">gint</span> <span style="color: #a0522d;">line</span>,
<span style="color: #228b22;">GObject</span> *<span style="color: #a0522d;">object</span>,
<span style="color: #a020f0;">const</span> <span style="color: #228b22;">gchar</span> *<span style="color: #a0522d;">format</span>,
...);
</pre>
</div>
<dl class="org-dl">
<dt><code>category</code></dt><dd><p>
カテゴリーと呼ばれる、ログの種別を指定します。エレメントや、エレメントで使われるライブラリーなどは、小文字を使ったカテゴリー名を使います。例えば <code>pipeline</code> 、 <code>bus</code> 、 <code>bin</code> 、 <code>basesink</code> 、 <code>basesrc</code> 、 <code>videotestsrc</code> など、エレメントの名前がそのまま使われている事が多いです。
</p>
<p>
逆に GStreamer のコアは、 <code>GST_</code> で始まるカテゴリー名を使っています。 <code>GST_STATES</code> 、 <code>GST_CLOCK</code> 、 <code>GST_PADS</code> 、 <code>GST_BUS</code> など抽象的な概念、 <code>GST_INIT</code> や <code>GST_MEMORY</code> <code>、GST_PLUGIN_LOADING</code> 、 <code>GST_REGISTRY</code> などコア機能部分などです。
</p>
<p>
自分でアプリを作成する場合には、自分のアプリのカテゴリーを作るとログを分別するのに便利です。これについては後ほど
</p>
<p>
特に指定がなければ <code>GST_CAT_DEFAULT</code> を使います。こちらも後ほど詳しく説明します
</p></dd>
<dt><code>level</code></dt><dd><p>
severity と呼ばれる「ヤバイ度」を表すレベルを指定します。重度の方から
</p>
<ul class="org-ul">
<li><code>GST_LEVEL_ERROR</code></li>
<li><code>GST_LEVEL_WARNING</code></li>
<li><code>GST_LEVEL_FIXME</code></li>
<li><code>GST_LEVEL_INFO</code></li>
<li><code>GST_LEVEL_DEBUG</code></li>
<li><code>GST_LEVEL_LOG</code></li>
<li><code>GST_LEVEL_TRACE</code></li>
<li><code>GST_LEVEL_MEMDUMP</code></li>
</ul>
<p>
となっています。 <code>ERROR</code> から順に 1, 2, 3… と番号でも表わすことができます。 <code>TRACE</code> が 7 で、8 が バージョン 1.10.0 現在では定義されておらず、 <code>MEMDUMP</code> は 9 です
</p></dd>
<dt><code>file</code> / <code>function</code> / <code>line</code></dt><dd>ファイル名、関数名、行番号を指定します。 <code>gst_debug_log()</code> を直接呼び出すことは、実際のコードではあまりなく、それぞれ <code>__FILE__</code> <code>__fun__</code> <code>__LINE__</code> がマクロで指定されます。 <code>gst_debug_log()</code> を直接呼ぶなら嘘を書くこともできます</dd>
<dt><code>object</code></dt><dd><code>GObject</code> から派生したオジェクトを渡すことができます。 <code>gst_debug_print_object()</code> を使ってオジェクトを綺麗に print してくれます</dd>
<dt><code>format</code> / …</dt><dd><code>printf()</code> と同じく format に続いて引数を列べます</dd>
</dl>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
gst_init(&argc, &argv);
gst_debug_log(GST_CAT_DEFAULT,
GST_LEVEL_ERROR,
<span style="color: #8b2252;">"debuglog.c"</span>,
<span style="color: #8b2252;">"main"</span>,
10,
<span style="color: #008b8b;">NULL</span>,
<span style="color: #8b2252;">"hello from gst_debug_log!"</span>);
GST_CAT_LEVEL_LOG(GST_CAT_DEFAULT,
GST_LEVEL_ERROR,
<span style="color: #008b8b;">NULL</span>,
<span style="color: #8b2252;">"this should be similer to the line above"</span>);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<pre class="example">
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-1.0) debuglog.c
$ ./a.out
$ ./a.out --gst-debug 1
0:00:00.012686366 29952 0x56142d48fe90 ERROR default debuglog.c:10:main: hello from gst_debug_log!
0:00:00.012716649 29952 0x56142d48fe90 ERROR default debuglog.c:18:main: this should be similer to the line above
$ ./a.out --gst-debug ERROR
0:00:00.016021714 29979 0x55f65aae9e90 ERROR default debuglog.c:10:main: hello from gst_debug_log!
0:00:00.016052525 29979 0x55f65aae9e90 ERROR default debuglog.c:18:main: this should be similer to the line above
$ ./a.out --gst-debug default:6
0:00:00.000672566 30012 0x560b988048f0 DEBUG default gstelement.c:194:gst_element_setup_thread_pool: creating element thread pool
0:00:00.022098288 30012 0x560b988048f0 DEBUG default gsttracerutils.c:78:_priv_gst_tracing_init: Initializing GstTracer
0:00:00.022144095 30012 0x560b988048f0 ERROR default debuglog.c:10:main: hello from gst_debug_log!
0:00:00.022150816 30012 0x560b988048f0 ERROR default debuglog.c:18:main: this should be similer to the line above
</pre>
<p>
<code>gst-launch-1.0</code> ではなく、自作のアプリでも <code>gst_init()</code> をしていると、上記のように <code>--gst-debug</code> が使えます。説明のために <code>GST_LEVEL_ERROR</code> を使っています。 <code>GST_LEVEL_ERROR</code> は 1 と等価なので <code>--gst-debug 1</code> と指定しても <code>--gst-debug ERROR</code> と指定しても同じ結果になります。
</p>
<p>
<code>--gst-debug</code> の代りに、環境変数 <code>GST_DEBUG</code> でも同じように指定できます。
</p>
<p>
<code>--gst-debug</code> のフォーマットは、 「カテゴリー : レベル」と指定します。サンプルコードで、カテゴリーが <code>"default"</code> の ERROR だけを表示したい場合は <code>default:1</code> 、または <code>default:ERROR</code> と指定します。 <code>LOG</code> (6) や <code>DEBUG</code> (5) まで表示したい場合は <code>default:6</code> と指定します。 <code>gstelement.c</code> や <code>gsttracerutils.c</code> にも <code>default</code> カテゴリーを使っているものがあるのが分ります。
</p>
</div>
</div>
<div id="outline-container-orgc6bd1e6" class="outline-2">
<h2 id="orgc6bd1e6"><span class="section-number-2">3</span> 便利なマクロ達</h2>
<div class="outline-text-2" id="text-3">
<p>
実際にコードを書いている時には <code>gst_debug_log()</code> は面倒なので使いません。もっと簡単に使える以下のマクロを使います。
</p>
<ul class="org-ul">
<li><code>GST_ERROR()</code></li>
<li><code>GST_WARNING()</code></li>
<li><code>GST_INFO()</code></li>
<li><code>GST_DEBUG()</code></li>
<li><code>GST_LOG()</code></li>
<li><code>GST_FIXME()</code></li>
<li><code>GST_TRACE()</code></li>
</ul>
<p>
それぞれ、suffix になっているレベルでログを表示してくれます。カテゴリーは <code>GST_CAT_DEFAULT</code> です。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
gst_init(&argc, &argv);
GST_ERROR(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">1</span>
GST_WARNING(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">2</span>
GST_INFO(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">3</span>
GST_DEBUG(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">4</span>
GST_LOG(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">5</span>
GST_FIXME(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">6</span>
GST_TRACE(<span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">7</span>
GST_CAT_ERROR(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">1</span>
GST_CAT_WARNING(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">2</span>
GST_CAT_INFO(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">3</span>
GST_CAT_DEBUG(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">4</span>
GST_CAT_LOG(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">5</span>
GST_CAT_FIXME(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">6</span>
GST_CAT_TRACE(GST_CAT_DEFAULT, <span style="color: #8b2252;">"foo"</span>); <span style="color: #b22222;">// </span><span style="color: #b22222;">7</span>
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
つまり、上と下のマクロは同じ意味になります。上の方がカテゴリーを省略して書けるので便利ですね。GStreamer の本体でも良く使われているマクロの1つです。
</p>
<pre class="example">
$ ./a.out --gst-debug default:6
0:00:00.000326411 31064 0x55e3cd8a38f0 DEBUG default gstelement.c:194:gst_element_setup_thread_pool: creating element thread pool
0:00:00.012841797 31064 0x55e3cd8a38f0 DEBUG default gsttracerutils.c:78:_priv_gst_tracing_init: Initializing GstTracer
0:00:00.012881297 31064 0x55e3cd8a38f0 ERROR default log.c:12:main: foo
0:00:00.012886168 31064 0x55e3cd8a38f0 WARN default log.c:13:main: foo
0:00:00.012890248 31064 0x55e3cd8a38f0 INFO default log.c:14:main: foo
0:00:00.012893221 31064 0x55e3cd8a38f0 DEBUG default log.c:15:main: foo
0:00:00.012898387 31064 0x55e3cd8a38f0 LOG default log.c:16:main: foo
0:00:00.012901336 31064 0x55e3cd8a38f0 FIXME default log.c:17:main: foo
0:00:00.012904926 31064 0x55e3cd8a38f0 ERROR default log.c:20:main: foo
0:00:00.012909571 31064 0x55e3cd8a38f0 WARN default log.c:21:main: foo
0:00:00.012913609 31064 0x55e3cd8a38f0 INFO default log.c:22:main: foo
0:00:00.012917039 31064 0x55e3cd8a38f0 DEBUG default log.c:23:main: foo
0:00:00.012919887 31064 0x55e3cd8a38f0 LOG default log.c:24:main: foo
0:00:00.012923130 31064 0x55e3cd8a38f0 FIXME default log.c:25:main: foo
</pre>
<p>
<code>:6</code> を <code>:5</code> や <code>:3</code> に変更すると表示されるものが変るので、試してみてください。
</p>
</div>
</div>
<div id="outline-container-org74db4a2" class="outline-2">
<h2 id="org74db4a2"><span class="section-number-2">4</span> カテゴリーの作り方</h2>
<div class="outline-text-2" id="text-4">
<p>
さて、今回の本題である「自分用のカテゴリーの作り方」に入ります。
</p>
<p>
作り方は簡単で、 <code>GstDebugCategory</code> を1つ作るだけです。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
<span style="color: #228b22;">GstDebugCategory</span> *<span style="color: #a0522d;">cat</span>;
gst_init(&argc, &argv);
cat = _gst_debug_category_new(<span style="color: #8b2252;">"my category"</span>, 0, <span style="color: #8b2252;">"This is my category"</span>);
GST_CAT_ERROR(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_WARNING(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_INFO(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_DEBUG(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_LOG(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_FIXME(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_TRACE(cat, <span style="color: #8b2252;">"foo"</span>);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
ただ、これだと <code>main()</code> の中でしか使えないので、大体はファイルグローバルの変数として宣言してしまいます。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstDebugCategory</span> *<span style="color: #a0522d;">cat</span>;
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
gst_init(&argc, &argv);
cat = _gst_debug_category_new(<span style="color: #8b2252;">"my category"</span>, 0, <span style="color: #8b2252;">"This is my category"</span>);
GST_CAT_ERROR(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_WARNING(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_INFO(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_DEBUG(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_LOG(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_FIXME(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_TRACE(cat, <span style="color: #8b2252;">"foo"</span>);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
これを <code>GST_DEBUG_CATEGORY_STATIC</code> と <code>GST_DEBUG_CATEGORY_INIT</code> というマクロで書くと
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
GST_DEBUG_CATEGORY_STATIC(cat);
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
gst_init(&argc, &argv);
GST_DEBUG_CATEGORY_INIT (cat, <span style="color: #8b2252;">"my category"</span>, 0, <span style="color: #8b2252;">"This is my category"</span>);
GST_CAT_ERROR(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_WARNING(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_INFO(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_DEBUG(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_LOG(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_FIXME(cat, <span style="color: #8b2252;">"foo"</span>);
GST_CAT_TRACE(cat, <span style="color: #8b2252;">"foo"</span>);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
となります。 <code>_gst_debug_category_new()</code> がアンダーバー <code>_</code> で始まっていることからも、これはマクロから使われる為だけで公開関数ではないことが分ります。
</p>
<p>
さらにカテゴリーをわざわざ指定するの面倒なので、 自分のカテゴリーを GST_CAT_DEFAULT に define してしまいます。これで、やっと <a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstInfo.html#gstreamer-GstInfo.description">GstInfo の説明に書いてあるコード</a> と同じになりました。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
GST_DEBUG_CATEGORY_STATIC(cat);
<span style="color: #483d8b;">#define</span> <span style="color: #a0522d;">GST_CAT_DEFAULT</span> cat
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
gst_init(&argc, &argv);
GST_DEBUG_CATEGORY_INIT (cat, <span style="color: #8b2252;">"my category"</span>, 0, <span style="color: #8b2252;">"This is my category"</span>);
GST_ERROR(<span style="color: #8b2252;">"foo"</span>);
GST_WARNING(<span style="color: #8b2252;">"foo"</span>);
GST_INFO(<span style="color: #8b2252;">"foo"</span>);
GST_DEBUG(<span style="color: #8b2252;">"foo"</span>);
GST_LOG(<span style="color: #8b2252;">"foo"</span>);
GST_FIXME(<span style="color: #8b2252;">"foo"</span>);
GST_TRACE(<span style="color: #8b2252;">"foo"</span>);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
すると、こんな風に使えるようになります。
</p>
<pre class="example">
$ ./a.out --gst-debug "my category":6
0:00:00.012787531 30961 0x557846935e90 ERROR my category mycat.c:12:main: foo
0:00:00.012817629 30961 0x557846935e90 WARN my category mycat.c:13:main: foo
0:00:00.012826697 30961 0x557846935e90 INFO my category mycat.c:14:main: foo
0:00:00.012833958 30961 0x557846935e90 DEBUG my category mycat.c:15:main: foo
0:00:00.012839721 30961 0x557846935e90 LOG my category mycat.c:16:main: foo
0:00:00.012846188 30961 0x557846935e90 FIXME my category mycat.c:17:main: foo
</pre>
<p>
<code>"my category"</code> にはスペースが入っているので、「"」で括るのを忘れずに。
</p>
</div>
</div>
<div id="outline-container-org91c5ad0" class="outline-2">
<h2 id="org91c5ad0"><span class="section-number-2">5</span> おわりに</h2>
<div class="outline-text-2" id="text-5">
<p>
アプリを書く時も、エレメントを作成する時も、とりあえずボイラープレートとして自分のカテゴリーを登録してしまうと、後からのデバッグが楽になります。 <code>--gst-debug</code> には複数のカテゴリーを列べることもできますし、ワイルドカード「*」での指定も可能です。自分のプログラム内で、複数のカテゴリーを登録する時に決まった形の prefix を使えば
</p>
<pre class="example">
--gst-debug "myapp_*:6"
</pre>
<p>
という感じでカテゴリーを選択できるので便利です。
</p>
<p>
ところで、 <code>GST_CAT_DEFAULT</code> の妙に気付いた人はいたでしょうか? 元々あった default のカテゴリーも <code>GST_CAT_DEFAULT</code> ですし、自分で define したのも <code>GST_CAT_DEFAULT</code> です。これ、考えてみると二重定義にならないのって変じゃないです?
</p>
<p>
答は、もちろんソースにあります。 <code>gstinfo.h</code> の <a href="https://cgit.freedesktop.org/gstreamer/gstreamer/tree/gst/gstinfo.h?h=1.10#n536">550行目あたり</a>に
</p>
<div class="org-src-container">
<pre class="src src-C">GST_EXPORT <span style="color: #228b22;">GstDebugCategory</span> * <span style="color: #a0522d;">GST_CAT_DEFAULT</span>;
</pre>
</div>
<p>
って書いてあるはずです。そうです、自分で define していない <code>GST_CAT_DEFAULT</code> は、実は大文字の変数名なんですね。
</p>
<p>
C では、すでに宣言されている変数名と同じ名前で define することは許されています。 define すると、そちらの方がプリプロセッサーで先に処理されて 自分で作成した <code>GstDebugCategory</code> の変数に置き換わります。
</p>
<p>
define していない場合は、GStreamer が用意している変数がそのまま使われるという仕組みです。良く考えられてますねー。
</p>
<p>
分りました? もし分からなかっったらもう一度、 <code>gstinfo.h</code> と上のサンプルコードをじーっと眺めてみてください。
</p>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-13204251507972882972016-12-28T12:57:00.001+09:002016-12-30T17:38:03.745+09:00GStreamer でプログラミング 7 (Adapter)<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org990ae38">1. はじめに</a></li>
<li><a href="#orgbebc6ea">2. Adapt してくれる物</a></li>
<li><a href="#org0729b6c">3. Take vs Get</a></li>
<li><a href="#orgabf6e99">4. map / unmap</a></li>
<li><a href="#orgf232004">5. おわりに</a></li>
</ul>
</div>
</div>
<div id="outline-container-org990ae38" class="outline-2">
<h2 id="org990ae38"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
<code>GstBuffer</code> が完結している場合は良いのですが、Parser を通す前だと、必要以上のデーターが入っていたり、逆に全然データーが足りない場合があります。そんな時に活躍するのが <code>GstAdapter</code> です。今回は、このクラスを覗いてみましょう。
</p>
</div>
</div>
<div id="outline-container-orgbebc6ea" class="outline-2">
<h2 id="orgbebc6ea"><span class="section-number-2">2</span> Adapt してくれる物</h2>
<div class="outline-text-2" id="text-2">
<p>
Adapter は、「Adapt する物」という意味です。 <code>GstBuffer</code> を Adapt する、つまり要求に「合わせて」くれるクラスです。ここで言う <code>GstBuffer</code> への要求とは、大きさ/サイズの変更です。
</p>
<p>
四の五の言わずに、さっそくサンプルコードを見てみましょう。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/base/gstadapter.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
<span style="color: #228b22;">GstAdapter</span> *<span style="color: #a0522d;">a</span>;
<span style="color: #228b22;">GstBuffer</span> *<span style="color: #a0522d;">b</span>;
gst_init(&argc, &argv);
a = gst_adapter_new();
b = gst_buffer_new_allocate(<span style="color: #008b8b;">NULL</span>, 10, <span style="color: #008b8b;">NULL</span>);
gst_adapter_push(a, b);
b = gst_buffer_new_allocate(<span style="color: #008b8b;">NULL</span>, 5, <span style="color: #008b8b;">NULL</span>);
gst_adapter_push(a, b);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
b = gst_adapter_take_buffer(a, 2);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">", buffer: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>,
gst_adapter_available(a),
gst_buffer_get_size(b));
gst_adapter_flush(a, 3);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
gst_adapter_clear(a);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<pre class="example">
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-base-1.0) a.c
$ ./a.out
size: 15
size: 13, buffer: 2
size: 10
size: 0
</pre>
<p>
<code>GstAdapter</code> には <code>gst_adapter_push()</code> することで、バッファーを入れることができます。 <code>GstBuffer</code> に入っているバッファーの総バイト数を <code>gst_adapter_available()</code> することで取得できます。
</p>
<p>
入れたバッファーを取り出すには、 <code>gst_adapter_take_buffer()</code> が便利です。 指定したバイト数入った <code>GstBuffer</code> が貰えます。
</p>
<p>
他にも、 <code>GstAdapter</code> の先頭から指定バイト数捨てる (flushする) <code>gst_adapter_flush()</code> や、中に入っているすべてのデーターを捨ててしまう、 <code>gst_adapter_clear()</code> があります。このあたりは、リファレンスマニュアルにも詳しく書いてあるので参考にしてください。
</p>
</div>
</div>
<div id="outline-container-org0729b6c" class="outline-2">
<h2 id="org0729b6c"><span class="section-number-2">3</span> Take vs Get</h2>
<div class="outline-text-2" id="text-3">
<p>
<code>GstAdapter</code> には take 系の関数群と get 系の関数群があります。
</p>
<ul class="org-ul">
<li>take 系
<ul class="org-ul">
<li><code>gst_adapter_take()</code></li>
<li><code>gst_adapter_take_buffer()</code></li>
<li><code>gst_adapter_take_buffer_fast()</code></li>
<li><code>gst_adapter_take_list()</code></li>
<li><code>gst_adapter_take_buffer_list()</code></li>
</ul></li>
<li>get 系
<ul class="org-ul">
<li><code>gst_adapter_get_buffer()</code></li>
<li><code>gst_adapter_get_buffer_fast()</code></li>
<li><code>gst_adapter_get_list()</code></li>
<li><code>gst_adapter_get_buffer_list()</code></li>
</ul></li>
</ul>
<p>
take でも get でも同じような意味なので、英語に慣れていないと、どっちがどっちなのか分らなくなりそうです。 英語では take の方が若干「奪う」意味が入ります。でも、オブジェクト指向で書いている時に getter として良く使うのは名前の通り get じゃないでしょうか?
</p>
<p>
<code>GstAdapter</code> のメソッドでは、
</p>
<dl class="org-dl">
<dt><code>take()</code></dt><dd>実際にデーターを Adapter から抜きとる</dd>
<dt><code>get()</code></dt><dd>実データーは Adapter に残したまま</dd>
</dl>
<p>
になります。そうすると <code>get()</code> した時には、何が帰ってくるのかというと、 <code>GstAdapter</code> 内にあるデーターのコピーです。実装上は、 戻ってくる <code>GstBuffer</code> と <code>GstAdapter</code> 内にある <code>GstMemory</code> がシェアーされている状態になります。または、 <code>take()</code> の方は <code>get()</code> した後に <code>flush()</code> していると考えても良いかもしれません。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/base/gstadapter.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
<span style="color: #228b22;">GstAdapter</span> *<span style="color: #a0522d;">a</span>;
<span style="color: #228b22;">GstBuffer</span> *<span style="color: #a0522d;">b</span>, *<span style="color: #a0522d;">b1</span>, *<span style="color: #a0522d;">b2</span>;
gst_init(&argc, &argv);
a = gst_adapter_new();
b1 = gst_buffer_new_allocate(<span style="color: #008b8b;">NULL</span>, 10, <span style="color: #008b8b;">NULL</span>);
g_print(<span style="color: #8b2252;">"b1 %p\n"</span>, b1);
b2 = gst_buffer_new_allocate(<span style="color: #008b8b;">NULL</span>, 20, <span style="color: #008b8b;">NULL</span>);
gst_adapter_push(a, b1);
gst_adapter_push(a, b2);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
b = gst_adapter_get_buffer(a, 5);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
g_print(<span style="color: #8b2252;">"b %p\n"</span>, b);
b = gst_adapter_take_buffer(a, 5);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
g_print(<span style="color: #8b2252;">"b %p\n"</span>, b);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<pre class="example">
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-base-1.0) take_vs_get.c
$ ./a.out
b1 0x55eb735c20b0
size: 30
size: 30
b 0x55eb735c22d0
size: 25
b 0x55eb735c23e0
</pre>
<p>
<code>GstBuffer</code> と <code>GstMemory</code> の関係については、<a href="https://hellolibraryworld.blogspot.jp/2015/12/gstreamer-6-buffer-memory.html">こちら</a> を参照してください。
</p>
<p>
さて、take/get の関数ですが、リファレンスマニュアルにも記載があるので簡単にだけ。
</p>
<dl class="org-dl">
<dt><code>take_buffer()</code> / <code>get_buffer()</code></dt><dd><code>GstBuffer</code> を返します。 <code>take_buffer()</code> の場合は、 <code>GstAdapter</code> 内からデーターを取り出してしまいます。</dd>
<dt><code>take_buffer_fast()</code> / <code>get_buffer_fast()</code></dt><dd>戻ってきた <code>GstBuffer</code> が複数の <code>GstMemory</code> で構成されている可能性があります。つまり <code>GstMemory</code> が merge されていません。大きなデーターになると merge する時間、つまりデーターコピーの時間が問題になることがあります。そのため <code>_fast()</code> を使って merge されない状態で <code>GstBuffer</code> を貰います。逆に言うと <code>take_buffer()</code> や <code>get_buffer()</code> では merge されていることが保証されています。</dd>
<dt><code>take_list()</code> / <code>get_list()</code></dt><dd>指定したバイト数分の <code>GstBuffer</code> が <code>GList</code> に繋がれた状態で貰えます。 <code>take_buffer_fast()</code> のように <code>GstBuffer</code> 内に <code>GstMemory</code> が連なっているのではなく、 <code>GstMemory</code> が <code>GList</code> に連なっているわけですね</dd>
<dt><code>take_buffer_list()</code> / <code>get_buffer_list()</code></dt><dd><code>GList</code> ではなく、~GstBufferList~ に繋がれた状態で貰えます</dd>
<dt><code>take()</code></dt><dd>生の takeメソッドです。戻り値はメモリーアドレスなので、読んだり書いたりできます。このタイプだけ生の <code>get()</code> はありません。理由は以下で。</dd>
</dl>
<p>
用途に合わせて、どの getter を使うのか決めることができます。
</p>
</div>
</div>
<div id="outline-container-orgabf6e99" class="outline-2">
<h2 id="orgabf6e99"><span class="section-number-2">4</span> map / unmap</h2>
<div class="outline-text-2" id="text-4">
<p>
<code>GstAdapter</code> も <code>GstBuffer</code> や <code>GstMemory</code> と同じように <code>map()</code> / <code>unmap()</code> メソッドを持っています。しかし、 <code>map()</code> メソッドの使い方は <code>GstBuffer</code> とは異なります。 <code>map()</code> / <code>unmap()</code> は <code>get()</code> の汎用型のメソッドになっています。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #228b22;">gconstpointer</span>
<span style="color: #0000ff;">gst_adapter_map</span> (<span style="color: #228b22;">GstAdapter</span> *<span style="color: #a0522d;">adapter</span>,
<span style="color: #228b22;">gsize</span> <span style="color: #a0522d;">size</span>);
</pre>
</div>
<p>
関数のシグネチャーから分る通り <code>map()</code> は、指定した <code>size</code> 分のデーターが書込まれたメモリーアドレスを返してくれます。メモリアドレスは <code>gconstpointer</code> で読み専用で、書き込む事はできません。
</p>
<p>
<code>gst_adapter_take()</code> があるのに、 <code>gst_adapter_get()</code> がない理由がこれです。 <code>gst_adapter_map()</code> は <code>gst_adapter_get()</code> に alias されていても良いですね。
</p>
<p>
メモリーを使い終ったら <code>unmap()</code> してください。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><stdio.h></span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/base/gstadapter.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
<span style="color: #228b22;">GstAdapter</span> *<span style="color: #a0522d;">a</span>;
<span style="color: #228b22;">GstBuffer</span> *<span style="color: #a0522d;">b</span>;
<span style="color: #228b22;">char</span> *<span style="color: #a0522d;">buf</span>;
<span style="color: #228b22;">char</span> <span style="color: #a020f0;">const</span> * <span style="color: #a0522d;">p</span>;
<span style="color: #228b22;">GstMapInfo</span> <span style="color: #a0522d;">i</span>;
gst_init(&argc, &argv);
a = gst_adapter_new();
buf = g_malloc0(10);
sprintf(buf, <span style="color: #8b2252;">"abc"</span>);
b = gst_buffer_new_wrapped(buf, 10);
gst_adapter_push(a, b);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
p = gst_adapter_map(a, 4);
g_print(<span style="color: #8b2252;">"%s\n"</span>, p);
gst_adapter_unmap(a);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
b = gst_adapter_take_buffer(a, 4);
gst_buffer_map(b, &i, GST_MAP_READ);
g_print(<span style="color: #8b2252;">"%s\n"</span>, i.data);
gst_buffer_unmap(b, &i);
g_print(<span style="color: #8b2252;">"size: %"</span> G_GSIZE_FORMAT <span style="color: #8b2252;">"\n"</span>, gst_adapter_available(a));
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<pre class="example">
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-base-1.0) map.c
$ ./a.out
size: 10
abc
size: 10
abc
size: 6
</pre>
</div>
</div>
<div id="outline-container-orgf232004" class="outline-2">
<h2 id="orgf232004"><span class="section-number-2">5</span> おわりに</h2>
<div class="outline-text-2" id="text-5">
<p>
<a href="http://hellolibraryworld.blogspot.jp/2016/12/gstreamer-3-textparse-parse.html">Parser を作る時</a> に重宝する <code>GstAdapter</code> を紹介しました。 <code>GstBaseParse</code> でも実際に内部で使われています。 <code>GstBaseParse</code> の子クラスで実装しなければいけない <code>handle_frame()</code> メソッド に渡ってくる <code>frame->buffer</code> は、実は <code>gst_adapter_get_buffer()</code> したバッファーです。そう <code>take_buffer()</code> じゃないんですね。 <code>finish_frame()</code> した時にはじめて <code>flush()</code> されるようになっています。
</p>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-47277002050805512682016-12-25T20:42:00.001+09:002016-12-30T17:38:03.765+09:00GStreamer でテキスト処理 3: 行に分割する textparse (Parse)<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org0b95422">1. はじめに</a></li>
<li><a href="#org376027a">2. 決り文句</a></li>
<li><a href="#orgef09f6a">3. 必ず実装するもの</a>
<ul>
<li><a href="#org134f8c9">3.1. handle_frame</a></li>
<li><a href="#org296d76c">3.2. Src Pad の Caps を決定</a></li>
</ul>
</li>
<li><a href="#org50a3b10">4. Finding a new line</a></li>
<li><a href="#orgbb7e122">5. さいごに</a></li>
</ul>
</div>
</div>
<div id="outline-container-org0b95422" class="outline-2">
<h2 id="org0b95422"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
「GStreamer でテキスト処理 1: Core機能だけで cat, cp, dd, & tee」の<a href="http://hellolibraryworld.blogspot.jp/2016/12/gstreamer-1-core-cat-cp-dd-tee.html#org883c7aa">おわりに</a>で触れたように、GStreamer には「行」という概念がありません。しかし、多くの Unix ツールは、「行」を基本データーとして扱います。 <code>grep</code> しかり、 <code>sed</code> しかり。そこで、ストリーム内に流れるデーターを行毎に区切ってからダウンストリームに渡すプラグインを作ってみたいと思います。
</p>
<p>
GStreamer では、ある条件に従ってデーターを区切るエレメントを Parser と呼びます。今回は「改行があれば、そこで区切る」という条件を持った Parser を作成します。 Upstream からは、行を無視して <code>GstBuffer</code> にテキストデーターが詰められてやってきます。これから作成するエレメントは、一行分のデーターだけが入った <code>GstBuffer</code> を Downstream に流すように作ります。
</p>
<p>
<code>GstElement</code> から派生して作成しても良いのですが、せっかくなので <a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstBaseParse.html"><code>GstBaseParse</code></a> クラスを使ってみましょう。 <code>GstBaseParse</code> は、パーサーエレメントを作るときに便利なベースクラスです。パーサーとしてやらなければいけない多くの事をやってくれるので、子クラスでは「どのようにデーターをパースするか」というパーサー固有の部分を実装すれば良いようになっています。
</p>
<p>
GStreamer は、すでに多くのパーサーエレメントを持っています。パーサーエレメントは、だいたい "xxxparse" という名前になっているので、以下のコマンドでリストすることができます。多くのパーサーはすでに <code>GstBaseParse</code> を使って実装されているので自作パーサーを作るときにも参考になります。
</p>
<pre class="example">
$ gst-inspect-1.0 | grep parse
</pre>
</div>
</div>
<div id="outline-container-org376027a" class="outline-2">
<h2 id="org376027a"><span class="section-number-2">2</span> 決り文句</h2>
<div class="outline-text-2" id="text-2">
<p>
それでは、いつものように、class のボイラープレート(決まり文句)から始めます。
</p>
<p>
<a href="http://hellolibraryworld.blogspot.jp/2016/12/gstreamer-2-identity-textnoop-element.html">前回</a> と違うのは、 <code>GstElement</code> ではなく <code>GstBaseParse</code> を継承するところです。
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 1: </span>gsttextparse.h</label><pre class="src src-C"><span style="color: #483d8b;">#if</span><span style="color: #483d8b;">n</span><span style="color: #483d8b;">def</span> __GST_TEXT_PARSE_H__
<span style="color: #483d8b;">#define</span> <span style="color: #a0522d;">__GST_TEXT_PARSE_H__</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/base/gstbaseparse.h></span>
<span style="color: #228b22;">G_BEGIN_DECLS</span>
<span style="color: #0000ff;">G_DECLARE_FINAL_TYPE</span> (GstTextParse, gst_text_parse, GST_TEXT, PARSE, GstBaseParse)
G_END_DECLS
<span style="color: #483d8b;">#endif</span> <span style="color: #b22222;">/* </span><span style="color: #b22222;">__GST_TEXT_PARSE_H__ </span><span style="color: #b22222;">*/</span>
</pre>
</div>
<dl class="org-dl">
<dt><code>#include <gst/base/gstbaseparse.h></code></dt><dd>GstBaseParse クラスを使うので、そのヘッダーファイルを include</dd>
<dt><code>G_DECLARE_FINAL_TYPE</code></dt><dd><code>GstElement</code> ではなく <code>GstBaseParse</code> を親クラスに指定します。</dd>
</dl>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 2: </span>gsttextparse.c</label><pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextparse.h"</span>
<span style="color: #a020f0;">struct</span> <span style="color: #228b22;">_GstTextParse</span>
{
<span style="color: #228b22;">GstBaseParse</span> <span style="color: #a0522d;">parent</span>;
};
G_DEFINE_TYPE(GstTextParse, gst_text_parse, GST_TYPE_BASE_PARSE)
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">sinktemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"sink"</span>,
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">srctemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"src"</span>,
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_parse_class_init</span> (<span style="color: #228b22;">GstTextParseClass</span> * <span style="color: #a0522d;">klass</span>)
{
<span style="color: #228b22;">GstElementClass</span> *<span style="color: #a0522d;">element_class</span> = GST_ELEMENT_CLASS(klass);
gst_element_class_set_static_metadata (element_class,
<span style="color: #8b2252;">"Text Parser element"</span>,
<span style="color: #8b2252;">"Filter"</span>,
<span style="color: #8b2252;">"Parse text stream"</span>,
<span style="color: #8b2252;">"Yasushi SHOJI <yasushi.shoji@gmail.com"</span>);
gst_element_class_add_static_pad_template (element_class, &srctemplate);
gst_element_class_add_static_pad_template (element_class, &sinktemplate);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_parse_init</span> (G_GNUC_UNUSED <span style="color: #228b22;">GstTextParse</span> * <span style="color: #a0522d;">parse</span>)
{
}
</pre>
</div>
<dl class="org-dl">
<dt><code>#include "gsttextparse.h"</code></dt><dd>先程作ったヘッダーを include</dd>
<dt><code>G_DEFINE_TYPE</code></dt><dd>GstTextParse クラスを作るので、その名前で作成します</dd>
<dt><code>GST_STATIC_PAD_TEMPLATE</code></dt><dd>パッドテンプレートは必要なので、入れてしまいます。今回もとりあえず ANY で</dd>
<dt><code>gst_element_class_set_static_metadata()</code></dt><dd>メタデーターの情報も、Text Parser に合せて更新しておきます。</dd>
<dt><code>gst_element_class_add_static_pad_template()</code></dt><dd>作成したテンプレートも追加しておきます</dd>
<dt><code>gst_text_parse_init()</code></dt><dd>インスタンスの初期化関数は、とりあえず空っぽにしておきましょう</dd>
</dl>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 3: </span>gsttext.c</label><pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"config.h"</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextnoop.h"</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextparse.h"</span>
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">gboolean</span>
<span style="color: #0000ff;">plugin_init</span> (<span style="color: #228b22;">GstPlugin</span> * <span style="color: #a0522d;">plugin</span>)
{
gst_element_register(plugin, <span style="color: #8b2252;">"textnoop"</span>, GST_RANK_NONE, gst_text_noop_get_type());
gst_element_register(plugin, <span style="color: #8b2252;">"textparse"</span>, GST_RANK_NONE, gst_text_parse_get_type());
<span style="color: #a020f0;">return</span> TRUE;
}
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
gsttext,
<span style="color: #8b2252;">"Text Plugins for GStreamer"</span>,
plugin_init,
PACKAGE_VERSION,
<span style="color: #8b2252;">"LGPL"</span>,
<span style="color: #8b2252;">"GStreamer Text Package"</span>,
<span style="color: #8b2252;">"https://github/yashi/gst-plugins-text"</span>)
</pre>
</div>
<dl class="org-dl">
<dt><code>gst_element_register()</code></dt><dd>textparse を追加しました</dd>
</dl>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 4: </span>meson.build</label><pre class="src src-Meson">project('gst-plugins-text', 'c', version : '0.1.0')
src = ['src/gsttext.c', 'src/gsttextnoop.c', 'src/gsttextparse.c']
gst_dep = dependency('gstreamer-base-1.0', version : '>1.0')
cdata = configuration_data()
cdata.set_quoted('PACKAGE', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
configure_file(output : 'config.h', configuration : cdata)
gsttext = library('gsttext', src, dependencies : gst_dep)
</pre>
</div>
<dl class="org-dl">
<dt><code>src</code></dt><dd>作成した <code>'src/gsttextparse.c'</code> を追加しています。左にあるソースコードから順番にビルドされるようです</dd>
<dt><a href="https://github.com/mesonbuild/meson/wiki/Reference%20manual#dependency"><code>dependency()</code></a></dt><dd><code>gstreamer-1.0</code> ではなく、 <code>gstreamer-base-1.0</code> に変更しています。 <code>GstBaseParse</code> が <code>gstreamer-base-1.0</code> に含まれている為です。</dd>
</dl>
</div>
</div>
<div id="outline-container-orgef09f6a" class="outline-2">
<h2 id="orgef09f6a"><span class="section-number-2">3</span> 必ず実装するもの</h2>
<div class="outline-text-2" id="text-3">
<p>
<code>GstBaseParse</code> から派生させた子クラスでは、以下の要件を必ず実装しなければなりません。
</p>
<ul class="org-ul">
<li><code>src</code> と <code>sink</code> と名前を付けた、パットテンプレートを持つ</li>
<li><code>handle_frame</code> メソッドを実装する</li>
<li>ソースパットの Caps を確定(Fixate)する</li>
</ul>
</div>
<div id="outline-container-org134f8c9" class="outline-3">
<h3 id="org134f8c9"><span class="section-number-3">3.1</span> handle_frame</h3>
<div class="outline-text-3" id="text-3-1">
<p>
<code>handle_frame()</code> を実装していないと、 Segmentation Fault が発生します。
</p>
<pre class="example">
$ GST_PLUGIN_PATH=. gst-launch-1.0 filesrc location=/tmp/a.txt ! textparse ! filesink location=/tmp/b.txt
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Caught SIGSEGV
</pre>
<p>
理由は、 <code>GstBaseParse</code> が Pure Virtual Method の <code>handle_frame()</code> を実装されているか確認せずに呼び出すためです。
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 5: </span>gstbaseparse.c</label><pre class="src src-C"><span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstFlowReturn</span>
<span style="color: #0000ff;">gst_base_parse_handle_buffer</span> (<span style="color: #228b22;">GstBaseParse</span> * <span style="color: #a0522d;">parse</span>, <span style="color: #228b22;">GstBuffer</span> * <span style="color: #a0522d;">buffer</span>,
<span style="color: #228b22;">gint</span> * <span style="color: #a0522d;">skip</span>, <span style="color: #228b22;">gint</span> * <span style="color: #a0522d;">flushed</span>)
{
:
:
frame = gst_base_parse_prepare_frame (parse, buffer);
ret = klass->handle_frame (parse, frame, skip);
:
:
}
</pre>
</div>
<p>
以下のように <code>handle_frame()</code> を実装しました。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_parse_class_init</span> (<span style="color: #228b22;">GstTextParseClass</span> * <span style="color: #a0522d;">klass</span>)
{
<span style="color: #228b22;">GstElementClass</span> *<span style="color: #a0522d;">element_class</span> = GST_ELEMENT_CLASS(klass);
<span style="color: #228b22;">GstBaseParseClass</span> *<span style="color: #a0522d;">base_class</span> = GST_BASE_PARSE_CLASS(klass);
gst_element_class_set_static_metadata (element_class,
<span style="color: #8b2252;">"Text Parser element"</span>,
<span style="color: #8b2252;">"Filter"</span>,
<span style="color: #8b2252;">"Parse text stream "</span>,
<span style="color: #8b2252;">"Yasushi SHOJI <yasushi.shoji@gmail.com"</span>);
gst_element_class_add_static_pad_template (element_class, &srctemplate);
gst_element_class_add_static_pad_template (element_class, &sinktemplate);
base_class->handle_frame = gst_text_parse_handle_frame;
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstFlowReturn</span>
<span style="color: #0000ff;">gst_text_parse_handle_frame</span> (<span style="color: #228b22;">GstBaseParse</span> * <span style="color: #a0522d;">parse</span>,
<span style="color: #228b22;">GstBaseParseFrame</span> * <span style="color: #a0522d;">frame</span>,
G_GNUC_UNUSED <span style="color: #228b22;">gint</span> * <span style="color: #a0522d;">skipsize</span>)
{
<span style="color: #228b22;">gint</span> <span style="color: #a0522d;">size</span>;
size = gst_buffer_get_size(frame->buffer);
<span style="color: #a020f0;">return</span> gst_base_parse_finish_frame(parse, frame, size);
}
</pre>
</div>
<dl class="org-dl">
<dt><code>base_class->handle_frame =</code></dt><dd><code>class_init()</code> の中で、 <code>base_class->handle_frame</code> を設定します</dd>
<dt><code>gst_text_parse_handle_frame()</code></dt><dd><code>handle_frame()</code> は、 <code>GstBaseParse</code> と <code>GstBaseParseFrame</code> 、そして <code>int</code> を貰い、 <code>GstFlowRetrun</code> を返す関数です</dd>
<dt><code>gst_base_parse_finish_frame()</code></dt><dd><code>finish_frame()</code> を使って、ダウンストリームにデーターを流します。 <code>finish_frame()</code> は、 <code>frame->buffer</code> のうち「何バイトダウンストリームに流すか」という情報を第3引数の <code>size</code> で受けとります。そのために、 <code>gst_buffer_get_size()</code> を使ってバッファーのサイズを取得しています。とりあえず <code>frame->buffer</code> すべてをダウンストリームに流したいので、 <code>get_size()</code> で得たサイズをそのまま <code>finish_frame()</code> に渡します</dd>
</dl>
</div>
</div>
<div id="outline-container-org296d76c" class="outline-3">
<h3 id="org296d76c"><span class="section-number-3">3.2</span> Src Pad の Caps を決定</h3>
<div class="outline-text-3" id="text-3-2">
<p>
ソースパッドの Caps が Fix されていないと、実行時に Baseクラスに怒られます。
</p>
<pre class="example">
$ GST_PLUGIN_PATH=. gst-launch-1.0 filesrc location=/tmp/a.txt ! textparse ! filesink location=/tmp/b.txt
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
ERROR: from element /GstPipeline:pipeline0/GstTextParse:textparse0: No caps set
Additional debug info:
gstbaseparse.c(2606): gst_base_parse_push_frame (): /GstPipeline:pipeline0/GstTextParse:textparse0
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
Freeing pipeline ...
</pre>
<p>
<code>GstBaseParse</code> には、「 <code>finish_frame()</code> を呼ばれる前に、 Sink pad の Caps が Fixed されていなければならない」というルールがあるようです。これは 「GstBaseParse がそのように実装されている」というだけで GStreamer の制限ではありません。でも考えてみれば、 Parser なのだからダウンストリームに流すデーターは固定されているべきですよね。
</p>
<p>
ドキュメントには「Fixate the source pad caps when appropriate」と書いてあります。「when appropriate (適切な時に)」って、いつ(?)、どこ(?)なんでしょう? 作っているパーサーによって異なるのでドキュメントでは明言されていません。 <code>gst_base_parse_finish_frame()</code> の前には決定していなければいけないので、 <code>handle_frame()</code> の中でとりあえずやってしまいます。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstFlowReturn</span>
<span style="color: #0000ff;">gst_text_parse_handle_frame</span> (<span style="color: #228b22;">GstBaseParse</span> * <span style="color: #a0522d;">parse</span>,
<span style="color: #228b22;">GstBaseParseFrame</span> * <span style="color: #a0522d;">frame</span>,
G_GNUC_UNUSED <span style="color: #228b22;">gint</span> * <span style="color: #a0522d;">skipsize</span>)
{
<span style="color: #228b22;">gint</span> <span style="color: #a0522d;">size</span>;
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">srcpad</span> = gst_element_get_static_pad(GST_ELEMENT(parse), <span style="color: #8b2252;">"src"</span>);
<span style="color: #a020f0;">if</span> (!gst_pad_has_current_caps(srcpad))
gst_pad_set_caps(srcpad, gst_caps_new_empty_simple (<span style="color: #8b2252;">"text/x-raw"</span>));
size = gst_buffer_get_size(frame->buffer);
<span style="color: #a020f0;">return</span> gst_base_parse_finish_frame(parse, frame, size);
}
</pre>
</div>
<p>
やっと、パイプラインが動作するようになりました。この状態で <code>cp</code> と同じように <code>filesrc</code> で指定したファイルを <code>filesink</code> に指定したファイルにコピーすることができます。
</p>
<pre class="example">
$ GST_DEBUG_NO_COLOR=1 GST_PLUGIN_PATH=. gst-launch-1.0 filesrc location=/tmp/a.txt ! textparse ! filesink location=/tmp/b.txt
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 0:00:00.000257185
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...
$ diff -u /tmp/a.txt /tmp/b.txt
$
</pre>
</div>
</div>
</div>
<div id="outline-container-org50a3b10" class="outline-2">
<h2 id="org50a3b10"><span class="section-number-2">4</span> Finding a new line</h2>
<div class="outline-text-2" id="text-4">
<p>
さて、次は本題の「改行毎に区切ってダウンストリームに流す」部分を作ります。 <code>handle_frame()</code> に渡ってきた <code>frame</code> には、バッファーが付いてきています。 <code>frame->buffer</code> の中から、改行文字列を探しだし、一行分のデーター長を <code>gst_base_parse_finish_frame()</code> に教えてあげれば、完成です。難しいことは <code>GstBaseParse</code> クラスがやってくれるのでとても簡単です。
</p>
<p>
<code>GstBuffer</code> の中を触るには、 <code>gst_buffer_map()</code> と <code>gst_buffer_unmap()</code> を使うというのは、<a href="http://hellolibraryworld.blogspot.jp/2015/12/gstreamer-6-buffer-memory.html">前回</a> やった通りです。
</p>
<p>
<code>GstBuffer</code> が持っているデーターの中から <code>'\n'</code> を探し出します。文字列の中からある文字を探し出す C の関数は <code>strstr()</code> です。今回もこの関数を使うことができますが、GstBuffer には文字の終端を表わす NUL 文字 (<code>\0</code>)も入っているかもしれません。今回は、NUL 文字の事も考えて <code>memchr()</code> を使います。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstFlowReturn</span>
<span style="color: #0000ff;">gst_text_parse_handle_frame</span> (<span style="color: #228b22;">GstBaseParse</span> * <span style="color: #a0522d;">parse</span>,
<span style="color: #228b22;">GstBaseParseFrame</span> * <span style="color: #a0522d;">frame</span>,
G_GNUC_UNUSED <span style="color: #228b22;">gint</span> * <span style="color: #a0522d;">skipsize</span>)
{
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">srcpad</span>;
<span style="color: #228b22;">ptrdiff_t</span> <span style="color: #a0522d;">len</span>;
<span style="color: #228b22;">guint8</span> *<span style="color: #a0522d;">pos</span>;
<span style="color: #228b22;">GstMapInfo</span> <span style="color: #a0522d;">info</span>;
srcpad = gst_element_get_static_pad(GST_ELEMENT(parse), <span style="color: #8b2252;">"src"</span>);
<span style="color: #a020f0;">if</span> (!gst_pad_has_current_caps(srcpad))
gst_pad_set_caps(srcpad, gst_caps_new_empty_simple (<span style="color: #8b2252;">"text/x-raw"</span>));
gst_buffer_map(frame->buffer, &info, GST_MAP_READ);
pos = memchr(info.data, <span style="color: #8b2252;">'\n'</span>, info.size);
<span style="color: #a020f0;">if</span> (!pos)
<span style="color: #a020f0;">return</span> GST_FLOW_OK;
len = pos - info.data;
gst_buffer_unmap(frame->buffer, &info);
<span style="color: #a020f0;">return</span> gst_base_parse_finish_frame(parse, frame, len+1);
}
</pre>
</div>
<dl class="org-dl">
<dt><code>gst_buffer_map()</code></dt><dd><code>GstBuffer</code> にアクセスするための情報を &info で貰う</dd>
<dt><code>memchr()</code></dt><dd>info.data の中に改行文字 (<code>'\n'</code>) が含まれているか検索。含まれていたら、改行文字のアドレスを戻り値で返す</dd>
<dt><code>if (!pos)</code></dt><dd>貰った <code>frame->buffer</code> の中に改行文字を見付けられなかった場合は、 <code>NULL</code> が帰る。その時は <code>GST_FLOW_OK</code> を返せば、次のデーターと一緒にまた <code>handle_frame()</code> が呼ばれる仕組みになっている</dd>
<dt><code>len = pos - info.data;</code></dt><dd>見つかった改行文字の場所から、データーの先頭アドレスを引く事で、一行のバイト数が分る</dd>
<dt><code>gst_buffer_unmap()</code></dt><dd><code>GstBuffer</code> へのアクセスが終ったことを伝える</dd>
<dt><code>gst_base_parse_finish_frame()</code></dt><dd>ダウンストリームに、一行分のデーターが入った <code>GstBuffer</code> を流す。</dd>
</dl>
<p>
<code>gst_base_parse_finish_frame()</code> の第3引数で <code>len+1</code> としているのは、改行も含めてダウンストリームに流したいからです。
</p>
<a href="https://2.bp.blogspot.com/-VVKPYpiv_zY/WF-tVbBR0jI/AAAAAAAAH8Q/AtLqK5ku0GUc7vy3PV8TCrUOpJ30xcDOgCLcB/s1600/len.png" imageanchor="1" ><img border="0" src="https://2.bp.blogspot.com/-VVKPYpiv_zY/WF-tVbBR0jI/AAAAAAAAH8Q/AtLqK5ku0GUc7vy3PV8TCrUOpJ30xcDOgCLcB/s320/len.png" width="320" height="123" /></a>
<p>
これで、動作するはずです。実際に一行づつに分れて流れているか <code>identity</code> を使ってデーターを <code>dump</code> してみます。
</p>
<pre class="example">
$ GST_PLUGIN_PATH=. gst-launch-1.0 filesrc location=/tmp/sonnet.txt ! textparse ! identity dump=true ! filesink location=/tmp/b.txt
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
00000000 (0x7f7d40006530): 46 52 4f 4d 20 66 61 69 72 65 73 74 20 63 72 65 FROM fairest cre
00000010 (0x7f7d40006540): 61 74 75 72 65 73 20 77 65 20 64 65 73 69 72 65 atures we desire
00000020 (0x7f7d40006550): 20 69 6e 63 72 65 61 73 65 2c 0a increase,.
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
00000000 (0x7f7d4000a3f0): 54 68 61 74 20 74 68 65 72 65 62 79 20 62 65 61 That thereby bea
00000010 (0x7f7d4000a400): 75 74 79 27 73 20 72 6f 73 65 20 6d 69 67 68 74 uty's rose might
00000020 (0x7f7d4000a410): 20 6e 65 76 65 72 20 64 69 65 2c 0a never die,.
00000000 (0x7f7d4000c3e0): 42 75 74 20 61 73 20 74 68 65 20 72 69 70 65 72 But as the riper
00000010 (0x7f7d4000c3f0): 20 73 68 6f 75 6c 64 20 62 79 20 74 69 6d 65 20 should by time
00000020 (0x7f7d4000c400): 64 65 63 65 61 73 65 2c 0a decease,.
00000000 (0x7f7d4000e350): 48 69 73 20 74 65 6e 64 65 72 20 68 65 69 72 20 His tender heir
00000010 (0x7f7d4000e360): 6d 69 67 68 74 20 62 65 61 72 20 68 69 73 20 6d might bear his m
00000020 (0x7f7d4000e370): 65 6d 6f 72 79 3a 0a emory:.
00000000 (0x7f7d400102f0): 42 75 74 20 74 68 6f 75 2c 20 63 6f 6e 74 72 61 But thou, contra
00000010 (0x7f7d40010300): 63 74 65 64 20 74 6f 20 74 68 69 6e 65 20 6f 77 cted to thine ow
00000020 (0x7f7d40010310): 6e 20 62 72 69 67 68 74 20 65 79 65 73 2c 0a n bright eyes,.
00000000 (0x7f7d400123a0): 46 65 65 64 27 73 74 20 74 68 79 20 6c 69 67 68 Feed'st thy ligh
00000010 (0x7f7d400123b0): 74 27 73 74 20 66 6c 61 6d 65 20 77 69 74 68 20 t'st flame with
00000020 (0x7f7d400123c0): 73 65 6c 66 2d 73 75 62 73 74 61 6e 74 69 61 6c self-substantial
00000030 (0x7f7d400123d0): 20 66 75 65 6c 2c 0a fuel,.
00000000 (0x7f7d400142a0): 4d 61 6b 69 6e 67 20 61 20 66 61 6d 69 6e 65 20 Making a famine
00000010 (0x7f7d400142b0): 77 68 65 72 65 20 61 62 75 6e 64 61 6e 63 65 20 where abundance
00000020 (0x7f7d400142c0): 6c 69 65 73 2c 0a lies,.
00000000 (0x7f7d40015350): 54 68 79 73 65 6c 66 20 74 68 79 20 66 6f 65 2c Thyself thy foe,
00000010 (0x7f7d40015360): 20 74 6f 20 74 68 79 20 73 77 65 65 74 20 73 65 to thy sweet se
00000020 (0x7f7d40015370): 6c 66 20 74 6f 6f 20 63 72 75 65 6c 2e 0a lf too cruel..
00000000 (0x7f7d40016340): 54 68 6f 75 20 74 68 61 74 20 61 72 74 20 6e 6f Thou that art no
00000010 (0x7f7d40016350): 77 20 74 68 65 20 77 6f 72 6c 64 27 73 20 66 72 w the world's fr
00000020 (0x7f7d40016360): 65 73 68 20 6f 72 6e 61 6d 65 6e 74 0a esh ornament.
00000000 (0x7f7d40017200): 41 6e 64 20 6f 6e 6c 79 20 68 65 72 61 6c 64 20 And only herald
00000010 (0x7f7d40017210): 74 6f 20 74 68 65 20 67 61 75 64 79 20 73 70 72 to the gaudy spr
00000020 (0x7f7d40017220): 69 6e 67 2c 0a ing,.
00000000 (0x7f7d400181e0): 57 69 74 68 69 6e 20 74 68 69 6e 65 20 6f 77 6e Within thine own
00000010 (0x7f7d400181f0): 20 62 75 64 20 62 75 72 69 65 73 74 20 74 68 79 bud buriest thy
00000020 (0x7f7d40018200): 20 63 6f 6e 74 65 6e 74 0a content.
00000000 (0x563a714e0750): 41 6e 64 2c 20 74 65 6e 64 65 72 20 63 68 75 72 And, tender chur
00000010 (0x563a714e0760): 6c 2c 20 6d 61 6b 65 73 74 20 77 61 73 74 65 20 l, makest waste
00000020 (0x563a714e0770): 69 6e 20 6e 69 67 67 61 72 64 69 6e 67 2e 0a in niggarding..
00000000 (0x7f7d40019190): 50 69 74 79 20 74 68 65 20 77 6f 72 6c 64 2c 20 Pity the world,
00000010 (0x7f7d400191a0): 6f 72 20 65 6c 73 65 20 74 68 69 73 20 67 6c 75 or else this glu
00000020 (0x7f7d400191b0): 74 74 6f 6e 20 62 65 2c 0a tton be,.
00000000 (0x563a71423760): 54 6f 20 65 61 74 20 74 68 65 20 77 6f 72 6c 64 To eat the world
00000010 (0x563a71423770): 27 73 20 64 75 65 2c 20 62 79 20 74 68 65 20 67 's due, by the g
00000020 (0x563a71423780): 72 61 76 65 20 61 6e 64 20 74 68 65 65 2e 0a rave and thee..
Got EOS from element "pipeline0".
Execution ended after 0:00:00.000613045
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...
</pre>
<p>
分りやすいように、オフセット 0 の所で改行を入れてみました。ちゃんと <code>GstBuffer</code> には一行づつのデーターが入っているようです。
</p>
</div>
</div>
<div id="outline-container-orgbb7e122" class="outline-2">
<h2 id="orgbb7e122"><span class="section-number-2">5</span> さいごに</h2>
<div class="outline-text-2" id="text-5">
<p>
どうだったでしょうか? 結局新しく実装したのは、 <code>memchr()</code> まわりだけです。これだけのコード量で簡単な Parser なら実装できてしまいます。
</p>
<div class="org-src-container">
<pre class="src src-C">pos = memchr(info.data, <span style="color: #8b2252;">'\n'</span>, info.size);
<span style="color: #a020f0;">if</span> (!pos)
<span style="color: #a020f0;">return</span> GST_FLOW_OK;
len = pos - info.data;
</pre>
</div>
<p>
しかし、残念なことにこのコードには1つだけバグがあります。入力ファイルが改行で終っていない場合には、最後の行だけ処理されません。ファイルの最後の行が改行で終っていない場合にも、最後の行を down stream に流すように改造するのは、みなさんへの宿題としたいと思います。
</p>
<p>
それでは、 Merry Christmas & Happy Coding! ;-)</p>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-21183547767175607422016-12-14T19:49:00.001+09:002016-12-30T17:38:19.010+09:00Glib Object System: 派生クラスの作成<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org1664071">1. まずは C で書く</a></li>
<li><a href="#orgd46a89c">2. 次は Vala でも書いてみる</a></li>
<li><a href="#org82e73c4">3. ref</a></li>
</ul>
</div>
</div>
<p>
「そもそも、Glib / GObject を使ってクラスを作る方法が分らない」という話があったので、書いてみようかと思います。
</p>
<div id="outline-container-org1664071" class="outline-2">
<h2 id="org1664071"><span class="section-number-2">1</span> まずは C で書く</h2>
<div class="outline-text-2" id="text-1">
<p>
40行程度なので、いきなりコードから
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #b22222;">/* </span><span style="color: #b22222;">Declaration Begin </span><span style="color: #b22222;">*/</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><glib-object.h></span>
<span style="color: #483d8b;">#define</span> <span style="color: #a0522d;">MY_TYPE_FOO</span> (my_foo_get_type())
G_DECLARE_FINAL_TYPE (MyFoo, my_foo, MY, FOO, GObject)
<span style="color: #b22222;">/* </span><span style="color: #b22222;">Declaration End </span><span style="color: #b22222;">*/</span>
<span style="color: #b22222;">/* </span><span style="color: #b22222;">Definition Begin </span><span style="color: #b22222;">*/</span>
<span style="color: #a020f0;">struct</span> <span style="color: #228b22;">_MyFoo</span>
{
<span style="color: #228b22;">GObject</span> <span style="color: #a0522d;">parent_class</span>;
};
G_DEFINE_TYPE(MyFoo, my_foo, G_TYPE_OBJECT)
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">my_foo_class_init</span> (<span style="color: #228b22;">MyFooClass</span> * <span style="color: #a0522d;">klass</span>)
{
g_print(<span style="color: #8b2252;">"class init\n"</span>);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">my_foo_init</span> (<span style="color: #228b22;">MyFoo</span> * <span style="color: #a0522d;">noop</span>)
{
g_print(<span style="color: #8b2252;">"instance init\n"</span>);
}
<span style="color: #228b22;">MyFoo</span> * <span style="color: #0000ff;">my_foo_new</span>(<span style="color: #228b22;">void</span>)
{
<span style="color: #a020f0;">return</span> (<span style="color: #228b22;">MyFoo</span>*) g_type_create_instance(MY_TYPE_FOO);
}
<span style="color: #b22222;">/* </span><span style="color: #b22222;">Definition End </span><span style="color: #b22222;">*/</span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>()
{
g_print(<span style="color: #8b2252;">"main\n"</span>);
my_foo_new();
my_foo_new();
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
これで全部です。
</p>
<p>
では、最初の行から説明していきます。
</p>
<dl class="org-dl">
<dt><code>#include <glib-object.h></code></dt><dd>GObject を使う場合に include するヘッダーです</dd>
<dt><code>#define MY_TYPE_FOO (my_foo_get_type())</code></dt><dd>これだけは、 <code>G_DECLARE_FINAL_TYPE</code> が生成できないので手で作る必要があります。 <code>my_foo_get_type()</code> と書けば事足りるので、「そもそも、必要あるのか?」と自分は思ってしまうのですが、 GObject の流儀なので作成しておきましょう。 <code>G_DECLARE_FINAL_TYPE</code> がこのマクロを作成できないのは、C 言語の制限で、C言語のマクロ( <code>#define</code> )の中では <code>#define</code> できない為です</dd>
<dt><a href="https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DECLARE-FINAL-TYPE:CAPS"><code>G_DECLARE_FINAL_TYPE</code></a></dt><dd><code>MyFoo</code> クラスの宣言をしてくれます。 <code>my_foo</code> という「モジュール_クラス」の名前を宣言します。 <code>MY</code> というモジュールの下で <code>FOO</code> というクラスを作成することになります。こんな感じに 2種類の宣言を書かなければいけない所が C に無理矢理オブジェクトシステムを入れたイマイチ感を匂わせます。最後の引数が親クラスです。GObject から派生させたクラスにしたいので、 <code>GObject</code> を指定します。GStreamer のエレメントを作る場合は、 <code>GstElemet</code> を指定したりします。</dd>
</dl>
<p>
ここまでが宣言になります。もし他のファイルからこのクラスを使う場合は、ここまでをヘッダーファイル <code>.h</code> に記載します。ここからは実際のクラスの定義に入って行きます。他のコードと分けるには、ここからのコードは <code>.c</code> に記載してください。
</p>
<dl class="org-dl">
<dt>struct _MyFoo</dt><dd>ここからがクラス本体です。メソッドがないので、親クラスである GObject を内包しているだけの <code>struct</code> です</dd>
<dt><a href="https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DEFINE-TYPE:CAPS"><code>G_DEFINE_TYPE</code></a></dt><dd>GObject タイプシステムとして必要なコードを生成してくれるマクロです。 <code>_get_type()</code> の生成がメインです。作成するタイプの<a href="https://ja.wikipedia.org/wiki/%E3%82%AD%E3%83%A3%E3%83%A1%E3%83%AB%E3%82%B1%E3%83%BC%E3%82%B9">キャメルケース</a> を第1引数に、<a href="https://en.wikipedia.org/wiki/Snake_case">スネークケース</a> を第2引数に指定します。最後は親のタイプ名、ここでは GObject のタイプ名、を指定します</dd>
<dt><code>my_foo_class_init()</code></dt><dd>クラスの初期化関数です。 GObject Type System が <code>MyFoo</code> クラスを始めて使う場合に呼ばれます。大抵の場合は最初のインスタンスを作成する時でしょうか。</dd>
<dt><code>my_foo_init()</code></dt><dd>インスタンスの初期化関数です。インスタンスが生成される度に呼び出されます</dd>
<dt><code>my_foo_new()</code></dt><dd>MyFoo クラスのコンストラクターです。シンプルな場合は、直接 Type System のジェネリックなコンストラクタ <code>g_type_create_instance()</code> を呼んでも良いですが、ラップしておいた方が無難です。</dd>
</dl>
<p>
main関数で、インスタンスを2つ作成して、どのタイミングでクラスの初期化関数とインスタンスの初期化関数が呼ばれるか確認してみます。
</p>
<pre class="example">
$ meson . build
$ ninja -C build
$ build/foo
main
class init
instance init
instance init
</pre>
<p>
main関数が始まって、「main」と表示されます。次に <code>my_foo_new()</code> が始めて呼び出された時に GObject Type System は MyFoo タイプを初期化します。これが結果的に <code>my_foo_class_init()</code> を呼び出します。クラスが初期化されると実際にインスタンスが生成され <code>my_foo_init()</code> が呼び出されます。
</p>
<p>
2回目に <code>my_foo_init()</code> が呼び出された時には Type System は <code>MyFoo</code> クラスを知っているのでクラスが初期化されることはありません。すぐにインスタンスの初期化関数 <code>my_foo_init()</code> が呼び出されます。
</p>
<p>
こんな感じに、シンプルなクラスであれば、それなりの行数で作成することができます。もちろん GObject を継承しているので <code>MyFoo</code> のオブジェクトも <a href="https://developer.gnome.org/gobject/stable/gobject-properties.html">プロパティー</a> を持ったり <a href="https://developer.gnome.org/gobject/stable/signal.html">シグナル</a> を扱うことができます。
</p>
<p>
とは言え Ruby や C# のように class 生成をサポートしている言語には敵いませんね。
</p>
</div>
</div>
<div id="outline-container-orgd46a89c" class="outline-2">
<h2 id="orgd46a89c"><span class="section-number-2">2</span> 次は Vala でも書いてみる</h2>
<div class="outline-text-2" id="text-2">
<p>
GObject Type System を使った言語で <a href="https://en.wikipedia.org/wiki/Vala_(programming_language)">Vala</a> という言語があります。 <a href="https://wiki.gnome.org/Projects/Vala/Tutorial#A_First_Program">Hello World</a> はこんな感じです。
</p>
<div class="org-src-container">
<pre class="src src-vala"><span style="color: #a020f0;">class</span> <span style="color: #008b8b;">Demo</span>.<span style="color: #228b22;">HelloWorld</span> : <span style="color: #008b8b;">GLib</span>.Object {
<span style="color: #a020f0;">public</span> <span style="color: #a020f0;">static</span> <span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">string</span>[] <span style="color: #a0522d;">args</span>) {
<span style="color: #008b8b;">stdout</span>.printf(<span style="color: #8b2252;">"Hello, World\n"</span>);
<span style="color: #a020f0;">return</span> 0;
}
}
</pre>
</div>
<p>
この Vala、「Vala → C → ネイティブコード」という順番にコンパイルしています。つまり、実行ファイルを生成する前に C へのコンパイルで止めてあげれば、コードジェネレーターとして使うことができます。
</p>
<p>
先程の C のコードと同じ動きをする Vala のコードは、こんな感じです。
</p>
<div class="org-src-container">
<pre class="src src-vala"><span style="color: #a020f0;">class</span> <span style="color: #008b8b;">My</span>.<span style="color: #228b22;">Foo</span> {
<span style="color: #a020f0;">static</span> <span style="color: #a020f0;">construct</span> {
<span style="color: #008b8b;">stdout</span>.printf(<span style="color: #8b2252;">"class init\n"</span>);
}
<span style="color: #a020f0;">public</span> Foo() {
<span style="color: #008b8b;">stdout</span>.printf(<span style="color: #8b2252;">"instance init\n"</span>);
}
}
<span style="color: #a020f0;">public</span> <span style="color: #a020f0;">static</span> <span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">string</span>[] <span style="color: #a0522d;">args</span>) {
<span style="color: #008b8b;">stdout</span>.printf(<span style="color: #8b2252;">"main\n"</span>);
<span style="color: #a020f0;">new</span> <span style="color: #008b8b;">My</span>.Foo();
<span style="color: #a020f0;">new</span> <span style="color: #008b8b;">My</span>.Foo();
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<pre class="example">
$ valac myfoo.vala
$ ./myfoo
main
class init
instance init
instance init
</pre>
<p>
この Vala のコードから C のコードを生成するには
</p>
<pre class="example">
$ valac -h myfoo.h -C myfoo.vala
</pre>
<p>
とします。 <code>myfoo.h</code> と <code>myfoo.c</code> が生成されます。生成されたコードは、数百行あるので掲載は割愛します。内容を確認してみると勉強になりますよ。
</p>
</div>
</div>
<div id="outline-container-org82e73c4" class="outline-2">
<h2 id="org82e73c4"><span class="section-number-2">3</span> ref</h2>
<div class="outline-text-2" id="text-3">
<ul class="org-ul">
<li><a href="https://github.com/yashi/gobject-subclass-example">https://github.com/yashi/gobject-subclass-example</a></li>
<li><a href="https://developer.gnome.org/SubclassGObject/">https://developer.gnome.org/SubclassGObject/</a></li>
<li><a href="https://developer.gnome.org/gobject/stable/howto-gobject.html">https://developer.gnome.org/gobject/stable/howto-gobject.html</a></li>
</ul>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-83422452036414691542016-12-13T00:00:00.000+09:002016-12-30T17:38:03.778+09:00GStreamer でテキスト処理 2: なにもしない identity もどきのエレメント textnoop (Element)<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org7a571c9">1. はじめに</a></li>
<li><a href="#org3e2a1e5">2. 決まり文句</a></li>
<li><a href="#org9d69d59">3. Pad</a></li>
<li><a href="#org0ece865">4. Pad: Template</a></li>
<li><a href="#orgc0a9cac">5. Pad: chain</a></li>
<li><a href="#org2ca25c1">6. おわりに</a></li>
</ul>
</div>
</div>
<div id="outline-container-org7a571c9" class="outline-2">
<h2 id="org7a571c9"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
一番簡単なエレメントは、アップストリームから受け取ったデーターをなにもせずにダウンストリームに流す <code>identity</code> の様なエレメントです。<a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-identity.html">本物の <code>identity</code> エレメント</a>は、 <a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstBaseTransform.html"><code>GstBaseTransform</code></a> を継承し、10以上のプロパティーを持ったエレメントで、コードの行数も <a href="https://cgit.freedesktop.org/gstreamer/gstreamer/tree/plugins/elements/gstidentity.c">1000 行近く</a>あります。
</p>
<p>
ここでは、GStreamer の基本クラスである <code>GstElement</code> から派生させ、簡単なエレメント <code>GstTextNoop</code> を作成してみます。まだ一度もプラグインをビルドしたことが無い人は、空っぽのプラグインをビルドする「<a href="http://hellolibraryworld.blogspot.jp/2016/12/the-meson-build-system.html">The Meson Build System</a>」を読んでみてください。
</p>
<p>
詳しい情報は、 GStreamer の <a href="https://gstreamer.freedesktop.org/documentation/plugin-development/">Plugin Writer's Guide</a> を参照してください。
</p>
</div>
</div>
<div id="outline-container-org3e2a1e5" class="outline-2">
<h2 id="org3e2a1e5"><span class="section-number-2">2</span> 決まり文句</h2>
<div class="outline-text-2" id="text-2">
<p>
GStreamer は <a href="https://developer.gnome.org/platform-overview/unstable/tech-glib.html">Glib</a> が提供している <a href="https://developer.gnome.org/gobject/stable/chapter-gobject.html">GObject</a> (と <a href="https://developer.gnome.org/gobject/stable/gobject-Type-Information.html">GType</a>) を使って オブジェクト指向なプログラミング環境をユーザーに提供しています。C言語は、元々 オブジェクト指向ではない言語なので、GObject のような Object System を導入したとしても、クラスを1つ作成する為にも、以前は面倒な記述が必要でした。しかし Glib バージョン 2.44 から <code>G_DECLARE_FINAL_TYPE()</code> が導入され、一行でクラスの宣言が可能になりました。
</p>
<pre class="example">
G_DECLARE_FINAL_TYPE (GstTextNoop, gst_text_noop, GST_TEXT_NOOP, TEXT_NOOP, GstElement)
</pre>
<p>
このように、 <code>GstElement</code> を継承した <code>GstTextNoop</code> クラスの宣言ができるようになりました。それでは早速 <code>GstTextNoop</code> クラスを見ていきましょう。最初はヘッダーファイルからです。
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 1: </span><code>gsttextnoop.h</code></label><pre class="src src-C"><span style="color: #483d8b;">#if</span><span style="color: #483d8b;">n</span><span style="color: #483d8b;">def</span> __GST_TEXT_NOOP_H__
<span style="color: #483d8b;">#define</span> <span style="color: #a0522d;">__GST_TEXT_NOOP_H__</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #228b22;">G_BEGIN_DECLS</span>
<span style="color: #0000ff;">G_DECLARE_FINAL_TYPE</span> (GstTextNoop, gst_text_noop, GST_TEXT, NOOP, GstElement)
G_END_DECLS
<span style="color: #483d8b;">#endif</span> <span style="color: #b22222;">/* </span><span style="color: #b22222;">__GST_TEXT_NOOP_H__ </span><span style="color: #b22222;">*/</span>
</pre>
</div>
<dl class="org-dl">
<dt><code>__GST_TEXT_NOOP_H__</code></dt><dd>ヘッダーが複数回 include されないようにガード</dd>
<dt><code>#include <gst/gst.h></code></dt><dd>GStreamer のヘッダーを include</dd>
<dt><a href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html#G-BEGIN-DECLS:CAPS"><code>G_BEGIN_DECLS</code></a></dt><dd>C++ からでも使えるようにするためのマクロ。この辺りまでは GStreamer の作法的に毎回一緒です</dd>
<dt><a href="https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DECLARE-FINAL-TYPE:CAPS"><code>G_DECLARE_FINAL_TYPE</code></a></dt><dd>拡張を禁止したクラス <code>GstTextNoop</code> を作成します。Java の final class や C# の sealed class と同じです</dd>
<dt><a href="https://developer.gnome.org/glib/stable/glib-Miscellaneous-Macros.html#G-END-DECLS:CAPS"><code>G_END_DECLS</code></a></dt><dd><code>G_DECLARE_FINAL_TYPE</code> で始めてので、=G_END_DECLS= で終ります</dd>
</dl>
<p>
続いて、Cファイル。こちらは、あたりまえですが、宣言(declaration)だけではなく、実体/定義 (definition) が入ります。
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 2: </span><code>gsttextnoop.c</code></label><pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextnoop.h"</span>
<span style="color: #a020f0;">struct</span> <span style="color: #228b22;">_GstTextNoop</span>
{
<span style="color: #228b22;">GstElement</span> <span style="color: #a0522d;">parent_class</span>;
};
G_DEFINE_TYPE(GstTextNoop, gst_text_noop, GST_TYPE_ELEMENT)
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_class_init</span> (<span style="color: #228b22;">GstTextNoopClass</span> * <span style="color: #a0522d;">klass</span>)
{
<span style="color: #228b22;">GstElementClass</span> *<span style="color: #a0522d;">gstelement_class</span>;
gstelement_class = (<span style="color: #228b22;">GstElementClass</span> *) (klass);
gst_element_class_set_static_metadata (gstelement_class,
<span style="color: #8b2252;">"Noop Element"</span>,
<span style="color: #8b2252;">"Filter"</span>,
<span style="color: #8b2252;">"Simple element like Identity"</span>,
<span style="color: #8b2252;">"Me"</span>);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_init</span> (<span style="color: #228b22;">GstTextNoop</span> * <span style="color: #a0522d;">noop</span>)
{
}
</pre>
</div>
<dl class="org-dl">
<dt><code>#include "gsttextnoop.h"</code></dt><dd>上で作成したヘッダーファイルを include</dd>
<dt><code>struct _GstTextNoop</code></dt><dd><code>GstTextNoop</code> の実体です。マクロで <code>GstTextNoop</code> に typedef されています。実体を .c に隠すのは opaque な struct にするためです。こうすることで外部から <code>GstTextNoop</code> の中が見えなくなり、<a href="https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%97%E3%82%BB%E3%83%AB%E5%8C%96">カプセル化</a>することができます。</dd>
<dt><a href=""><code>G_DEFINE_TYPE</code></a></dt><dd><code>G_DECLARE_FINAL_TYPE</code> で宣言した型の定型部分を実装します。これも決り文句の1つです</dd>
<dt><code>gst_text_noop_class_init()</code></dt><dd>クラスの初期化関数です。 <code>G_DECLARE_FINAL_TYPE</code> や <code>G_DEFINE_TYPE</code> で使った <code>gst_text_noop</code> に <code>_class_init</code> を付けた関数名で作成する必要があります。クラスが初期化された時に呼ばれます。</dd>
<dt><code>gst_element_class_set_static_metadata()</code></dt><dd>GStreamer のクラスではメタデーターが設定されていないとエラーになります。このクラスの名前や種類、説明、作者を記載します</dd>
<dt><code>gst_text_noop_init()</code></dt><dd>インスタンスの初期化関数です。インスタンスが生成された時に呼ばれます。まだなにも必要ないので、空っぽで良いです</dd>
</dl>
<p>
これでクラスは作成できました。名前を置き換えれば、自分のクラスを作ることができます。
</p>
<p>
<a href="https://cgit.freedesktop.org/gstreamer/gst-template">gst-template</a> にはテンプレートから <a href="https://cgit.freedesktop.org/gstreamer/gst-template/tree/gst-plugin/tools/make_element">クラスのコードを生成するスクリプト</a> もあり、Plugin Writer's Guide でも<a href="https://gstreamer.freedesktop.org/documentation/plugin-development/basics/boiler.html#using-the-project-stamp">これを使っています</a>。しかし、最初から生成されるコードが多いと嫌になるので、今回はあえて手で作成しました。 また、Vala コンパイラーを使うことででも簡単にクラスのボイラープレートコードを生成することができます。
</p>
<p>
それでは、作成したクラスを、<a href="http://hellolibraryworld.blogspot.jp/2016/12/the-meson-build-system.html">ここ</a> で作成した空っぽのプラグインに追加してみましょう。
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 3: </span><code>gsttext.c</code></label><pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"config.h"</span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextnoop.h"</span>
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">gboolean</span>
<span style="color: #0000ff;">plugin_init</span> (<span style="color: #228b22;">GstPlugin</span> * <span style="color: #a0522d;">plugin</span>)
{
gst_element_register(plugin, <span style="color: #8b2252;">"textnoop"</span>, GST_RANK_NONE, gst_text_noop_get_type());
<span style="color: #a020f0;">return</span> TRUE;
}
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
gsttext,
<span style="color: #8b2252;">"Text Plugins for GStreamer"</span>,
plugin_init,
PACKAGE_VERSION,
<span style="color: #8b2252;">"LGPL"</span>,
<span style="color: #8b2252;">"GStreamer Text Package"</span>,
<span style="color: #8b2252;">"https://github/yashi/gst-plugins-text"</span>)
</pre>
</div>
<dl class="org-dl">
<dt><code>#include "gsttextnoop.h"</code></dt><dd><code>GstTextNoop</code> クラスのヘッダーを include</dd>
<dt><a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElementFactory.html#gst-element-register"><code>gst_element_register()</code></a></dt><dd>エレメントをプラグインに追加します。第1引数は受け取ったプラグイン、第2引数はエレメントの名前「 <code>textnoop</code> 」、第3引数はランクです。<a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPluginFeature.html#GstRank">ランク</a> は4つから選べます。とりあえずは、一番優先度が低い <code>NONE</code> にしておきましょう。最後の引数は <code>GstTextNoop</code> のタイプを取得するための関数を指定します。 <code>G_DEFINE_TYPE</code> が生成してくれているので、自分で作った覚えがなくても大丈夫です</dd>
</dl>
<p>
ソースコードは以上です。ビルドするためには、ビルドシステムにソースコードを教えてあげる必要があります。
</p>
<div class="org-src-container">
<label class="org-src-name"><span class="listing-number">Listing 4: </span>meson.build</label><pre class="src src-Meson">project('gst-plugins-text', 'c', version : '0.1.0')
src = ['src/gsttextnoop.c', 'src/gsttext.c']
gst_dep = dependency('gstreamer-1.0', version : '>1.0')
cdata = configuration_data()
cdata.set_quoted('PACKAGE', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
configure_file(output : 'config.h', configuration : cdata)
gsttext = library('gsttext', src, dependencies : gst_dep)
</pre>
</div>
<dl class="org-dl">
<dt>src</dt><dd>作成した <code>'src/gsttextnoop.c'</code> を追加します。他は変更しなくても大丈夫です</dd>
</dl>
<pre class="example">
$ GST_PLUGIN_PATH=`pwd`/build gst-inspect-1.0 gsttext
Plugin Details:
Name gsttext
Description Text Plugins for GStreamer
Filename ./libgsttext.so
Version 0.1.0
License LGPL
Source module gst-plugins-text
Binary package GStreamer Text Package
Origin URL https://github/yashi/gst-plugins-text
textnoop: Noop Element
1 features:
+-- 1 elements
</pre>
<p>
エレメントの情報も、取ることができます。
</p>
<pre class="example">
$ GST_PLUGIN_PATH=`pwd`/build gst-inspect-1.0 textnoop
Factory Details:
Rank none (0)
Long-name Noop Element
Klass Filter
Description Simple element like Identity
Author Me
Plugin Details:
Name gsttext
Description Text Plugins for GStreamer
Filename ./libgsttext.so
Version 0.1.0
License LGPL
Source module gst-plugins-text
Binary package GStreamer Text Package
Origin URL https://github/yashi/gst-plugins-text
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstTextNoop
Pad Templates:
none
Element Flags:
no flags set
Element Implementation:
Has change_state() function: gst_element_change_state_func
Element has no clocking capabilities.
Element has no URI handling capabilities.
Pads:
none
Element Properties:
name : The name of the object
flags: readable, writable
String. Default: "textnoop0"
parent : The parent of the object
flags: readable, writable
Object of type "GstObject"
</pre>
</div>
</div>
<div id="outline-container-org9d69d59" class="outline-2">
<h2 id="org9d69d59"><span class="section-number-2">3</span> Pad</h2>
<div class="outline-text-2" id="text-3">
<p>
インスペクトは正しく認識するようになりましたが、まだパイプラインを形成できません。
</p>
<pre class="example">
GST_PLUGIN_PATH=build gst-launch-1.0 -q fakesrc num-buffers=0 ! textnoop ! fakesink
WARNING: erroneous pipeline: could not link fakesrc0 to textnoop0
</pre>
<p>
<code>fakesrc</code> から <code>textnoop</code> エレメントに link できないと言われました。<a href="http://hellolibraryworld.blogspot.jp/2015/12/gstreamer-5-pad-event.html">エレメントを繋ぐのは Pad</a> なので、pad がないと繋がりません。
</p>
<p>
Pad を作成するのに良く使われる方法は、Pad Template からの作成です。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextnoop.h"</span>
<span style="color: #a020f0;">struct</span> <span style="color: #228b22;">_GstTextNoop</span>
{
<span style="color: #228b22;">GstElement</span> <span style="color: #a0522d;">parent_class</span>;
};
G_DEFINE_TYPE(GstTextNoop, gst_text_noop, GST_TYPE_ELEMENT)
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">sinktemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"sink"</span>,
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">srctemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"src"</span>,
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_class_init</span> (<span style="color: #228b22;">GstTextNoopClass</span> * <span style="color: #a0522d;">klass</span>)
{
<span style="color: #228b22;">GstElementClass</span> *<span style="color: #a0522d;">gstelement_class</span>;
gstelement_class = (<span style="color: #228b22;">GstElementClass</span> *) (klass);
gst_element_class_set_static_metadata (gstelement_class,
<span style="color: #8b2252;">"Noop Element"</span>,
<span style="color: #8b2252;">"Filter"</span>,
<span style="color: #8b2252;">"Simple element like Identity"</span>,
<span style="color: #8b2252;">"Me"</span>);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_init</span> (<span style="color: #228b22;">GstTextNoop</span> * <span style="color: #a0522d;">noop</span>)
{
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">srcpad</span>;
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">sinkpad</span>;
srcpad = gst_pad_new_from_static_template(&srctemplate, <span style="color: #8b2252;">"src"</span>);
gst_element_add_pad(GST_ELEMENT(noop), srcpad);
sinkpad = gst_pad_new_from_static_template(&sinktemplate, <span style="color: #8b2252;">"sink"</span>);
gst_element_add_pad(GST_ELEMENT(noop), sinkpad);
}
</pre>
</div>
<dl class="org-dl">
<dt><a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPadTemplate.html#GST-STATIC-PAD-TEMPLATE:CAPS">GST_STATIC_PAD_TEMPLATE</a></dt><dd>static の Pad Template を生成するマクロ。テンプレートの名前、<a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#GstPadDirection">Padの方向</a> (SRC / SINK)、<a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPadTemplate.html#GstPadPresence">Pad がいつ存在するか</a>、static の Caps (<a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstCaps.html#GST-STATIC-CAPS-ANY:CAPS">ANY</a> / <a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstCaps.html#GST-STATIC-CAPS-NONE:CAPS">NONE</a>) を指定します。 <code>textnoop</code> エレメントは、source 側にも sink 側にも繋がるエレメントなので 2つパッドを作ります。テンプレートもそれぞれ作成します。なにが繋がっても良いので <code>GST_STATIC_CAPS_ANY</code> を指定します。</dd>
<dt><a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-new-from-static-template"><code>gst_pad_new_from_static_template()</code></a></dt><dd>テンプレートから Padを作成します。第1引数にテンプレートを、第2引数に作成する Pad の名前を指定します。こちらも、 source 側と sink 側の両方作成します</dd>
<dt><a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-add-pad"><code>gst_element_add_pad</code></a></dt><dd>noop エレメントに Pad を追加します。 <code>GstElement</code> クラスのメソッドなので noop を <code>GST_ELEMENT</code> に変換し、第1引数に渡します。第2引数には <code>gst_pad_new_from_static_template()</code> で作成した Pad を指定します</dd>
</dl>
<p>
これでエラーせずに繋がりました。
</p>
<pre class="example">
GST_PLUGIN_PATH=. gst-launch-1.0 -q fakesrc num-buffers=0 ! textnoop ! fakesink
</pre>
</div>
</div>
<div id="outline-container-org0ece865" class="outline-2">
<h2 id="org0ece865"><span class="section-number-2">4</span> Pad: Template</h2>
<div class="outline-text-2" id="text-4">
<p>
パッドを作成して繋がるところまではできましたが、Pad の情報が inspect で出てきません。
</p>
<pre class="example">
GST_PLUGIN_PATH=. gst-inspect-1.0 noop
Factory Details:
Rank none (0)
Long-name Noop Element
Klass Filter
Description Simple element like Identity
Author Me
Plugin Details:
Name gsttext
Description Text Plugins for GStreamer
Filename ./libgsttext.so
Version 0.1.0
License LGPL
Source module gst-plugins-text
Binary package GStreamer Text Package
Origin URL https://github/yashi/gst-plugins-text
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstTextNoop
Pad Templates:
none ← ここね
Element Flags:
no flags set
Element Implementation:
Has change_state() function: gst_element_change_state_func
Element has no clocking capabilities.
Element has no URI handling capabilities.
Pads:
SRC: 'src'
Pad Template: 'src'
SINK: 'sink'
Pad Template: 'sink'
Element Properties:
name : The name of the object
flags: readable, writable
String. Default: "textnoop0"
parent : The parent of the object
flags: readable, writable
Object of type "GstObject"
</pre>
<p>
これは、クラスに Pad Tempalte を追加していないからです。追加してしまいましょう。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextnoop.h"</span>
<span style="color: #a020f0;">struct</span> <span style="color: #228b22;">_GstTextNoop</span>
{
<span style="color: #228b22;">GstElement</span> <span style="color: #a0522d;">parent_class</span>;
};
G_DEFINE_TYPE(GstTextNoop, gst_text_noop, GST_TYPE_ELEMENT)
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">sinktemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"sink"</span>,
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">srctemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"src"</span>,
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_class_init</span> (<span style="color: #228b22;">GstTextNoopClass</span> * <span style="color: #a0522d;">klass</span>)
{
<span style="color: #228b22;">GstElementClass</span> *<span style="color: #a0522d;">gstelement_class</span>;
gstelement_class = (<span style="color: #228b22;">GstElementClass</span> *) (klass);
gst_element_class_set_static_metadata (gstelement_class,
<span style="color: #8b2252;">"Noop Element"</span>,
<span style="color: #8b2252;">"Filter"</span>,
<span style="color: #8b2252;">"Simple element like Identity"</span>,
<span style="color: #8b2252;">"Me"</span>);
gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_init</span> (<span style="color: #228b22;">GstTextNoop</span> * <span style="color: #a0522d;">noop</span>)
{
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">srcpad</span>;
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">sinkpad</span>;
srcpad = gst_pad_new_from_static_template(&srctemplate, <span style="color: #8b2252;">"src"</span>);
gst_element_add_pad(GST_ELEMENT(noop), srcpad);
sinkpad = gst_pad_new_from_static_template(&sinktemplate, <span style="color: #8b2252;">"sink"</span>);
gst_element_add_pad(GST_ELEMENT(noop), sinkpad);
}
</pre>
</div>
<dl class="org-dl">
<dt><a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-class-add-static-pad-template"><code>gst_element_class_add_static_pad_template()</code></a></dt><dd>noop エレメントのクラスに、Pad Template を追加します</dd>
</dl>
<pre class="example">
Factory Details:
Rank none (0)
Long-name Noop Element
Klass Filter
Description Simple element like Identity
Author Me
Plugin Details:
Name gsttext
Description Text Plugins for GStreamer
Filename ./libgsttext.so
Version 0.1.0
License LGPL
Source module gst-plugins-text
Binary package GStreamer Text Package
Origin URL https://github/yashi/gst-plugins-text
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstTextNoop
Pad Templates:
SINK template: 'sink'
Availability: Always
Capabilities:
ANY
SRC template: 'src'
Availability: Always
Capabilities:
ANY
Element Flags:
no flags set
Element Implementation:
Has change_state() function: gst_element_change_state_func
Element has no clocking capabilities.
Element has no URI handling capabilities.
Pads:
SRC: 'src'
Pad Template: 'src'
SINK: 'sink'
Pad Template: 'sink'
Element Properties:
name : The name of the object
flags: readable, writable
String. Default: "textnoop0"
parent : The parent of the object
flags: readable, writable
Object of type "GstObject"
</pre>
</div>
</div>
<div id="outline-container-orgc0a9cac" class="outline-2">
<h2 id="orgc0a9cac"><span class="section-number-2">5</span> Pad: chain</h2>
<div class="outline-text-2" id="text-5">
<p>
ところが、データーを流そうとすると怒られます。いろいろ起りますね…。もうちょいです。
</p>
<pre class="example">
GST_PLUGIN_PATH=. gst-launch-1.0 -q fakesrc num-buffers=1 ! textnoop ! fakesink
(gst-launch-1.0:20837): GStreamer-CRITICAL **: chain on pad textnoop0:sink but it has no chainfunction
ERROR: from element /GstPipeline:pipeline0/GstFakeSrc:fakesrc0: Internal data stream error.
Additional debug info:
gstbasesrc.c(2950): gst_base_src_loop (): /GstPipeline:pipeline0/GstFakeSrc:fakesrc0:
streaming stopped, reason not-supported (-6)
ERROR: pipeline doesn't want to preroll.
</pre>
<p>
chain on pad textnoop0:sink but it has no chainfunction (textnoop の sink pad で chain しようとしたけど、チェイン関数ないよ) って言われています。まぁ、たしかに追加していないので、無いわけですが..。 chain / チェイン / チェーン 関数とは、 GStreamer のパイプラインに <code>GstBuffer</code> を流している張本人の関数です。ソースエレメントから始まってシンクエレメントに辿りつくまでに、各エレメント内の chain 関数を数珠繋ぎに呼び出すことから chain 関数と呼ばれています。
</p>
<p>
<a href="https://hellolibraryworld.blogspot.jp/2015/12/gstreamer-5-pad-event.html">各エレメントは Pad で繋る</a>と言う話をしたと思いますが、これには変更がありません。つまり「エレメント内の chain 関数」とは、 「Pad に登録されている chain 用の関数」ということなのです。 <a href="https://gstreamer.freedesktop.org/documentation/plugin-development/element-types/n-to-one.html">Muxer</a> のようなエレメントは、Pad によって音声を流したり映像を流したりします。なので、chain 関数はエレメント単位ではなく、 Pad 単位になっています。
</p>
<p>
関数名も <code>gst_pad_set_chain_function()</code> となっています。
</p>
<p>
パイプラインの中は、上流から下流に、つまりsourceエレメントから sink エレメントに流れます。 source エレメントの source pad に繋っているのは、あるエレメントの sink Pad です。今回例であれば noop エレメントの sink Pad です。上流のエレメントは<a href="http://hellolibraryworld.blogspot.jp/2015/12/gstreamer-5-pad-event.html">下流のエレメントの sink pad を探し</a>、その Pad に登録されている chain 関数を呼びだすようになっています。なので noop でも sink パッドに chain 関数を登録します。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"gsttextnoop.h"</span>
<span style="color: #a020f0;">struct</span> <span style="color: #228b22;">_GstTextNoop</span>
{
<span style="color: #228b22;">GstElement</span> <span style="color: #a0522d;">parent_class</span>;
};
G_DEFINE_TYPE(GstTextNoop, gst_text_noop, GST_TYPE_ELEMENT)
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">sinktemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"sink"</span>,
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstStaticPadTemplate</span> <span style="color: #a0522d;">srctemplate</span> =
GST_STATIC_PAD_TEMPLATE (<span style="color: #8b2252;">"src"</span>,
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstFlowReturn</span> <span style="color: #0000ff;">gst_text_noop_chain</span>(<span style="color: #228b22;">GstPad</span> * <span style="color: #a0522d;">pad</span>, <span style="color: #228b22;">GstObject</span> * <span style="color: #a0522d;">parent</span>,
<span style="color: #228b22;">GstBuffer</span> * <span style="color: #a0522d;">buffer</span>);
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_class_init</span> (<span style="color: #228b22;">GstTextNoopClass</span> * <span style="color: #a0522d;">klass</span>)
{
<span style="color: #228b22;">GstElementClass</span> *<span style="color: #a0522d;">gstelement_class</span>;
gstelement_class = (<span style="color: #228b22;">GstElementClass</span> *) (klass);
gst_element_class_set_static_metadata (gstelement_class,
<span style="color: #8b2252;">"Noop Element"</span>,
<span style="color: #8b2252;">"Filter"</span>,
<span style="color: #8b2252;">"Simple element like Identity"</span>,
<span style="color: #8b2252;">"Me"</span>);
gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">void</span>
<span style="color: #0000ff;">gst_text_noop_init</span> (<span style="color: #228b22;">GstTextNoop</span> * <span style="color: #a0522d;">noop</span>)
{
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">srcpad</span>;
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">sinkpad</span>;
srcpad = gst_pad_new_from_static_template(&srctemplate, <span style="color: #8b2252;">"src"</span>);
gst_element_add_pad(GST_ELEMENT(noop), srcpad);
sinkpad = gst_pad_new_from_static_template(&sinktemplate, <span style="color: #8b2252;">"sink"</span>);
gst_element_add_pad(GST_ELEMENT(noop), sinkpad);
gst_pad_set_chain_function(sinkpad, gst_text_noop_chain);
}
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">GstFlowReturn</span>
<span style="color: #0000ff;">gst_text_noop_chain</span>(<span style="color: #228b22;">GstPad</span> * <span style="color: #a0522d;">sinkpad</span>,
<span style="color: #228b22;">GstObject</span> * <span style="color: #a0522d;">parent</span>,
<span style="color: #228b22;">GstBuffer</span> * <span style="color: #a0522d;">buffer</span>)
{
<span style="color: #228b22;">GstPad</span> *<span style="color: #a0522d;">srcpad</span>;
<span style="color: #228b22;">GstFlowRetrun</span> <span style="color: #a0522d;">ret</span>;
srcpad = gst_element_get_static_pad(GST_ELEMENT(parent), <span style="color: #8b2252;">"src"</span>);
ret = gst_pad_push(srcpad, buffer);
gst_object_ref(srcpad);
<span style="color: #a020f0;">return</span> ret;
}
</pre>
</div>
<dl class="org-dl">
<dt>static GstFlowReturn gst_text_noop_chain();</dt><dd>forward declaration です。関数は先に宣言しておいて、下に実体を書くのが GObject 流の作法のようです。</dd>
<dt><a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-set-chain-function"><code>gst_pad_set_chain_function()</code></a></dt><dd>第1引数に対象の Pad を、第2引数に関数を指定します</dd>
<dt>gst_text_noop_chain()</dt><dd>chain 関数の実体です。 <code>srcpad</code> を取得し、引数で渡ってきた <code>GstBuffer</code> を <code>srcpad</code> に push します。 <code>get()</code> した <code>srcpad</code> はリファレンスが増えているので忘れずに <code>gst_object_ref()</code> で減らしてください。</dd>
</dl>
<pre class="example">
GST_PLUGIN_PATH=. gst-launch-1.0 -q filesrc location=/tmp/a.txt ! textnoop ! filesink location=/tmp/b.txt
cmp /tmp/a.txt /tmp/b.txt
</pre>
<p>
これで、正しくデーターが流れるようになりました。 <code>a.txt</code> をコピーした <code>b.txt</code> が同じ内容になっています。
</p>
</div>
</div>
<div id="outline-container-org2ca25c1" class="outline-2">
<h2 id="org2ca25c1"><span class="section-number-2">6</span> おわりに</h2>
<div class="outline-text-2" id="text-6">
<p>
他にもエレメントでは、イベントの処理や、クエリーに反応したり、プロパティーの設定など、いろいろな事をやらなければなりません。それらの話は、また今度。</p>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-89218402274343854162016-12-12T12:55:00.000+09:002016-12-30T17:38:29.697+09:00The Meson Build System<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#org8bf4fd7">1. はじめに</a></li>
<li><a href="#org507f47d">2. Hello World</a></li>
<li><a href="#orgb4576f0">3. Build Application against GStreamer with Meson</a></li>
<li><a href="#orgbc8c85d">4. Build GStreamer Plugin with Meson</a></li>
<li><a href="#org5c71173">5. おわりに</a></li>
<li><a href="#orge217648">6. prio work</a></li>
<li><a href="#orga9165ad">7. ref</a></li>
</ul>
</div>
</div>
<div id="outline-container-org8bf4fd7" class="outline-2">
<h2 id="org8bf4fd7"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
<a href="http://mesonbuild.com/">Meson</a> というビルドシステムをご存知でしょうか? Jussi Pakkanen が作成したビルドシステムで、最近 GNOME 界隈で人気です。 Meson 自体は、 GNU Make の様に実際に build せず、 ビルド自体は Chrome Project で作られた <a href="https://ninja-build.org/">Ninja</a> を使います。 つまり Meson は GYP や CMake と同じ立ち位置です。
</p>
<p>
GYP → Make から GYP → Ninja 、Meson → Ninja と感じでしょうか。
</p>
<p>
Ninja は、 build system の高速 assembler を目指して作られただけあって、いろいろな Generator が生まれました。 その1つが Meson です。
</p>
</div>
</div>
<div id="outline-container-org507f47d" class="outline-2">
<h2 id="org507f47d"><span class="section-number-2">2</span> Hello World</h2>
<div class="outline-text-2" id="text-2">
<p>
まず最初は、C の Hello World でどのように Mesonを記述するのか見てみましょう。
</p>
<p>
C のコードはいたってふつうの Hello World です。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><stdio.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>()
{
printf(<span style="color: #8b2252;">"Hello, World!\n"</span>);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
このコードをコンパイルできるようにする Meson のコードは、次の2行です。これを <code>meson.build</code> というファイルに記載します。
</p>
<div class="org-src-container">
<pre class="src src-meson">project('helloworld', 'c')
executable('hello', 'hello.c')
</pre>
</div>
<p>
<a href="https://github.com/mesonbuild/meson/wiki/Reference%20manual#project">project()</a> でプロジェクト名と言語を、 <a href="https://github.com/mesonbuild/meson/wiki/Reference%20manual#executable">executable()</a> で実行ファイル名とソースファイル名を記述します。
</p>
<p>
Meson は In-Tree ビルドに対応していません。かならず Out-of-Tree ビルドになります。 Meson を実行するには、
</p>
<pre class="example">
meson [source dir] [build dir]
</pre>
<p>
と、します。hello.c が置いてあるディレクトリで実行するなら、次のようになります。
</p>
<pre class="example">
$ ls
hello.c meson.build
</pre>
<pre class="example">
$ meson . build
The Meson build system
Version: 0.36.0
Source dir: /tmp/meson
Build dir: /tmp/meson/build
Build type: native build
Project name: helloworld
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Build targets in project: 1
</pre>
<p>
Meson がファイルを生成し終ったら Ninja を使ってビルドします。
</p>
<pre class="example">
$ ninja -C build
ninja: Entering directory `build'
[2/2] Linking target hello
</pre>
<p>
無事、 <code>build/hello</code> が生成されました。
</p>
<pre class="example">
$ build/hello
Hello, World!
</pre>
</div>
</div>
<div id="outline-container-orgb4576f0" class="outline-2">
<h2 id="orgb4576f0"><span class="section-number-2">3</span> Build Application against GStreamer with Meson</h2>
<div class="outline-text-2" id="text-3">
<p>
ということで、次は GStreamer を使ったアプリを Meson でビルドしてみます。こちらも<a href="https://gist.github.com/yashi/1decada9a1f0e3df2a85#file-test-c">とてもシンプルなコード</a> で試してみます。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #228b22;">int</span> <span style="color: #0000ff;">main</span>(<span style="color: #228b22;">int</span> <span style="color: #a0522d;">argc</span>, <span style="color: #228b22;">char</span> *<span style="color: #a0522d;">argv</span>[])
{
<span style="color: #228b22;">GMainLoop</span> *<span style="color: #a0522d;">mainloop</span>;
<span style="color: #228b22;">GstElement</span> *<span style="color: #a0522d;">pipeline</span>;
<span style="color: #228b22;">GError</span> *<span style="color: #a0522d;">error</span> = <span style="color: #008b8b;">NULL</span>;
gst_init(&argc, &argv);
mainloop = g_main_loop_new(<span style="color: #008b8b;">NULL</span>, FALSE);
pipeline = gst_parse_launch(<span style="color: #8b2252;">"videotestsrc ! autovideosink"</span>, &error);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_main_loop_run(mainloop);
<span style="color: #a020f0;">return</span> 0;
}
</pre>
</div>
<p>
このコードを、先程と同じ <code>meson.build</code> を使ってビルドすると
</p>
<pre class="example">
[1/2] Compiling c object 'hellogst@exe/hellogst.c.o'
FAILED: hellogst@exe/hellogst.c.o
ccache cc '-Ihellogst@exe' '-fdiagnostics-color=always' '-I.' '-I..' '-pipe' '-Wall' '-Winvalid-pch' '-O0' '-g' '-MMD' '-MQ' 'hellogst@exe/hellogst.c.o' '-MF' 'hellogst@exe/hellogst.c.o.d' -o 'hellogst@exe/hellogst.c.o' -c ../hellogst.c
../hellogst.c:1:21: fatal error: gst/gst.h: No such file or directory
#include <gst/gst.h>
^
compilation terminated.
ninja: build stopped: subcommand failed.
</pre>
<p>
と、 <code>gst/gst.h</code> が見つからないと怒られてしまいます。それもそのはずで、ビルドシステムは GStreamer のヘッダーに関してなにも知りません。そこで、このアプリは GStreamer 1.0 に依存していることを教えてあげます。
</p>
<div class="org-src-container">
<pre class="src src-Meson">project('hello-gst', 'c')
gst_dep = dependency('gstreamer-1.0', version : '>=1.0')
executable('hellogst', 'hellogst.c', dependencies : gst_dep)
</pre>
</div>
<p>
<a href="https://github.com/mesonbuild/meson/wiki/Reference%20manual#dependency">dependency()</a> が、依存関係の記述です。 <code>gstreamer-1.0</code> に依存し、バージョンは <code>1.0以上</code> という風に指定しました。この記述、実は <a href="https://www.freedesktop.org/wiki/Software/pkg-config/">pkg-config</a> のモジュールの書き方と一緒です。 Meson は実行されているシステムでどのように依存関係を解決すべきか知っています。 Linux 上では pkg-config を使って解決してくれます。 もちろん Meson は Multi Platform 対応なので Windows 上でも MacOS 上でも、同じ書き方で GStreamer の依存関係を解決してくれます。
</p>
<p>
依存関係を追記したら、 <code>build</code> ディレクトリを消して試してみましょう。 (正確には Meson は一度実行された後は、自動で設定が変った後に自分自身を再度実行します。そのため削除する必要はありません。ここでは、あえて GStreamer 1.0 を見つけるログを表示するために削除しています。)
</p>
<pre class="example">
$ rm -r build
$ meson . build
The Meson build system
Version: 0.36.0
Source dir: /tmp/hello-gst
Build dir: /tmp/hello-gst/build
Build type: native build
Project name: hello-gst
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (0.29)
Native dependency gstreamer-1.0 found: YES 1.10.2 ← GStreamer を見つけました
Build targets in project: 1
</pre>
<p>
続いて ninja でビルドします。
</p>
<pre class="example">
$ ninja -C build
[0/1] Regenerating build files
The Meson build system
Version: 0.36.0
Source dir: /tmp/hello-gst
Build dir: /tmp/hello-gst/build
Build type: native build
Project name: hello-gst
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Build targets in project: 1
[2/2] Linking target hellogst
</pre>
<pre class="example">
$ cd build
$ ls
build.ninja hellogst meson-logs
compile_commands.json hellogst@exe meson-private
</pre>
<p>
<code>hellogst</code> が生成されました。
</p>
<p>
他にも、いろいろな中間ファイルが生成されています。
</p>
<pre class="example">
$ tree
.
├── build.ninja
├── compile_commands.json
├── hellogst
├── hellogst@exe
│ └── hellogst.c.o
├── meson-logs
│ └── meson-log.txt
└── meson-private
├── build.dat
├── coredata.dat
├── install.dat
├── meson_benchmark_setup.dat
├── meson_test_setup.dat
├── sanitycheckc.c
└── sanitycheckc.exe
3 directories, 12 files
</pre>
</div>
</div>
<div id="outline-container-orgbc8c85d" class="outline-2">
<h2 id="orgbc8c85d"><span class="section-number-2">4</span> Build GStreamer Plugin with Meson</h2>
<div class="outline-text-2" id="text-4">
<p>
さて、やっと本題です。 GStreamer の Plugin を Meson でビルドしてみます。次の空っぽの Plugin をビルドします。
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #483d8b;">#include</span> <span style="color: #8b2252;"><gst/gst.h></span>
<span style="color: #483d8b;">#include</span> <span style="color: #8b2252;">"config.h"</span>
<span style="color: #a020f0;">static</span> <span style="color: #228b22;">gboolean</span>
<span style="color: #0000ff;">plugin_init</span> (<span style="color: #228b22;">GstPlugin</span> * <span style="color: #a0522d;">plugin</span>)
{
<span style="color: #a020f0;">return</span> TRUE;
}
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
gsttext,
<span style="color: #8b2252;">"Text Plugins for GStreamer"</span>,
plugin_init,
PACKAGE_VERSION,
<span style="color: #8b2252;">"LGPL"</span>,
<span style="color: #8b2252;">"GStreamer Text Package"</span>,
<span style="color: #8b2252;">"https://github/yashi/gst-plugins-text"</span>)
</pre>
</div>
<p>
<code>Meson.build</code> は次のようになります。
</p>
<div class="org-src-container">
<pre class="src src-Meson">project('gst-plugins-text', 'c', version : '0.1.0')
src = ['src/gsttext.c']
gst_dep = dependency('gstreamer-1.0', version : '>1.0')
cdata = configuration_data()
cdata.set_quoted('PACKAGE', meson.project_name())
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
configure_file(output : 'config.h', configuration : cdata)
gsttext = library('gsttext', src, dependencies : gst_dep)
</pre>
</div>
<dl class="org-dl">
<dt>project()</dt><dd>新しく <code>version</code> を追加しています。それ以外は、名前が異なるだけで同じ内容です</dd>
<dt>src</dt><dd><code>executable()</code> に直接指定していたソースコードを変数に外出ししました。ファイルのリストなので <code>[</code> <code>]</code> で括っています</dd>
<dt>configuration_data()</dt><dd><p>
設定を記載するためのデーターを作成します。最初はからっぽ。言語で C を選択していると <code>#define</code> が記述されたファイルが生成されます
</p>
<div class="org-src-container">
<pre class="src src-C"><span style="color: #b22222;">/*</span>
<span style="color: #b22222;"> * Autogenerated by the Meson build system.</span>
<span style="color: #b22222;"> * Do not edit, your changes will be lost.</span>
<span style="color: #b22222;"> </span><span style="color: #b22222;">*/</span>
<span style="color: #483d8b;">#pragma</span> once
<span style="color: #483d8b;">#define</span> <span style="color: #a0522d;">PACKAGE</span> <span style="color: #8b2252;">"gst-plugins-text"</span>
<span style="color: #483d8b;">#define</span> <span style="color: #a0522d;">PACKAGE_VERSION</span> <span style="color: #8b2252;">"0.1.0"</span>
</pre>
</div></dd>
<dt>cdata.set_quoted()</dt><dd>設定を追加します。設定値を <code>"</code> <code>"</code> で括りたいので <code>_quoted</code> を使っています。括らないなら <code>set()</code> が使えます</dd>
<dt>configure_file()</dt><dd>設定ができあがったら、ファイルに書き出します。ここでは autotools の名残りで <code>config.h</code> にしてみました</dd>
<dt>library()</dt><dd>実行ファイルではなくライブラリを作成したいので、 <code>executable()</code> ではなく <code>library()</code> を使います。ファイル名と、ソースコード、そして依存を記載します</dd>
</dl>
<pre class="example">
$ meson . build
The Meson build system
Version: 0.36.0
Source dir: /home/yashi/src/gst/gst-plugins-text
Build dir: /home/yashi/src/gst/gst-plugins-text/build
Build type: native build
Project name: gst-plugins-text
Native c compiler: ccache cc (gcc 6.2.1)
Build machine cpu family: x86_64
Build machine cpu: x86_64
Found pkg-config: /usr/bin/pkg-config (0.29)
Native dependency gstreamer-1.0 found: YES 1.10.2
Build targets in project: 1
</pre>
<pre class="example">
ninja -C build
ninja: Entering directory `build'
[2/2] Linking target libgsttext.so
</pre>
<pre class="example">
GST_PLUGIN_PATH=`pwd`/build gst-inspect-1.0 gsttext
Plugin Details:
Name gsttext
Description Text Plugins for GStreamer
Filename /home/yashi/src/gst/gst-plugins-text/build/libgsttext.so
Version 0.1.0
License LGPL
Source module gst-plugins-text
Binary package GStreamer Text Package
Origin URL https://github/yashi/gst-plugins-text
0 features:
</pre>
</div>
</div>
<div id="outline-container-org5c71173" class="outline-2">
<h2 id="org5c71173"><span class="section-number-2">5</span> おわりに</h2>
<div class="outline-text-2" id="text-5">
<p>
いかがだったでしょうか? ビルドスクリプトは頻繁に更新するものではないので、Autotools の書き方を毎回忘れてしまうという人でも Meson だったら簡単じゃないでしょうか? Linux でも Windows でも MacOS でも使えるという利点や、依存関係が Python と ninja だけになるという点も嬉しいです。しかし、プログラマーにとって一番嬉しいのは、ビルド時間が劇的に早くなることによって、コンパイルによって集中が途切れず、開発効率が改善されることじゃないでしょうか。え? <a href="https://www.xkcd.com/303/">コンパイル中に休憩</a> できなくなって困るなんてことはないですよね?
</p>
</div>
</div>
<div id="outline-container-orge217648" class="outline-2">
<h2 id="orge217648"><span class="section-number-2">6</span> prio work</h2>
<div class="outline-text-2" id="text-6">
<ul class="org-ul">
<li><a href="https://www.gnu.org/software/make/">GNU Make</a></li>
<li><a href="https://www.gnu.org/software/autoconf/autoconf.html">GNU Autotools</a></li>
<li><a href="https://cmake.org/">CMake</a></li>
<li><a href="https://gyp.gsrc.io/">GYP</a></li>
<li><a href="https://ninja-build.org/">Ninja</a></li>
</ul>
</div>
</div>
<div id="outline-container-orga9165ad" class="outline-2">
<h2 id="orga9165ad"><span class="section-number-2">7</span> ref</h2>
<div class="outline-text-2" id="text-7">
<ul class="org-ul">
<li><a href="http://mesonbuild.com/">http://mesonbuild.com/</a></li>
<li><a href="https://www.youtube.com/watch?v=ae9_rNuFaQM">https://www.youtube.com/watch?v=ae9_rNuFaQM</a></li>
<li><a href="https://lists.freedesktop.org/archives/wayland-devel/2016-November/031984.html">https://lists.freedesktop.org/archives/wayland-devel/2016-November/031984.html</a></li>
<li><a href="https://cgit.freedesktop.org/gstreamer/gstreamer/commit/?id=b2f9808722a0254acba17ef98a612a2792184e12">https://cgit.freedesktop.org/gstreamer/gstreamer/commit/?id=b2f9808722a0254acba17ef98a612a2792184e12</a></li>
<li><a href="https://lists.freedesktop.org/archives/gstreamer-devel/2016-September/060231.html">https://lists.freedesktop.org/archives/gstreamer-devel/2016-September/060231.html</a></li>
<li><a href="https://ninja-build.org/">https://ninja-build.org/</a></li>
<li><a href="https://www.youtube.com/watch?v=KPi0AuVpxLI">https://www.youtube.com/watch?v=KPi0AuVpxLI</a></li>
<li><a href="https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git/plain/README">https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git/plain/README</a></li>
<li><a href="https://www.xkcd.com/303/">https://www.xkcd.com/303/</a></li>
</ul>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-4203047984565163352016-12-06T11:42:00.001+09:002016-12-30T17:38:03.762+09:00GStreamer でテキスト処理 1: Core機能だけで cat, cp, dd, & tee<div id="table-of-contents">
<h2>Table of Contents</h2>
<div id="text-table-of-contents">
<ul>
<li><a href="#orgf5e80e5">1. はじめに</a></li>
<li><a href="#orgf406c96">2. cat & cp</a></li>
<li><a href="#orgb15031a">3. dd</a></li>
<li><a href="#org55ec598">4. tee</a></li>
<li><a href="#org883c7aa">5. おわりに</a></li>
</ul>
</div>
</div>
<div id="outline-container-orgf5e80e5" class="outline-2">
<h2 id="orgf5e80e5"><span class="section-number-2">1</span> はじめに</h2>
<div class="outline-text-2" id="text-1">
<p>
GStreamer は、パイプラインでエレメントを繋いでいく形でデーターを処理する、マルチメディアフレームワークです。この仕組み、Unix のパイプと似ていると思ったことはありませんか?
</p>
<pre class="example">
cat /tmp/a.txt | grep foo
echo foo | tee /tmp/a.txt
cat /tmp/a.txt /tmp/b.txt >> /tmp/c.txt
</pre>
<p>
<a href="https://en.wikipedia.org/wiki/Unix_philosophy#Doug_McIlroy_on_Unix_programming">Doug McIlroy が述べた</a>ように Unix の Philosophy の1つに、"Write programs to handle text streams, because that is a universal interface." 「テキストのストリームを扱うプログラムを書こう。だってそれが共通のインターフェイスなのだから。」というのがあります。 Unix がテキストストリームを共通インターフェイスとしているパイプラインならば、GStreamer は GstBuffer を共通インターフェイスにしたパイプライン構造です。GStreamer は Multimedia Stream を扱うことに特化していますが、テキストもまたメディアデーターの1形態だとすれば テキストファイルも GStreamer でも扱えるはずです。
</p>
<p>
このシリーズでは、テキスト処理を題材に GStreamer Plugin の作成方法を紹介したいと思います。
</p>
<p>
第1回目は、おさらいという意味も含め Plugin を作成しなくてもできる cat と cp、dd、tee の紹介です。
</p>
</div>
</div>
<div id="outline-container-orgf406c96" class="outline-2">
<h2 id="orgf406c96"><span class="section-number-2">2</span> cat & cp</h2>
<div class="outline-text-2" id="text-2">
<ul class="org-ul">
<li><p>
cat a.txt
</p>
<pre class="example">
gst-launch-1.0 -q filesrc location=a.txt ! fdsink
</pre>
<p>
最初は簡単に、a.txt を cat します。cat は指定されたファイルを標準出力に書き出します。GStreamer でファイルを指定するには filesrc を、標準出力を指定するには fdsink を使います。
</p></li>
<li><p>
cat a.txt | cat
</p>
<pre class="example">
gst-launch-1.0 -q filesrc location=a.txt ! identity ! fdsink
</pre>
<p>
次は cat したデーターを cat に渡してみましょう。cat コマンドは、標準入力から受けたデーターをそのまま標準出力に書き出します。GStreamer では identity というエレメントがアップストリームから受けたデーターをそのままダウンストリームに渡します。identity はそのまま受け渡す以外にも <a href="https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-identity.html">いろいろ使える機能</a> が入っているので、マニュアルを確認してみると面白いです。
</p></li>
<li><p>
cat a.txt > b.txt; cp a.txt b.txt
</p>
<pre class="example">
gst-launch-1.0 -q filesrc location=a.txt ! filesink location=b.txt
</pre>
<p>
今度は、リダイレクトしてみましょう。これは cp と同じ結果になります。標準出力ではなく、ファイルに書き出す場合は filesink を使います。
</p></li>
<li><p>
cat a.txt >> b.txt
</p>
<pre class="example">
gst-launch-1.0 -q filesrc location=a.txt ! filesink append=true location=b.txt
</pre>
<p>
もちろん、追記も可能です。 filesink の append プロパティを true にします。
</p></li>
<li><p>
cat a.txt b.txt > c.txt
</p>
<pre class="example">
gst-launch-1.0 -q concat name=c ! filesink location=c.txt filesrc location=a.txt ! c. filesrc location=b.txt ! c.
</pre>
<p>
cat コマンドは、複数のファイルを concat (連結) するところから名前が付きました。GStreamer にも concat するエレメントがあります。2つの filesrc で指定された a.txt と b.txt が concat エレメントによって1つになり c.txt に書き出されます。
</p></li>
<li><p>
cat *.txt > all
</p>
<pre class="example">
gst-launch-1.0 -q splitfilesrc location='*.txt' ! filesink location=all
</pre>
<p>
いちいちファイルを指定するのが面倒なとき、よく wildcard 「*」を使いますよね? GStreamer でも可能です。splitfilesrc は「*」に対応しています。shellが「*」を展開しないように、シングルクオート「'」でくくってください。
</p></li>
<li><p>
cat a-01.txt a-02.txt a-03.txt > b.txt
</p>
<pre class="example">
gst-launch-1.0 -q multifilesrc location=a-%02d.txt ! filesink location=b.txt
</pre>
<p>
もしファイルに連番が振られているなら multifilesrc が便利です。「%d」を使ってファイル名の連番部分を指定します。「%d」は printf() と同じ表記です。
</p></li>
<li><p>
cat a.txt > /dev/null
</p>
<pre class="example">
gst-launch-1.0 -q filesrc location=a.txt ! fakesink
</pre>
<p>
出力を捨てたいときも良くありますよね。そんな時は /dev/null の代りに fakesink に捨てましょう。
</p></li>
<li><p>
cat /dev/null > a.txt
</p>
<pre class="example">
gst-launch-1.0 -q fakesrc num-buffers=0 ! filesink location=a.txt
</pre>
<p>
逆にファイルを空っぽにしたいこともあります。そんな時は fakesrc を使うことができます。
</p></li>
</ul>
</div>
</div>
<div id="outline-container-orgb15031a" class="outline-2">
<h2 id="orgb15031a"><span class="section-number-2">3</span> dd</h2>
<div class="outline-text-2" id="text-3">
<ul class="org-ul">
<li><p>
dd if=a.txt bs=1 count=1
</p>
<pre class="example">
gst-launch-1.0 -q filesrc location=/tmp/a.txt blocksize=1 num-buffers=1 ! fdsink
</pre>
<p>
ddは cat と違いファイルの一部を取り出すときに良く使います。最初の1バイトだけ取り出したい時は blocksize を 1 にして num-buffers で一枚だけ取り出します。
</p></li>
<li><p>
dd if=/dev/zero bs=100 count=2
</p>
<pre class="example">
gst-launch-1.0 -q fakesrc sizetype=fixed sizemax=100 num-buffers=2 ! filesink location=/tmp/a.txt
</pre>
<p>
ゼロ埋めされたファイルを作成するときも、dd は活躍します。200バイトのゼロ埋めされたファイルは、100バイトのバッファー2枚という指定でも作成できます。
</p></li>
</ul>
</div>
</div>
<div id="outline-container-org55ec598" class="outline-2">
<h2 id="org55ec598"><span class="section-number-2">4</span> tee</h2>
<div class="outline-text-2" id="text-4">
<ul class="org-ul">
<li><p>
cat a.txt | tee b.txt
</p>
<pre class="example">
gst-launch-1.0 filesrc location=/tmp/a.txt ! tee name=t t.src_0 ! queue ! fdsink t.src_1 ! filesink location=/tmp/b.txt
</pre>
<p>
標準出力にもファイルにも書き出したいときに tee コマンドはとても便利です。GStreamer の tee エレメントは2ストリーム以上にも対応しているので、もっと多くの場所に同時に書き出すことも可能です。
</p></li>
</ul>
</div>
</div>
<div id="outline-container-org883c7aa" class="outline-2">
<h2 id="org883c7aa"><span class="section-number-2">5</span> おわりに</h2>
<div class="outline-text-2" id="text-5">
<p>
このように、テキストファイルも所詮データーなので、GstBuffer に格納すれば GStreamer のパイプラインを流すことが可能です。マルチメディアデーターとテキストデーターが違う点と言えば、処理をする単位が画像や映像のフレームや音のサンプル毎ではなく、「行」毎に処理をするという点です。 grep コマンドが行毎に検索することを考えても Unixコマンドは、行を基本単位として動いています。
</p>
<p>
GStreamer には「行」という概念がありません。正確には、フレームやサンプルという概念もなく、フレームに分けるパーサーエレメントがあるだけです。つまり行毎に分けるパーサーを作れば、テキストデーターを行毎に処理できるようになります。次回は、テキストデーターを行に分ける Plugin の作成から入ってみようと思います。
</p>
</div>
</div>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-30072120239353612082015-12-11T19:50:00.000+09:002016-12-30T17:38:03.759+09:00GStreamer でプログラミング 6 (Buffer と Memory)<p>
GStreamer のパイプライン内を流れているのは <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html"><code>GstEvent</code></a> と <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html"><code>GstBuffer</code></a> ということでしたが、 実際にマルチメディアデーターを運んでいる方の <code>GstBuffer</code> を覗いてみましょう。
</p>
<p>
<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GstBuffer-struct"><code>GstBuffer</code> の構造体</a> は、
</p>
<script src="https://gist.github.com/yashi/59d07dc2019bea34a9ab.js"></script>
<p>
と定義されています。
</p>
<p>
<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#GstBuffer.description">APIドキュメント</a>によると
</p>
<blockquote>
<p>
バッファーは、GStreamerのデーターを運ぶ基本ユニットであり、タイミング情報や、オフセット、バッファーが持つ GstMemory ブロックに関係するメタデーターなどが含まれている。
</p>
</blockquote>
<p>
と言うことらしいです。メタデーターはとりあえず置いといて、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstMemory.html"><code>GstMemory</code></a> が気になりますね。だって、 <code>struct GstBuffer</code> の中に <code>GstMemory</code> なんて入っていないし、どうなってんでしょう? 答は <a href="http://cgit.freedesktop.org/gstreamer/gstreamer/tree/gst/gstbuffer.c?id=1.6.0#n153"><code>GstBufferImpl</code></a> にありました。
</p>
<script src="https://gist.github.com/yashi/5f5f5f4cc04f2a5a8cf1.js"></script>
<p>
つまり、
</p>
<div class="figure">
<p><a href="http://3.bp.blogspot.com/-UqMCtf4seWg/Vmqp1I2-eFI/AAAAAAAAFbI/hXcDkYCF7hE/s1600/buffer-memory.png" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-UqMCtf4seWg/Vmqp1I2-eFI/AAAAAAAAFbI/hXcDkYCF7hE/s320/buffer-memory.png" /></a>
</p>
</div>
<p>
こんな風に、<a href="https://ja.wikipedia.org/wiki/Bridge_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3">Bridge パターン</a>を使って <code>GstBufferImpl</code> の方で <code>GstMemory</code> を持っているんですね。
</p>
<p>
さて、 <code>GstMemory</code> の方に行ってみましょう。 <code>GstMemory</code> は <code>GstAllocator</code> によって確保されるメモリです。 <code>GstAllocator</code> は、「いろいろな条件に合ったメモリをよしなに確保してくれるアロケーター」とでも今は覚えておいてください。 <code>gst_allocator_alloc()</code> でアロケーターを指定しない、つまり NULL を指定すると、システムのデフォルトアロケーターが使われます。
</p>
<div class="figure">
<p><object type="image/svg+xml" data="https://upload.wikimedia.org/wikipedia/commons/7/7d/Question_opening-closing.svg" >
Sorry, your browser does not support SVG.</object>
</p>
</div>
<p>
確保できたメモリは、 <code>malloc()</code> されたメモリのように、そのまま扱うことができません。どのようなメモリが確保できたかは、利用したアロケーターによって異なります。もしかすると、ぜんぜんメモリとは異なる状態かもしれません。このようなデーターを 「<a href="https://en.wikipedia.org/wiki/Opaque_data_type">Opaque data type</a>」と言います。
</p>
<p>
どのような構造のメモリなのか分らないので、そのままではアクセスすることができません。そのため CPUから利用する場合は、かならず「アクセスするよ (map)」「終ったよ (unmap)」と指示する必要があります。それぞれ、 <a href="https://developer.gnome.org/gstreamer/stable/gstreamer-GstMemory.html#gst-memory-map"><code>gst_memory_map()</code></a> と <a href="https://developer.gnome.org/gstreamer/stable/gstreamer-GstMemory.html#gst-memory-unmap"><code>gst_memory_unmap()</code></a> です。 組み込みやカーネルのコードを知っている人であれば、「メモリ空間にマップしたので、触れる」と言えば、感覚として分るでしょうか? または、ファイルを <a href="https://ja.wikipedia.org/wiki/Mmap"><code>mmap()</code></a> してメモリとして触るような感じでしょうか。
</p>
<p>
<a href="https://ja.wikipedia.org/wiki/Malloc"><code>malloc()</code></a> されるようなシステムメモリであれば、このような仕組みは不要です。しかし GStreamer はマルチメディアを扱うフレームワークです。ビデオ処理や OpenGL 用のメモリを確保する場合もあります。その時 GPU 側のメモリの方が都合が良いかもしれません。 <a href="http://devblogs.nvidia.com/parallelforall/unified-memory-in-cuda-6/">CUDA 6 の Unified Memory</a> や <a href="https://en.wikipedia.org/wiki/Heterogeneous_System_Architecture">AMD の HSA</a> の様に CPU から直接触れる GPU メモリも増えそうですが、実際のハードウェアや OS によって状況が異なります。そのため、メモリアクセスの前後で、必要な処理をするタイミングを作ってあげる必要があったのです。
</p>
<p>
それでは、早速 <code>GstBuffer</code> と <code>GstMemory</code> を使って実験してみましょう。次の 4つを試してみたいと思います。
</p>
<ol class="org-ol">
<li>GstBuffer を確保</li>
<li>GstMemory を確保して、"abc" と書き、GstBuffer に追加</li>
<li>もう1つ GstMemory を確保して、"12345" と書き、GstBuffer に追加</li>
<li>GstBuffer を確認</li>
</ol>
<p>
まずは、 <code>GstBuffer</code> です。
</p>
<script src="https://gist.github.com/yashi/8dfb65d973f080a2603e.js"></script>
<p>
<code>GstBuffer</code> は、 <a href="https://developer.gnome.org/gstreamer/stable/gstreamer-GstBuffer.html#gst-buffer-new"><code>gst_buffer_new()</code></a> <a href="https://developer.gnome.org/gstreamer/stable/gstreamer-GstBuffer.html#gst-buffer-new-allocate">な</a> <a href="https://developer.gnome.org/gstreamer/stable/gstreamer-GstBuffer.html#gst-buffer-new-wrapped">ど</a> で取得します。 <code>gst_buffer_new()</code> で取得したときは、サイズは 0、持っている <code>GstMemory</code> ( <code>nr</code> ) も 0 です。
</p>
<pre class="example">
buf:
size: 0
maxsize: 0
nr: 0
</pre>
<p>
次は、 <code>GstMemory</code> を作成してみます。
</p>
<script src="https://gist.github.com/yashi/bde0e3699adf94e520e7.js"></script>
<p>
<code>GstMemory</code> は、 <code>gst_allocator_alloc()</code> で取得します。この実験ではアロケーターとアロケーターへのパラメーターは気にしないので、NULL を指定します。確保するメモリは、3 byte にしてみましょう。これで確保できたメモリは、ちゃんと size が 3 になっています。 maxsize が 10 なのは、後で少し追加可能なように、ちょっと多めにメモリが確保されるようになっているからです。
</p>
<p>
このメモリに、3文字 <code>"abc"</code> と書き込みます<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>。 <code>gst_memory_map()</code> と <code>gst_memory_unmap()</code> で括るのを忘れずに。これで最初に確保した <code>GstMemory</code> には "abc" と書かれました。では、このメモリを、先程確保した <code>GstBuffer</code> に追加してみましょう。
</p>
<pre class="example">
mem 1:
size: 3
maxsize: 10
buf:
size: 3
maxsize: 10
nr: 1
</pre>
<p>
ちゃんと、メモリブロックの数が 1 になりました。 <code>GstBuffer</code> が表示するサイズは、内包するメモリブロックのままのようです。
</p>
<p>
もう1つ、 <code>GstMemory</code> を確保します。
</p>
<script src="https://gist.github.com/yashi/c2afa2541608d65a95de.js"></script>
<p>
今度は、確保する領域を 6 byte にし、"12345" と書き込みます。今度は、NUL 文字も含め 6文字です。 今回の <code>GstMemory</code> の <code>maxsize</code> は、13 になるようです。
</p>
<pre class="example">
mem 2:
size: 6
maxsize: 13
buf:
size: 9
maxsize: 16
nr: 2
abc12345
</pre>
<p>
2つ目のメモリブロックが追加された <code>GstBuffer</code> の方は、どうでしょう? <code>size</code> は前回の 3 と 今回の 6 で 9 になり、 <code>nr</code> は 2 になっています。でも、 <code>maxsize</code> は 10 + 13 = 23 を期待していたのに、16となりました。なぜでしょう?
</p>
<div class="figure">
<p><a href="http://4.bp.blogspot.com/-ljgSX4PXmY8/Vmqpy9cpCBI/AAAAAAAAFbM/F5xVOJUcXf4/s1600/maxsize.png" imageanchor="1" ><img border="0" src="http://4.bp.blogspot.com/-ljgSX4PXmY8/Vmqpy9cpCBI/AAAAAAAAFbM/F5xVOJUcXf4/s320/maxsize.png" /></a>
</p>
</div>
<p>
<code>GstBuffer</code> は、内部に持っているメモリブロックを列べ、あたかも連続したメモリ空間のように見せてくれます。その時 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html#gst-buffer-get-sizes">maxsize として見えるのは最後のメモリブロックの空き領域分だけ</a>のようです。これは、そういう仕様だと理解するしかないようです。
</p>
<p>
メモリバッファーと言えば、「リニアなメモリ空間」というシンプルな物を想像しますが、GStreamer では、とても複雑なことをしています。この <code>GstMemory</code> の機能は、長年続いた Gstreamer 0.x 系から、1.x系にするときに追加された機能です。たとえば <a href="https://en.wikipedia.org/wiki/YUV">YUV 4:2:0</a> のように <a href="https://en.wikipedia.org/wiki/Luma_(video)">Luma</a> と <a href="https://en.wikipedia.org/wiki/Chrominance">Chrominance</a> が空間として分れている場合、ハードウェアがバラバラのメモリ空間にデーターがあることを期待しているかもしれません。しかし CPU から触るときは、まとまったデーターとして触りたい。なので map すると内部にあるメモリが合わさって (mergeされて) 見える作りになっています。GStreamer は、さまざまなデーターを扱うため、どうしてもこの柔軟な機能が必要だったようです。
</p>
<p>
GStreamer を使っていないくても、不連続なメモリを使いたいことは良くあります。そんなとき使ってみたくなりませんか?
</p>
<p>
ぜひ、お試しあれ。
</p>
<script src="https://gist.github.com/yashi/c47c443c6b17bc6a4aba.js"></script>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">
<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1">1</a></sup> <div class="footpara"><p class="footpara">
実験のため、NUL文字を省いて書き込んでいます。そのため、文字列として扱うのは危険ですので注意してください。
</p></div></div>
</div>
</div>yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-65616223519876957382015-12-10T01:01:00.000+09:002016-12-30T17:38:03.771+09:00GStreamer でプログラミング 5 (Pad と Event)<p>
パイプライン構造をしている GStreamer で、各エレメントを繋ぐ大事な役割をしているのが <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html">GstPad</a> です。
</p>
<p>
<a href="http://hellolibraryworld.blogspot.jp/2015/12/gstreamer-2-bus-message.html">cat の例</a> では、 <code>filesrc</code> エレメントと <code>fdsink</code> エレメントが繋がっています。 <code>gst-launch</code> の記法では、「 <code>!</code> 」を使って、「左側のエレメントと右側のエレメントを繋ぐ」を表現しています。 Unix パイプの「 <code>|</code> 」と同じ使い方です。
</p>
<div class="figure">
<p><a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-elements-link.html"><img src="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/images/linked-elements.png" alt="linked-elements.png" /></a>
</p>
<p><span class="figure-number">Figure 1:</span> GStreamer Application Development Manual の Linking elementsから抜粋</p>
</div>
<p>
パイプラインの図を見ても分るように、各エレメントはいくつかのパッド(Pad)を持っていて、これらのパッドが繋がることでエレメントが繋がることができます。ある瞬間にひとつのパッドが繋がることができるのは、1つだけです。かならず 1対1の関係になります。
</p>
<p>
<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/index.html">マニュアル</a> では、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-link"><code>gst_element_link()</code></a> を使って<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/section-elements-link.html">2つのエレメントを繋いで</a> いますが、実はこの関数 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-link-pads"><code>gst_element_link_pads()</code></a> のラッパー関数です。本来なら繋ぐのはパッド同士なので、「エレメントA のパッド1 を エレメント B のパッド2に繋げ」となるところですが、 <code>gst_element_link()</code> では、「Pad の名前は指定しないので、よしなに繋いでおいて」という感じでしょうか。
</p>
<p>
各エレメントがどのようなパッドを持つのかというのは、しっかりとドキュメント化されています。たとえば <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-filesrc.html"><code>filesrc</code></a> であれば、
</p>
<dl class="org-dl">
<dt>name</dt><dd>src</dd>
<dt>direction</dt><dd>source</dd>
<dt>presence</dt><dd>always</dd>
<dt>details</dt><dd>ANY</dd>
</dl>
<p>
という感じに。 <code>filesrc</code> は、方向(direction) が "source" のパッド1つしか持っていません。source 方向のパッドは下位 (downstream) にデーターを出すためのパッドです。 <code>filesrc</code> が「Source Element」と言われる所以です。名前(name)はそのまま "src"。Presence が "always" となっています。"always" なパッドは、エレメントが生成された後であれば、いつでも存在するという意味です。この様なパッドは、「Static pad」と呼ばれます。逆に必要にならないと存在しないパッドは、 「Dyanmic Pad」と呼ばれます。
</p>
<p>
次に、フィルターエレメントである <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-tee.html"><code>tee</code></a> も見てみましょう。
</p>
<dl class="org-dl">
<dt>name</dt><dd>sink</dd>
<dt>direction</dt><dd>sink</dd>
<dt>presence</dt><dd>always</dd>
<dt>details</dt><dd>ANY</dd>
</dl>
<dl class="org-dl">
<dt>name</dt><dd>src_%u</dd>
<dt>direction</dt><dd>source</dd>
<dt>presence</dt><dd>request</dd>
<dt>details</dt><dd>ANY</dd>
</dl>
<p>
フィルターエレメントは、上流と下流の両方で他のエレメントと繋がります。そのため、方向(direction)が "sink" と "source" の 2種類のパッドを持ちます。 <code>tee</code> は、上流から来たデーターを複製するエレメントです。そのため、下流に流す Sourceパッドを複数持ちます。それぞれのパッドには、0始まりのインデックス番号が振られます。"src_%u" と書かれているのはそのためです。また、"request" された時、つまり繋がるエレメントの数に合わせてパッドが生成されるので presence には "request" と記載されています。
</p>
<p>
その他パッドについては、マニュアルの「<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-pads.html">Pads and capabilities</a>」が詳しいです。
</p>
<p>
さて、Pad 同士が繋っているなら、辿って行けば対になっているパッドが分るはずです。さらにパッドは自分を保持しているエレメントの事も知っています。それなら、端のエレメントから辿って行くことで、隣りのエレメントまで行けるはずですよね?
</p>
<pre class="example">
filesrc0 → src pad → sink pad → fdsink0
</pre>
<p>
と、たどってみましょう。
</p>
<script src="https://gist.github.com/yashi/8662e1b64ed228d8d4a6.js"></script>
<p>
Presense が "always" のパッドは、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-static-pad"><code>gst_element_get_static_pad()</code></a> で取り出します。名前は "src" でした。<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-get-peer"><code>gst_pad_get_peer()</code></a> という関数は、指定したパッドに繋っているパッドを返してくれます。取り出したパッドは <code>fdsink0</code> の sink pad なはず。このパッドを持っているエレメント、つまり親のエレメントを <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-get-parent-element"><code>gst_pad_get_parent_element()</code></a> で取り出せば、ちゃんと名前が <code>"fdsink0"</code> となっているエレメントになりました。
</p>
<pre class="example">
./a.out
name: fdsink0
hello
</pre>
<p>
もう1つパッドには重要な仕事があります。隣のエレメントにデーターを渡すという大事な仕事です。 GStreamer がパイプライン構造をしているのは、何らかの情報を流すためですもんね。パイプラインの中を流れるデーターは <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html"><code>GstEvent</code></a> や <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBuffer.html"><code>GstBuffer</code></a> というオジェクトです。
</p>
<p>
パッドを眺めていると、流れているデーターを見ることができます。医療や検査で、ある場所を調査する道具を <a href="https://en.wikipedia.org/wiki/Test_probe">プローブ</a> と言いますが、パッドにもプローブ(Probe)を付けて覗き見ることができます。その名も <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#gst-pad-add-probe"><code>gst_pad_add_probe()</code></a> 。必要に応じてプローブの種類を選べます。指定は、<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#GstPadProbeType">enum GstPadProbeType</a> で行います。
</p>
<p>
ここでは例として、以前紹介した End of Stream を拾ってみましょう。End of Stream は Event Type なので、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#GST-PAD-PROBE-TYPE-EVENT-DOWNSTREAM:CAPS"><code>GST_PAD_PROBE_TYPE_BUFFER_EVENT_DOWNSTREAM</code></a> を指定します。
</p>
<script src="https://gist.github.com/yashi/05299ff10bb892f77018.js"></script>
<p>
イベントが流れたときに、 <code>on_probe()</code> を呼び出してもらいます。 <code>on_probe()</code> には、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPad.html#GstPadProbeInfo"><code>GstPadProbeInfo</code></a> が渡ってくるので、この情報から <code>event</code> を取り出し、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstEvent.html#GST-EVENT-TYPE-NAME:CAPS"><code>GST_EVENT_TYPE_NAME()</code></a> で種類を表示します。
</p>
<p>
ついでに <code>on_message()</code> も修正して、End of Stream のメッセージが来たら表示してみます。これで、パッド上をイベントが流れる方が先か、バスにメッセージが投げられるのが先か分りますね。実行すると、 <code>stream-start</code> や <code>segment</code> というイベントの後に、 <code>eos</code> が流れています。どうやらバスにメッセージが流れる方が後のようです。 <code>on_message()</code> の方が後なのは、 sink エレメントにまで EOS が届いてから、バスにメッセージが投げられるからです。
</p>
<pre class="example">
./a.out
name: fdsink0
event: stream-start
event: segment
hello
event: eos
message: eos
</pre>
<p>
お試しあれ。
</p>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-67208735255358403822015-12-09T10:53:00.001+09:002016-12-30T17:38:03.775+09:00GStreamer でプログラミング 4 (Bin と Iterator)<p>
もし本当に GStreamer の pipeline に入っているエレメントの名前が分らなかったら?
</p>
<p>
pipeline は自分が持っているエレメントを知っています。なので、pipeline に問い合わせて、持っているエレメントをイテレーターで貰うことができます。これ、pipeline の親クラスである <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBin.html"><code>GstBin</code></a> の機能なんです。
</p>
<p>
Ruby のように <a href="https://en.wikipedia.org/wiki/Iterator#Implicit_iterators">Internal Iterator</a> (内部イテレータ)かつ、<a href="https://en.wikipedia.org/wiki/Type_system#Dynamic_type-checking_and_runtime_type_information">Dynamic Typing</a> (<a href="https://ja.wikipedia.org/wiki/%E5%8B%95%E7%9A%84%E5%9E%8B%E4%BB%98%E3%81%91">動的型付け</a>) であれば
</p>
<script src="https://gist.github.com/yashi/68c434b87d1a66ad21a3.js"></script>
<p>
と書けるのですが、C で実装されている GStreamer では、ちょっと面倒ですね。
</p>
<ol class="org-ol">
<li>Pipelineから外部イテレータを貰い ( <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBin.html#gst-bin-iterate-elements"><code>gst_bin_iterate_elements()</code></a> )</li>
<li>次のエレメントをイテレーターから貰います。( <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstIterator.html#gst-iterator-next"><code>gst_iterator_next()</code></a> )</li>
<li>貰ったエレメントは、実は <a href="https://developer.gnome.org/gobject/unstable/gobject-Generic-values.html">GValue</a> という「なんでも内包できる構造体」なので、これから実際のエレメントを取り出します。 ( <code>g_value_get_object()</code> )</li>
</ol>
<script src="https://gist.github.com/yashi/252e3fff2c5af3521d99.js"></script>
<p>
<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstIterator.html#gst-iterator-foreach"><code>gst_iterator_foreach()</code></a> もあるのですが <a href="https://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B_.28since_C.2B.2B11.29">Lambda が使えない C</a> では、関数を指定する必要があります。
</p>
<p>
GValue は、なんでも入れることができるという点で、「void*」のようなものですが、型情報を持っている点が異なります。型が必須なので必ず使う前に <a href="https://developer.gnome.org/gobject/stable/gobject-Generic-values.html#G-VALUE-INIT:CAPS"><code>G_VALUE_INIT</code></a> または <a href="https://developer.gnome.org/gobject/stable/gobject-Generic-values.html#g-value-init"><code>g_value_init()</code></a> で初期化してください。
</p>
<p>
GValue や GstElement は、Dynamic Typing を持っていない C のために実装された <a href="https://developer.gnome.org/gobject/stable/chapter-gtype.html">Glib Dynamic Type System</a> を使っています。 <a href="https://developer.gnome.org/gobject/stable/chapter-gobject.html">GObject</a> が基本クラスです。Ruby C API で言うところの、 <a href="http://docs.ruby-lang.org/en/2.2.0/README_EXT.html"><code>VALUE</code></a> ですね。
</p>
<p>
他のエレメントを内包できるエレメントは、イテレーターが使えることが多いので、一度やり方を覚えると便利です。お試しあれ。
</p>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-5469046547924075782015-12-08T12:14:00.000+09:002016-12-30T17:38:03.768+09:00GStreamer でプログラミング 3 (Element と Property)<p>
GStreamer の <a href="http://www.slideshare.net/shocrunch/about-gstreamer-10-application-development-for-beginners-55594448/14">pipeline には複数のエレメントが含まれている</a>ようですが、どうやってエレメントを取り出すんでしょうか? 自分でエレメントを作成し、pineline に追加した時は良いのですが、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstParse.html"><code>gst_parse_launch()</code></a> を使った場合は?
</p>
<p>
答は、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBin.html"><code>gst_bin_get_by_name()</code></a> を使います。でも取り出したいエレメントの名前が分らない? 各エレメントのインスタンス名は、デフォルトで「<a href="http://cgit.freedesktop.org/gstreamer/gstreamer/tree/gst/gstobject.c?id=1.6.0#n561">"エレメント名" + "インデックス番号"</a>」となるので簡単です。インデックスは、0 始まりなので <code>filesrc</code> を取り出すときは、 <code>"filesrc0"</code> を指定してあげれば良いです。パイプライン中で、同じエレメントの複数のインスタンスがある場合、順次番号が増えていきます。また、 <code>queue2</code> のようにエレメント名が数字で終っている場合は、「<a href="http://cgit.freedesktop.org/gstreamer/gstreamer/tree/gst/gstobject.c?id=1.6.0#n556">"エレメント名" + "-" + "インデックス番号"</a>」と間にハイフンが入ります。
</p>
<p>
前回のコードの <code>filesrc</code> を取り出すなら、こんな感じです。
</p>
<script src="https://gist.github.com/yashi/20653d3fe2e173f0af3d.js"></script>
<pre class="example">
gst-launch-1.0 -q \
videotestsrc ! tee name=t \
t. ! queue ! ximagesink \
t. ! queue ! ximagesink \
t. ! queue ! ximagesink \
t. ! queue ! ximagesink
</pre>
<p>
よく、こんな風に <code>name=</code> となっているものを<a href="http://qiita.com/shocrunch/items/8438f993afe068d66d40">見かけ</a>ます。 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-filesrc.html"><code>tee</code></a> や <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-qtdemux.html"><code>demux</code></a> を使うときに使われることが多いようです。実はこれが、 <code>gst-launch</code> で名前を付ける方法です。 <code>gst-launch</code> の時も、名前を指定しなければ <code>tee0</code> と指定できます。
</p>
<pre class="example">
gst-launch-1.0 -q \
videotestsrc ! tee \
tee0. ! queue ! ximagesink \
tee0. ! queue ! ximagesink \
tee0. ! queue ! ximagesink \
tee0. ! queue ! ximagesink
</pre>
<p>
なので、この2つのコマンドは同じように動きます。ただし、同じエレメントを複数使った場合は紛らわしかったり、実装が変って違う名前が付くと動かなくなるので、明示的に指定しています。
</p>
<p>
さて、C に戻ります。
</p>
<pre class="example">
gst-launch-1.0 filesrc name=mysrc location=a.txt ! fdsink
</pre>
<p>
これをそのまま <code>gst_parse_launch()</code> に渡し
</p>
<div class="org-src-container">
<pre class="src src-C">pipeline = gst_parse_launch(<span style="color: #e9b96e;">"filesrc name=mysrc location=a.txt ! fdsink"</span>, &error);
</pre>
</div>
<p>
とすると、
</p>
<div class="org-src-container">
<pre class="src src-C">src = gst_bin_get_by_name(GST_BIN(pipeline), <span style="color: #e9b96e;">"mysrc"</span>);
</pre>
</div>
<p>
として取れるんですね。取れた <code>filesrc</code> エレメントの名前は、もちろん <code>"mysrc"</code> です。 <code>gst_element_get_name()</code> で確認できます。 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html"><code>GstElement</code></a> の元になっている <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstObject.html"><code>GstObject</code></a> に <code>name</code> というプロパティがあるので、 <code>GstElement</code> から派生しているオジェクトであれば、みんな名前が取れます。 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstPipeline.html#GstPipeline.object-hierarchy"><code>pipeline</code></a> でも。お試しあれ。
</p>
<script src="https://gist.github.com/yashi/926c3999b2c9cb005741.js"></script>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-84574750513501380782015-12-07T00:06:00.000+09:002016-12-30T17:38:03.782+09:00GStreamer でプログラミング 2 (Bus と Message)<p>
GStreamer を使って <code>cat</code> コマンドのようなプログラムを作成するには? <code>gst-launch</code> を使うと、こんな感じでしょうか。
</p>
<pre class="example">
echo hello > a.txt
gst-launch-1.0 filesrc location=a.txt ! fdsink
hello
</pre>
<p>
C で書いても簡単で、こんな感じです。
</p>
<script src="https://gist.github.com/yashi/1fd947973b87b917c59d.js"></script>
<p>
これを <a href="http://hellolibraryworld.blogspot.jp/2015/12/gstreamer-1-pipeline-parse.html">前回</a>のプログラムと比較してみると、文字列部分を <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-filesrc.html"><code>filesrc</code></a> と <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-fdsink.html"><code>fdsink</code></a> に変更しているだけだということが分ります。
</p>
<p>
しかし、このままでは 「hello」と表示された後、プログラムが終了せずに止ってしまいます。理由は、指定したファイルを最後まで読み出したにもかかわらず、 <code>mainloop</code> から抜けてこないからです。 <a href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html">glib の main loop</a> から抜けるには、 <a href="https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-main-loop-quit"><code>g_main_loop_quit()</code></a> を使いますが、どうやったら「最後まで読み出した」ということが分るのでしょう?
</p>
<p>
答は、<a href="http://www.slideshare.net/shocrunch/about-gstreamer-10-application-development-for-beginners-55594448/12">Bus</a> を見ると分ります。 Bus は、プログラムと pipeline がやりとりを行うためのオブジェクトです。pipeline になにかあったときには、かならず bus に<a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstBus.html">メッセージ</a>(GstMessage) が流れてきます。このメッセージを見てみましょう。
</p>
<p>
Bus は、 <code>pipeline</code> が持っています。 pipeline から <code>gst_element_get_bus()</code> を使って bus を取り出します。
取り出した bus に、「なにか変化があったらこの関数を呼んで」という <code>gst_bus_add_watch()</code> で、 <code>on_message()</code> を登録しておきます。
</p>
<p>
<code>on_message()</code> では、届いたメッセージによって適切な処理をさせます。今回のように「ファイルを最後まで読み出した」時、 Bus には <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/section-events-definitions.html#section-events-eos">End of Stream (EOS)</a> が届くはずですので、EOS が届いたら、 <code>g_main_loop_quit()</code> を呼び mainloop から抜けるように指示します。
</p>
<script src="https://gist.github.com/yashi/e029db46e16b0194bb7e.js"></script>
<p>
これで、hello と表示した後にプログラムが終了するようになります。
</p>
<p>
本物の <code>cat</code> は、複数のファイルを引数に取って concat するコマンドですが、 <code>filesrc</code> では複数のファイルを扱えません。 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-multifilesrc.html"><code>multifilesrc</code></a> や <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-splitfilesrc.html"><code>splitfilesrc</code></a> というエレメントもありますが、若干挙動が異なります。 <code>cat</code> と同じよう動作をさせる方法は、また今度紹介します。
</p>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0tag:blogger.com,1999:blog-70023934373588417.post-16648545601291641552015-12-06T09:20:00.000+09:002016-12-30T17:38:03.749+09:00GStreamer でプログラミング 1 (Pipeline と Parse )<p>
<a href="http://qiita.com/advent-calendar/2015/gstreamer">GStreamerの Advent Calendar</a>に誘われたので、ちょっとだけ書いてみます。
</p>
<p>
<a href="http://gstreamer.freedesktop.org/">GStreamer</a> は、gst-launch というデバッグ用ツールでも簡単にパイプラインを構成できて、とても便利です。しかし、GStreamerの本当の力は、ライブラリーを使ってプログラムを書いたときに見えてくると思います。そこで、このシリーズではマルチメディアデータを使わずに、GStreamer の素晴らしさを紹介してみたいと思います。
</p>
<p>
まずは、「<a href="http://qiita.com/shocrunch/items/8438f993afe068d66d40">CoreElements について</a>」でも紹介されている、 <a href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-videotestsrc.html"><code>videotestsrc</code></a> を使った例をコードにしてみます。
</p>
<pre class="example">
gst-launch-1.0 videotestsrc ! autovideosink
</pre>
<p>
と同じことをするコードです。
</p>
<script src="https://gist.github.com/yashi/1decada9a1f0e3df2a85.js"></script>
<p>
結構簡単に C のコードになりそうです。
</p>
<ol class="org-ol">
<li>gst_init() で、初期化</li>
<li>main loop 作成</li>
<li>pipeline 作成</li>
<li>再生</li>
<li>main loop入る</li>
</ol>
<p>
で、 <code>gst-launch</code> 版と同じような動作をするプログラムが書けました。
</p>
yashihttp://www.blogger.com/profile/01750991940524874285noreply@blogger.com0