1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //#define LOG_NDEBUG 0 6 #define LOG_TAG "codec2" 7 8 #include <C2VDAComponent.h> 9 10 #include <C2Buffer.h> 11 #include <C2BufferPriv.h> 12 #include <C2Component.h> 13 #include <C2PlatformSupport.h> 14 #include <C2Work.h> 15 #include <SimpleC2Interface.h> 16 17 #include <binder/IServiceManager.h> 18 #include <binder/ProcessState.h> 19 #include <gui/GLConsumer.h> 20 #include <gui/IProducerListener.h> 21 #include <gui/Surface.h> 22 #include <gui/SurfaceComposerClient.h> 23 #include <media/DataSource.h> 24 #include <media/ICrypto.h> 25 #include <media/IMediaHTTPService.h> 26 #include <media/MediaExtractor.h> 27 #include <media/MediaSource.h> 28 #include <media/stagefright/DataSourceFactory.h> 29 #include <media/stagefright/MediaDefs.h> 30 #include <media/stagefright/MediaErrors.h> 31 #include <media/stagefright/MediaExtractorFactory.h> 32 #include <media/stagefright/MetaData.h> 33 #include <media/stagefright/Utils.h> 34 #include <media/stagefright/foundation/ABuffer.h> 35 #include <media/stagefright/foundation/ALooper.h> 36 #include <media/stagefright/foundation/AMessage.h> 37 #include <media/stagefright/foundation/AUtils.h> 38 39 #include <fcntl.h> 40 #include <inttypes.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <sys/stat.h> 44 #include <sys/time.h> 45 #include <sys/types.h> 46 #include <thread> 47 48 using namespace android; 49 using namespace std::chrono_literals; 50 51 namespace { 52 53 const std::string kH264DecoderName = "c2.vda.avc.decoder"; 54 const std::string kVP8DecoderName = "c2.vda.vp8.decoder"; 55 const std::string kVP9DecoderName = "c2.vda.vp9.decoder"; 56 57 const int kWidth = 416; 58 const int kHeight = 240; // BigBuckBunny.mp4 59 //const int kWidth = 560; 60 //const int kHeight = 320; // small.mp4 61 const std::string kComponentName = kH264DecoderName; 62 63 class C2VDALinearBuffer : public C2Buffer { 64 public: 65 explicit C2VDALinearBuffer(const std::shared_ptr<C2LinearBlock>& block) 66 : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {} 67 }; 68 69 class Listener; 70 71 class SimplePlayer { 72 public: 73 SimplePlayer(); 74 ~SimplePlayer(); 75 76 void onWorkDone(std::weak_ptr<C2Component> component, 77 std::list<std::unique_ptr<C2Work>> workItems); 78 void onTripped(std::weak_ptr<C2Component> component, 79 std::vector<std::shared_ptr<C2SettingResult>> settingResult); 80 void onError(std::weak_ptr<C2Component> component, uint32_t errorCode); 81 82 status_t play(const sp<IMediaSource>& source); 83 84 private: 85 typedef std::unique_lock<std::mutex> ULock; 86 87 enum { 88 kInputBufferCount = 8, 89 kDefaultInputBufferSize = 1024 * 1024, 90 }; 91 92 std::shared_ptr<Listener> mListener; 93 94 sp<IProducerListener> mProducerListener; 95 96 // Allocators 97 std::shared_ptr<C2Allocator> mLinearAlloc; 98 std::shared_ptr<C2BlockPool> mLinearBlockPool; 99 100 std::mutex mQueueLock; 101 std::condition_variable mQueueCondition; 102 std::list<std::unique_ptr<C2Work>> mWorkQueue; 103 104 std::mutex mProcessedLock; 105 std::condition_variable mProcessedCondition; 106 std::list<std::unique_ptr<C2Work>> mProcessedWork; 107 108 sp<Surface> mSurface; 109 sp<SurfaceComposerClient> mComposerClient; 110 sp<SurfaceControl> mControl; 111 }; 112 113 class Listener : public C2Component::Listener { 114 public: 115 explicit Listener(SimplePlayer* thiz) : mThis(thiz) {} 116 virtual ~Listener() = default; 117 118 virtual void onWorkDone_nb(std::weak_ptr<C2Component> component, 119 std::list<std::unique_ptr<C2Work>> workItems) override { 120 mThis->onWorkDone(component, std::move(workItems)); 121 } 122 123 virtual void onTripped_nb( 124 std::weak_ptr<C2Component> component, 125 std::vector<std::shared_ptr<C2SettingResult>> settingResult) override { 126 mThis->onTripped(component, settingResult); 127 } 128 129 virtual void onError_nb(std::weak_ptr<C2Component> component, uint32_t errorCode) override { 130 mThis->onError(component, errorCode); 131 } 132 133 private: 134 SimplePlayer* const mThis; 135 }; 136 137 SimplePlayer::SimplePlayer() 138 : mListener(new Listener(this)), 139 mProducerListener(new DummyProducerListener), 140 mComposerClient(new SurfaceComposerClient) { 141 CHECK_EQ(mComposerClient->initCheck(), OK); 142 143 std::shared_ptr<C2AllocatorStore> store = GetCodec2PlatformAllocatorStore(); 144 CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAlloc), C2_OK); 145 146 mLinearBlockPool = std::make_shared<C2BasicLinearBlockPool>(mLinearAlloc); 147 148 mControl = mComposerClient->createSurface(String8("A Surface"), kWidth, kHeight, 149 HAL_PIXEL_FORMAT_YV12); 150 151 CHECK(mControl != nullptr); 152 CHECK(mControl->isValid()); 153 154 SurfaceComposerClient::Transaction{}.setLayer(mControl, INT_MAX).show(mControl).apply(); 155 156 mSurface = mControl->getSurface(); 157 CHECK(mSurface != nullptr); 158 mSurface->connect(NATIVE_WINDOW_API_CPU, mProducerListener); 159 } 160 161 SimplePlayer::~SimplePlayer() { 162 mComposerClient->dispose(); 163 } 164 165 void SimplePlayer::onWorkDone(std::weak_ptr<C2Component> component, 166 std::list<std::unique_ptr<C2Work>> workItems) { 167 (void)component; 168 ULock l(mProcessedLock); 169 for (auto& item : workItems) { 170 mProcessedWork.emplace_back(std::move(item)); 171 } 172 mProcessedCondition.notify_all(); 173 } 174 175 void SimplePlayer::onTripped(std::weak_ptr<C2Component> component, 176 std::vector<std::shared_ptr<C2SettingResult>> settingResult) { 177 (void)component; 178 (void)settingResult; 179 // TODO 180 } 181 182 void SimplePlayer::onError(std::weak_ptr<C2Component> component, uint32_t errorCode) { 183 (void)component; 184 (void)errorCode; 185 // TODO 186 } 187 188 status_t SimplePlayer::play(const sp<IMediaSource>& source) { 189 std::deque<sp<ABuffer>> csds; 190 if (kComponentName == kH264DecoderName) { 191 sp<AMessage> format; 192 (void)convertMetaDataToMessage(source->getFormat(), &format); 193 194 csds.resize(2); 195 format->findBuffer("csd-0", &csds[0]); 196 format->findBuffer("csd-1", &csds[1]); 197 } 198 199 status_t err = source->start(); 200 201 if (err != OK) { 202 ALOGE("source returned error %d (0x%08x)", err, err); 203 fprintf(stderr, "source returned error %d (0x%08x)\n", err, err); 204 return err; 205 } 206 207 std::shared_ptr<C2Component> component(std::make_shared<C2VDAComponent>( 208 kComponentName, 0, std::make_shared<C2ReflectorHelper>())); 209 210 component->setListener_vb(mListener, C2_DONT_BLOCK); 211 std::unique_ptr<C2PortBlockPoolsTuning::output> pools = 212 C2PortBlockPoolsTuning::output::AllocUnique( 213 {static_cast<uint64_t>(C2BlockPool::BASIC_GRAPHIC)}); 214 std::vector<std::unique_ptr<C2SettingResult>> result; 215 (void)component->intf()->config_vb({pools.get()}, C2_DONT_BLOCK, &result); 216 component->start(); 217 218 mProcessedWork.clear(); 219 for (int i = 0; i < kInputBufferCount; ++i) { 220 mWorkQueue.emplace_back(new C2Work); 221 } 222 223 std::atomic_bool running(true); 224 std::thread surfaceThread([this, &running]() { 225 const sp<IGraphicBufferProducer>& igbp = mSurface->getIGraphicBufferProducer(); 226 std::vector<std::shared_ptr<C2Buffer>> pendingDisplayBuffers; 227 pendingDisplayBuffers.resize(BufferQueue::NUM_BUFFER_SLOTS); 228 while (running) { 229 std::unique_ptr<C2Work> work; 230 { 231 ULock l(mProcessedLock); 232 if (mProcessedWork.empty()) { 233 mProcessedCondition.wait_for(l, 100ms); 234 if (mProcessedWork.empty()) { 235 continue; 236 } 237 } 238 work = std::move(mProcessedWork.front()); 239 mProcessedWork.pop_front(); 240 } 241 242 CHECK_EQ(work->worklets.size(), 1u); 243 if (work->worklets.front()->output.buffers.size() == 1u) { 244 int slot; 245 sp<Fence> fence; 246 std::shared_ptr<C2Buffer> output = work->worklets.front()->output.buffers[0]; 247 C2ConstGraphicBlock graphic_block = output->data().graphicBlocks().front(); 248 249 sp<GraphicBuffer> buffer(new GraphicBuffer( 250 graphic_block.handle(), GraphicBuffer::CLONE_HANDLE, graphic_block.width(), 251 graphic_block.height(), HAL_PIXEL_FORMAT_YCbCr_420_888, 1 /* layerCount */, 252 GRALLOC_USAGE_SW_READ_OFTEN, graphic_block.width())); 253 254 CHECK_EQ(igbp->attachBuffer(&slot, buffer), OK); 255 ALOGV("attachBuffer slot=%d ts=%lld", slot, 256 (work->worklets.front()->output.ordinal.timestamp * 1000ll).peekll()); 257 258 IGraphicBufferProducer::QueueBufferInput qbi( 259 (work->worklets.front()->output.ordinal.timestamp * 1000ll).peekll(), false, 260 HAL_DATASPACE_UNKNOWN, Rect(graphic_block.width(), graphic_block.height()), 261 NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, Fence::NO_FENCE, 0); 262 IGraphicBufferProducer::QueueBufferOutput qbo; 263 CHECK_EQ(igbp->queueBuffer(slot, qbi, &qbo), OK); 264 265 // If the slot is reused then we can make sure the previous graphic buffer is 266 // displayed (consumed), so we could returned the graphic buffer. 267 pendingDisplayBuffers[slot].swap(output); 268 } 269 270 bool eos = work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM; 271 // input buffer should be reset in component side. 272 CHECK_EQ(work->input.buffers.size(), 1u); 273 CHECK(work->input.buffers.front() == nullptr); 274 work->worklets.clear(); 275 work->workletsProcessed = 0; 276 277 if (eos) { 278 running.store(false); // stop the thread 279 } 280 281 ULock l(mQueueLock); 282 mWorkQueue.emplace_back(std::move(work)); 283 mQueueCondition.notify_all(); 284 } 285 }); 286 287 long numFrames = 0; 288 289 for (;;) { 290 size_t size = 0u; 291 void* data = nullptr; 292 int64_t timestamp = 0u; 293 MediaBufferBase* buffer = nullptr; 294 sp<ABuffer> csd; 295 if (!csds.empty()) { 296 csd = std::move(csds.front()); 297 csds.pop_front(); 298 size = csd->size(); 299 data = csd->data(); 300 } else { 301 status_t err = source->read(&buffer); 302 if (err != OK) { 303 CHECK(buffer == nullptr); 304 305 if (err == INFO_FORMAT_CHANGED) { 306 continue; 307 } 308 309 break; 310 } 311 MetaDataBase& meta = buffer->meta_data(); 312 CHECK(meta.findInt64(kKeyTime, ×tamp)); 313 314 size = buffer->size(); 315 data = buffer->data(); 316 } 317 318 // Prepare C2Work 319 320 std::unique_ptr<C2Work> work; 321 while (!work) { 322 ULock l(mQueueLock); 323 if (!mWorkQueue.empty()) { 324 work = std::move(mWorkQueue.front()); 325 mWorkQueue.pop_front(); 326 } else { 327 mQueueCondition.wait_for(l, 100ms); 328 } 329 } 330 work->input.flags = static_cast<C2FrameData::flags_t>(0); 331 work->input.ordinal.timestamp = timestamp; 332 work->input.ordinal.frameIndex = numFrames; 333 334 // Allocate input buffer. 335 std::shared_ptr<C2LinearBlock> block; 336 mLinearBlockPool->fetchLinearBlock( 337 size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block); 338 C2WriteView view = block->map().get(); 339 if (view.error() != C2_OK) { 340 fprintf(stderr, "C2LinearBlock::map() failed : %d\n", view.error()); 341 break; 342 } 343 memcpy(view.base(), data, size); 344 345 work->input.buffers.clear(); 346 work->input.buffers.emplace_back(new C2VDALinearBuffer(std::move(block))); 347 work->worklets.clear(); 348 work->worklets.emplace_back(new C2Worklet); 349 350 std::list<std::unique_ptr<C2Work>> items; 351 items.push_back(std::move(work)); 352 353 // DO THE DECODING 354 component->queue_nb(&items); 355 356 if (buffer) { 357 buffer->release(); 358 } 359 ++numFrames; 360 } 361 component->drain_nb(C2Component::DRAIN_COMPONENT_WITH_EOS); 362 363 surfaceThread.join(); 364 365 source->stop(); 366 component->stop(); 367 printf("finished...\n"); 368 return OK; 369 } 370 371 } // namespace 372 373 static bool getMediaSourceFromFile(const char* filename, sp<IMediaSource>* source) { 374 source->clear(); 375 376 sp<DataSource> dataSource = 377 DataSourceFactory::CreateFromURI(nullptr /* httpService */, filename); 378 379 if (dataSource == nullptr) { 380 fprintf(stderr, "Unable to create data source.\n"); 381 return false; 382 } 383 384 sp<IMediaExtractor> extractor = MediaExtractorFactory::Create(dataSource); 385 if (extractor == nullptr) { 386 fprintf(stderr, "could not create extractor.\n"); 387 return false; 388 } 389 390 std::string expectedMime; 391 if (kComponentName == kH264DecoderName) { 392 expectedMime = "video/avc"; 393 } else if (kComponentName == kVP8DecoderName) { 394 expectedMime = "video/x-vnd.on2.vp8"; 395 } else if (kComponentName == kVP9DecoderName) { 396 expectedMime = "video/x-vnd.on2.vp9"; 397 } else { 398 fprintf(stderr, "unrecognized component name: %s\n", kComponentName.c_str()); 399 return false; 400 } 401 402 for (size_t i = 0, numTracks = extractor->countTracks(); i < numTracks; ++i) { 403 sp<MetaData> meta = 404 extractor->getTrackMetaData(i, MediaExtractor::kIncludeExtensiveMetaData); 405 if (meta == nullptr) { 406 continue; 407 } 408 const char* mime; 409 meta->findCString(kKeyMIMEType, &mime); 410 if (!strcasecmp(mime, expectedMime.c_str())) { 411 *source = extractor->getTrack(i); 412 if (*source == nullptr) { 413 fprintf(stderr, "It's nullptr track for track %zu.\n", i); 414 return false; 415 } 416 return true; 417 } 418 } 419 fprintf(stderr, "No track found.\n"); 420 return false; 421 } 422 423 static void usage(const char* me) { 424 fprintf(stderr, "usage: %s [options] [input_filename]...\n", me); 425 fprintf(stderr, " -h(elp)\n"); 426 } 427 428 int main(int argc, char** argv) { 429 android::ProcessState::self()->startThreadPool(); 430 431 int res; 432 while ((res = getopt(argc, argv, "h")) >= 0) { 433 switch (res) { 434 case 'h': 435 default: { 436 usage(argv[0]); 437 exit(1); 438 break; 439 } 440 } 441 } 442 443 argc -= optind; 444 argv += optind; 445 446 if (argc < 1) { 447 fprintf(stderr, "No input file specified\n"); 448 return 1; 449 } 450 451 SimplePlayer player; 452 453 for (int k = 0; k < argc; ++k) { 454 sp<IMediaSource> mediaSource; 455 if (!getMediaSourceFromFile(argv[k], &mediaSource)) { 456 fprintf(stderr, "Unable to get media source from file: %s\n", argv[k]); 457 return -1; 458 } 459 if (player.play(mediaSource) != OK) { 460 fprintf(stderr, "Player failed to play media source: %s\n", argv[k]); 461 return -1; 462 } 463 } 464 465 return 0; 466 } 467