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