15778822d86b0337407514b9372562b86edfa91cdAndreas Huber/*
25778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Copyright (C) 2012 The Android Open Source Project
35778822d86b0337407514b9372562b86edfa91cdAndreas Huber *
45778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
55778822d86b0337407514b9372562b86edfa91cdAndreas Huber * you may not use this file except in compliance with the License.
65778822d86b0337407514b9372562b86edfa91cdAndreas Huber * You may obtain a copy of the License at
75778822d86b0337407514b9372562b86edfa91cdAndreas Huber *
85778822d86b0337407514b9372562b86edfa91cdAndreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
95778822d86b0337407514b9372562b86edfa91cdAndreas Huber *
105778822d86b0337407514b9372562b86edfa91cdAndreas Huber * Unless required by applicable law or agreed to in writing, software
115778822d86b0337407514b9372562b86edfa91cdAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
125778822d86b0337407514b9372562b86edfa91cdAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135778822d86b0337407514b9372562b86edfa91cdAndreas Huber * See the License for the specific language governing permissions and
145778822d86b0337407514b9372562b86edfa91cdAndreas Huber * limitations under the License.
155778822d86b0337407514b9372562b86edfa91cdAndreas Huber */
165778822d86b0337407514b9372562b86edfa91cdAndreas Huber
175778822d86b0337407514b9372562b86edfa91cdAndreas Huber//#define LOG_NDEBUG 0
185778822d86b0337407514b9372562b86edfa91cdAndreas Huber#define LOG_TAG "codec"
19377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT#include <inttypes.h>
205778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <utils/Log.h>
215778822d86b0337407514b9372562b86edfa91cdAndreas Huber
225778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include "SimplePlayer.h"
235778822d86b0337407514b9372562b86edfa91cdAndreas Huber
241bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber#include <binder/IServiceManager.h>
255778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <binder/ProcessState.h>
261bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber#include <media/ICrypto.h>
271b86fe063badb5f28c467ade39be0f4008688947Andreas Huber#include <media/IMediaHTTPService.h>
281bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber#include <media/IMediaPlayerService.h>
297e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim#include <media/MediaCodecBuffer.h>
305778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/foundation/ABuffer.h>
315778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/foundation/ADebug.h>
325778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/foundation/ALooper.h>
335778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/foundation/AMessage.h>
345b8987e7de9d04b09153f329c680d2316cdb44ecAndreas Huber#include <media/stagefright/foundation/AString.h>
355778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/MediaCodec.h>
36ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber#include <media/stagefright/MediaCodecList.h>
375778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/MediaDefs.h>
385778822d86b0337407514b9372562b86edfa91cdAndreas Huber#include <media/stagefright/NuMediaExtractor.h>
39a6195decfe4f9021bbbd7deb050495c33371366bJeff Brown#include <gui/ISurfaceComposer.h>
40df712ea86e6350f7005a02ab0e1c60c28a343ed0Mathias Agopian#include <gui/SurfaceComposerClient.h>
411a2952aee048ca7b1765e2bc09ebe9aeddaeafa3Mathias Agopian#include <gui/Surface.h>
423dca4c7a5622fc6aa03397d749c4b4c1201cc4f3Mathias Agopian#include <ui/DisplayInfo.h>
435778822d86b0337407514b9372562b86edfa91cdAndreas Huber
445778822d86b0337407514b9372562b86edfa91cdAndreas Huberstatic void usage(const char *me) {
455778822d86b0337407514b9372562b86edfa91cdAndreas Huber    fprintf(stderr, "usage: %s [-a] use audio\n"
465778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    "\t\t[-v] use video\n"
47bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                    "\t\t[-p] playback\n"
48fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    "\t\t[-S] allocate buffers from a surface\n"
49fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    "\t\t[-R] render output to surface (enables -S)\n"
50fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    "\t\t[-T] use render timestamps (enables -R)\n",
51ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber                    me);
525778822d86b0337407514b9372562b86edfa91cdAndreas Huber    exit(1);
535778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
545778822d86b0337407514b9372562b86edfa91cdAndreas Huber
555778822d86b0337407514b9372562b86edfa91cdAndreas Hubernamespace android {
565778822d86b0337407514b9372562b86edfa91cdAndreas Huber
575778822d86b0337407514b9372562b86edfa91cdAndreas Huberstruct CodecState {
585778822d86b0337407514b9372562b86edfa91cdAndreas Huber    sp<MediaCodec> mCodec;
597e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim    Vector<sp<MediaCodecBuffer> > mInBuffers;
607e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim    Vector<sp<MediaCodecBuffer> > mOutBuffers;
615aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber    bool mSignalledInputEOS;
625778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool mSawOutputEOS;
63bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    int64_t mNumBuffersDecoded;
64bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    int64_t mNumBytesDecoded;
65bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    bool mIsAudio;
665778822d86b0337407514b9372562b86edfa91cdAndreas Huber};
675778822d86b0337407514b9372562b86edfa91cdAndreas Huber
685778822d86b0337407514b9372562b86edfa91cdAndreas Huber}  // namespace android
695778822d86b0337407514b9372562b86edfa91cdAndreas Huber
705778822d86b0337407514b9372562b86edfa91cdAndreas Huberstatic int decode(
715778822d86b0337407514b9372562b86edfa91cdAndreas Huber        const android::sp<android::ALooper> &looper,
725778822d86b0337407514b9372562b86edfa91cdAndreas Huber        const char *path,
735778822d86b0337407514b9372562b86edfa91cdAndreas Huber        bool useAudio,
74bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        bool useVideo,
75fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith        const android::sp<android::Surface> &surface,
76fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith        bool renderSurface,
77fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith        bool useTimestamp) {
785778822d86b0337407514b9372562b86edfa91cdAndreas Huber    using namespace android;
795778822d86b0337407514b9372562b86edfa91cdAndreas Huber
80bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    static int64_t kTimeout = 500ll;
81bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
825778822d86b0337407514b9372562b86edfa91cdAndreas Huber    sp<NuMediaExtractor> extractor = new NuMediaExtractor;
831b86fe063badb5f28c467ade39be0f4008688947Andreas Huber    if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
845778822d86b0337407514b9372562b86edfa91cdAndreas Huber        fprintf(stderr, "unable to instantiate extractor.\n");
855778822d86b0337407514b9372562b86edfa91cdAndreas Huber        return 1;
865778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
875778822d86b0337407514b9372562b86edfa91cdAndreas Huber
885778822d86b0337407514b9372562b86edfa91cdAndreas Huber    KeyedVector<size_t, CodecState> stateByTrack;
895778822d86b0337407514b9372562b86edfa91cdAndreas Huber
905778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool haveAudio = false;
915778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool haveVideo = false;
925778822d86b0337407514b9372562b86edfa91cdAndreas Huber    for (size_t i = 0; i < extractor->countTracks(); ++i) {
935778822d86b0337407514b9372562b86edfa91cdAndreas Huber        sp<AMessage> format;
945778822d86b0337407514b9372562b86edfa91cdAndreas Huber        status_t err = extractor->getTrackFormat(i, &format);
955778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ(err, (status_t)OK);
965778822d86b0337407514b9372562b86edfa91cdAndreas Huber
975778822d86b0337407514b9372562b86edfa91cdAndreas Huber        AString mime;
985778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK(format->findString("mime", &mime));
995778822d86b0337407514b9372562b86edfa91cdAndreas Huber
100bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
101bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
102bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
103bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        if (useAudio && !haveAudio && isAudio) {
1045778822d86b0337407514b9372562b86edfa91cdAndreas Huber            haveAudio = true;
105bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        } else if (useVideo && !haveVideo && isVideo) {
1065778822d86b0337407514b9372562b86edfa91cdAndreas Huber            haveVideo = true;
1075778822d86b0337407514b9372562b86edfa91cdAndreas Huber        } else {
1085778822d86b0337407514b9372562b86edfa91cdAndreas Huber            continue;
1095778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
1105778822d86b0337407514b9372562b86edfa91cdAndreas Huber
11131de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar        ALOGV("selecting track %zu", i);
1125778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1135778822d86b0337407514b9372562b86edfa91cdAndreas Huber        err = extractor->selectTrack(i);
1145778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ(err, (status_t)OK);
1155778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1165778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CodecState *state =
1175778822d86b0337407514b9372562b86edfa91cdAndreas Huber            &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
1185778822d86b0337407514b9372562b86edfa91cdAndreas Huber
119bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        state->mNumBytesDecoded = 0;
120bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        state->mNumBuffersDecoded = 0;
121bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        state->mIsAudio = isAudio;
122bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
123f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber        state->mCodec = MediaCodec::CreateByType(
124f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                looper, mime.c_str(), false /* encoder */);
1255778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1265778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK(state->mCodec != NULL);
1275778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1285778822d86b0337407514b9372562b86edfa91cdAndreas Huber        err = state->mCodec->configure(
129ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber                format, isVideo ? surface : NULL,
130f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                NULL /* crypto */,
1311bd139a2a68690e80398b70b27ca59550fea0e65Andreas Huber                0 /* flags */);
1325778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1335778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ(err, (status_t)OK);
1345778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1355aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber        state->mSignalledInputEOS = false;
1365778822d86b0337407514b9372562b86edfa91cdAndreas Huber        state->mSawOutputEOS = false;
1375778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
1385778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1395778822d86b0337407514b9372562b86edfa91cdAndreas Huber    CHECK(!stateByTrack.isEmpty());
1405778822d86b0337407514b9372562b86edfa91cdAndreas Huber
141bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    int64_t startTimeUs = ALooper::GetNowUs();
142fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith    int64_t startTimeRender = -1;
143bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
1445778822d86b0337407514b9372562b86edfa91cdAndreas Huber    for (size_t i = 0; i < stateByTrack.size(); ++i) {
1455778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CodecState *state = &stateByTrack.editValueAt(i);
1465778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1475778822d86b0337407514b9372562b86edfa91cdAndreas Huber        sp<MediaCodec> codec = state->mCodec;
1485778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1495778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ((status_t)OK, codec->start());
1505778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1515778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
1525778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
1535778822d86b0337407514b9372562b86edfa91cdAndreas Huber
15431de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar        ALOGV("got %zu input and %zu output buffers",
1555778822d86b0337407514b9372562b86edfa91cdAndreas Huber              state->mInBuffers.size(), state->mOutBuffers.size());
1565778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
1575778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1585778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool sawInputEOS = false;
1595778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1605778822d86b0337407514b9372562b86edfa91cdAndreas Huber    for (;;) {
1615778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (!sawInputEOS) {
1625778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t trackIndex;
1635778822d86b0337407514b9372562b86edfa91cdAndreas Huber            status_t err = extractor->getSampleTrackIndex(&trackIndex);
1645778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1655778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (err != OK) {
1665aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                ALOGV("saw input eos");
1675778822d86b0337407514b9372562b86edfa91cdAndreas Huber                sawInputEOS = true;
1685778822d86b0337407514b9372562b86edfa91cdAndreas Huber            } else {
1695778822d86b0337407514b9372562b86edfa91cdAndreas Huber                CodecState *state = &stateByTrack.editValueFor(trackIndex);
1705778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1715778822d86b0337407514b9372562b86edfa91cdAndreas Huber                size_t index;
172bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
1735778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1745778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (err == OK) {
17531de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                    ALOGV("filling input buffer %zu", index);
1765778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1777e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim                    const sp<MediaCodecBuffer> &buffer = state->mInBuffers.itemAt(index);
1787e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim                    sp<ABuffer> abuffer = new ABuffer(buffer->base(), buffer->capacity());
1795778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1807e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim                    err = extractor->readSampleData(abuffer);
1815778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    CHECK_EQ(err, (status_t)OK);
1827e34bf5af26f8752d4786d3098740cdf51e2438fWonsik Kim                    buffer->setRange(abuffer->offset(), abuffer->size());
1835778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1845778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    int64_t timeUs;
1855778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    err = extractor->getSampleTime(&timeUs);
1865778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    CHECK_EQ(err, (status_t)OK);
1875778822d86b0337407514b9372562b86edfa91cdAndreas Huber
188ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber                    uint32_t bufferFlags = 0;
189ed3e3e046840d5bf1ca84a8c0cc097425e89d6d6Andreas Huber
190f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                    err = state->mCodec->queueInputBuffer(
191f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                            index,
192f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                            0 /* offset */,
193f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                            buffer->size(),
194f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                            timeUs,
195f69e53033f23f9f70fcdb28a3c2e650de0147459Andreas Huber                            bufferFlags);
1965778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1975778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    CHECK_EQ(err, (status_t)OK);
1985778822d86b0337407514b9372562b86edfa91cdAndreas Huber
1995778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    extractor->advance();
2005778822d86b0337407514b9372562b86edfa91cdAndreas Huber                } else {
2015778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    CHECK_EQ(err, -EAGAIN);
2025778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
2035778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
2045aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber        } else {
2055aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber            for (size_t i = 0; i < stateByTrack.size(); ++i) {
2065aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                CodecState *state = &stateByTrack.editValueAt(i);
2075aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber
2085aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                if (!state->mSignalledInputEOS) {
2095aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                    size_t index;
2105aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                    status_t err =
2115aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                        state->mCodec->dequeueInputBuffer(&index, kTimeout);
2125aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber
2135aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                    if (err == OK) {
21431de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                        ALOGV("signalling input EOS on track %zu", i);
2155aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber
2165aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                        err = state->mCodec->queueInputBuffer(
2175aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                                index,
2185aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                                0 /* offset */,
2195aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                                0 /* size */,
2205aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                                0ll /* timeUs */,
2215aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                                MediaCodec::BUFFER_FLAG_EOS);
2225aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber
2235aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                        CHECK_EQ(err, (status_t)OK);
2245aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber
2255aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                        state->mSignalledInputEOS = true;
2265aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                    } else {
2275aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                        CHECK_EQ(err, -EAGAIN);
2285aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                    }
2295aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber                }
2305aaeb0d64fc98f9b019a4378eb39f0ee49ee6ec4Andreas Huber            }
2315778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2325778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2335778822d86b0337407514b9372562b86edfa91cdAndreas Huber        bool sawOutputEOSOnAllTracks = true;
2345778822d86b0337407514b9372562b86edfa91cdAndreas Huber        for (size_t i = 0; i < stateByTrack.size(); ++i) {
2355778822d86b0337407514b9372562b86edfa91cdAndreas Huber            CodecState *state = &stateByTrack.editValueAt(i);
2365778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (!state->mSawOutputEOS) {
2375778822d86b0337407514b9372562b86edfa91cdAndreas Huber                sawOutputEOSOnAllTracks = false;
2385778822d86b0337407514b9372562b86edfa91cdAndreas Huber                break;
2395778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
2405778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2415778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2425778822d86b0337407514b9372562b86edfa91cdAndreas Huber        if (sawOutputEOSOnAllTracks) {
2435778822d86b0337407514b9372562b86edfa91cdAndreas Huber            break;
2445778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
2455778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2465778822d86b0337407514b9372562b86edfa91cdAndreas Huber        for (size_t i = 0; i < stateByTrack.size(); ++i) {
2475778822d86b0337407514b9372562b86edfa91cdAndreas Huber            CodecState *state = &stateByTrack.editValueAt(i);
2485778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2495778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (state->mSawOutputEOS) {
2505778822d86b0337407514b9372562b86edfa91cdAndreas Huber                continue;
2515778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
2525778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2535778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t index;
2545778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t offset;
2555778822d86b0337407514b9372562b86edfa91cdAndreas Huber            size_t size;
2565778822d86b0337407514b9372562b86edfa91cdAndreas Huber            int64_t presentationTimeUs;
2575778822d86b0337407514b9372562b86edfa91cdAndreas Huber            uint32_t flags;
2585778822d86b0337407514b9372562b86edfa91cdAndreas Huber            status_t err = state->mCodec->dequeueOutputBuffer(
2595778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    &index, &offset, &size, &presentationTimeUs, &flags,
260bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                    kTimeout);
2615778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2625778822d86b0337407514b9372562b86edfa91cdAndreas Huber            if (err == OK) {
26331de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                ALOGV("draining output buffer %zu, time = %lld us",
26431de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                      index, (long long)presentationTimeUs);
2655778822d86b0337407514b9372562b86edfa91cdAndreas Huber
266bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                ++state->mNumBuffersDecoded;
267bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                state->mNumBytesDecoded += size;
268bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
269fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                if (surface == NULL || !renderSurface) {
270fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    err = state->mCodec->releaseOutputBuffer(index);
271fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                } else if (useTimestamp) {
272fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    if (startTimeRender == -1) {
273fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                        // begin rendering 2 vsyncs (~33ms) after first decode
274fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                        startTimeRender =
275fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                                systemTime(SYSTEM_TIME_MONOTONIC) + 33000000
276fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                                - (presentationTimeUs * 1000);
277fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    }
278fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    presentationTimeUs =
279fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                            (presentationTimeUs * 1000) + startTimeRender;
280fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    err = state->mCodec->renderOutputBufferAndRelease(
281fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                            index, presentationTimeUs);
282fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                } else {
283fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                    err = state->mCodec->renderOutputBufferAndRelease(index);
284fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                }
285fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith
2865778822d86b0337407514b9372562b86edfa91cdAndreas Huber                CHECK_EQ(err, (status_t)OK);
2875778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2885778822d86b0337407514b9372562b86edfa91cdAndreas Huber                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
2895778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    ALOGV("reached EOS on output.");
2905778822d86b0337407514b9372562b86edfa91cdAndreas Huber
2915778822d86b0337407514b9372562b86edfa91cdAndreas Huber                    state->mSawOutputEOS = true;
2925778822d86b0337407514b9372562b86edfa91cdAndreas Huber                }
2935778822d86b0337407514b9372562b86edfa91cdAndreas Huber            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
2945778822d86b0337407514b9372562b86edfa91cdAndreas Huber                ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
2955778822d86b0337407514b9372562b86edfa91cdAndreas Huber                CHECK_EQ((status_t)OK,
2965778822d86b0337407514b9372562b86edfa91cdAndreas Huber                         state->mCodec->getOutputBuffers(&state->mOutBuffers));
2975778822d86b0337407514b9372562b86edfa91cdAndreas Huber
29831de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                ALOGV("got %zu output buffers", state->mOutBuffers.size());
2995778822d86b0337407514b9372562b86edfa91cdAndreas Huber            } else if (err == INFO_FORMAT_CHANGED) {
3005778822d86b0337407514b9372562b86edfa91cdAndreas Huber                sp<AMessage> format;
3015778822d86b0337407514b9372562b86edfa91cdAndreas Huber                CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
3025778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3035778822d86b0337407514b9372562b86edfa91cdAndreas Huber                ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
3045778822d86b0337407514b9372562b86edfa91cdAndreas Huber            } else {
3055778822d86b0337407514b9372562b86edfa91cdAndreas Huber                CHECK_EQ(err, -EAGAIN);
3065778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
3075778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
3085778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3095778822d86b0337407514b9372562b86edfa91cdAndreas Huber
310bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
311bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
3125778822d86b0337407514b9372562b86edfa91cdAndreas Huber    for (size_t i = 0; i < stateByTrack.size(); ++i) {
3135778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CodecState *state = &stateByTrack.editValueAt(i);
3145778822d86b0337407514b9372562b86edfa91cdAndreas Huber
315c95c2ddcdfc974f42408a377fbe2de51b94a8c94Andreas Huber        CHECK_EQ((status_t)OK, state->mCodec->release());
316bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
317bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        if (state->mIsAudio) {
31831de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar            printf("track %zu: %lld bytes received. %.2f KB/sec\n",
319bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                   i,
32031de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                   (long long)state->mNumBytesDecoded,
321bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
322bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        } else {
32331de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar            printf("track %zu: %lld frames decoded, %.2f fps. %lld"
324377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT                    " bytes received. %.2f KB/sec\n",
325bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                   i,
32631de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                   (long long)state->mNumBuffersDecoded,
327bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                   state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
32831de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar                   (long long)state->mNumBytesDecoded,
329bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
330bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        }
3315778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3325778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3335778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return 0;
3345778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
3355778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3365778822d86b0337407514b9372562b86edfa91cdAndreas Huberint main(int argc, char **argv) {
3375778822d86b0337407514b9372562b86edfa91cdAndreas Huber    using namespace android;
3385778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3395778822d86b0337407514b9372562b86edfa91cdAndreas Huber    const char *me = argv[0];
3405778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3415778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool useAudio = false;
3425778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool useVideo = false;
3435778822d86b0337407514b9372562b86edfa91cdAndreas Huber    bool playback = false;
344bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    bool useSurface = false;
345fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith    bool renderSurface = false;
346fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith    bool useTimestamp = false;
3475778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3485778822d86b0337407514b9372562b86edfa91cdAndreas Huber    int res;
349fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith    while ((res = getopt(argc, argv, "havpSDRT")) >= 0) {
3505778822d86b0337407514b9372562b86edfa91cdAndreas Huber        switch (res) {
3515778822d86b0337407514b9372562b86edfa91cdAndreas Huber            case 'a':
3525778822d86b0337407514b9372562b86edfa91cdAndreas Huber            {
3535778822d86b0337407514b9372562b86edfa91cdAndreas Huber                useAudio = true;
3545778822d86b0337407514b9372562b86edfa91cdAndreas Huber                break;
3555778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
3565778822d86b0337407514b9372562b86edfa91cdAndreas Huber            case 'v':
3575778822d86b0337407514b9372562b86edfa91cdAndreas Huber            {
3585778822d86b0337407514b9372562b86edfa91cdAndreas Huber                useVideo = true;
3595778822d86b0337407514b9372562b86edfa91cdAndreas Huber                break;
3605778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
3615778822d86b0337407514b9372562b86edfa91cdAndreas Huber            case 'p':
3625778822d86b0337407514b9372562b86edfa91cdAndreas Huber            {
3635778822d86b0337407514b9372562b86edfa91cdAndreas Huber                playback = true;
3645778822d86b0337407514b9372562b86edfa91cdAndreas Huber                break;
3655778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
366fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            case 'T':
367fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            {
368fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                useTimestamp = true;
369fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            }
370fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            // fall through
371fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            case 'R':
372fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            {
373fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                renderSurface = true;
374fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            }
375fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith            // fall through
376bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber            case 'S':
377bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber            {
378bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                useSurface = true;
379bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                break;
380bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber            }
3815778822d86b0337407514b9372562b86edfa91cdAndreas Huber            case '?':
3825778822d86b0337407514b9372562b86edfa91cdAndreas Huber            case 'h':
3835778822d86b0337407514b9372562b86edfa91cdAndreas Huber            default:
3845778822d86b0337407514b9372562b86edfa91cdAndreas Huber            {
3855778822d86b0337407514b9372562b86edfa91cdAndreas Huber                usage(me);
3865778822d86b0337407514b9372562b86edfa91cdAndreas Huber            }
3875778822d86b0337407514b9372562b86edfa91cdAndreas Huber        }
3885778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3895778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3905778822d86b0337407514b9372562b86edfa91cdAndreas Huber    argc -= optind;
3915778822d86b0337407514b9372562b86edfa91cdAndreas Huber    argv += optind;
3925778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3935778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (argc != 1) {
3945778822d86b0337407514b9372562b86edfa91cdAndreas Huber        usage(me);
3955778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
3965778822d86b0337407514b9372562b86edfa91cdAndreas Huber
3975778822d86b0337407514b9372562b86edfa91cdAndreas Huber    if (!useAudio && !useVideo) {
3985778822d86b0337407514b9372562b86edfa91cdAndreas Huber        useAudio = useVideo = true;
3995778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
4005778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4015778822d86b0337407514b9372562b86edfa91cdAndreas Huber    ProcessState::self()->startThreadPool();
4025778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4035778822d86b0337407514b9372562b86edfa91cdAndreas Huber    sp<ALooper> looper = new ALooper;
4045778822d86b0337407514b9372562b86edfa91cdAndreas Huber    looper->start();
4055778822d86b0337407514b9372562b86edfa91cdAndreas Huber
406bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    sp<SurfaceComposerClient> composerClient;
407bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    sp<SurfaceControl> control;
408bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    sp<Surface> surface;
409bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber
410bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    if (playback || (useSurface && useVideo)) {
411bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        composerClient = new SurfaceComposerClient;
4125778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
4135778822d86b0337407514b9372562b86edfa91cdAndreas Huber
414a6195decfe4f9021bbbd7deb050495c33371366bJeff Brown        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
415a6195decfe4f9021bbbd7deb050495c33371366bJeff Brown                ISurfaceComposer::eDisplayIdMain));
4163dca4c7a5622fc6aa03397d749c4b4c1201cc4f3Mathias Agopian        DisplayInfo info;
417a6195decfe4f9021bbbd7deb050495c33371366bJeff Brown        SurfaceComposerClient::getDisplayInfo(display, &info);
4183dca4c7a5622fc6aa03397d749c4b4c1201cc4f3Mathias Agopian        ssize_t displayWidth = info.w;
4193dca4c7a5622fc6aa03397d749c4b4c1201cc4f3Mathias Agopian        ssize_t displayHeight = info.h;
4205778822d86b0337407514b9372562b86edfa91cdAndreas Huber
42131de88566257d5546cf4eee9064d96926a4b0c24Lajos Molnar        ALOGV("display is %zd x %zd\n", displayWidth, displayHeight);
4225778822d86b0337407514b9372562b86edfa91cdAndreas Huber
423bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        control = composerClient->createSurface(
424bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                String8("A Surface"),
425bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                displayWidth,
426bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                displayHeight,
427bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                PIXEL_FORMAT_RGB_565,
428bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber                0);
4295778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4305778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK(control != NULL);
4315778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK(control->isValid());
4325778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4335778822d86b0337407514b9372562b86edfa91cdAndreas Huber        SurfaceComposerClient::openGlobalTransaction();
4345778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
4355778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK_EQ(control->show(), (status_t)OK);
4365778822d86b0337407514b9372562b86edfa91cdAndreas Huber        SurfaceComposerClient::closeGlobalTransaction();
4375778822d86b0337407514b9372562b86edfa91cdAndreas Huber
438bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber        surface = control->getSurface();
4395778822d86b0337407514b9372562b86edfa91cdAndreas Huber        CHECK(surface != NULL);
440bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    }
4415778822d86b0337407514b9372562b86edfa91cdAndreas Huber
442bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    if (playback) {
4435778822d86b0337407514b9372562b86edfa91cdAndreas Huber        sp<SimplePlayer> player = new SimplePlayer;
4445778822d86b0337407514b9372562b86edfa91cdAndreas Huber        looper->registerHandler(player);
4455778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4465778822d86b0337407514b9372562b86edfa91cdAndreas Huber        player->setDataSource(argv[0]);
4471a2952aee048ca7b1765e2bc09ebe9aeddaeafa3Mathias Agopian        player->setSurface(surface->getIGraphicBufferProducer());
4485778822d86b0337407514b9372562b86edfa91cdAndreas Huber        player->start();
449e98f8c04faf27df3b1829d336299ad51dad569cfAndreas Huber        sleep(60);
4505778822d86b0337407514b9372562b86edfa91cdAndreas Huber        player->stop();
4515778822d86b0337407514b9372562b86edfa91cdAndreas Huber        player->reset();
452bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    } else {
453fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith        decode(looper, argv[0], useAudio, useVideo, surface, renderSurface,
454fab8f4679795b86c7aaaf63f6be6b019cf7ea0cdDavid Smith                useTimestamp);
455bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    }
4565778822d86b0337407514b9372562b86edfa91cdAndreas Huber
457bae6f72d16a1cfc2122b4ce9b484c026ecd896b1Andreas Huber    if (playback || (useSurface && useVideo)) {
4585778822d86b0337407514b9372562b86edfa91cdAndreas Huber        composerClient->dispose();
4595778822d86b0337407514b9372562b86edfa91cdAndreas Huber    }
4605778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4615778822d86b0337407514b9372562b86edfa91cdAndreas Huber    looper->stop();
4625778822d86b0337407514b9372562b86edfa91cdAndreas Huber
4635778822d86b0337407514b9372562b86edfa91cdAndreas Huber    return 0;
4645778822d86b0337407514b9372562b86edfa91cdAndreas Huber}
465