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, ×tamp));
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