link もっと前
   2017年 11月 7日 -
      2017年 11月 16日  
link もっと後

link 未来から過去へ表示
link 過去から未来へ表示(*)

日々

link permalink

Android メディア処理

昨日(2017年 11月 6日の日記参照)の続きです。

メッセージの宛先

メッセージが OMXNodeInstance::onMessages() 関数にたどり着き、次に OMXNodeInstance::mObserver に渡されていることはわかりましたが、これは一体何者でしょうか?

observer とは?

//android/frameworks/av/media/libstagefright/include/OMXNodeInstance.h

struct OMXNodeInstance {
...
private:
...
    sp<IOMXObserver> mObserver;


//android/frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp

OMXNodeInstance::OMXNodeInstance(
        OMX *owner, const sp<IOMXObserver> &observer, const char *name)
    : mOwner(owner),
      mNodeID(0),
      mHandle(NULL),
      mObserver(observer), //★★コンストラクタの 2番目の引数 observer で初期化している★★
      mDying(false),
      mSailed(false),
      mQueriedProhibitedExtensions(false),
      mBufferIDCount(0)
{


//android/frameworks/av/media/libstagefright/omx/OMX.cpp

status_t OMX::allocateNode(
        const char *name, const sp<IOMXObserver> &observer,
        sp<IBinder> *nodeBinder, node_id *node) {

...

    OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name); //★★allocateNode の 2番目の引数 observer を渡している★★

残念ながら allocateNode() の引数がわからないため、observer に何が指定されているかわかりません。

allocateNode の observer にたどり着くのは大変

//android/frameworks/av/media/libstagefright/ACodec.cpp

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {

...

    OMXClient client; //★★binder のクライアント★★
    if (client.connect() != OK) { //★★デコーダは別プロセスで実行されているので、接続する★★
        mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
        return false;
    }

...

    sp<IOMX> omx = client.interface(); //★★binder を使って通信するためのインタフェース★★


//android/frameworks/av/media/libstagefright/OMXClient.cpp

class OMXClient {
public:
    OMXClient();

    status_t connect();
    void disconnect();

    sp<IOMX> interface() {
        return mOMX; //★★インタフェースはこれ★★
    }


//android/frameworks/av/media/libstagefright/OMXClient.cpp

status_t OMXClient::connect() {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> playerbinder = sm->getService(String16("media.player"));
    sp<IMediaPlayerService> mediaservice = interface_cast<IMediaPlayerService>(playerbinder);

...

    sp<IOMX> mediaServerOMX = mediaservice->getOMX();

...

    sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
    sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);

...

    sp<IOMX> mediaCodecOMX = codecservice->getOMX();

...

    mOMX = new MuxOMX(mediaServerOMX, mediaCodecOMX); //★★インタフェースはここで設定している★★

    return OK;
}

なかなか複雑ですね。このインタフェースとやらの実体は MuxOMX だと思われます。

allocateNode の observer

//android/frameworks/av/media/libstagefright/ACodec.cpp

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {

...

    sp<IOMX> omx = client.interface(); //★★MuxOMX のオブジェクトのはず★★

...

    sp<CodecObserver> observer = new CodecObserver; //★★たぶんこれが observer★★
    IOMX::node_id node = 0;

    status_t err = NAME_NOT_FOUND;
    for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
            ++matchIndex) {
        componentName = matchingCodecs[matchIndex];
        quirks = MediaCodecList::getQuirksFor(componentName.c_str());

        pid_t tid = gettid();
        int prevPriority = androidGetThreadPriority(tid);
        androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
        err = omx->allocateNode(componentName.c_str(), observer, &mCodec->mNodeBinder, &node); //★★ここで observer を MuxOMX::allocateNode に渡す★★


//android/frameworks/av/media/libstagefright/OMXClient.cpp

status_t MuxOMX::allocateNode(
        const char *name, const sp<IOMXObserver> &observer,
        sp<IBinder> *nodeBinder,
        node_id *node) {

...

    sp<IOMX> omx;

    node_location loc = getPreferredCodecLocation(name);
    if (loc == CODECPROCESS) {
        omx = mMediaCodecOMX;
    } else if (loc == MEDIAPROCESS) {
        omx = mMediaServerOMX;
    } else {
        if (mLocalOMX == NULL) {
            mLocalOMX = new OMX;
        }
        omx = mLocalOMX;
    }

    status_t err = omx->allocateNode(name, observer, nodeBinder, node); //★★OMX::allocateNode() などに渡す★★
    ALOGV("allocated node_id %x on %s OMX", *node, omx == mMediaCodecOMX ? "codecprocess" :
            omx == mMediaServerOMX ? "mediaserver" : "local");

突然、ここで三択(mMediaCodecOMX と mMediaServerOMX と mLocalOMX)になりますが、いずれの選択肢を選んでも、渡す observer は変わらず CodecObserver のはずです。それさえわかれば、とりあえず OK です。

[編集者: すずき]
[更新: 2017年 11月 23日 21:38]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

Android メディア処理

昨日(2017年 11月 7日の日記参照)の続きです。

どうも Android のメッセージシステムのたらい回しが激しすぎて、話が一向に進みません。本来見たかった道をざっくりまとめておくと、

  • デコード終わり
  • コールバック OMXNodeInstance::OnFillBufferDone()
  • instance->owner()->OnFillBufferDone() → OMX::OnFillBufferDone()
  • OMX::CallbackDispatcher::post()

これが 2017年 11月 6日の日記の前半部分です。post() によってメッセージがキューに追加されます。

  • OMX::CallbackDispatcher::loop()
  • OMX::CallbackDispatcher::dispatch()
  • mOwner->onMessages() → OMXNodeInstance::onMessages()
  • mObserver->onMessages() → ?

これが 2017年 11月 6日の日記の後半部分です。キューに追加されたメッセージは別スレッドで処理され、mObserver なるものに渡されていました。

  • mObserver->onMessages() → CodecObserver::onMessages()

そして 2017年 11月 7日の日記を丸々使い、OMXNodeInstance::mObserver の正体が CodecObserver だと思われるところまで来ました。

やっと来た observer

//android/frameworks/av/media/libstagefright/ACodec.cpp

struct CodecObserver : public BnOMXObserver {

...

    // from IOMXObserver
    virtual void onMessages(const std::list<omx_message> &messages) {
...

        sp<AMessage> notify = mNotify->dup();
        bool first = true;
        sp<MessageList> msgList = new MessageList();
        for (std::list<omx_message>::const_iterator it = messages.cbegin();
              it != messages.cend(); ++it) {
            const omx_message &omx_msg = *it;
            if (first) {
                notify->setInt32("node", omx_msg.node);
                first = false;
            }

            sp<AMessage> msg = new AMessage;
            //★★omx_msg.type は OMX::OnFillBufferDone() にて FILL_BUFFER_DONE に設定★★
            msg->setInt32("type", omx_msg.type);
            switch (omx_msg.type) {
...
                case omx_message::FILL_BUFFER_DONE:
                {
                    //★★omx_message から AMessage に変換している★★
                    msg->setInt32(
                            "buffer", omx_msg.u.extended_buffer_data.buffer);
                    msg->setInt32(
                            "range_offset",
                            omx_msg.u.extended_buffer_data.range_offset);
                    msg->setInt32(
                            "range_length",
                            omx_msg.u.extended_buffer_data.range_length);
                    msg->setInt32(
                            "flags",
                            omx_msg.u.extended_buffer_data.flags);
                    msg->setInt64(
                            "timestamp",
                            omx_msg.u.extended_buffer_data.timestamp);
                    msg->setInt32(
                            "fence_fd", omx_msg.fenceFd);
                    break;
                }
...
            }
            msgList->getList().push_back(msg);
        }
        notify->setObject("messages", msgList);
        notify->post(); //★★notify とは??★★
    }

また変なものが出てきました。notify = mNotify->dup() なので、次に mNotify が何者かを見ていきます。

今度は notify

//android/frameworks/av/media/libstagefright/ACodec.cpp

struct CodecObserver : public BnOMXObserver {
...

    void setNotificationMessage(const sp<AMessage> &msg) {
        mNotify = msg;
    }


bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {

...

    sp<CodecObserver> observer = new CodecObserver;
    IOMX::node_id node = 0;

...

    status_t err = NAME_NOT_FOUND;
    for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
            ++matchIndex) {
        componentName = matchingCodecs[matchIndex];
        quirks = MediaCodecList::getQuirksFor(componentName.c_str());

        pid_t tid = gettid();
        int prevPriority = androidGetThreadPriority(tid);
        androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
        err = omx->allocateNode(componentName.c_str(), observer, &mCodec->mNodeBinder, &node); //★★11月 7日の日記参照★★

...

    notify = new AMessage(kWhatOMXMessageList, mCodec);
    observer->setNotificationMessage(notify); //★★ここで設定している★★

従って mNotify は AMessage(kWhatOMXMessageList, mCodec) です。dup() は複製しているだけでしょうから、notify->post() は AMessage::post() が呼ばれるのでしょう。

今度は AMessage

//android/frameworks/av/media/libstagefright/foundation/AMessage.cpp

status_t AMessage::post(int64_t delayUs) {
    sp<ALooper> looper = mLooper.promote();
    if (looper == NULL) {
        ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
        return -ENOENT;
    }

    looper->post(this, delayUs); //★★たらい回し再び、mLooper とは?★★
    return OK;
}

...

AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
    : mWhat(what),
      mNumItems(0) {
    setTarget(handler); //★★mLooper はここから設定★★
}

...

void AMessage::setTarget(const sp<const AHandler> &handler) {
    if (handler == NULL) {
        mTarget = 0;
        mHandler.clear();
        mLooper.clear();
    } else {
        mTarget = handler->id();
        mHandler = handler->getHandler();
        mLooper = handler->getLooper(); //★★mLooper は AMessage コンストラクタの 2番目の引数の getLooper() が返す値★★
    }
}

うーん、また訳の分からないものが出てきましたね…。

[編集者: すずき]
[更新: 2017年 11月 23日 23:54]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

Android メディア処理

昨日(2017年 11月 8日の日記参照)の続きです。

本来見たかった道をざっくりまとめておくと、

  • デコード終わり
  • コールバック OMXNodeInstance::OnFillBufferDone()
  • instance->owner()->OnFillBufferDone() → OMX::OnFillBufferDone()
  • OMX::CallbackDispatcher::post()

これが 2017年 11月 6日の日記の前半で分かった部分。

  • OMX::CallbackDispatcher::loop()
  • OMX::CallbackDispatcher::dispatch()
  • mOwner->onMessages() → OMXNodeInstance::onMessages()
  • mObserver->onMessages() → ?

これが 2017年 11月 6日の日記の後半で分かった部分。

  • mObserver->onMessages() → CodecObserver::onMessages()

これが 2017年 11月 7日の日記で分かった部分。

  • mObserver->onMessages() → CodecObserver::onMessages()
  • notify->post() → AMessage::post()
  • looper->post() → ?

これが 2017年 11月 8日の日記で分かった部分です。そのあとは looper とは何ぞや?という点を追いかけていましたが、まだわからない状態です。

  • looper->post() → ?
  • looper = AMessage::mLooper
  • mLooper = handler->getLooper()
  • handler は AMessage() の 2番目の引数
  • notify = mNotify = AMessage(kWhatOMXMessageList, mCodec) だから、handler = ACodec::BaseState::mCodec
  • looper->post() → mCodec->getLooper()->post() のはず

再開

肝心の ACodec::BaseState::mCodec に何が入っているのか?については UninitializedState を手掛かりに見ていきます。

mCodec

//android/frameworks/av/media/libstagefright/ACodec.cpp

struct ACodec::BaseState : public AState {
    BaseState(ACodec *codec, const sp<AState> &parentState = NULL);

...

    ACodec *mCodec; //★★これが知りたい★★


//★★UninitializedState を手掛かりに見てみる★★

struct ACodec::UninitializedState : public ACodec::BaseState {

...

ACodec::UninitializedState::UninitializedState(ACodec *codec)
    : BaseState(codec) { //★★BaseState に丸投げ★★
}


//★★BaseState を見てみる★★

struct ACodec::BaseState : public AState {
    BaseState(ACodec *codec, const sp<AState> &parentState = NULL);

...

ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
    : AState(parentState),
      mCodec(codec) { //★★引数をそのまま設定しているだけ★★
}


//★★UninitializedState の生成個所を探す★★

ACodec::ACodec()
    : mQuirks(0),
...
      mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0) {
    mUninitializedState = new UninitializedState(this); //★★this が指すものは ACodec★★
    mLoadedState = new LoadedState(this);

つまり ACodec::BaseState::mCodec は、UninitializeState を生成した ACodec です。もう一つの謎 getLooper() が何を返すのか?も見てみます。

getLooper

//android/frameworks/av/include/media/stagefright/foundation/AHandler.h

struct AHandler : public RefBase {

...

    wp<ALooper> getLooper() const {
        return mLooper; //★★mLooper を返すだけ★★
    }

...

    inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
        mID = id;
        mLooper = looper; //★★mLooper は setID の引数そのまま★★
    }


//android/frameworks/av/include/media/libstagefright/foundation/ALooperRoster.cpp

ALooper::handler_id ALooperRoster::registerHandler(
        const sp<ALooper> looper, const sp<AHandler> &handler) {
    Mutex::Autolock autoLock(mLock);

    if (handler->id() != 0) {
        CHECK(!"A handler must only be registered once.");
        return INVALID_OPERATION;
    }

    HandlerInfo info;
    info.mLooper = looper;
    info.mHandler = handler;
    ALooper::handler_id handlerID = mNextHandlerID++;
    mHandlers.add(handlerID, info);

    handler->setID(handlerID, looper); //★★setID を呼んでいる個所はここだけ★★

    return handlerID;
}


//media/libstagefright/foundation/ALooper.cpp

ALooperRoster gLooperRoster;

...

ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
    return gLooperRoster.registerHandler(this, handler);
}

ALooper::registerHandler は ALooper を AHandler に登録する仕組み、AHandler::getLooper() は AHandler に登録された ALooper を返す仕組みのようです。取得 / 設定が一致しないのでややこしいです。設計を失敗したのかなあ?

例えば AHandler *hoge と ALooper *fuga があって fuga->registerHandler(hoge) としたならば、hoge->getLooper() は先ほど登録した fuga を返します。

  • looper->post() → ?
  • looper = AMessage::mLooper
  • mLooper = handler->getLooper()
  • handler は AMessage() の 2番目の引数
  • notify = mNotify = AMessage(kWhatOMXMessageList, mCodec) だから、handler = ACodec::BaseState::mCodec
  • looper->post() → mCodec->getLooper()->post() のはず
  • ACodec::BaseState::mCodec は、UninitializeState を生成した ACodec だから
  • looper->post() → ACodec::getLooper()->post() のはず

ちなみに ACodec は AHandler を継承しているので getLooper() 関数を持っています。

ここまで分かれば ALooper::registerHandler() を呼んでいる個所を見て、引数が ACodec オブジェクトであろう場所を見つければ、looper が指しているのが、どの ALooper なのか?がやっと判明します。

しかし registerHandler() の呼び出し箇所は非常に多くて、追いきれません。うーん、別のアプローチが必要でしょうか……?

[編集者: すずき]
[更新: 2017年 11月 24日 00:38]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

ポケモン GO

ポケモン GO のアプリはいつまで経ってもバグだらけです。新しく実装された機能(ジムバトル)は当然バグバグで、通信周りが弱くハングしまくります。

  • ジムで木の実投げるときにジムから離れると操作不能
  • 木の実を投げたときに対象のポケモンが別のプレーヤに倒されると操作不能
  • ジムバトルの開始時にハング、勝利時にもハング
  • ログイン画面で WiFi から 3G/4G に切り換えるとログイン不能
  • ポケモン捕獲時にハングする
  • キャラクターが真っ黒になる
  • 地図が一面海になる

操作不能になったり、ハングされたりするとアプリを再起動するしかないですが、ハイエンド機じゃないせいか起動も動作も遅くてイライラします。

1日 15分もやってないのにこの有様なので、もっと長時間遊んでいる人はイライラで憤死するんじゃなかろうか?

折角面白いのにアプリが残念すぎる……。

[編集者: すずき]
[更新: 2017年 11月 19日 20:24]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

Kindle の変なフォントが直っていた

いつのまにか Kindle がアップデートされており、フォントが変になる問題(2017年 10月 13日の日記参照)が直っていました。あとストアアプリのメニューがダブって表示される問題(2017年 10月 12日の日記参照)も直っていました。

直してくれてありがとう。やっぱりおかしいってわかってたんだね……。

[編集者: すずき]
[更新: 2017年 11月 19日 20:16]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

テレビの栄枯盛衰

一応、テレビ向けの SoC を作るお仕事をしていますので、たまに電器屋さんにテレビを見に行ってますが、どこに行ってもテレビのコーナーは年々狭くなっています。

土曜日に梅田ヨドバシに行きましたが、一時期は 3F をテレビが支配していたのに、今や 1/3 位です。ホームシアターを除いて純粋にテレビだけでカウントしたら、もっと狭いかもしれません。テレビを家電の 1つと見れば、フロアの 1/3 を占めているのは破格の待遇と言えますが、つい過去の栄光と比べてしまいます。

同じ階にはオーディオコーナーと、キャンプ用品コーナーがありました。テレビはオーディオコーナーと同じか、やや負けてるくらいの広さでしょうか?この先、テレビの面積が復活することは無いでしょうから、そのうちオーディオと合併して、オーディオ・ビジュアルコーナーになるんでしょう、たぶん。

レコーダーはどこ?

レコーダーは悲惨で棚 2つしかありませんでした。BD-R とか DVD-R みたいなメディアそのものを売っている棚の方が多いように見えますけど、バランスおかしくないです??

番組を録画する文化は日本特有らしく、もともとレコーダーは日本でしか流行っていません。海外でも販売していますが、プレーヤーの方が好まれるようです。頼みの日本がこの状態だと、そのうちレコーダーという製品は無くなるかもしれません。

プレーヤーは細々と続くと思います。とはいえ、黒物家電メーカーは全員ボロボロで、次世代の光ディスク規格を作るほどの元気は無いでしょう。BD を 8K 規格まで延命して、ネットにバトンタッチして終わりか、下手したら 4K で燃え尽きて終わりかもね……。

[編集者: すずき]
[更新: 2017年 11月 19日 21:16]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
   2017年 11月 7日 -
      2017年 11月 16日  
link もっと後

管理用メニュー

link 記事を新規作成

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDF ファイル RSS 1.0
QR コード QR コード

最終更新: 5/22 22:26

カレンダー

<2017>
<<<11>>>
---1234
567891011
12131415161718
19202122232425
2627282930--

最近のコメント 5件

  • link 18年05月20日
    すずき 「数えたことはありませんが Windows...」
    (更新:05/22 22:26)
  • link 18年05月20日
    hdk 「Linux も、先日の Meltdown...」
    (更新:05/21 22:55)
  • link 15年12月27日
    すずき 「お役に立てて何よりです。」
    (更新:05/12 21:45)
  • link 15年12月27日
    名前 「助かりました。勉強になります。」
    (更新:05/11 12:40)
  • link 13年09月13日
    すずき 「コメントありがとうございます、お役に立て...」
    (更新:05/10 09:32)

最近の記事 3件

link もっとみる
  • link 18年05月10日
    すずき 「[ポケモン GO] エラーが出て起動しなくなってしまいました。しつ...」
    (更新:05/21 02:09)
  • link 18年05月13日
    すずき 「[自動車税] 今年も自動車税の支払い時期が来ました。税額は 45,...」
    (更新:05/21 02:03)
  • link 18年05月20日
    すずき 「[最初の設計が肝心] 初期段階の設計失敗を、最終段階の設定や運用で...」
    (更新:05/21 01:41)

こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報