Home | History | Annotate | Download | only in cmds
      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, &timestamp));
    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