stagefright.cpp revision 5228dd1b7468bfc86a807a299f515d33048f96ac
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/HTTPDataSource.h> 28#include <media/stagefright/JPEGSource.h> 29#include <media/stagefright/MediaDebug.h> 30#include <media/stagefright/MediaDefs.h> 31#include <media/stagefright/MediaPlayerImpl.h> 32#include <media/stagefright/MediaExtractor.h> 33#include <media/stagefright/MediaSource.h> 34#include <media/stagefright/MetaData.h> 35#include <media/stagefright/MmapSource.h> 36#include <media/stagefright/OMXClient.h> 37#include <media/stagefright/OMXCodec.h> 38 39using namespace android; 40 41static long gNumRepetitions; 42static long gMaxNumFrames; // 0 means decode all available. 43static long gReproduceBug; // if not -1. 44 45static int64_t getNowUs() { 46 struct timeval tv; 47 gettimeofday(&tv, NULL); 48 49 return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; 50} 51 52static void playSource(OMXClient *client, const sp<MediaSource> &source) { 53 sp<MetaData> meta = source->getFormat(); 54 55 sp<OMXCodec> decoder = OMXCodec::Create( 56 client->interface(), meta, false /* createEncoder */, source); 57 58 if (decoder == NULL) { 59 return; 60 } 61 62 decoder->start(); 63 64 if (gReproduceBug == 3) { 65 status_t err; 66 MediaBuffer *buffer; 67 MediaSource::ReadOptions options; 68 int64_t seekTimeUs = -1; 69 for (;;) { 70 err = decoder->read(&buffer, &options); 71 options.clearSeekTo(); 72 73 bool shouldSeek = false; 74 if (err != OK) { 75 printf("reached EOF.\n"); 76 77 shouldSeek = true; 78 } else { 79 int32_t units, scale; 80 CHECK(buffer->meta_data()->findInt32(kKeyTimeUnits, &units)); 81 CHECK(buffer->meta_data()->findInt32(kKeyTimeScale, &scale)); 82 int64_t timestamp = ((OMX_TICKS)units * 1000000) / scale; 83 84 bool failed = false; 85 if (seekTimeUs >= 0) { 86 int64_t diff = timestamp - seekTimeUs; 87 88 if (diff > 500000) { 89 printf("ERROR: "); 90 failed = true; 91 } 92 } 93 94 printf("buffer has timestamp %lld us (%.2f secs)\n", 95 timestamp, timestamp / 1E6); 96 97 buffer->release(); 98 buffer = NULL; 99 100 if (failed) { 101 break; 102 } 103 104 shouldSeek = ((double)rand() / RAND_MAX) < 0.1; 105 shouldSeek = false; 106 } 107 108 seekTimeUs = -1; 109 110 if (shouldSeek) { 111 seekTimeUs = (rand() * 30E6) / RAND_MAX; 112 options.setSeekTo(seekTimeUs); 113 114 printf("seeking to %lld us (%.2f secs)\n", 115 seekTimeUs, seekTimeUs / 1E6); 116 } 117 } 118 119 decoder->stop(); 120 121 return; 122 } 123 124 int n = 0; 125 int64_t startTime = getNowUs(); 126 127 long numIterationsLeft = gNumRepetitions; 128 MediaSource::ReadOptions options; 129 130 while (numIterationsLeft-- > 0) { 131 long numFrames = 0; 132 133 MediaBuffer *buffer; 134 135 for (;;) { 136 status_t err = decoder->read(&buffer, &options); 137 options.clearSeekTo(); 138 139 if (err != OK) { 140 CHECK_EQ(buffer, NULL); 141 break; 142 } 143 144 if ((n++ % 16) == 0) { 145 printf("."); 146 fflush(stdout); 147 } 148 149 buffer->release(); 150 buffer = NULL; 151 152 ++numFrames; 153 if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { 154 break; 155 } 156 157 if (gReproduceBug == 1 && numFrames == 40) { 158 printf("seeking past the end now."); 159 options.setSeekTo(0x7fffffffL); 160 } else if (gReproduceBug == 2 && numFrames == 40) { 161 printf("seeking to 5 secs."); 162 options.setSeekTo(5000000); 163 } 164 } 165 166 printf("$"); 167 fflush(stdout); 168 169 options.setSeekTo(0); 170 } 171 172 decoder->stop(); 173 printf("\n"); 174 175 int64_t delay = getNowUs() - startTime; 176 printf("avg. %.2f fps\n", n * 1E6 / delay); 177 178 printf("decoded a total of %d frame(s).\n", n); 179} 180 181static void usage(const char *me) { 182 fprintf(stderr, "usage: %s\n", me); 183 fprintf(stderr, " -h(elp)\n"); 184 fprintf(stderr, " -a(udio)\n"); 185 fprintf(stderr, " -n repetitions\n"); 186 fprintf(stderr, " -l(ist) components\n"); 187 fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); 188 fprintf(stderr, " -b bug to reproduce\n"); 189 fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n"); 190} 191 192int main(int argc, char **argv) { 193 android::ProcessState::self()->startThreadPool(); 194 195 bool audioOnly = false; 196 bool listComponents = false; 197 bool dumpProfiles = false; 198 gNumRepetitions = 1; 199 gMaxNumFrames = 0; 200 gReproduceBug = -1; 201 202 int res; 203 while ((res = getopt(argc, argv, "han:lm:b:p")) >= 0) { 204 switch (res) { 205 case 'a': 206 { 207 audioOnly = true; 208 break; 209 } 210 211 case 'l': 212 { 213 listComponents = true; 214 break; 215 } 216 217 case 'm': 218 case 'n': 219 case 'b': 220 { 221 char *end; 222 long x = strtol(optarg, &end, 10); 223 224 if (*end != '\0' || end == optarg || x <= 0) { 225 x = 1; 226 } 227 228 if (res == 'n') { 229 gNumRepetitions = x; 230 } else if (res == 'm') { 231 gMaxNumFrames = x; 232 } else { 233 CHECK_EQ(res, 'b'); 234 gReproduceBug = x; 235 } 236 break; 237 } 238 239 case 'p': 240 { 241 dumpProfiles = true; 242 break; 243 } 244 245 case '?': 246 case 'h': 247 default: 248 { 249 usage(argv[0]); 250 exit(1); 251 break; 252 } 253 } 254 } 255 256 argc -= optind; 257 argv += optind; 258 259 if (dumpProfiles) { 260 sp<IServiceManager> sm = defaultServiceManager(); 261 sp<IBinder> binder = sm->getService(String16("media.player")); 262 sp<IMediaPlayerService> service = 263 interface_cast<IMediaPlayerService>(binder); 264 265 CHECK(service.get() != NULL); 266 267 sp<IOMX> omx = service->createOMX(); 268 CHECK(omx.get() != NULL); 269 270 const char *kMimeTypes[] = { 271 MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4, 272 MEDIA_MIMETYPE_VIDEO_H263 273 }; 274 275 for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); 276 ++k) { 277 printf("type '%s':\n", kMimeTypes[k]); 278 279 Vector<CodecCapabilities> results; 280 CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], 281 true, // queryDecoders 282 &results), OK); 283 284 for (size_t i = 0; i < results.size(); ++i) { 285 printf(" decoder '%s' supports ", 286 results[i].mComponentName.string()); 287 288 if (results[i].mProfileLevels.size() == 0) { 289 printf("NOTHING.\n"); 290 continue; 291 } 292 293 for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) { 294 const CodecProfileLevel &profileLevel = 295 results[i].mProfileLevels[j]; 296 297 printf("%s%ld/%ld", j > 0 ? ", " : "", 298 profileLevel.mProfile, profileLevel.mLevel); 299 } 300 301 printf("\n"); 302 } 303 } 304 } 305 306 if (listComponents) { 307 sp<IServiceManager> sm = defaultServiceManager(); 308 sp<IBinder> binder = sm->getService(String16("media.player")); 309 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 310 311 CHECK(service.get() != NULL); 312 313 sp<IOMX> omx = service->createOMX(); 314 CHECK(omx.get() != NULL); 315 316 List<String8> list; 317 omx->list_nodes(&list); 318 319 for (List<String8>::iterator it = list.begin(); 320 it != list.end(); ++it) { 321 printf("%s\n", (*it).string()); 322 } 323 } 324 325 DataSource::RegisterDefaultSniffers(); 326 327 OMXClient client; 328 status_t err = client.connect(); 329 330 for (int k = 0; k < argc; ++k) { 331 const char *filename = argv[k]; 332 333 sp<DataSource> dataSource; 334 if (!strncasecmp("http://", filename, 7)) { 335 dataSource = new HTTPDataSource(filename); 336 dataSource = new CachingDataSource(dataSource, 64 * 1024, 10); 337 } else { 338 dataSource = new MmapSource(filename); 339 } 340 341 bool isJPEG = false; 342 343 size_t len = strlen(filename); 344 if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) { 345 isJPEG = true; 346 } 347 348 sp<MediaSource> mediaSource; 349 350 if (isJPEG) { 351 mediaSource = new JPEGSource(dataSource); 352 } else { 353 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 354 355 size_t numTracks = extractor->countTracks(); 356 357 sp<MetaData> meta; 358 size_t i; 359 for (i = 0; i < numTracks; ++i) { 360 meta = extractor->getTrackMetaData(i); 361 362 const char *mime; 363 meta->findCString(kKeyMIMEType, &mime); 364 365 if (audioOnly && !strncasecmp(mime, "audio/", 6)) { 366 break; 367 } 368 369 if (!audioOnly && !strncasecmp(mime, "video/", 6)) { 370 break; 371 } 372 } 373 374 mediaSource = extractor->getTrack(i); 375 } 376 377 playSource(&client, mediaSource); 378 } 379 380 client.disconnect(); 381 382 return 0; 383} 384