• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
C2VDALinearBuffer(const std::shared_ptr<C2LinearBlock> & block)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:
Listener(SimplePlayer * thiz)115     explicit Listener(SimplePlayer* thiz) : mThis(thiz) {}
116     virtual ~Listener() = default;
117 
onWorkDone_nb(std::weak_ptr<C2Component> component,std::list<std::unique_ptr<C2Work>> workItems)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 
onTripped_nb(std::weak_ptr<C2Component> component,std::vector<std::shared_ptr<C2SettingResult>> settingResult)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 
onError_nb(std::weak_ptr<C2Component> component,uint32_t errorCode)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 
SimplePlayer()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 
~SimplePlayer()161 SimplePlayer::~SimplePlayer() {
162     mComposerClient->dispose();
163 }
164 
onWorkDone(std::weak_ptr<C2Component> component,std::list<std::unique_ptr<C2Work>> workItems)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 
onTripped(std::weak_ptr<C2Component> component,std::vector<std::shared_ptr<C2SettingResult>> settingResult)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 
onError(std::weak_ptr<C2Component> component,uint32_t errorCode)182 void SimplePlayer::onError(std::weak_ptr<C2Component> component, uint32_t errorCode) {
183     (void)component;
184     (void)errorCode;
185     // TODO
186 }
187 
play(const sp<IMediaSource> & source)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 
getMediaSourceFromFile(const char * filename,sp<IMediaSource> * source)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 
usage(const char * me)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 
main(int argc,char ** argv)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