codec.cpp revision 4b75a9c8b93a90749bc5d22912ad0d96c12f4ecf
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/IServiceManager.h>
24#include <binder/ProcessState.h>
25#include <media/ICrypto.h>
26#include <media/IMediaPlayerService.h>
27#include <media/stagefright/foundation/ABuffer.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/ALooper.h>
30#include <media/stagefright/foundation/AMessage.h>
31#include <media/stagefright/DataSource.h>
32#include <media/stagefright/MediaCodec.h>
33#include <media/stagefright/MediaCodecList.h>
34#include <media/stagefright/MediaDefs.h>
35#include <media/stagefright/NuMediaExtractor.h>
36#include <gui/SurfaceComposerClient.h>
37
38static void usage(const char *me) {
39    fprintf(stderr, "usage: %s [-a] use audio\n"
40                    "\t\t[-v] use video\n"
41                    "\t\t[-p] playback\n"
42                    "\t\t[-S] allocate buffers from a surface\n"
43                    "\t\t[-D] decrypt input buffers\n",
44                    me);
45
46    exit(1);
47}
48
49namespace android {
50
51struct CodecState {
52    sp<MediaCodec> mCodec;
53    Vector<sp<ABuffer> > mCSD;
54    size_t mCSDIndex;
55    Vector<sp<ABuffer> > mInBuffers;
56    Vector<sp<ABuffer> > mOutBuffers;
57    bool mSignalledInputEOS;
58    bool mSawOutputEOS;
59    int64_t mNumBuffersDecoded;
60    int64_t mNumBytesDecoded;
61    bool mIsAudio;
62};
63
64static sp<ICrypto> makeCrypto(
65        const uint8_t uuid[16], const void *data, size_t size) {
66    sp<IServiceManager> sm = defaultServiceManager();
67
68    sp<IBinder> binder =
69        sm->getService(String16("media.player"));
70
71    sp<IMediaPlayerService> service =
72        interface_cast<IMediaPlayerService>(binder);
73
74    CHECK(service != NULL);
75
76    sp<ICrypto> crypto = service->makeCrypto();
77
78    if (crypto == NULL || crypto->initCheck() != OK) {
79        return NULL;
80    }
81
82    status_t err = crypto->createPlugin(uuid, data, size);
83
84    if (err != OK) {
85        return NULL;
86    }
87
88    return crypto;
89}
90
91}  // namespace android
92
93static int decode(
94        const android::sp<android::ALooper> &looper,
95        const char *path,
96        bool useAudio,
97        bool useVideo,
98        const android::sp<android::Surface> &surface,
99        bool decryptInputBuffers) {
100    using namespace android;
101
102    static int64_t kTimeout = 500ll;
103
104    sp<NuMediaExtractor> extractor = new NuMediaExtractor;
105    if (extractor->setDataSource(path) != OK) {
106        fprintf(stderr, "unable to instantiate extractor.\n");
107        return 1;
108    }
109
110    sp<ICrypto> crypto;
111
112    KeyedVector<size_t, CodecState> stateByTrack;
113
114    bool haveAudio = false;
115    bool haveVideo = false;
116    for (size_t i = 0; i < extractor->countTracks(); ++i) {
117        sp<AMessage> format;
118        status_t err = extractor->getTrackFormat(i, &format);
119        CHECK_EQ(err, (status_t)OK);
120
121        AString mime;
122        CHECK(format->findString("mime", &mime));
123
124        bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
125        bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
126
127        if (useAudio && !haveAudio && isAudio) {
128            haveAudio = true;
129        } else if (useVideo && !haveVideo && isVideo) {
130            haveVideo = true;
131        } else {
132            continue;
133        }
134
135        ALOGV("selecting track %d", i);
136
137        err = extractor->selectTrack(i);
138        CHECK_EQ(err, (status_t)OK);
139
140        CodecState *state =
141            &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
142
143        state->mNumBytesDecoded = 0;
144        state->mNumBuffersDecoded = 0;
145        state->mIsAudio = isAudio;
146
147        if (decryptInputBuffers && crypto == NULL) {
148            sp<ABuffer> emm;
149            CHECK(format->findBuffer("emm", &emm));
150
151            sp<ABuffer> ecm;
152            CHECK(format->findBuffer("ecm", &ecm));
153
154            struct WVOpaqueInitData {
155                uint8_t mEMM[16];
156                uint8_t mECM[32];
157
158            } opaque;
159
160            CHECK_EQ(emm->size(), sizeof(opaque.mEMM));
161            memcpy(opaque.mEMM, emm->data(), emm->size());
162
163            CHECK_EQ(ecm->size(), 80u);
164            // bytes 16..47 of the original ecm stream data.
165            memcpy(opaque.mECM, ecm->data() + 16, 32);
166
167            static const uint8_t kUUIDWidevine[16] = {
168                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
169                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
170            };
171
172            crypto = makeCrypto(kUUIDWidevine, &opaque, sizeof(opaque));
173            CHECK(crypto != NULL);
174            CHECK_EQ(crypto->initCheck(), (status_t)OK);
175        }
176
177        if (decryptInputBuffers
178                && crypto->requiresSecureDecoderComponent(mime.c_str())) {
179            static const MediaCodecList *list = MediaCodecList::getInstance();
180
181            ssize_t index =
182                list->findCodecByType(mime.c_str(), false /* encoder */);
183
184            CHECK_GE(index, 0);
185
186            const char *componentName = list->getCodecName(index);
187
188            AString fullName = componentName;
189            fullName.append(".secure");
190
191            state->mCodec = MediaCodec::CreateByComponentName(
192                    looper, fullName.c_str());
193        } else {
194            state->mCodec = MediaCodec::CreateByType(
195                    looper, mime.c_str(), false /* encoder */);
196        }
197
198        CHECK(state->mCodec != NULL);
199
200        err = state->mCodec->configure(
201                format, isVideo ? surface : NULL,
202                crypto,
203                0 /* flags */);
204
205        CHECK_EQ(err, (status_t)OK);
206
207        size_t j = 0;
208        sp<ABuffer> buffer;
209        while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) {
210            state->mCSD.push_back(buffer);
211
212            ++j;
213        }
214
215        state->mCSDIndex = 0;
216        state->mSignalledInputEOS = false;
217        state->mSawOutputEOS = false;
218
219        ALOGV("got %d pieces of codec specific data.", state->mCSD.size());
220    }
221
222    CHECK(!stateByTrack.isEmpty());
223
224    int64_t startTimeUs = ALooper::GetNowUs();
225
226    for (size_t i = 0; i < stateByTrack.size(); ++i) {
227        CodecState *state = &stateByTrack.editValueAt(i);
228
229        sp<MediaCodec> codec = state->mCodec;
230
231        CHECK_EQ((status_t)OK, codec->start());
232
233        CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
234        CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
235
236        ALOGV("got %d input and %d output buffers",
237              state->mInBuffers.size(), state->mOutBuffers.size());
238
239        while (state->mCSDIndex < state->mCSD.size()) {
240            size_t index;
241            status_t err = codec->dequeueInputBuffer(&index, -1ll);
242            CHECK_EQ(err, (status_t)OK);
243
244            const sp<ABuffer> &srcBuffer =
245                state->mCSD.itemAt(state->mCSDIndex++);
246
247            const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
248
249            memcpy(buffer->data(), srcBuffer->data(), srcBuffer->size());
250
251            err = codec->queueInputBuffer(
252                    index,
253                    0 /* offset */,
254                    srcBuffer->size(),
255                    0ll /* timeUs */,
256                    MediaCodec::BUFFER_FLAG_CODECCONFIG);
257
258            CHECK_EQ(err, (status_t)OK);
259        }
260    }
261
262    bool sawInputEOS = false;
263
264    for (;;) {
265        if (!sawInputEOS) {
266            size_t trackIndex;
267            status_t err = extractor->getSampleTrackIndex(&trackIndex);
268
269            if (err != OK) {
270                ALOGV("saw input eos");
271                sawInputEOS = true;
272            } else {
273                CodecState *state = &stateByTrack.editValueFor(trackIndex);
274
275                size_t index;
276                err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
277
278                if (err == OK) {
279                    ALOGV("filling input buffer %d", index);
280
281                    const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
282
283                    err = extractor->readSampleData(buffer);
284                    CHECK_EQ(err, (status_t)OK);
285
286                    int64_t timeUs;
287                    err = extractor->getSampleTime(&timeUs);
288                    CHECK_EQ(err, (status_t)OK);
289
290                    uint32_t bufferFlags = 0;
291
292                    uint32_t sampleFlags;
293                    err = extractor->getSampleFlags(&sampleFlags);
294                    CHECK_EQ(err, (status_t)OK);
295
296                    if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) {
297                        CHECK(decryptInputBuffers);
298
299                        CryptoPlugin::SubSample ss;
300                        ss.mNumBytesOfClearData = 0;
301                        ss.mNumBytesOfEncryptedData = buffer->size();
302
303                        err = state->mCodec->queueSecureInputBuffer(
304                                index,
305                                0 /* offset */,
306                                &ss,
307                                1 /* numSubSamples */,
308                                NULL /* key */,
309                                NULL /* iv */,
310                                CryptoPlugin::kMode_AES_WV,
311                                timeUs,
312                                bufferFlags);
313                    } else {
314                        err = state->mCodec->queueInputBuffer(
315                                index,
316                                0 /* offset */,
317                                buffer->size(),
318                                timeUs,
319                                bufferFlags);
320                    }
321
322                    CHECK_EQ(err, (status_t)OK);
323
324                    extractor->advance();
325                } else {
326                    CHECK_EQ(err, -EAGAIN);
327                }
328            }
329        } else {
330            for (size_t i = 0; i < stateByTrack.size(); ++i) {
331                CodecState *state = &stateByTrack.editValueAt(i);
332
333                if (!state->mSignalledInputEOS) {
334                    size_t index;
335                    status_t err =
336                        state->mCodec->dequeueInputBuffer(&index, kTimeout);
337
338                    if (err == OK) {
339                        ALOGV("signalling input EOS on track %d", i);
340
341                        err = state->mCodec->queueInputBuffer(
342                                index,
343                                0 /* offset */,
344                                0 /* size */,
345                                0ll /* timeUs */,
346                                MediaCodec::BUFFER_FLAG_EOS);
347
348                        CHECK_EQ(err, (status_t)OK);
349
350                        state->mSignalledInputEOS = true;
351                    } else {
352                        CHECK_EQ(err, -EAGAIN);
353                    }
354                }
355            }
356        }
357
358        bool sawOutputEOSOnAllTracks = true;
359        for (size_t i = 0; i < stateByTrack.size(); ++i) {
360            CodecState *state = &stateByTrack.editValueAt(i);
361            if (!state->mSawOutputEOS) {
362                sawOutputEOSOnAllTracks = false;
363                break;
364            }
365        }
366
367        if (sawOutputEOSOnAllTracks) {
368            break;
369        }
370
371        for (size_t i = 0; i < stateByTrack.size(); ++i) {
372            CodecState *state = &stateByTrack.editValueAt(i);
373
374            if (state->mSawOutputEOS) {
375                continue;
376            }
377
378            size_t index;
379            size_t offset;
380            size_t size;
381            int64_t presentationTimeUs;
382            uint32_t flags;
383            status_t err = state->mCodec->dequeueOutputBuffer(
384                    &index, &offset, &size, &presentationTimeUs, &flags,
385                    kTimeout);
386
387            if (err == OK) {
388                ALOGV("draining output buffer %d, time = %lld us",
389                      index, presentationTimeUs);
390
391                ++state->mNumBuffersDecoded;
392                state->mNumBytesDecoded += size;
393
394                err = state->mCodec->releaseOutputBuffer(index);
395                CHECK_EQ(err, (status_t)OK);
396
397                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
398                    ALOGV("reached EOS on output.");
399
400                    state->mSawOutputEOS = true;
401                }
402            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
403                ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
404                CHECK_EQ((status_t)OK,
405                         state->mCodec->getOutputBuffers(&state->mOutBuffers));
406
407                ALOGV("got %d output buffers", state->mOutBuffers.size());
408            } else if (err == INFO_FORMAT_CHANGED) {
409                sp<AMessage> format;
410                CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
411
412                ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
413            } else {
414                CHECK_EQ(err, -EAGAIN);
415            }
416        }
417    }
418
419    int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
420
421    for (size_t i = 0; i < stateByTrack.size(); ++i) {
422        CodecState *state = &stateByTrack.editValueAt(i);
423
424        CHECK_EQ((status_t)OK, state->mCodec->release());
425
426        if (state->mIsAudio) {
427            printf("track %d: %lld bytes received. %.2f KB/sec\n",
428                   i,
429                   state->mNumBytesDecoded,
430                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
431        } else {
432            printf("track %d: %lld frames decoded, %.2f fps. %lld bytes "
433                   "received. %.2f KB/sec\n",
434                   i,
435                   state->mNumBuffersDecoded,
436                   state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
437                   state->mNumBytesDecoded,
438                   state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
439        }
440    }
441
442    return 0;
443}
444
445int main(int argc, char **argv) {
446    using namespace android;
447
448    const char *me = argv[0];
449
450    bool useAudio = false;
451    bool useVideo = false;
452    bool playback = false;
453    bool useSurface = false;
454    bool decryptInputBuffers = false;
455
456    int res;
457    while ((res = getopt(argc, argv, "havpSD")) >= 0) {
458        switch (res) {
459            case 'a':
460            {
461                useAudio = true;
462                break;
463            }
464
465            case 'v':
466            {
467                useVideo = true;
468                break;
469            }
470
471            case 'p':
472            {
473                playback = true;
474                break;
475            }
476
477            case 'S':
478            {
479                useSurface = true;
480                break;
481            }
482
483            case 'D':
484            {
485                decryptInputBuffers = true;
486                break;
487            }
488
489            case '?':
490            case 'h':
491            default:
492            {
493                usage(me);
494            }
495        }
496    }
497
498    argc -= optind;
499    argv += optind;
500
501    if (argc != 1) {
502        usage(me);
503    }
504
505    if (!useAudio && !useVideo) {
506        useAudio = useVideo = true;
507    }
508
509    ProcessState::self()->startThreadPool();
510
511    DataSource::RegisterDefaultSniffers();
512
513    sp<ALooper> looper = new ALooper;
514    looper->start();
515
516    sp<SurfaceComposerClient> composerClient;
517    sp<SurfaceControl> control;
518    sp<Surface> surface;
519
520    if (playback || (useSurface && useVideo)) {
521        composerClient = new SurfaceComposerClient;
522        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
523
524        ssize_t displayWidth = composerClient->getDisplayWidth(0);
525        ssize_t displayHeight = composerClient->getDisplayHeight(0);
526
527        ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
528
529        control = composerClient->createSurface(
530                String8("A Surface"),
531                0,
532                displayWidth,
533                displayHeight,
534                PIXEL_FORMAT_RGB_565,
535                0);
536
537        CHECK(control != NULL);
538        CHECK(control->isValid());
539
540        SurfaceComposerClient::openGlobalTransaction();
541        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
542        CHECK_EQ(control->show(), (status_t)OK);
543        SurfaceComposerClient::closeGlobalTransaction();
544
545        surface = control->getSurface();
546        CHECK(surface != NULL);
547    }
548
549    if (playback) {
550        sp<SimplePlayer> player = new SimplePlayer;
551        looper->registerHandler(player);
552
553        player->setDataSource(argv[0]);
554        player->setSurface(surface->getSurfaceTexture());
555        player->start();
556        sleep(60);
557        player->stop();
558        player->reset();
559    } else {
560        decode(looper, argv[0],
561               useAudio, useVideo, surface, decryptInputBuffers);
562    }
563
564    if (playback || (useSurface && useVideo)) {
565        composerClient->dispose();
566    }
567
568    looper->stop();
569
570    return 0;
571}
572