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