stagefright.cpp revision 5c1e3581978164d169050686c73810ce59304471
1/* 2 * Copyright (C) 2009 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#include <sys/time.h> 18 19#include <stdlib.h> 20#include <string.h> 21#include <unistd.h> 22 23#include <binder/IServiceManager.h> 24#include <binder/ProcessState.h> 25#include <media/IMediaPlayerService.h> 26#include <media/stagefright/CachingDataSource.h> 27#include <media/stagefright/FileSource.h> 28#include <media/stagefright/HTTPDataSource.h> 29#include <media/stagefright/JPEGSource.h> 30#include <media/stagefright/MediaDebug.h> 31#include <media/stagefright/MediaDefs.h> 32#include <media/stagefright/MediaExtractor.h> 33#include <media/stagefright/MediaSource.h> 34#include <media/stagefright/MetaData.h> 35#include <media/stagefright/OMXClient.h> 36#include <media/stagefright/OMXCodec.h> 37#include <media/mediametadataretriever.h> 38 39using namespace android; 40 41static long gNumRepetitions; 42static long gMaxNumFrames; // 0 means decode all available. 43static long gReproduceBug; // if not -1. 44static bool gPreferSoftwareCodec; 45 46static int64_t getNowUs() { 47 struct timeval tv; 48 gettimeofday(&tv, NULL); 49 50 return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; 51} 52 53static void playSource(OMXClient *client, const sp<MediaSource> &source) { 54 sp<MetaData> meta = source->getFormat(); 55 56 const char *mime; 57 CHECK(meta->findCString(kKeyMIMEType, &mime)); 58 59 sp<MediaSource> rawSource; 60 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) { 61 rawSource = source; 62 } else { 63 rawSource = OMXCodec::Create( 64 client->interface(), meta, false /* createEncoder */, source, 65 NULL /* matchComponentName */, 66 gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0); 67 68 if (rawSource == NULL) { 69 fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime); 70 return; 71 } 72 } 73 74 rawSource->start(); 75 76 if (gReproduceBug >= 3 && gReproduceBug <= 5) { 77 int64_t durationUs; 78 CHECK(meta->findInt64(kKeyDuration, &durationUs)); 79 80 status_t err; 81 MediaBuffer *buffer; 82 MediaSource::ReadOptions options; 83 int64_t seekTimeUs = -1; 84 for (;;) { 85 err = rawSource->read(&buffer, &options); 86 options.clearSeekTo(); 87 88 bool shouldSeek = false; 89 if (err == INFO_FORMAT_CHANGED) { 90 CHECK_EQ(buffer, NULL); 91 92 printf("format changed.\n"); 93 continue; 94 } else if (err != OK) { 95 printf("reached EOF.\n"); 96 97 shouldSeek = true; 98 } else { 99 int64_t timestampUs; 100 CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); 101 102 bool failed = false; 103 104 if (seekTimeUs >= 0) { 105 int64_t diff = timestampUs - seekTimeUs; 106 107 if (diff < 0) { 108 diff = -diff; 109 } 110 111 if ((gReproduceBug == 4 && diff > 500000) 112 || (gReproduceBug == 5 && timestampUs < 0)) { 113 printf("wanted: %.2f secs, got: %.2f secs\n", 114 seekTimeUs / 1E6, timestampUs / 1E6); 115 116 printf("ERROR: "); 117 failed = true; 118 } 119 } 120 121 printf("buffer has timestamp %lld us (%.2f secs)\n", 122 timestampUs, timestampUs / 1E6); 123 124 buffer->release(); 125 buffer = NULL; 126 127 if (failed) { 128 break; 129 } 130 131 shouldSeek = ((double)rand() / RAND_MAX) < 0.1; 132 133 if (gReproduceBug == 3) { 134 shouldSeek = false; 135 } 136 } 137 138 seekTimeUs = -1; 139 140 if (shouldSeek) { 141 seekTimeUs = (rand() * (float)durationUs) / RAND_MAX; 142 options.setSeekTo(seekTimeUs); 143 144 printf("seeking to %lld us (%.2f secs)\n", 145 seekTimeUs, seekTimeUs / 1E6); 146 } 147 } 148 149 rawSource->stop(); 150 151 return; 152 } 153 154 int n = 0; 155 int64_t startTime = getNowUs(); 156 157 long numIterationsLeft = gNumRepetitions; 158 MediaSource::ReadOptions options; 159 160 while (numIterationsLeft-- > 0) { 161 long numFrames = 0; 162 163 MediaBuffer *buffer; 164 165 for (;;) { 166 status_t err = rawSource->read(&buffer, &options); 167 options.clearSeekTo(); 168 169 if (err != OK) { 170 CHECK_EQ(buffer, NULL); 171 172 if (err == INFO_FORMAT_CHANGED) { 173 printf("format changed.\n"); 174 continue; 175 } 176 177 break; 178 } 179 180 if (buffer->range_length() > 0 && (n++ % 16) == 0) { 181 printf("."); 182 fflush(stdout); 183 } 184 185 buffer->release(); 186 buffer = NULL; 187 188 ++numFrames; 189 if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { 190 break; 191 } 192 193 if (gReproduceBug == 1 && numFrames == 40) { 194 printf("seeking past the end now."); 195 options.setSeekTo(0x7fffffffL); 196 } else if (gReproduceBug == 2 && numFrames == 40) { 197 printf("seeking to 5 secs."); 198 options.setSeekTo(5000000); 199 } 200 } 201 202 printf("$"); 203 fflush(stdout); 204 205 options.setSeekTo(0); 206 } 207 208 rawSource->stop(); 209 printf("\n"); 210 211 int64_t delay = getNowUs() - startTime; 212 printf("avg. %.2f fps\n", n * 1E6 / delay); 213 214 printf("decoded a total of %d frame(s).\n", n); 215} 216 217static void usage(const char *me) { 218 fprintf(stderr, "usage: %s\n", me); 219 fprintf(stderr, " -h(elp)\n"); 220 fprintf(stderr, " -a(udio)\n"); 221 fprintf(stderr, " -n repetitions\n"); 222 fprintf(stderr, " -l(ist) components\n"); 223 fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); 224 fprintf(stderr, " -b bug to reproduce\n"); 225 fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n"); 226 fprintf(stderr, " -t(humbnail) extract video thumbnail\n"); 227 fprintf(stderr, " -s(oftware) prefer software codec\n"); 228} 229 230int main(int argc, char **argv) { 231 android::ProcessState::self()->startThreadPool(); 232 233 bool audioOnly = false; 234 bool listComponents = false; 235 bool dumpProfiles = false; 236 bool extractThumbnail = false; 237 gNumRepetitions = 1; 238 gMaxNumFrames = 0; 239 gReproduceBug = -1; 240 gPreferSoftwareCodec = false; 241 242 int res; 243 while ((res = getopt(argc, argv, "han:lm:b:pts")) >= 0) { 244 switch (res) { 245 case 'a': 246 { 247 audioOnly = true; 248 break; 249 } 250 251 case 'l': 252 { 253 listComponents = true; 254 break; 255 } 256 257 case 'm': 258 case 'n': 259 case 'b': 260 { 261 char *end; 262 long x = strtol(optarg, &end, 10); 263 264 if (*end != '\0' || end == optarg || x <= 0) { 265 x = 1; 266 } 267 268 if (res == 'n') { 269 gNumRepetitions = x; 270 } else if (res == 'm') { 271 gMaxNumFrames = x; 272 } else { 273 CHECK_EQ(res, 'b'); 274 gReproduceBug = x; 275 } 276 break; 277 } 278 279 case 'p': 280 { 281 dumpProfiles = true; 282 break; 283 } 284 285 case 't': 286 { 287 extractThumbnail = true; 288 break; 289 } 290 291 case 's': 292 { 293 gPreferSoftwareCodec = true; 294 break; 295 } 296 297 case '?': 298 case 'h': 299 default: 300 { 301 usage(argv[0]); 302 exit(1); 303 break; 304 } 305 } 306 } 307 308 argc -= optind; 309 argv += optind; 310 311 if (extractThumbnail) { 312 sp<IServiceManager> sm = defaultServiceManager(); 313 sp<IBinder> binder = sm->getService(String16("media.player")); 314 sp<IMediaPlayerService> service = 315 interface_cast<IMediaPlayerService>(binder); 316 317 CHECK(service.get() != NULL); 318 319 sp<IMediaMetadataRetriever> retriever = 320 service->createMetadataRetriever(getpid()); 321 322 CHECK(retriever != NULL); 323 324 for (int k = 0; k < argc; ++k) { 325 const char *filename = argv[k]; 326 327 CHECK_EQ(retriever->setDataSource(filename), OK); 328 CHECK_EQ(retriever->setMode(METADATA_MODE_FRAME_CAPTURE_ONLY), OK); 329 330 sp<IMemory> mem = retriever->captureFrame(); 331 332 printf("captureFrame(%s) => %s\n", 333 filename, mem != NULL ? "OK" : "FAILED"); 334 } 335 336 return 0; 337 } 338 339 if (dumpProfiles) { 340 sp<IServiceManager> sm = defaultServiceManager(); 341 sp<IBinder> binder = sm->getService(String16("media.player")); 342 sp<IMediaPlayerService> service = 343 interface_cast<IMediaPlayerService>(binder); 344 345 CHECK(service.get() != NULL); 346 347 sp<IOMX> omx = service->getOMX(); 348 CHECK(omx.get() != NULL); 349 350 const char *kMimeTypes[] = { 351 MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4, 352 MEDIA_MIMETYPE_VIDEO_H263 353 }; 354 355 for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); 356 ++k) { 357 printf("type '%s':\n", kMimeTypes[k]); 358 359 Vector<CodecCapabilities> results; 360 CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], 361 true, // queryDecoders 362 &results), OK); 363 364 for (size_t i = 0; i < results.size(); ++i) { 365 printf(" decoder '%s' supports ", 366 results[i].mComponentName.string()); 367 368 if (results[i].mProfileLevels.size() == 0) { 369 printf("NOTHING.\n"); 370 continue; 371 } 372 373 for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) { 374 const CodecProfileLevel &profileLevel = 375 results[i].mProfileLevels[j]; 376 377 printf("%s%ld/%ld", j > 0 ? ", " : "", 378 profileLevel.mProfile, profileLevel.mLevel); 379 } 380 381 printf("\n"); 382 } 383 } 384 } 385 386 if (listComponents) { 387 sp<IServiceManager> sm = defaultServiceManager(); 388 sp<IBinder> binder = sm->getService(String16("media.player")); 389 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 390 391 CHECK(service.get() != NULL); 392 393 sp<IOMX> omx = service->getOMX(); 394 CHECK(omx.get() != NULL); 395 396 List<IOMX::ComponentInfo> list; 397 omx->listNodes(&list); 398 399 for (List<IOMX::ComponentInfo>::iterator it = list.begin(); 400 it != list.end(); ++it) { 401 printf("%s\n", (*it).mName.string()); 402 } 403 } 404 405 DataSource::RegisterDefaultSniffers(); 406 407 OMXClient client; 408 status_t err = client.connect(); 409 410 for (int k = 0; k < argc; ++k) { 411 const char *filename = argv[k]; 412 413 sp<DataSource> dataSource; 414 if (!strncasecmp("http://", filename, 7)) { 415 dataSource = new HTTPDataSource(filename); 416 dataSource = new CachingDataSource(dataSource, 64 * 1024, 10); 417 } else { 418 dataSource = new FileSource(filename); 419 } 420 421 bool isJPEG = false; 422 423 size_t len = strlen(filename); 424 if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) { 425 isJPEG = true; 426 } 427 428 sp<MediaSource> mediaSource; 429 430 if (isJPEG) { 431 mediaSource = new JPEGSource(dataSource); 432 } else { 433 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 434 435 size_t numTracks = extractor->countTracks(); 436 437 sp<MetaData> meta; 438 size_t i; 439 for (i = 0; i < numTracks; ++i) { 440 meta = extractor->getTrackMetaData( 441 i, MediaExtractor::kIncludeExtensiveMetaData); 442 443 const char *mime; 444 meta->findCString(kKeyMIMEType, &mime); 445 446 if (audioOnly && !strncasecmp(mime, "audio/", 6)) { 447 break; 448 } 449 450 if (!audioOnly && !strncasecmp(mime, "video/", 6)) { 451 break; 452 } 453 } 454 455 int64_t thumbTimeUs; 456 if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { 457 printf("thumbnailTime: %lld us (%.2f secs)\n", 458 thumbTimeUs, thumbTimeUs / 1E6); 459 } 460 461 mediaSource = extractor->getTrack(i); 462 } 463 464 playSource(&client, mediaSource); 465 } 466 467 client.disconnect(); 468 469 return 0; 470} 471