blob: cf2909ed76f7ee08ca897ee98a39ddfd080d5b42 [file] [log] [blame]
Andreas Huber88572f72012-02-21 11:47:18 -08001/*
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>
Andreas Huber9b8e4962012-03-26 11:13:27 -070031#include <media/stagefright/MediaCodecList.h>
Andreas Huber88572f72012-02-21 11:47:18 -080032#include <media/stagefright/MediaDefs.h>
33#include <media/stagefright/NuMediaExtractor.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080034#include <gui/SurfaceComposerClient.h>
Andreas Huber88572f72012-02-21 11:47:18 -080035
36static void usage(const char *me) {
37 fprintf(stderr, "usage: %s [-a] use audio\n"
38 "\t\t[-v] use video\n"
Andreas Hubere5760e32012-03-07 12:40:59 -080039 "\t\t[-p] playback\n"
Andreas Huber9b8e4962012-03-26 11:13:27 -070040 "\t\t[-S] allocate buffers from a surface\n"
41 "\t\t[-D] decrypt input buffers\n",
42 me);
Andreas Huber88572f72012-02-21 11:47:18 -080043
44 exit(1);
45}
46
47namespace android {
48
49struct CodecState {
50 sp<MediaCodec> mCodec;
51 Vector<sp<ABuffer> > mCSD;
52 size_t mCSDIndex;
53 Vector<sp<ABuffer> > mInBuffers;
54 Vector<sp<ABuffer> > mOutBuffers;
Andreas Huber442df222012-03-09 09:46:33 -080055 bool mSignalledInputEOS;
Andreas Huber88572f72012-02-21 11:47:18 -080056 bool mSawOutputEOS;
Andreas Hubere5760e32012-03-07 12:40:59 -080057 int64_t mNumBuffersDecoded;
58 int64_t mNumBytesDecoded;
59 bool mIsAudio;
Andreas Huber88572f72012-02-21 11:47:18 -080060};
61
62} // namespace android
63
64static int decode(
65 const android::sp<android::ALooper> &looper,
66 const char *path,
67 bool useAudio,
Andreas Hubere5760e32012-03-07 12:40:59 -080068 bool useVideo,
Andreas Huber9b8e4962012-03-26 11:13:27 -070069 const android::sp<android::Surface> &surface,
70 bool decryptInputBuffers) {
Andreas Huber88572f72012-02-21 11:47:18 -080071 using namespace android;
72
Andreas Hubere5760e32012-03-07 12:40:59 -080073 static int64_t kTimeout = 500ll;
74
Andreas Huber88572f72012-02-21 11:47:18 -080075 sp<NuMediaExtractor> extractor = new NuMediaExtractor;
76 if (extractor->setDataSource(path) != OK) {
77 fprintf(stderr, "unable to instantiate extractor.\n");
78 return 1;
79 }
80
81 KeyedVector<size_t, CodecState> stateByTrack;
82
83 bool haveAudio = false;
84 bool haveVideo = false;
85 for (size_t i = 0; i < extractor->countTracks(); ++i) {
86 sp<AMessage> format;
87 status_t err = extractor->getTrackFormat(i, &format);
88 CHECK_EQ(err, (status_t)OK);
89
90 AString mime;
91 CHECK(format->findString("mime", &mime));
92
Andreas Hubere5760e32012-03-07 12:40:59 -080093 bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
94 bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
95
96 if (useAudio && !haveAudio && isAudio) {
Andreas Huber88572f72012-02-21 11:47:18 -080097 haveAudio = true;
Andreas Hubere5760e32012-03-07 12:40:59 -080098 } else if (useVideo && !haveVideo && isVideo) {
Andreas Huber88572f72012-02-21 11:47:18 -080099 haveVideo = true;
100 } else {
101 continue;
102 }
103
104 ALOGV("selecting track %d", i);
105
106 err = extractor->selectTrack(i);
107 CHECK_EQ(err, (status_t)OK);
108
109 CodecState *state =
110 &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
111
Andreas Hubere5760e32012-03-07 12:40:59 -0800112 state->mNumBytesDecoded = 0;
113 state->mNumBuffersDecoded = 0;
114 state->mIsAudio = isAudio;
115
Andreas Huber9b8e4962012-03-26 11:13:27 -0700116 if (decryptInputBuffers && !isAudio) {
117 static const MediaCodecList *list = MediaCodecList::getInstance();
118
119 ssize_t index =
120 list->findCodecByType(mime.c_str(), false /* encoder */);
121
122 CHECK_GE(index, 0);
123
124 const char *componentName = list->getCodecName(index);
125
126 AString fullName = componentName;
127 fullName.append(".secure");
128
129 state->mCodec = MediaCodec::CreateByComponentName(
130 looper, fullName.c_str());
131 } else {
132 state->mCodec = MediaCodec::CreateByType(
133 looper, mime.c_str(), false /* encoder */);
134 }
Andreas Huber88572f72012-02-21 11:47:18 -0800135
136 CHECK(state->mCodec != NULL);
137
138 err = state->mCodec->configure(
Andreas Huber9b8e4962012-03-26 11:13:27 -0700139 format, isVideo ? surface : NULL,
140 decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
Andreas Huber88572f72012-02-21 11:47:18 -0800141
142 CHECK_EQ(err, (status_t)OK);
143
144 size_t j = 0;
Andreas Huber6281fa12012-02-24 13:42:47 -0800145 sp<ABuffer> buffer;
146 while (format->findBuffer(StringPrintf("csd-%d", j).c_str(), &buffer)) {
Andreas Huber88572f72012-02-21 11:47:18 -0800147 state->mCSD.push_back(buffer);
148
149 ++j;
150 }
151
152 state->mCSDIndex = 0;
Andreas Huber442df222012-03-09 09:46:33 -0800153 state->mSignalledInputEOS = false;
Andreas Huber88572f72012-02-21 11:47:18 -0800154 state->mSawOutputEOS = false;
155
156 ALOGV("got %d pieces of codec specific data.", state->mCSD.size());
157 }
158
159 CHECK(!stateByTrack.isEmpty());
160
Andreas Hubere5760e32012-03-07 12:40:59 -0800161 int64_t startTimeUs = ALooper::GetNowUs();
162
Andreas Huber88572f72012-02-21 11:47:18 -0800163 for (size_t i = 0; i < stateByTrack.size(); ++i) {
164 CodecState *state = &stateByTrack.editValueAt(i);
165
166 sp<MediaCodec> codec = state->mCodec;
167
168 CHECK_EQ((status_t)OK, codec->start());
169
170 CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
171 CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
172
173 ALOGV("got %d input and %d output buffers",
174 state->mInBuffers.size(), state->mOutBuffers.size());
175
176 while (state->mCSDIndex < state->mCSD.size()) {
177 size_t index;
Andreas Hubere5760e32012-03-07 12:40:59 -0800178 status_t err = codec->dequeueInputBuffer(&index, -1ll);
Andreas Huber88572f72012-02-21 11:47:18 -0800179 CHECK_EQ(err, (status_t)OK);
180
181 const sp<ABuffer> &srcBuffer =
182 state->mCSD.itemAt(state->mCSDIndex++);
183
184 const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
185
186 memcpy(buffer->data(), srcBuffer->data(), srcBuffer->size());
187
188 err = codec->queueInputBuffer(
189 index,
190 0 /* offset */,
191 srcBuffer->size(),
192 0ll /* timeUs */,
193 MediaCodec::BUFFER_FLAG_CODECCONFIG);
194
195 CHECK_EQ(err, (status_t)OK);
196 }
197 }
198
199 bool sawInputEOS = false;
200
201 for (;;) {
202 if (!sawInputEOS) {
203 size_t trackIndex;
204 status_t err = extractor->getSampleTrackIndex(&trackIndex);
205
206 if (err != OK) {
Andreas Huber442df222012-03-09 09:46:33 -0800207 ALOGV("saw input eos");
Andreas Huber88572f72012-02-21 11:47:18 -0800208 sawInputEOS = true;
209 } else {
210 CodecState *state = &stateByTrack.editValueFor(trackIndex);
211
212 size_t index;
Andreas Hubere5760e32012-03-07 12:40:59 -0800213 err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
Andreas Huber88572f72012-02-21 11:47:18 -0800214
215 if (err == OK) {
216 ALOGV("filling input buffer %d", index);
217
218 const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
219
220 err = extractor->readSampleData(buffer);
221 CHECK_EQ(err, (status_t)OK);
222
223 int64_t timeUs;
224 err = extractor->getSampleTime(&timeUs);
225 CHECK_EQ(err, (status_t)OK);
226
Andreas Huber9b8e4962012-03-26 11:13:27 -0700227 uint32_t bufferFlags = 0;
228
229 uint32_t sampleFlags;
230 err = extractor->getSampleFlags(&sampleFlags);
231 CHECK_EQ(err, (status_t)OK);
232
233 if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) {
234 CHECK(decryptInputBuffers);
235
236 bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED;
237 }
238
Andreas Huber88572f72012-02-21 11:47:18 -0800239 err = state->mCodec->queueInputBuffer(
240 index,
241 0 /* offset */,
242 buffer->size(),
243 timeUs,
Andreas Huber9b8e4962012-03-26 11:13:27 -0700244 bufferFlags);
Andreas Huber88572f72012-02-21 11:47:18 -0800245
246 CHECK_EQ(err, (status_t)OK);
247
248 extractor->advance();
249 } else {
250 CHECK_EQ(err, -EAGAIN);
251 }
252 }
Andreas Huber442df222012-03-09 09:46:33 -0800253 } else {
254 for (size_t i = 0; i < stateByTrack.size(); ++i) {
255 CodecState *state = &stateByTrack.editValueAt(i);
256
257 if (!state->mSignalledInputEOS) {
258 size_t index;
259 status_t err =
260 state->mCodec->dequeueInputBuffer(&index, kTimeout);
261
262 if (err == OK) {
263 ALOGV("signalling input EOS on track %d", i);
264
265 err = state->mCodec->queueInputBuffer(
266 index,
267 0 /* offset */,
268 0 /* size */,
269 0ll /* timeUs */,
270 MediaCodec::BUFFER_FLAG_EOS);
271
272 CHECK_EQ(err, (status_t)OK);
273
274 state->mSignalledInputEOS = true;
275 } else {
276 CHECK_EQ(err, -EAGAIN);
277 }
278 }
279 }
Andreas Huber88572f72012-02-21 11:47:18 -0800280 }
281
282 bool sawOutputEOSOnAllTracks = true;
283 for (size_t i = 0; i < stateByTrack.size(); ++i) {
284 CodecState *state = &stateByTrack.editValueAt(i);
285 if (!state->mSawOutputEOS) {
286 sawOutputEOSOnAllTracks = false;
287 break;
288 }
289 }
290
291 if (sawOutputEOSOnAllTracks) {
292 break;
293 }
294
295 for (size_t i = 0; i < stateByTrack.size(); ++i) {
296 CodecState *state = &stateByTrack.editValueAt(i);
297
298 if (state->mSawOutputEOS) {
299 continue;
300 }
301
302 size_t index;
303 size_t offset;
304 size_t size;
305 int64_t presentationTimeUs;
306 uint32_t flags;
307 status_t err = state->mCodec->dequeueOutputBuffer(
308 &index, &offset, &size, &presentationTimeUs, &flags,
Andreas Hubere5760e32012-03-07 12:40:59 -0800309 kTimeout);
Andreas Huber88572f72012-02-21 11:47:18 -0800310
311 if (err == OK) {
312 ALOGV("draining output buffer %d, time = %lld us",
313 index, presentationTimeUs);
314
Andreas Hubere5760e32012-03-07 12:40:59 -0800315 ++state->mNumBuffersDecoded;
316 state->mNumBytesDecoded += size;
317
Andreas Huber88572f72012-02-21 11:47:18 -0800318 err = state->mCodec->releaseOutputBuffer(index);
319 CHECK_EQ(err, (status_t)OK);
320
321 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
322 ALOGV("reached EOS on output.");
323
324 state->mSawOutputEOS = true;
325 }
326 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
327 ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
328 CHECK_EQ((status_t)OK,
329 state->mCodec->getOutputBuffers(&state->mOutBuffers));
330
331 ALOGV("got %d output buffers", state->mOutBuffers.size());
332 } else if (err == INFO_FORMAT_CHANGED) {
333 sp<AMessage> format;
334 CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
335
336 ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
337 } else {
338 CHECK_EQ(err, -EAGAIN);
339 }
340 }
341 }
342
Andreas Hubere5760e32012-03-07 12:40:59 -0800343 int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
344
Andreas Huber88572f72012-02-21 11:47:18 -0800345 for (size_t i = 0; i < stateByTrack.size(); ++i) {
346 CodecState *state = &stateByTrack.editValueAt(i);
347
Andreas Huber4484bdd2012-02-28 15:54:51 -0800348 CHECK_EQ((status_t)OK, state->mCodec->release());
Andreas Hubere5760e32012-03-07 12:40:59 -0800349
350 if (state->mIsAudio) {
351 printf("track %d: %lld bytes received. %.2f KB/sec\n",
352 i,
353 state->mNumBytesDecoded,
354 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
355 } else {
356 printf("track %d: %lld frames decoded, %.2f fps. %lld bytes "
357 "received. %.2f KB/sec\n",
358 i,
359 state->mNumBuffersDecoded,
360 state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
361 state->mNumBytesDecoded,
362 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
363 }
Andreas Huber88572f72012-02-21 11:47:18 -0800364 }
365
366 return 0;
367}
368
369int main(int argc, char **argv) {
370 using namespace android;
371
372 const char *me = argv[0];
373
374 bool useAudio = false;
375 bool useVideo = false;
376 bool playback = false;
Andreas Hubere5760e32012-03-07 12:40:59 -0800377 bool useSurface = false;
Andreas Huber9b8e4962012-03-26 11:13:27 -0700378 bool decryptInputBuffers = false;
Andreas Huber88572f72012-02-21 11:47:18 -0800379
380 int res;
Andreas Huber9b8e4962012-03-26 11:13:27 -0700381 while ((res = getopt(argc, argv, "havpSD")) >= 0) {
Andreas Huber88572f72012-02-21 11:47:18 -0800382 switch (res) {
383 case 'a':
384 {
385 useAudio = true;
386 break;
387 }
388
389 case 'v':
390 {
391 useVideo = true;
392 break;
393 }
394
395 case 'p':
396 {
397 playback = true;
398 break;
399 }
400
Andreas Hubere5760e32012-03-07 12:40:59 -0800401 case 'S':
402 {
403 useSurface = true;
404 break;
405 }
406
Andreas Huber9b8e4962012-03-26 11:13:27 -0700407 case 'D':
408 {
409 decryptInputBuffers = true;
410 break;
411 }
412
Andreas Huber88572f72012-02-21 11:47:18 -0800413 case '?':
414 case 'h':
415 default:
416 {
417 usage(me);
418 }
419 }
420 }
421
422 argc -= optind;
423 argv += optind;
424
425 if (argc != 1) {
426 usage(me);
427 }
428
429 if (!useAudio && !useVideo) {
430 useAudio = useVideo = true;
431 }
432
433 ProcessState::self()->startThreadPool();
434
435 DataSource::RegisterDefaultSniffers();
436
437 sp<ALooper> looper = new ALooper;
438 looper->start();
439
Andreas Hubere5760e32012-03-07 12:40:59 -0800440 sp<SurfaceComposerClient> composerClient;
441 sp<SurfaceControl> control;
442 sp<Surface> surface;
443
444 if (playback || (useSurface && useVideo)) {
445 composerClient = new SurfaceComposerClient;
Andreas Huber88572f72012-02-21 11:47:18 -0800446 CHECK_EQ(composerClient->initCheck(), (status_t)OK);
447
448 ssize_t displayWidth = composerClient->getDisplayWidth(0);
449 ssize_t displayHeight = composerClient->getDisplayHeight(0);
450
451 ALOGV("display is %ld x %ld\n", displayWidth, displayHeight);
452
Andreas Hubere5760e32012-03-07 12:40:59 -0800453 control = composerClient->createSurface(
454 String8("A Surface"),
455 0,
456 displayWidth,
457 displayHeight,
458 PIXEL_FORMAT_RGB_565,
459 0);
Andreas Huber88572f72012-02-21 11:47:18 -0800460
461 CHECK(control != NULL);
462 CHECK(control->isValid());
463
464 SurfaceComposerClient::openGlobalTransaction();
465 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
466 CHECK_EQ(control->show(), (status_t)OK);
467 SurfaceComposerClient::closeGlobalTransaction();
468
Andreas Hubere5760e32012-03-07 12:40:59 -0800469 surface = control->getSurface();
Andreas Huber88572f72012-02-21 11:47:18 -0800470 CHECK(surface != NULL);
Andreas Hubere5760e32012-03-07 12:40:59 -0800471 }
Andreas Huber88572f72012-02-21 11:47:18 -0800472
Andreas Hubere5760e32012-03-07 12:40:59 -0800473 if (playback) {
Andreas Huber88572f72012-02-21 11:47:18 -0800474 sp<SimplePlayer> player = new SimplePlayer;
475 looper->registerHandler(player);
476
477 player->setDataSource(argv[0]);
478 player->setSurface(surface->getSurfaceTexture());
479 player->start();
Andreas Hubera2798e22012-02-23 11:21:43 -0800480 sleep(60);
Andreas Huber88572f72012-02-21 11:47:18 -0800481 player->stop();
482 player->reset();
Andreas Huber88572f72012-02-21 11:47:18 -0800483 } else {
Andreas Huber9b8e4962012-03-26 11:13:27 -0700484 decode(looper, argv[0],
485 useAudio, useVideo, surface, decryptInputBuffers);
Andreas Hubere5760e32012-03-07 12:40:59 -0800486 }
487
488 if (playback || (useSurface && useVideo)) {
489 composerClient->dispose();
Andreas Huber88572f72012-02-21 11:47:18 -0800490 }
491
492 looper->stop();
493
494 return 0;
495}