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