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