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