1 /* 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/IServiceManager.h> 24 #include <binder/ProcessState.h> 25 #include <media/ICrypto.h> 26 #include <media/IMediaPlayerService.h> 27 #include <media/stagefright/foundation/ABuffer.h> 28 #include <media/stagefright/foundation/ADebug.h> 29 #include <media/stagefright/foundation/ALooper.h> 30 #include <media/stagefright/foundation/AMessage.h> 31 #include <media/stagefright/foundation/AString.h> 32 #include <media/stagefright/DataSource.h> 33 #include <media/stagefright/MediaCodec.h> 34 #include <media/stagefright/MediaCodecList.h> 35 #include <media/stagefright/MediaDefs.h> 36 #include <media/stagefright/NuMediaExtractor.h> 37 #include <gui/ISurfaceComposer.h> 38 #include <gui/SurfaceComposerClient.h> 39 #include <gui/Surface.h> 40 #include <ui/DisplayInfo.h> 41 42 static void usage(const char *me) { 43 fprintf(stderr, "usage: %s [-a] use audio\n" 44 "\t\t[-v] use video\n" 45 "\t\t[-p] playback\n" 46 "\t\t[-S] allocate buffers from a surface\n", 47 me); 48 49 exit(1); 50 } 51 52 namespace android { 53 54 struct CodecState { 55 sp<MediaCodec> mCodec; 56 Vector<sp<ABuffer> > mInBuffers; 57 Vector<sp<ABuffer> > mOutBuffers; 58 bool mSignalledInputEOS; 59 bool mSawOutputEOS; 60 int64_t mNumBuffersDecoded; 61 int64_t mNumBytesDecoded; 62 bool mIsAudio; 63 }; 64 65 } // namespace android 66 67 static int decode( 68 const android::sp<android::ALooper> &looper, 69 const char *path, 70 bool useAudio, 71 bool useVideo, 72 const android::sp<android::Surface> &surface) { 73 using namespace android; 74 75 static int64_t kTimeout = 500ll; 76 77 sp<NuMediaExtractor> extractor = new NuMediaExtractor; 78 if (extractor->setDataSource(path) != OK) { 79 fprintf(stderr, "unable to instantiate extractor.\n"); 80 return 1; 81 } 82 83 KeyedVector<size_t, CodecState> stateByTrack; 84 85 bool haveAudio = false; 86 bool haveVideo = false; 87 for (size_t i = 0; i < extractor->countTracks(); ++i) { 88 sp<AMessage> format; 89 status_t err = extractor->getTrackFormat(i, &format); 90 CHECK_EQ(err, (status_t)OK); 91 92 AString mime; 93 CHECK(format->findString("mime", &mime)); 94 95 bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6); 96 bool isVideo = !strncasecmp(mime.c_str(), "video/", 6); 97 98 if (useAudio && !haveAudio && isAudio) { 99 haveAudio = true; 100 } else if (useVideo && !haveVideo && isVideo) { 101 haveVideo = true; 102 } else { 103 continue; 104 } 105 106 ALOGV("selecting track %d", i); 107 108 err = extractor->selectTrack(i); 109 CHECK_EQ(err, (status_t)OK); 110 111 CodecState *state = 112 &stateByTrack.editValueAt(stateByTrack.add(i, CodecState())); 113 114 state->mNumBytesDecoded = 0; 115 state->mNumBuffersDecoded = 0; 116 state->mIsAudio = isAudio; 117 118 state->mCodec = MediaCodec::CreateByType( 119 looper, mime.c_str(), false /* encoder */); 120 121 CHECK(state->mCodec != NULL); 122 123 err = state->mCodec->configure( 124 format, isVideo ? surface : NULL, 125 NULL /* crypto */, 126 0 /* flags */); 127 128 CHECK_EQ(err, (status_t)OK); 129 130 state->mSignalledInputEOS = false; 131 state->mSawOutputEOS = false; 132 } 133 134 CHECK(!stateByTrack.isEmpty()); 135 136 int64_t startTimeUs = ALooper::GetNowUs(); 137 138 for (size_t i = 0; i < stateByTrack.size(); ++i) { 139 CodecState *state = &stateByTrack.editValueAt(i); 140 141 sp<MediaCodec> codec = state->mCodec; 142 143 CHECK_EQ((status_t)OK, codec->start()); 144 145 CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers)); 146 CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers)); 147 148 ALOGV("got %d input and %d output buffers", 149 state->mInBuffers.size(), state->mOutBuffers.size()); 150 } 151 152 bool sawInputEOS = false; 153 154 for (;;) { 155 if (!sawInputEOS) { 156 size_t trackIndex; 157 status_t err = extractor->getSampleTrackIndex(&trackIndex); 158 159 if (err != OK) { 160 ALOGV("saw input eos"); 161 sawInputEOS = true; 162 } else { 163 CodecState *state = &stateByTrack.editValueFor(trackIndex); 164 165 size_t index; 166 err = state->mCodec->dequeueInputBuffer(&index, kTimeout); 167 168 if (err == OK) { 169 ALOGV("filling input buffer %d", index); 170 171 const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index); 172 173 err = extractor->readSampleData(buffer); 174 CHECK_EQ(err, (status_t)OK); 175 176 int64_t timeUs; 177 err = extractor->getSampleTime(&timeUs); 178 CHECK_EQ(err, (status_t)OK); 179 180 uint32_t bufferFlags = 0; 181 182 err = state->mCodec->queueInputBuffer( 183 index, 184 0 /* offset */, 185 buffer->size(), 186 timeUs, 187 bufferFlags); 188 189 CHECK_EQ(err, (status_t)OK); 190 191 extractor->advance(); 192 } else { 193 CHECK_EQ(err, -EAGAIN); 194 } 195 } 196 } else { 197 for (size_t i = 0; i < stateByTrack.size(); ++i) { 198 CodecState *state = &stateByTrack.editValueAt(i); 199 200 if (!state->mSignalledInputEOS) { 201 size_t index; 202 status_t err = 203 state->mCodec->dequeueInputBuffer(&index, kTimeout); 204 205 if (err == OK) { 206 ALOGV("signalling input EOS on track %d", i); 207 208 err = state->mCodec->queueInputBuffer( 209 index, 210 0 /* offset */, 211 0 /* size */, 212 0ll /* timeUs */, 213 MediaCodec::BUFFER_FLAG_EOS); 214 215 CHECK_EQ(err, (status_t)OK); 216 217 state->mSignalledInputEOS = true; 218 } else { 219 CHECK_EQ(err, -EAGAIN); 220 } 221 } 222 } 223 } 224 225 bool sawOutputEOSOnAllTracks = true; 226 for (size_t i = 0; i < stateByTrack.size(); ++i) { 227 CodecState *state = &stateByTrack.editValueAt(i); 228 if (!state->mSawOutputEOS) { 229 sawOutputEOSOnAllTracks = false; 230 break; 231 } 232 } 233 234 if (sawOutputEOSOnAllTracks) { 235 break; 236 } 237 238 for (size_t i = 0; i < stateByTrack.size(); ++i) { 239 CodecState *state = &stateByTrack.editValueAt(i); 240 241 if (state->mSawOutputEOS) { 242 continue; 243 } 244 245 size_t index; 246 size_t offset; 247 size_t size; 248 int64_t presentationTimeUs; 249 uint32_t flags; 250 status_t err = state->mCodec->dequeueOutputBuffer( 251 &index, &offset, &size, &presentationTimeUs, &flags, 252 kTimeout); 253 254 if (err == OK) { 255 ALOGV("draining output buffer %d, time = %lld us", 256 index, presentationTimeUs); 257 258 ++state->mNumBuffersDecoded; 259 state->mNumBytesDecoded += size; 260 261 err = state->mCodec->releaseOutputBuffer(index); 262 CHECK_EQ(err, (status_t)OK); 263 264 if (flags & MediaCodec::BUFFER_FLAG_EOS) { 265 ALOGV("reached EOS on output."); 266 267 state->mSawOutputEOS = true; 268 } 269 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { 270 ALOGV("INFO_OUTPUT_BUFFERS_CHANGED"); 271 CHECK_EQ((status_t)OK, 272 state->mCodec->getOutputBuffers(&state->mOutBuffers)); 273 274 ALOGV("got %d output buffers", state->mOutBuffers.size()); 275 } else if (err == INFO_FORMAT_CHANGED) { 276 sp<AMessage> format; 277 CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format)); 278 279 ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str()); 280 } else { 281 CHECK_EQ(err, -EAGAIN); 282 } 283 } 284 } 285 286 int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs; 287 288 for (size_t i = 0; i < stateByTrack.size(); ++i) { 289 CodecState *state = &stateByTrack.editValueAt(i); 290 291 CHECK_EQ((status_t)OK, state->mCodec->release()); 292 293 if (state->mIsAudio) { 294 printf("track %d: %lld bytes received. %.2f KB/sec\n", 295 i, 296 state->mNumBytesDecoded, 297 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); 298 } else { 299 printf("track %d: %lld frames decoded, %.2f fps. %lld bytes " 300 "received. %.2f KB/sec\n", 301 i, 302 state->mNumBuffersDecoded, 303 state->mNumBuffersDecoded * 1E6 / elapsedTimeUs, 304 state->mNumBytesDecoded, 305 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); 306 } 307 } 308 309 return 0; 310 } 311 312 int main(int argc, char **argv) { 313 using namespace android; 314 315 const char *me = argv[0]; 316 317 bool useAudio = false; 318 bool useVideo = false; 319 bool playback = false; 320 bool useSurface = false; 321 322 int res; 323 while ((res = getopt(argc, argv, "havpSD")) >= 0) { 324 switch (res) { 325 case 'a': 326 { 327 useAudio = true; 328 break; 329 } 330 331 case 'v': 332 { 333 useVideo = true; 334 break; 335 } 336 337 case 'p': 338 { 339 playback = true; 340 break; 341 } 342 343 case 'S': 344 { 345 useSurface = true; 346 break; 347 } 348 349 case '?': 350 case 'h': 351 default: 352 { 353 usage(me); 354 } 355 } 356 } 357 358 argc -= optind; 359 argv += optind; 360 361 if (argc != 1) { 362 usage(me); 363 } 364 365 if (!useAudio && !useVideo) { 366 useAudio = useVideo = true; 367 } 368 369 ProcessState::self()->startThreadPool(); 370 371 DataSource::RegisterDefaultSniffers(); 372 373 sp<ALooper> looper = new ALooper; 374 looper->start(); 375 376 sp<SurfaceComposerClient> composerClient; 377 sp<SurfaceControl> control; 378 sp<Surface> surface; 379 380 if (playback || (useSurface && useVideo)) { 381 composerClient = new SurfaceComposerClient; 382 CHECK_EQ(composerClient->initCheck(), (status_t)OK); 383 384 sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay( 385 ISurfaceComposer::eDisplayIdMain)); 386 DisplayInfo info; 387 SurfaceComposerClient::getDisplayInfo(display, &info); 388 ssize_t displayWidth = info.w; 389 ssize_t displayHeight = info.h; 390 391 ALOGV("display is %ld x %ld\n", displayWidth, displayHeight); 392 393 control = composerClient->createSurface( 394 String8("A Surface"), 395 displayWidth, 396 displayHeight, 397 PIXEL_FORMAT_RGB_565, 398 0); 399 400 CHECK(control != NULL); 401 CHECK(control->isValid()); 402 403 SurfaceComposerClient::openGlobalTransaction(); 404 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); 405 CHECK_EQ(control->show(), (status_t)OK); 406 SurfaceComposerClient::closeGlobalTransaction(); 407 408 surface = control->getSurface(); 409 CHECK(surface != NULL); 410 } 411 412 if (playback) { 413 sp<SimplePlayer> player = new SimplePlayer; 414 looper->registerHandler(player); 415 416 player->setDataSource(argv[0]); 417 player->setSurface(surface->getIGraphicBufferProducer()); 418 player->start(); 419 sleep(60); 420 player->stop(); 421 player->reset(); 422 } else { 423 decode(looper, argv[0], useAudio, useVideo, surface); 424 } 425 426 if (playback || (useSurface && useVideo)) { 427 composerClient->dispose(); 428 } 429 430 looper->stop(); 431 432 return 0; 433 } 434