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