blob: ddd64ecf0445ef1434021324dfc780dc02d5ff41 [file] [log] [blame]
James Dong199d1c12011-03-17 11:48:13 -07001/*
2 * Copyright (C) 2010 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
Andreas Hubera1587462010-12-15 15:17:42 -080017#include <binder/ProcessState.h>
18
19#include <media/stagefright/foundation/hexdump.h>
20#include <media/stagefright/foundation/ABuffer.h>
21#include <media/stagefright/foundation/ADebug.h>
22#include <media/stagefright/foundation/ALooper.h>
23#include <media/stagefright/foundation/AMessage.h>
24
25#include <media/stagefright/ACodec.h>
26#include <media/stagefright/DataSource.h>
27#include <media/stagefright/MediaBuffer.h>
28#include <media/stagefright/MediaDefs.h>
29#include <media/stagefright/MediaExtractor.h>
30#include <media/stagefright/MediaSource.h>
31#include <media/stagefright/MetaData.h>
Andreas Hubere366f522011-06-28 10:51:41 -070032#include <media/stagefright/NativeWindowWrapper.h>
Andreas Hubera1587462010-12-15 15:17:42 -080033#include <media/stagefright/Utils.h>
34
35#include <surfaceflinger/ISurfaceComposer.h>
36#include <surfaceflinger/SurfaceComposerClient.h>
37
38#include "include/ESDS.h"
39
40using namespace android;
41
42struct Controller : public AHandler {
Andreas Hubere366f522011-06-28 10:51:41 -070043 Controller(const char *uri, bool decodeAudio,
44 const sp<Surface> &surface, bool renderToSurface)
Andreas Hubera1587462010-12-15 15:17:42 -080045 : mURI(uri),
46 mDecodeAudio(decodeAudio),
47 mSurface(surface),
Andreas Hubere366f522011-06-28 10:51:41 -070048 mRenderToSurface(renderToSurface),
Andreas Hubera1587462010-12-15 15:17:42 -080049 mCodec(new ACodec) {
50 CHECK(!mDecodeAudio || mSurface == NULL);
51 }
52
53 void startAsync() {
54 (new AMessage(kWhatStart, id()))->post();
55 }
56
57protected:
58 virtual ~Controller() {
59 }
60
61 virtual void onMessageReceived(const sp<AMessage> &msg) {
62 switch (msg->what()) {
63 case kWhatStart:
64 {
65#if 1
66 mDecodeLooper = looper();
67#else
68 mDecodeLooper = new ALooper;
69 mDecodeLooper->setName("sf2 decode looper");
70 mDecodeLooper->start();
71#endif
72
73 sp<DataSource> dataSource =
74 DataSource::CreateFromURI(mURI.c_str());
75
76 sp<MediaExtractor> extractor =
77 MediaExtractor::Create(dataSource);
78
79 for (size_t i = 0; i < extractor->countTracks(); ++i) {
80 sp<MetaData> meta = extractor->getTrackMetaData(i);
81
82 const char *mime;
83 CHECK(meta->findCString(kKeyMIMEType, &mime));
84
85 if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
86 mime, 6)) {
87 mSource = extractor->getTrack(i);
88 break;
89 }
90 }
91 CHECK(mSource != NULL);
92
93 CHECK_EQ(mSource->start(), (status_t)OK);
94
95 mDecodeLooper->registerHandler(mCodec);
96
97 mCodec->setNotificationMessage(
98 new AMessage(kWhatCodecNotify, id()));
99
100 sp<AMessage> format = makeFormat(mSource->getFormat());
101
102 if (mSurface != NULL) {
Andreas Hubere366f522011-06-28 10:51:41 -0700103 format->setObject(
104 "native-window", new NativeWindowWrapper(mSurface));
Andreas Hubera1587462010-12-15 15:17:42 -0800105 }
106
107 mCodec->initiateSetup(format);
108
109 mCSDIndex = 0;
110 mStartTimeUs = ALooper::GetNowUs();
111 mNumOutputBuffersReceived = 0;
112 mTotalBytesReceived = 0;
113 mLeftOverBuffer = NULL;
114 mFinalResult = OK;
115 mSeekState = SEEK_NONE;
116
117 // (new AMessage(kWhatSeek, id()))->post(5000000ll);
118 break;
119 }
120
121 case kWhatSeek:
122 {
123 printf("+");
124 fflush(stdout);
125
126 CHECK(mSeekState == SEEK_NONE
127 || mSeekState == SEEK_FLUSH_COMPLETED);
128
129 if (mLeftOverBuffer != NULL) {
130 mLeftOverBuffer->release();
131 mLeftOverBuffer = NULL;
132 }
133
134 mSeekState = SEEK_FLUSHING;
135 mSeekTimeUs = 30000000ll;
136
137 mCodec->signalFlush();
138 break;
139 }
140
141 case kWhatStop:
142 {
143 if (mLeftOverBuffer != NULL) {
144 mLeftOverBuffer->release();
145 mLeftOverBuffer = NULL;
146 }
147
148 CHECK_EQ(mSource->stop(), (status_t)OK);
149 mSource.clear();
150
151 mCodec->initiateShutdown();
152 break;
153 }
154
155 case kWhatCodecNotify:
156 {
157 int32_t what;
158 CHECK(msg->findInt32("what", &what));
159
160 if (what == ACodec::kWhatFillThisBuffer) {
161 onFillThisBuffer(msg);
162 } else if (what == ACodec::kWhatDrainThisBuffer) {
163 if ((mNumOutputBuffersReceived++ % 16) == 0) {
164 printf(".");
165 fflush(stdout);
166 }
167
168 onDrainThisBuffer(msg);
169 } else if (what == ACodec::kWhatEOS) {
170 printf("$\n");
171
172 int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
173
174 if (mDecodeAudio) {
175 printf("%lld bytes received. %.2f KB/sec\n",
176 mTotalBytesReceived,
177 mTotalBytesReceived * 1E6 / 1024 / delayUs);
178 } else {
179 printf("%d frames decoded, %.2f fps. %lld bytes "
180 "received. %.2f KB/sec\n",
181 mNumOutputBuffersReceived,
182 mNumOutputBuffersReceived * 1E6 / delayUs,
183 mTotalBytesReceived,
184 mTotalBytesReceived * 1E6 / 1024 / delayUs);
185 }
186
187 (new AMessage(kWhatStop, id()))->post();
188 } else if (what == ACodec::kWhatFlushCompleted) {
189 mSeekState = SEEK_FLUSH_COMPLETED;
190 mCodec->signalResume();
191
192 (new AMessage(kWhatSeek, id()))->post(5000000ll);
Andreas Huber5ea13722011-02-04 10:14:08 -0800193 } else if (what == ACodec::kWhatOutputFormatChanged) {
Andreas Hubera1587462010-12-15 15:17:42 -0800194 } else {
195 CHECK_EQ(what, (int32_t)ACodec::kWhatShutdownCompleted);
196
197 mDecodeLooper->unregisterHandler(mCodec->id());
198
199 if (mDecodeLooper != looper()) {
200 mDecodeLooper->stop();
201 }
202
203 looper()->stop();
204 }
205 break;
206 }
207
208 default:
209 TRESPASS();
210 break;
211 }
212 }
213
214private:
215 enum {
216 kWhatStart = 'strt',
217 kWhatStop = 'stop',
218 kWhatCodecNotify = 'noti',
219 kWhatSeek = 'seek',
220 };
221
222 sp<ALooper> mDecodeLooper;
223
224 AString mURI;
225 bool mDecodeAudio;
226 sp<Surface> mSurface;
Andreas Hubere366f522011-06-28 10:51:41 -0700227 bool mRenderToSurface;
Andreas Hubera1587462010-12-15 15:17:42 -0800228 sp<ACodec> mCodec;
229 sp<MediaSource> mSource;
230
231 Vector<sp<ABuffer> > mCSD;
232 size_t mCSDIndex;
233
234 MediaBuffer *mLeftOverBuffer;
235 status_t mFinalResult;
236
237 int64_t mStartTimeUs;
238 int32_t mNumOutputBuffersReceived;
239 int64_t mTotalBytesReceived;
240
241 enum SeekState {
242 SEEK_NONE,
243 SEEK_FLUSHING,
244 SEEK_FLUSH_COMPLETED,
245 };
246 SeekState mSeekState;
247 int64_t mSeekTimeUs;
248
249 sp<AMessage> makeFormat(const sp<MetaData> &meta) {
250 CHECK(mCSD.isEmpty());
251
252 const char *mime;
253 CHECK(meta->findCString(kKeyMIMEType, &mime));
254
255 sp<AMessage> msg = new AMessage;
256 msg->setString("mime", mime);
257
258 if (!strncasecmp("video/", mime, 6)) {
259 int32_t width, height;
260 CHECK(meta->findInt32(kKeyWidth, &width));
261 CHECK(meta->findInt32(kKeyHeight, &height));
262
263 msg->setInt32("width", width);
264 msg->setInt32("height", height);
265 } else {
266 CHECK(!strncasecmp("audio/", mime, 6));
267
268 int32_t numChannels, sampleRate;
269 CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
270 CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
271
272 msg->setInt32("channel-count", numChannels);
273 msg->setInt32("sample-rate", sampleRate);
274 }
275
276 uint32_t type;
277 const void *data;
278 size_t size;
279 if (meta->findData(kKeyAVCC, &type, &data, &size)) {
280 // Parse the AVCDecoderConfigurationRecord
281
282 const uint8_t *ptr = (const uint8_t *)data;
283
284 CHECK(size >= 7);
285 CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
286 uint8_t profile = ptr[1];
287 uint8_t level = ptr[3];
288
289 // There is decodable content out there that fails the following
290 // assertion, let's be lenient for now...
291 // CHECK((ptr[4] >> 2) == 0x3f); // reserved
292
293 size_t lengthSize = 1 + (ptr[4] & 3);
294
295 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
296 // violates it...
297 // CHECK((ptr[5] >> 5) == 7); // reserved
298
299 size_t numSeqParameterSets = ptr[5] & 31;
300
301 ptr += 6;
302 size -= 6;
303
304 sp<ABuffer> buffer = new ABuffer(1024);
305 buffer->setRange(0, 0);
306
307 for (size_t i = 0; i < numSeqParameterSets; ++i) {
308 CHECK(size >= 2);
309 size_t length = U16_AT(ptr);
310
311 ptr += 2;
312 size -= 2;
313
314 CHECK(size >= length);
315
316 memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
317 memcpy(buffer->data() + buffer->size() + 4, ptr, length);
318 buffer->setRange(0, buffer->size() + 4 + length);
319
320 ptr += length;
321 size -= length;
322 }
323
324 buffer->meta()->setInt32("csd", true);
325 mCSD.push(buffer);
326
327 buffer = new ABuffer(1024);
328 buffer->setRange(0, 0);
329
330 CHECK(size >= 1);
331 size_t numPictureParameterSets = *ptr;
332 ++ptr;
333 --size;
334
335 for (size_t i = 0; i < numPictureParameterSets; ++i) {
336 CHECK(size >= 2);
337 size_t length = U16_AT(ptr);
338
339 ptr += 2;
340 size -= 2;
341
342 CHECK(size >= length);
343
344 memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
345 memcpy(buffer->data() + buffer->size() + 4, ptr, length);
346 buffer->setRange(0, buffer->size() + 4 + length);
347
348 ptr += length;
349 size -= length;
350 }
351
352 buffer->meta()->setInt32("csd", true);
353 mCSD.push(buffer);
354
355 msg->setObject("csd", buffer);
356 } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
357 ESDS esds((const char *)data, size);
358 CHECK_EQ(esds.InitCheck(), (status_t)OK);
359
360 const void *codec_specific_data;
361 size_t codec_specific_data_size;
362 esds.getCodecSpecificInfo(
363 &codec_specific_data, &codec_specific_data_size);
364
365 sp<ABuffer> buffer = new ABuffer(codec_specific_data_size);
366
367 memcpy(buffer->data(), codec_specific_data,
368 codec_specific_data_size);
369
370 buffer->meta()->setInt32("csd", true);
371 mCSD.push(buffer);
372 }
373
374 int32_t maxInputSize;
375 if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
376 msg->setInt32("max-input-size", maxInputSize);
377 }
378
379 return msg;
380 }
381
382 void onFillThisBuffer(const sp<AMessage> &msg) {
383 sp<AMessage> reply;
384 CHECK(msg->findMessage("reply", &reply));
385
386 if (mSeekState == SEEK_FLUSHING) {
387 reply->post();
388 return;
389 }
390
391 sp<RefBase> obj;
392 CHECK(msg->findObject("buffer", &obj));
393 sp<ABuffer> outBuffer = static_cast<ABuffer *>(obj.get());
394
395 if (mCSDIndex < mCSD.size()) {
396 outBuffer = mCSD.editItemAt(mCSDIndex++);
397 outBuffer->meta()->setInt64("timeUs", 0);
398 } else {
399 size_t sizeLeft = outBuffer->capacity();
400 outBuffer->setRange(0, 0);
401
402 int32_t n = 0;
403
404 for (;;) {
405 MediaBuffer *inBuffer;
406
407 if (mLeftOverBuffer != NULL) {
408 inBuffer = mLeftOverBuffer;
409 mLeftOverBuffer = NULL;
410 } else if (mFinalResult != OK) {
411 break;
412 } else {
413 MediaSource::ReadOptions options;
414 if (mSeekState == SEEK_FLUSH_COMPLETED) {
415 options.setSeekTo(mSeekTimeUs);
416 mSeekState = SEEK_NONE;
417 }
418 status_t err = mSource->read(&inBuffer, &options);
419
420 if (err != OK) {
421 mFinalResult = err;
422 break;
423 }
424 }
425
426 if (inBuffer->range_length() > sizeLeft) {
427 if (outBuffer->size() == 0) {
428 LOGE("Unable to fit even a single input buffer of size %d.",
429 inBuffer->range_length());
430 }
431 CHECK_GT(outBuffer->size(), 0u);
432
433 mLeftOverBuffer = inBuffer;
434 break;
435 }
436
437 ++n;
438
439 if (outBuffer->size() == 0) {
440 int64_t timeUs;
441 CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
442
443 outBuffer->meta()->setInt64("timeUs", timeUs);
444 }
445
446 memcpy(outBuffer->data() + outBuffer->size(),
447 (const uint8_t *)inBuffer->data()
448 + inBuffer->range_offset(),
449 inBuffer->range_length());
450
451 outBuffer->setRange(
452 0, outBuffer->size() + inBuffer->range_length());
453
454 sizeLeft -= inBuffer->range_length();
455
456 inBuffer->release();
457 inBuffer = NULL;
458
Andreas Hubere366f522011-06-28 10:51:41 -0700459 break; // Don't coalesce
Andreas Hubera1587462010-12-15 15:17:42 -0800460 }
461
462 LOGV("coalesced %d input buffers", n);
463
464 if (outBuffer->size() == 0) {
465 CHECK_NE(mFinalResult, (status_t)OK);
466
467 reply->setInt32("err", mFinalResult);
468 reply->post();
469 return;
470 }
471 }
472
473 reply->setObject("buffer", outBuffer);
474 reply->post();
475 }
476
477 void onDrainThisBuffer(const sp<AMessage> &msg) {
478 sp<RefBase> obj;
479 CHECK(msg->findObject("buffer", &obj));
480
481 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
482 mTotalBytesReceived += buffer->size();
483
484 sp<AMessage> reply;
485 CHECK(msg->findMessage("reply", &reply));
486
Andreas Hubere366f522011-06-28 10:51:41 -0700487 if (mRenderToSurface) {
488 reply->setInt32("render", 1);
489 }
490
Andreas Hubera1587462010-12-15 15:17:42 -0800491 reply->post();
492 }
493
494 DISALLOW_EVIL_CONSTRUCTORS(Controller);
495};
496
497static void usage(const char *me) {
498 fprintf(stderr, "usage: %s\n", me);
499 fprintf(stderr, " -h(elp)\n");
500 fprintf(stderr, " -a(udio)\n");
501
502 fprintf(stderr,
Andreas Hubere366f522011-06-28 10:51:41 -0700503 " -S(urface) Allocate output buffers on a surface.\n"
504 " -R(ender) Render surface-allocated buffers.\n");
Andreas Hubera1587462010-12-15 15:17:42 -0800505}
506
507int main(int argc, char **argv) {
508 android::ProcessState::self()->startThreadPool();
509
510 bool decodeAudio = false;
511 bool useSurface = false;
Andreas Hubere366f522011-06-28 10:51:41 -0700512 bool renderToSurface = false;
Andreas Hubera1587462010-12-15 15:17:42 -0800513
514 int res;
Andreas Hubere366f522011-06-28 10:51:41 -0700515 while ((res = getopt(argc, argv, "haSR")) >= 0) {
Andreas Hubera1587462010-12-15 15:17:42 -0800516 switch (res) {
517 case 'a':
518 decodeAudio = true;
519 break;
520
Andreas Hubere366f522011-06-28 10:51:41 -0700521 case 'S':
Andreas Hubera1587462010-12-15 15:17:42 -0800522 useSurface = true;
523 break;
524
Andreas Hubere366f522011-06-28 10:51:41 -0700525 case 'R':
526 renderToSurface = true;
527 break;
528
Andreas Hubera1587462010-12-15 15:17:42 -0800529 case '?':
530 case 'h':
531 default:
532 {
533 usage(argv[0]);
534 return 1;
535 }
536 }
537 }
538
539 argc -= optind;
540 argv += optind;
541
542 if (argc != 1) {
543 usage(argv[-optind]);
544 return 1;
545 }
546
547 DataSource::RegisterDefaultSniffers();
548
549 sp<ALooper> looper = new ALooper;
550 looper->setName("sf2");
551
552 sp<SurfaceComposerClient> composerClient;
553 sp<SurfaceControl> control;
554 sp<Surface> surface;
555
556 if (!decodeAudio && useSurface) {
557 composerClient = new SurfaceComposerClient;
558 CHECK_EQ(composerClient->initCheck(), (status_t)OK);
559
560 control = composerClient->createSurface(
Andreas Hubera1587462010-12-15 15:17:42 -0800561 String8("A Surface"),
562 0,
563 1280,
564 800,
565 PIXEL_FORMAT_RGB_565,
566 0);
567
568 CHECK(control != NULL);
569 CHECK(control->isValid());
570
571 CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
572 CHECK_EQ(control->setLayer(30000), (status_t)OK);
573 CHECK_EQ(control->show(), (status_t)OK);
574 CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
575
576 surface = control->getSurface();
577 CHECK(surface != NULL);
578 }
579
Andreas Hubere366f522011-06-28 10:51:41 -0700580 sp<Controller> controller =
581 new Controller(argv[0], decodeAudio, surface, renderToSurface);
582
Andreas Hubera1587462010-12-15 15:17:42 -0800583 looper->registerHandler(controller);
584
585 controller->startAsync();
586
587 CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
588
589 looper->unregisterHandler(controller->id());
590
591 if (!decodeAudio && useSurface) {
592 composerClient->dispose();
593 }
594
595 return 0;
596}
597