codec.cpp revision 5778822d86b0337407514b9372562b86edfa91cd
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<RefBase> obj;
111        while (format->findObject(StringPrintf("csd-%d", j).c_str(), &obj)) {
112            sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
113            state->mCSD.push_back(buffer);
114
115            ++j;
116        }
117
118        state->mCSDIndex = 0;
119        state->mSawOutputEOS = false;
120
121        ALOGV("got %d pieces of codec specific data.", state->mCSD.size());
122    }
123
124    CHECK(!stateByTrack.isEmpty());
125
126    for (size_t i = 0; i < stateByTrack.size(); ++i) {
127        CodecState *state = &stateByTrack.editValueAt(i);
128
129        sp<MediaCodec> codec = state->mCodec;
130
131        CHECK_EQ((status_t)OK, codec->start());
132
133        CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
134        CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
135
136        ALOGV("got %d input and %d output buffers",
137              state->mInBuffers.size(), state->mOutBuffers.size());
138
139        while (state->mCSDIndex < state->mCSD.size()) {
140            size_t index;
141            status_t err = codec->dequeueInputBuffer(&index);
142
143            if (err == -EAGAIN) {
144                usleep(10000);
145                continue;
146            }
147
148            CHECK_EQ(err, (status_t)OK);
149
150            const sp<ABuffer> &srcBuffer =
151                state->mCSD.itemAt(state->mCSDIndex++);
152
153            const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
154
155            memcpy(buffer->data(), srcBuffer->data(), srcBuffer->size());
156
157            err = codec->queueInputBuffer(
158                    index,
159                    0 /* offset */,
160                    srcBuffer->size(),
161                    0ll /* timeUs */,
162                    MediaCodec::BUFFER_FLAG_CODECCONFIG);
163
164            CHECK_EQ(err, (status_t)OK);
165        }
166    }
167
168    bool sawInputEOS = false;
169
170    for (;;) {
171        if (!sawInputEOS) {
172            size_t trackIndex;
173            status_t err = extractor->getSampleTrackIndex(&trackIndex);
174
175            if (err != OK) {
176                ALOGV("signalling EOS.");
177
178                for (size_t i = 0; i < stateByTrack.size(); ++i) {
179                    CodecState *state = &stateByTrack.editValueAt(i);
180
181                    for (;;) {
182                        size_t index;
183                        err = state->mCodec->dequeueInputBuffer(&index);
184
185                        if (err == -EAGAIN) {
186                            continue;
187                        }
188
189                        CHECK_EQ(err, (status_t)OK);
190
191                        err = state->mCodec->queueInputBuffer(
192                                index,
193                                0 /* offset */,
194                                0 /* size */,
195                                0ll /* timeUs */,
196                                MediaCodec::BUFFER_FLAG_EOS);
197
198                        CHECK_EQ(err, (status_t)OK);
199                        break;
200                    }
201                }
202
203                sawInputEOS = true;
204            } else {
205                CodecState *state = &stateByTrack.editValueFor(trackIndex);
206
207                size_t index;
208                err = state->mCodec->dequeueInputBuffer(&index);
209
210                if (err == OK) {
211                    ALOGV("filling input buffer %d", index);
212
213                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
214
215                    err = extractor->readSampleData(buffer);
216                    CHECK_EQ(err, (status_t)OK);
217
218                    int64_t timeUs;
219                    err = extractor->getSampleTime(&timeUs);
220                    CHECK_EQ(err, (status_t)OK);
221
222                    err = state->mCodec->queueInputBuffer(
223                            index,
224                            0 /* offset */,
225                            buffer->size(),
226                            timeUs,
227                            0 /* flags */);
228
229                    CHECK_EQ(err, (status_t)OK);
230
231                    extractor->advance();
232                } else {
233                    CHECK_EQ(err, -EAGAIN);
234                }
235            }
236        }
237
238        bool sawOutputEOSOnAllTracks = true;
239        for (size_t i = 0; i < stateByTrack.size(); ++i) {
240            CodecState *state = &stateByTrack.editValueAt(i);
241            if (!state->mSawOutputEOS) {
242                sawOutputEOSOnAllTracks = false;
243                break;
244            }
245        }
246
247        if (sawOutputEOSOnAllTracks) {
248            break;
249        }
250
251        for (size_t i = 0; i < stateByTrack.size(); ++i) {
252            CodecState *state = &stateByTrack.editValueAt(i);
253
254            if (state->mSawOutputEOS) {
255                continue;
256            }
257
258            size_t index;
259            size_t offset;
260            size_t size;
261            int64_t presentationTimeUs;
262            uint32_t flags;
263            status_t err = state->mCodec->dequeueOutputBuffer(
264                    &index, &offset, &size, &presentationTimeUs, &flags,
265                    10000ll);
266
267            if (err == OK) {
268                ALOGV("draining output buffer %d, time = %lld us",
269                      index, presentationTimeUs);
270
271                err = state->mCodec->releaseOutputBuffer(index);
272                CHECK_EQ(err, (status_t)OK);
273
274                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
275                    ALOGV("reached EOS on output.");
276
277                    state->mSawOutputEOS = true;
278                }
279            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
280                ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
281                CHECK_EQ((status_t)OK,
282                         state->mCodec->getOutputBuffers(&state->mOutBuffers));
283
284                ALOGV("got %d output buffers", state->mOutBuffers.size());
285            } else if (err == INFO_FORMAT_CHANGED) {
286                sp<AMessage> format;
287                CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
288
289                ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
290            } else {
291                CHECK_EQ(err, -EAGAIN);
292            }
293        }
294    }
295
296    for (size_t i = 0; i < stateByTrack.size(); ++i) {
297        CodecState *state = &stateByTrack.editValueAt(i);
298
299        CHECK_EQ((status_t)OK, state->mCodec->stop());
300    }
301
302    return 0;
303}
304
305int main(int argc, char **argv) {
306    using namespace android;
307
308    const char *me = argv[0];
309
310    bool useAudio = false;
311    bool useVideo = false;
312    bool playback = false;
313
314    int res;
315    while ((res = getopt(argc, argv, "havp")) >= 0) {
316        switch (res) {
317            case 'a':
318            {
319                useAudio = true;
320                break;
321            }
322
323            case 'v':
324            {
325                useVideo = true;
326                break;
327            }
328
329            case 'p':
330            {
331                playback = true;
332                break;
333            }
334
335            case '?':
336            case 'h':
337            default:
338            {
339                usage(me);
340            }
341        }
342    }
343
344    argc -= optind;
345    argv += optind;
346
347    if (argc != 1) {
348        usage(me);
349    }
350
351    if (!useAudio && !useVideo) {
352        useAudio = useVideo = true;
353    }
354
355    ProcessState::self()->startThreadPool();
356
357    DataSource::RegisterDefaultSniffers();
358
359    sp<ALooper> looper = new ALooper;
360    looper->start();
361
362    if (playback) {
363        sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
364        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
365
366        ssize_t displayWidth = composerClient->getDisplayWidth(0);
367        ssize_t displayHeight = composerClient->getDisplayHeight(0);
368
369        ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
370
371        sp<SurfaceControl> control =
372            composerClient->createSurface(
373                    String8("A Surface"),
374                    0,
375                    displayWidth,
376                    displayHeight,
377                    PIXEL_FORMAT_RGB_565,
378                    0);
379
380        CHECK(control != NULL);
381        CHECK(control->isValid());
382
383        SurfaceComposerClient::openGlobalTransaction();
384        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
385        CHECK_EQ(control->show(), (status_t)OK);
386        SurfaceComposerClient::closeGlobalTransaction();
387
388        sp<Surface> surface = control->getSurface();
389        CHECK(surface != NULL);
390
391        sp<SimplePlayer> player = new SimplePlayer;
392        looper->registerHandler(player);
393
394        player->setDataSource(argv[0]);
395        player->setSurface(surface->getSurfaceTexture());
396        player->start();
397        sleep(10);
398        player->stop();
399        player->reset();
400
401        composerClient->dispose();
402    } else {
403        decode(looper, argv[0], useAudio, useVideo);
404    }
405
406    looper->stop();
407
408    return 0;
409}
410