codec.cpp revision bf6c85a013fb14960bac147c1ffd0a02a8d5f148
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "codec"
19#include <utils/Log.h>
20
21#include "SimplePlayer.h"
22
23#include <binder/ProcessState.h>
24
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/ALooper.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/DataSource.h>
30#include <media/stagefright/MediaCodec.h>
31#include <media/stagefright/MediaDefs.h>
32#include <media/stagefright/NuMediaExtractor.h>
33#include <surfaceflinger/SurfaceComposerClient.h>
34
35static void usage(const char *me) {
36    fprintf(stderr, "usage: %s [-a] use audio\n"
37                    "\t\t[-v] use video\n"
38                    "\t\t[-p] playback\n", me);
39
40    exit(1);
41}
42
43namespace android {
44
45struct CodecState {
46    sp<MediaCodec> mCodec;
47    Vector<sp<ABuffer> > mCSD;
48    size_t mCSDIndex;
49    Vector<sp<ABuffer> > mInBuffers;
50    Vector<sp<ABuffer> > mOutBuffers;
51    bool mSawOutputEOS;
52};
53
54}  // namespace android
55
56static int decode(
57        const android::sp<android::ALooper> &looper,
58        const char *path,
59        bool useAudio,
60        bool useVideo) {
61    using namespace android;
62
63    sp<NuMediaExtractor> extractor = new NuMediaExtractor;
64    if (extractor->setDataSource(path) != OK) {
65        fprintf(stderr, "unable to instantiate extractor.\n");
66        return 1;
67    }
68
69    KeyedVector<size_t, CodecState> stateByTrack;
70
71    bool haveAudio = false;
72    bool haveVideo = false;
73    for (size_t i = 0; i < extractor->countTracks(); ++i) {
74        sp<AMessage> format;
75        status_t err = extractor->getTrackFormat(i, &format);
76        CHECK_EQ(err, (status_t)OK);
77
78        AString mime;
79        CHECK(format->findString("mime", &mime));
80
81        if (useAudio && !haveAudio
82                && !strncasecmp(mime.c_str(), "audio/", 6)) {
83            haveAudio = true;
84        } else if (useVideo && !haveVideo
85                && !strncasecmp(mime.c_str(), "video/", 6)) {
86            haveVideo = true;
87        } else {
88            continue;
89        }
90
91        ALOGV("selecting track %d", i);
92
93        err = extractor->selectTrack(i);
94        CHECK_EQ(err, (status_t)OK);
95
96        CodecState *state =
97            &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
98
99        state->mCodec = MediaCodec::CreateByType(
100                looper, mime.c_str(), false /* encoder */);
101
102        CHECK(state->mCodec != NULL);
103
104        err = state->mCodec->configure(
105                format, NULL /* surfaceTexture */, 0 /* flags */);
106
107        CHECK_EQ(err, (status_t)OK);
108
109        size_t j = 0;
110        sp<ABuffer> buffer;
111        while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) {
112            state->mCSD.push_back(buffer);
113
114            ++j;
115        }
116
117        state->mCSDIndex = 0;
118        state->mSawOutputEOS = false;
119
120        ALOGV("got %d pieces of codec specific data.", state->mCSD.size());
121    }
122
123    CHECK(!stateByTrack.isEmpty());
124
125    for (size_t i = 0; i < stateByTrack.size(); ++i) {
126        CodecState *state = &stateByTrack.editValueAt(i);
127
128        sp<MediaCodec> codec = state->mCodec;
129
130        CHECK_EQ((status_t)OK, codec->start());
131
132        CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
133        CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
134
135        ALOGV("got %d input and %d output buffers",
136              state->mInBuffers.size(), state->mOutBuffers.size());
137
138        while (state->mCSDIndex < state->mCSD.size()) {
139            size_t index;
140            status_t err = codec->dequeueInputBuffer(&index);
141
142            if (err == -EAGAIN) {
143                usleep(10000);
144                continue;
145            }
146
147            CHECK_EQ(err, (status_t)OK);
148
149            const sp<ABuffer> &srcBuffer =
150                state->mCSD.itemAt(state->mCSDIndex++);
151
152            const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
153
154            memcpy(buffer->data(), srcBuffer->data(), srcBuffer->size());
155
156            err = codec->queueInputBuffer(
157                    index,
158                    0 /* offset */,
159                    srcBuffer->size(),
160                    0ll /* timeUs */,
161                    MediaCodec::BUFFER_FLAG_CODECCONFIG);
162
163            CHECK_EQ(err, (status_t)OK);
164        }
165    }
166
167    bool sawInputEOS = false;
168
169    for (;;) {
170        if (!sawInputEOS) {
171            size_t trackIndex;
172            status_t err = extractor->getSampleTrackIndex(&trackIndex);
173
174            if (err != OK) {
175                ALOGV("signalling EOS.");
176
177                for (size_t i = 0; i < stateByTrack.size(); ++i) {
178                    CodecState *state = &stateByTrack.editValueAt(i);
179
180                    for (;;) {
181                        size_t index;
182                        err = state->mCodec->dequeueInputBuffer(&index);
183
184                        if (err == -EAGAIN) {
185                            continue;
186                        }
187
188                        CHECK_EQ(err, (status_t)OK);
189
190                        err = state->mCodec->queueInputBuffer(
191                                index,
192                                0 /* offset */,
193                                0 /* size */,
194                                0ll /* timeUs */,
195                                MediaCodec::BUFFER_FLAG_EOS);
196
197                        CHECK_EQ(err, (status_t)OK);
198                        break;
199                    }
200                }
201
202                sawInputEOS = true;
203            } else {
204                CodecState *state = &stateByTrack.editValueFor(trackIndex);
205
206                size_t index;
207                err = state->mCodec->dequeueInputBuffer(&index);
208
209                if (err == OK) {
210                    ALOGV("filling input buffer %d", index);
211
212                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
213
214                    err = extractor->readSampleData(buffer);
215                    CHECK_EQ(err, (status_t)OK);
216
217                    int64_t timeUs;
218                    err = extractor->getSampleTime(&timeUs);
219                    CHECK_EQ(err, (status_t)OK);
220
221                    err = state->mCodec->queueInputBuffer(
222                            index,
223                            0 /* offset */,
224                            buffer->size(),
225                            timeUs,
226                            0 /* flags */);
227
228                    CHECK_EQ(err, (status_t)OK);
229
230                    extractor->advance();
231                } else {
232                    CHECK_EQ(err, -EAGAIN);
233                }
234            }
235        }
236
237        bool sawOutputEOSOnAllTracks = true;
238        for (size_t i = 0; i < stateByTrack.size(); ++i) {
239            CodecState *state = &stateByTrack.editValueAt(i);
240            if (!state->mSawOutputEOS) {
241                sawOutputEOSOnAllTracks = false;
242                break;
243            }
244        }
245
246        if (sawOutputEOSOnAllTracks) {
247            break;
248        }
249
250        for (size_t i = 0; i < stateByTrack.size(); ++i) {
251            CodecState *state = &stateByTrack.editValueAt(i);
252
253            if (state->mSawOutputEOS) {
254                continue;
255            }
256
257            size_t index;
258            size_t offset;
259            size_t size;
260            int64_t presentationTimeUs;
261            uint32_t flags;
262            status_t err = state->mCodec->dequeueOutputBuffer(
263                    &index, &offset, &size, &presentationTimeUs, &flags,
264                    10000ll);
265
266            if (err == OK) {
267                ALOGV("draining output buffer %d, time = %lld us",
268                      index, presentationTimeUs);
269
270                err = state->mCodec->releaseOutputBuffer(index);
271                CHECK_EQ(err, (status_t)OK);
272
273                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
274                    ALOGV("reached EOS on output.");
275
276                    state->mSawOutputEOS = true;
277                }
278            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
279                ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
280                CHECK_EQ((status_t)OK,
281                         state->mCodec->getOutputBuffers(&state->mOutBuffers));
282
283                ALOGV("got %d output buffers", state->mOutBuffers.size());
284            } else if (err == INFO_FORMAT_CHANGED) {
285                sp<AMessage> format;
286                CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
287
288                ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
289            } else {
290                CHECK_EQ(err, -EAGAIN);
291            }
292        }
293    }
294
295    for (size_t i = 0; i < stateByTrack.size(); ++i) {
296        CodecState *state = &stateByTrack.editValueAt(i);
297
298        CHECK_EQ((status_t)OK, state->mCodec->stop());
299    }
300
301    return 0;
302}
303
304int main(int argc, char **argv) {
305    using namespace android;
306
307    const char *me = argv[0];
308
309    bool useAudio = false;
310    bool useVideo = false;
311    bool playback = false;
312
313    int res;
314    while ((res = getopt(argc, argv, "havp")) >= 0) {
315        switch (res) {
316            case 'a':
317            {
318                useAudio = true;
319                break;
320            }
321
322            case 'v':
323            {
324                useVideo = true;
325                break;
326            }
327
328            case 'p':
329            {
330                playback = true;
331                break;
332            }
333
334            case '?':
335            case 'h':
336            default:
337            {
338                usage(me);
339            }
340        }
341    }
342
343    argc -= optind;
344    argv += optind;
345
346    if (argc != 1) {
347        usage(me);
348    }
349
350    if (!useAudio && !useVideo) {
351        useAudio = useVideo = true;
352    }
353
354    ProcessState::self()->startThreadPool();
355
356    DataSource::RegisterDefaultSniffers();
357
358    sp<ALooper> looper = new ALooper;
359    looper->start();
360
361    if (playback) {
362        sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
363        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
364
365        ssize_t displayWidth = composerClient->getDisplayWidth(0);
366        ssize_t displayHeight = composerClient->getDisplayHeight(0);
367
368        ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
369
370        sp<SurfaceControl> control =
371            composerClient->createSurface(
372                    String8("A Surface"),
373                    0,
374                    displayWidth,
375                    displayHeight,
376                    PIXEL_FORMAT_RGB_565,
377                    0);
378
379        CHECK(control != NULL);
380        CHECK(control->isValid());
381
382        SurfaceComposerClient::openGlobalTransaction();
383        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
384        CHECK_EQ(control->show(), (status_t)OK);
385        SurfaceComposerClient::closeGlobalTransaction();
386
387        sp<Surface> surface = control->getSurface();
388        CHECK(surface != NULL);
389
390        sp<SimplePlayer> player = new SimplePlayer;
391        looper->registerHandler(player);
392
393        player->setDataSource(argv[0]);
394        player->setSurface(surface->getSurfaceTexture());
395        player->start();
396        sleep(60);
397        player->stop();
398        player->reset();
399
400        composerClient->dispose();
401    } else {
402        decode(looper, argv[0], useAudio, useVideo);
403    }
404
405    looper->stop();
406
407    return 0;
408}
409