stagefright.cpp revision 693d271e62a3726689ff68f4505ba49228eb94b2
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 <pthread.h> 20#include <stdlib.h> 21 22#include <binder/IServiceManager.h> 23#include <binder/ProcessState.h> 24#include <media/IMediaPlayerService.h> 25#include <media/stagefright/AudioPlayer.h> 26#include <media/stagefright/CachingDataSource.h> 27#include <media/stagefright/ESDS.h> 28#include <media/stagefright/FileSource.h> 29#include <media/stagefright/MediaBuffer.h> 30#include <media/stagefright/MediaBufferGroup.h> 31#include <media/stagefright/MediaDebug.h> 32#include <media/stagefright/MediaPlayerImpl.h> 33#include <media/stagefright/MediaExtractor.h> 34#include <media/stagefright/MediaSource.h> 35#include <media/stagefright/MetaData.h> 36#include <media/stagefright/MmapSource.h> 37#include <media/stagefright/OMXClient.h> 38#include <media/stagefright/OMXCodec.h> 39#include <media/stagefright/OMXDecoder.h> 40 41#include "WaveWriter.h" 42 43using namespace android; 44 45//////////////////////////////////////////////////////////////////////////////// 46 47struct JPEGSource : public MediaSource { 48 // Assumes ownership of "source". 49 JPEGSource(const sp<DataSource> &source); 50 51 virtual status_t start(MetaData *params = NULL); 52 virtual status_t stop(); 53 virtual sp<MetaData> getFormat(); 54 55 virtual status_t read( 56 MediaBuffer **buffer, const ReadOptions *options = NULL); 57 58protected: 59 virtual ~JPEGSource(); 60 61private: 62 sp<DataSource> mSource; 63 MediaBufferGroup *mGroup; 64 bool mStarted; 65 off_t mSize; 66 int32_t mWidth, mHeight; 67 off_t mOffset; 68 69 status_t parseJPEG(); 70 71 JPEGSource(const JPEGSource &); 72 JPEGSource &operator=(const JPEGSource &); 73}; 74 75JPEGSource::JPEGSource(const sp<DataSource> &source) 76 : mSource(source), 77 mGroup(NULL), 78 mStarted(false), 79 mSize(0), 80 mWidth(0), 81 mHeight(0), 82 mOffset(0) { 83 CHECK_EQ(parseJPEG(), OK); 84} 85 86JPEGSource::~JPEGSource() { 87 if (mStarted) { 88 stop(); 89 } 90} 91 92status_t JPEGSource::start(MetaData *) { 93 if (mStarted) { 94 return UNKNOWN_ERROR; 95 } 96 97 if (mSource->getSize(&mSize) != OK) { 98 return UNKNOWN_ERROR; 99 } 100 101 mGroup = new MediaBufferGroup; 102 mGroup->add_buffer(new MediaBuffer(mSize)); 103 104 mOffset = 0; 105 106 mStarted = true; 107 108 return OK; 109} 110 111status_t JPEGSource::stop() { 112 if (!mStarted) { 113 return UNKNOWN_ERROR; 114 } 115 116 delete mGroup; 117 mGroup = NULL; 118 119 mStarted = false; 120 121 return OK; 122} 123 124sp<MetaData> JPEGSource::getFormat() { 125 sp<MetaData> meta = new MetaData; 126 meta->setCString(kKeyMIMEType, "image/jpeg"); 127 meta->setInt32(kKeyWidth, mWidth); 128 meta->setInt32(kKeyHeight, mHeight); 129 130 return meta; 131} 132 133status_t JPEGSource::read( 134 MediaBuffer **out, const ReadOptions *options) { 135 *out = NULL; 136 137 int64_t seekTimeUs; 138 if (options != NULL && options->getSeekTo(&seekTimeUs)) { 139 return UNKNOWN_ERROR; 140 } 141 142 MediaBuffer *buffer; 143 mGroup->acquire_buffer(&buffer); 144 145 ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset); 146 147 if (n <= 0) { 148 buffer->release(); 149 buffer = NULL; 150 151 return UNKNOWN_ERROR; 152 } 153 154 buffer->set_range(0, n); 155 156 mOffset += n; 157 158 *out = buffer; 159 160 return OK; 161} 162 163#define JPEG_SOF0 0xC0 /* nStart Of Frame N*/ 164#define JPEG_SOF1 0xC1 /* N indicates which compression process*/ 165#define JPEG_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use*/ 166#define JPEG_SOF3 0xC3 167#define JPEG_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers*/ 168#define JPEG_SOF6 0xC6 169#define JPEG_SOF7 0xC7 170#define JPEG_SOF9 0xC9 171#define JPEG_SOF10 0xCA 172#define JPEG_SOF11 0xCB 173#define JPEG_SOF13 0xCD 174#define JPEG_SOF14 0xCE 175#define JPEG_SOF15 0xCF 176#define JPEG_SOI 0xD8 /* nStart Of Image (beginning of datastream)*/ 177#define JPEG_EOI 0xD9 /* End Of Image (end of datastream)*/ 178#define JPEG_SOS 0xDA /* nStart Of Scan (begins compressed data)*/ 179#define JPEG_JFIF 0xE0 /* Jfif marker*/ 180#define JPEG_EXIF 0xE1 /* Exif marker*/ 181#define JPEG_COM 0xFE /* COMment */ 182#define JPEG_DQT 0xDB 183#define JPEG_DHT 0xC4 184#define JPEG_DRI 0xDD 185 186status_t JPEGSource::parseJPEG() { 187 mWidth = 0; 188 mHeight = 0; 189 190 off_t i = 0; 191 192 uint16_t soi; 193 if (!mSource->getUInt16(i, &soi)) { 194 return ERROR_IO; 195 } 196 197 i += 2; 198 199 if (soi != 0xffd8) { 200 return UNKNOWN_ERROR; 201 } 202 203 for (;;) { 204 uint8_t marker; 205 if (mSource->read_at(i++, &marker, 1) != 1) { 206 return ERROR_IO; 207 } 208 209 CHECK_EQ(marker, 0xff); 210 211 if (mSource->read_at(i++, &marker, 1) != 1) { 212 return ERROR_IO; 213 } 214 215 CHECK(marker != 0xff); 216 217 uint16_t chunkSize; 218 if (!mSource->getUInt16(i, &chunkSize)) { 219 return ERROR_IO; 220 } 221 222 i += 2; 223 224 if (chunkSize < 2) { 225 return UNKNOWN_ERROR; 226 } 227 228 switch (marker) { 229 case JPEG_SOS: 230 { 231 return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR; 232 } 233 234 case JPEG_EOI: 235 { 236 return UNKNOWN_ERROR; 237 } 238 239 case JPEG_SOF0: 240 case JPEG_SOF1: 241 case JPEG_SOF3: 242 case JPEG_SOF5: 243 case JPEG_SOF6: 244 case JPEG_SOF7: 245 case JPEG_SOF9: 246 case JPEG_SOF10: 247 case JPEG_SOF11: 248 case JPEG_SOF13: 249 case JPEG_SOF14: 250 case JPEG_SOF15: 251 { 252 uint16_t width, height; 253 if (!mSource->getUInt16(i + 1, &height) 254 || !mSource->getUInt16(i + 3, &width)) { 255 return ERROR_IO; 256 } 257 258 mWidth = width; 259 mHeight = height; 260 261 i += chunkSize - 2; 262 break; 263 } 264 265 default: 266 { 267 // Skip chunk 268 269 i += chunkSize - 2; 270 271 break; 272 } 273 } 274 } 275 276 return OK; 277} 278 279//////////////////////////////////////////////////////////////////////////////// 280 281static int64_t getNowUs() { 282 struct timeval tv; 283 gettimeofday(&tv, NULL); 284 285 return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; 286} 287 288#define USE_OMX_CODEC 1 289 290static void playSource(OMXClient *client, const sp<MediaSource> &source) { 291 sp<MetaData> meta = source->getFormat(); 292 293#if !USE_OMX_CODEC 294 sp<OMXDecoder> decoder = OMXDecoder::Create( 295 client, meta, false /* createEncoder */, source); 296#else 297 sp<OMXCodec> decoder = OMXCodec::Create( 298 client->interface(), meta, false /* createEncoder */, source); 299#endif 300 301 if (decoder == NULL) { 302 return; 303 } 304 305 decoder->start(); 306 307 int64_t startTime = getNowUs(); 308 309 int n = 0; 310 MediaBuffer *buffer; 311 status_t err; 312 while ((err = decoder->read(&buffer)) == OK) { 313 if ((++n % 16) == 0) { 314 printf("."); 315 fflush(stdout); 316 } 317 318 buffer->release(); 319 buffer = NULL; 320 } 321 decoder->stop(); 322 printf("\n"); 323 324 int64_t delay = getNowUs() - startTime; 325 printf("avg. %.2f fps\n", n * 1E6 / delay); 326 327 printf("decoded a total of %d frame(s).\n", n); 328} 329 330int main(int argc, char **argv) { 331 android::ProcessState::self()->startThreadPool(); 332 333 bool audioOnly = false; 334 if (argc > 1 && !strcmp(argv[1], "--list")) { 335 sp<IServiceManager> sm = defaultServiceManager(); 336 sp<IBinder> binder = sm->getService(String16("media.player")); 337 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 338 339 CHECK(service.get() != NULL); 340 341 sp<IOMX> omx = service->createOMX(); 342 CHECK(omx.get() != NULL); 343 344 List<String8> list; 345 omx->list_nodes(&list); 346 347 for (List<String8>::iterator it = list.begin(); 348 it != list.end(); ++it) { 349 printf("%s\n", (*it).string()); 350 } 351 352 return 0; 353 } else if (argc > 1 && !strcmp(argv[1], "--audio")) { 354 audioOnly = true; 355 ++argv; 356 --argc; 357 } 358 359 DataSource::RegisterDefaultSniffers(); 360 361 OMXClient client; 362 status_t err = client.connect(); 363 364 sp<MmapSource> dataSource = new MmapSource(argv[1]); 365 366 bool isJPEG = false; 367 368 size_t len = strlen(argv[1]); 369 if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) { 370 isJPEG = true; 371 } 372 373 sp<MediaSource> mediaSource; 374 375 if (isJPEG) { 376 mediaSource = new JPEGSource(dataSource); 377 } else { 378 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 379 380 size_t numTracks = extractor->countTracks(); 381 382 sp<MetaData> meta; 383 size_t i; 384 for (i = 0; i < numTracks; ++i) { 385 meta = extractor->getTrackMetaData(i); 386 387 const char *mime; 388 meta->findCString(kKeyMIMEType, &mime); 389 390 if (audioOnly && !strncasecmp(mime, "audio/", 6)) { 391 break; 392 } 393 394 if (!audioOnly && !strncasecmp(mime, "video/", 6)) { 395 break; 396 } 397 } 398 399 mediaSource = extractor->getTrack(i); 400 } 401 402 playSource(&client, mediaSource); 403 404 client.disconnect(); 405 406 return 0; 407} 408