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 <datasource/DataSourceFactory.h>
34 #include <media/DataSource.h>
35 #include <mediadrm/ICrypto.h>
36 #include <media/IMediaHTTPService.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/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, ×tamp));
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::getInstance()->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