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