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