1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // #define LOG_NDEBUG 0
6 #define LOG_TAG "MediaCodecDecoder"
7
8 #include "mediacodec_decoder.h"
9
10 #include <assert.h>
11 #include <inttypes.h>
12
13 #include <utility>
14 #include <vector>
15
16 #include <log/log.h>
17 #include <media/NdkMediaFormat.h>
18
19 namespace android {
20 namespace {
21 constexpr int64_t kSecToNs = 1000000000;
22 // The timeout of AMediaCodec_dequeueOutputBuffer function calls.
23 constexpr int kTimeoutWaitForOutputUs = 1000; // 1 millisecond
24
25 // The timeout of AMediaCodec_dequeueInputBuffer function calls.
26 constexpr int kTimeoutWaitForInputUs = 1000; // 1 millisecond
27
28 // The maximal retry times of doDecode routine.
29 // The maximal tolerable interval between two dequeued outputs will be:
30 // kTimeoutWaitForOutputUs * kTimeoutMaxRetries = 500 milliseconds
31 constexpr size_t kTimeoutMaxRetries = 500;
32
33 // Helper function to get possible C2 hardware decoder names from |type|.
34 // Note: A single test APK is built for both ARC++ and ARCVM, so both the VDA decoder and the new
35 // V4L2 decoder names need to be specified here (except for HEVC, which is only on ARCVM).
GetC2VideoDecoderNames(VideoCodecType type)36 std::vector<const char*> GetC2VideoDecoderNames(VideoCodecType type) {
37 switch (type) {
38 case VideoCodecType::H264:
39 return {"c2.v4l2.avc.decoder", "c2.vda.avc.decoder"};
40 case VideoCodecType::VP8:
41 return {"c2.v4l2.vp8.decoder", "c2.vda.vp8.decoder"};
42 case VideoCodecType::VP9:
43 return {"c2.v4l2.vp9.decoder", "c2.vda.vp9.decoder"};
44 case VideoCodecType::HEVC:
45 return {"c2.v4l2.hevc.decoder"};
46 default: // unknown type
47 return {};
48 }
49 }
50
51 // Helper function to get possible software decoder names from |type|.
52 // Note: A single test APK is built for both ARC++ and ARCVM, so both the OMX decoder used on
53 // Android P and the c2.android decoder used on Android R need to be specified here.
GetSwVideoDecoderNames(VideoCodecType type)54 std::vector<const char*> GetSwVideoDecoderNames(VideoCodecType type) {
55 switch (type) {
56 case VideoCodecType::H264:
57 return {"c2.android.avc.decoder", "OMX.google.h264.decoder"};
58 case VideoCodecType::VP8:
59 return {"c2.android.vp8.decoder", "OMX.google.vp8.decoder"};
60 case VideoCodecType::VP9:
61 return {"c2.android.vp9.decoder", "OMX.google.vp9.decoder"};
62 default: // unknown type
63 return {};
64 }
65 }
66
67 const uint32_t BUFFER_FLAG_CODEC_CONFIG = AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG;
68 const char* FORMAT_KEY_SLICE_HEIGHT = AMEDIAFORMAT_KEY_SLICE_HEIGHT;
69
GetCurrentTimeNs()70 int64_t GetCurrentTimeNs() {
71 timespec now;
72 clock_gettime(CLOCK_MONOTONIC, &now);
73 return now.tv_sec * UINT64_C(1000000000) + now.tv_nsec;
74 }
75
RoundUp(int64_t n,int64_t multiple)76 int64_t RoundUp(int64_t n, int64_t multiple) {
77 return ((n + (multiple - 1)) / multiple) * multiple;
78 }
79
80 } // namespace
81
82 // static
Create(const std::string & input_path,VideoCodecProfile profile,bool use_sw_decoder,const Size & video_size,int frame_rate,ANativeWindow * surface,bool render_on_release,bool loop,bool use_fake_renderer)83 std::unique_ptr<MediaCodecDecoder> MediaCodecDecoder::Create(
84 const std::string& input_path, VideoCodecProfile profile, bool use_sw_decoder,
85 const Size& video_size, int frame_rate, ANativeWindow* surface, bool render_on_release,
86 bool loop, bool use_fake_renderer) {
87 if (video_size.IsEmpty()) {
88 ALOGE("Size is not valid: %dx%d", video_size.width, video_size.height);
89 return nullptr;
90 }
91
92 VideoCodecType type = VideoCodecProfileToType(profile);
93
94 std::unique_ptr<EncodedDataHelper> encoded_data_helper(new EncodedDataHelper(input_path, type));
95 if (!encoded_data_helper->IsValid()) {
96 ALOGE("EncodedDataHelper is not created for file: %s", input_path.c_str());
97 return nullptr;
98 }
99
100 AMediaCodec* codec = nullptr;
101 auto decoder_names =
102 use_sw_decoder ? GetSwVideoDecoderNames(type) : GetC2VideoDecoderNames(type);
103 for (const auto& decoder_name : decoder_names) {
104 codec = AMediaCodec_createCodecByName(decoder_name);
105 if (codec) {
106 ALOGD("Created mediacodec decoder by name: %s", decoder_name);
107 break;
108 }
109 }
110 if (!codec) {
111 ALOGE("Failed to create mediacodec decoder.");
112 return nullptr;
113 }
114
115 auto ret = std::unique_ptr<MediaCodecDecoder>(
116 new MediaCodecDecoder(codec, std::move(encoded_data_helper), type, video_size,
117 frame_rate, surface, render_on_release, loop, use_fake_renderer));
118
119 AMediaCodecOnAsyncNotifyCallback cb{
120 .onAsyncInputAvailable =
121 [](AMediaCodec* codec, void* userdata, int32_t index) {
122 reinterpret_cast<MediaCodecDecoder*>(userdata)->OnAsyncInputAvailable(
123 index);
124 },
125 .onAsyncOutputAvailable =
126 [](AMediaCodec* codec, void* userdata, int32_t index,
127 AMediaCodecBufferInfo* buffer_info) {
128 reinterpret_cast<MediaCodecDecoder*>(userdata)->OnAsyncOutputAvailable(
129 index, buffer_info);
130 },
131 .onAsyncFormatChanged =
132 [](AMediaCodec* codec, void* userdata, AMediaFormat* format) {
133 reinterpret_cast<MediaCodecDecoder*>(userdata)->OnAsyncFormatChanged(
134 format);
135 },
136 .onAsyncError =
137 [](AMediaCodec* codec, void* userdata, media_status_t error, int32_t code,
138 const char* detail) {
139 ALOGE("Error %d (%d) %s", error, code, detail);
140 assert(false);
141 }};
142
143 auto status = AMediaCodec_setAsyncNotifyCallback(codec, cb, ret.get());
144 if (status != AMEDIA_OK) {
145 ALOGE("Failed to set async callback.");
146 return nullptr;
147 }
148
149 return ret;
150 }
151
MediaCodecDecoder(AMediaCodec * codec,std::unique_ptr<EncodedDataHelper> encoded_data_helper,VideoCodecType type,const Size & size,int frame_rate,ANativeWindow * surface,bool render_on_release,bool loop,bool use_fake_renderer)152 MediaCodecDecoder::MediaCodecDecoder(AMediaCodec* codec,
153 std::unique_ptr<EncodedDataHelper> encoded_data_helper,
154 VideoCodecType type, const Size& size, int frame_rate,
155 ANativeWindow* surface, bool render_on_release, bool loop,
156 bool use_fake_renderer)
157 : codec_(codec),
158 encoded_data_helper_(std::move(encoded_data_helper)),
159 type_(type),
160 input_visible_size_(size),
161 frame_rate_(frame_rate),
162 surface_(surface),
163 render_on_release_(render_on_release),
164 looping_(loop),
165 fake_renderer_running_(use_fake_renderer),
166 fake_render_thread_([](MediaCodecDecoder* dec) { dec->FakeRenderLoop(); }, this) {}
167
~MediaCodecDecoder()168 MediaCodecDecoder::~MediaCodecDecoder() {
169 if (codec_ != nullptr) {
170 AMediaCodec_delete(codec_);
171 }
172 fake_renderer_running_ = false;
173 fake_render_cv_.notify_one();
174 fake_render_thread_.join();
175 }
176
AddOutputBufferReadyCb(const OutputBufferReadyCb & cb)177 void MediaCodecDecoder::AddOutputBufferReadyCb(const OutputBufferReadyCb& cb) {
178 output_buffer_ready_cbs_.push_back(cb);
179 }
180
AddOutputFormatChangedCb(const OutputFormatChangedCb & cb)181 void MediaCodecDecoder::AddOutputFormatChangedCb(const OutputFormatChangedCb& cb) {
182 output_format_changed_cbs_.push_back(cb);
183 }
184
OnAsyncInputAvailable(int32_t idx)185 void MediaCodecDecoder::OnAsyncInputAvailable(int32_t idx) {
186 std::lock_guard<std::mutex> lock(event_queue_mut_);
187 event_queue_.push({.type = INPUT_AVAILABLE, .idx = idx});
188 event_queue_cv_.notify_one();
189 }
190
OnAsyncOutputAvailable(int32_t idx,AMediaCodecBufferInfo * info)191 void MediaCodecDecoder::OnAsyncOutputAvailable(int32_t idx, AMediaCodecBufferInfo* info) {
192 std::lock_guard<std::mutex> lock(event_queue_mut_);
193 event_queue_.push({.type = OUTPUT_AVAILABLE, .idx = idx, .info = *info});
194 event_queue_cv_.notify_one();
195 }
196
OnAsyncFormatChanged(AMediaFormat * format)197 void MediaCodecDecoder::OnAsyncFormatChanged(AMediaFormat* format) {
198 std::lock_guard<std::mutex> lock(event_queue_mut_);
199 event_queue_.push({.type = FORMAT_CHANGED});
200 event_queue_cv_.notify_one();
201 }
202
Rewind()203 void MediaCodecDecoder::Rewind() {
204 encoded_data_helper_->Rewind();
205 input_fragment_index_ = 0;
206 }
207
Configure()208 bool MediaCodecDecoder::Configure() {
209 ALOGD("configure: mime=%s, width=%d, height=%d", GetMimeType(type_), input_visible_size_.width,
210 input_visible_size_.height);
211 AMediaFormat* format = AMediaFormat_new();
212 AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, GetMimeType(type_));
213 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, input_visible_size_.width);
214 AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, input_visible_size_.height);
215 media_status_t ret =
216 AMediaCodec_configure(codec_, format, surface_, nullptr /* crtpto */, 0 /* flag */);
217 AMediaFormat_delete(format);
218 if (ret != AMEDIA_OK) {
219 ALOGE("Configure return error: %d", ret);
220 return false;
221 }
222 return true;
223 }
224
Start()225 bool MediaCodecDecoder::Start() {
226 media_status_t ret = AMediaCodec_start(codec_);
227 if (ret != AMEDIA_OK) {
228 ALOGE("Start return error: %d", ret);
229 return false;
230 }
231 return true;
232 }
233
Decode()234 bool MediaCodecDecoder::Decode() {
235 while (!output_done_) {
236 CodecEvent evt;
237 {
238 std::unique_lock<std::mutex> lock(event_queue_mut_);
239 while (event_queue_.empty()) {
240 event_queue_cv_.wait(lock);
241 }
242 evt = event_queue_.front();
243 event_queue_.pop();
244 }
245
246 bool success;
247 switch (evt.type) {
248 case INPUT_AVAILABLE:
249 success = EnqueueInputBuffers(evt.idx);
250 break;
251 case OUTPUT_AVAILABLE:
252 success = DequeueOutputBuffer(evt.idx, evt.info);
253 break;
254 case FORMAT_CHANGED:
255 success = GetOutputFormat();
256 break;
257 case FAKE_FRAME_RENDERED:
258 media_status_t status = AMediaCodec_releaseOutputBuffer(codec_, evt.idx, false);
259 if (status != AMEDIA_OK) {
260 ALOGE("Failed to releaseOutputBuffer(index=%zu): %d", evt.idx, status);
261 success = false;
262 }
263 break;
264 }
265 assert(success);
266 }
267 return true;
268 }
269
EnqueueInputBuffers(int32_t index)270 bool MediaCodecDecoder::EnqueueInputBuffers(int32_t index) {
271 if (index < 0) {
272 ALOGE("Unknown error while dequeueInputBuffer: %zd", index);
273 return false;
274 }
275
276 if (looping_ && encoded_data_helper_->ReachEndOfStream()) {
277 encoded_data_helper_->Rewind();
278 }
279
280 if (encoded_data_helper_->ReachEndOfStream()) {
281 if (!FeedEOSInputBuffer(index)) return false;
282 input_done_ = true;
283 } else {
284 if (!FeedInputBuffer(index)) return false;
285 }
286 return true;
287 }
288
DequeueOutputBuffer(int32_t index,AMediaCodecBufferInfo info)289 bool MediaCodecDecoder::DequeueOutputBuffer(int32_t index, AMediaCodecBufferInfo info) {
290 if (index < 0) {
291 ALOGE("Unknown error while dequeueOutputBuffer: %zd", index);
292 return false;
293 }
294
295 if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) output_done_ = true;
296
297 const uint64_t now = GetCurrentTimeNs();
298 bool render_frame = render_on_release_;
299 if (base_timestamp_ns_ == 0) {
300 assert(received_outputs_ == 0);
301 // The first output buffer is dequeued. Set the base timestamp.
302 base_timestamp_ns_ = now;
303 } else if (now > GetReleaseTimestampNs(received_outputs_)) {
304 drop_frame_count_++;
305 ALOGD("Drop frame #%d: frame %d deadline %" PRIu64 "us, actual %" PRIu64 "us",
306 drop_frame_count_, received_outputs_, (received_outputs_ * 1000000ull / frame_rate_),
307 (now - base_timestamp_ns_) / 1000);
308 render_frame = false; // We don't render the dropped frame.
309 }
310
311 if (!ReceiveOutputBuffer(index, info, render_frame)) return false;
312
313 return true;
314 }
315
Stop()316 bool MediaCodecDecoder::Stop() {
317 return AMediaCodec_stop(codec_) == AMEDIA_OK;
318 }
319
FeedInputBuffer(size_t index)320 bool MediaCodecDecoder::FeedInputBuffer(size_t index) {
321 assert(!encoded_data_helper_->ReachEndOfStream());
322
323 size_t buf_size = 0;
324 uint8_t* buf = AMediaCodec_getInputBuffer(codec_, index, &buf_size);
325 if (!buf) {
326 ALOGE("Failed to getInputBuffer: index=%zu", index);
327 return false;
328 }
329
330 auto fragment = encoded_data_helper_->GetNextFragment();
331 assert(fragment);
332
333 if (buf_size < fragment->data.size()) {
334 ALOGE("Input buffer size is not enough: buf_size=%zu, data_size=%zu", buf_size,
335 fragment->data.size());
336 return false;
337 }
338
339 memcpy(reinterpret_cast<char*>(buf), fragment->data.data(), fragment->data.size());
340
341 uint32_t input_flag = 0;
342 if (fragment->csd_flag) input_flag |= BUFFER_FLAG_CODEC_CONFIG;
343
344 // We don't parse the display order of each bitstream buffer. Let's trust the order of received
345 // output buffers from |codec_|.
346 uint64_t timestamp_us = 0;
347
348 ALOGV("queueInputBuffer(index=%zu, offset=0, size=%zu, time=%" PRIu64 ", flags=%u) #%d", index,
349 fragment->data.size(), timestamp_us, input_flag, input_fragment_index_);
350 media_status_t status = AMediaCodec_queueInputBuffer(
351 codec_, index, 0 /* offset */, fragment->data.size(), timestamp_us, input_flag);
352 if (status != AMEDIA_OK) {
353 ALOGE("Failed to queueInputBuffer: %d", status);
354 return false;
355 }
356 ++input_fragment_index_;
357 return true;
358 }
359
FeedEOSInputBuffer(size_t index)360 bool MediaCodecDecoder::FeedEOSInputBuffer(size_t index) {
361 // Timestamp of EOS input buffer is undefined, use 0 here to test decoder
362 // robustness.
363 uint64_t timestamp_us = 0;
364
365 ALOGV("queueInputBuffer(index=%zu) EOS", index);
366 media_status_t status =
367 AMediaCodec_queueInputBuffer(codec_, index, 0 /* offset */, 0 /* size */, timestamp_us,
368 AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
369 if (status != AMEDIA_OK) {
370 ALOGE("Failed to queueInputBuffer EOS: %d", status);
371 return false;
372 }
373 return true;
374 }
375
ReceiveOutputBuffer(int32_t index,const AMediaCodecBufferInfo & info,bool render_buffer)376 bool MediaCodecDecoder::ReceiveOutputBuffer(int32_t index, const AMediaCodecBufferInfo& info,
377 bool render_buffer) {
378 size_t out_size = 0;
379 uint8_t* buf = nullptr;
380 if (!surface_) {
381 buf = AMediaCodec_getOutputBuffer(codec_, index, &out_size);
382 if (!buf) {
383 ALOGE("Failed to getOutputBuffer(index=%zu)", index);
384 return false;
385 }
386 }
387
388 received_outputs_++;
389 ALOGV("ReceiveOutputBuffer(index=%zu, size=%d, flags=%u) #%d", index, info.size, info.flags,
390 received_outputs_);
391
392 // Do not callback for dummy EOS output (info.size == 0)
393 if (info.size > 0) {
394 for (const auto& callback : output_buffer_ready_cbs_)
395 callback(buf, info.size, received_outputs_);
396 }
397
398 if (fake_renderer_running_) {
399 std::lock_guard<std::mutex> lock(fake_render_mut_);
400 fake_render_frames_.emplace(index, GetReleaseTimestampNs(received_outputs_));
401 fake_render_cv_.notify_one();
402 } else {
403 media_status_t status =
404 render_buffer ? AMediaCodec_releaseOutputBufferAtTime(
405 codec_, index, GetReleaseTimestampNs(received_outputs_))
406 : AMediaCodec_releaseOutputBuffer(codec_, index, false /* render */);
407 if (status != AMEDIA_OK) {
408 ALOGE("Failed to releaseOutputBuffer(index=%zu): %d", index, status);
409 return false;
410 }
411 }
412 return true;
413 }
414
FakeRenderLoop()415 void MediaCodecDecoder::FakeRenderLoop() {
416 while (fake_renderer_running_) {
417 std::pair<int32_t, int64_t> next_frame;
418 {
419 std::unique_lock<std::mutex> lock(fake_render_mut_);
420 fake_render_cv_.wait(lock, [&]() {
421 return !fake_renderer_running_ || !fake_render_frames_.empty();
422 });
423 if (!fake_renderer_running_) {
424 break;
425 }
426
427 next_frame = fake_render_frames_.front();
428 fake_render_frames_.pop();
429 }
430
431 const uint64_t now = GetCurrentTimeNs();
432 if (now < next_frame.second) {
433 usleep((next_frame.second - now) / 1000);
434 }
435
436 std::lock_guard<std::mutex> lock(event_queue_mut_);
437 event_queue_.push({.type = FAKE_FRAME_RENDERED, .idx = next_frame.first});
438 event_queue_cv_.notify_one();
439 }
440 }
441
GetOutputFormat()442 bool MediaCodecDecoder::GetOutputFormat() {
443 AMediaFormat* format = AMediaCodec_getOutputFormat(codec_);
444 bool success = true;
445
446 // Required formats
447 int32_t width = 0;
448 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width)) {
449 ALOGE("Cannot find width in format.");
450 success = false;
451 }
452
453 int32_t height = 0;
454 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
455 ALOGE("Cannot find height in format.");
456 success = false;
457 }
458
459 int32_t color_format = 0;
460 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &color_format)) {
461 ALOGE("Cannot find color-format in format.");
462 success = false;
463 }
464
465 // Optional formats
466 int32_t crop_left = 0;
467 int32_t crop_top = 0;
468 int32_t crop_right = width - 1;
469 int32_t crop_bottom = height - 1;
470 // Crop info is only avaiable on NDK version >= Pie.
471 if (!AMediaFormat_getRect(format, AMEDIAFORMAT_KEY_DISPLAY_CROP, &crop_left, &crop_top,
472 &crop_right, &crop_bottom)) {
473 ALOGD("Cannot find crop window in format. Set as large as frame size.");
474 crop_left = 0;
475 crop_top = 0;
476 crop_right = width - 1;
477 crop_bottom = height - 1;
478 }
479
480 // In current exiting ARC video decoder crop origin is always at (0,0)
481 if (crop_left != 0 || crop_top != 0) {
482 ALOGE("Crop origin is not (0,0): (%d,%d)", crop_left, crop_top);
483 success = false;
484 }
485
486 int32_t stride = 0;
487 if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &stride)) {
488 ALOGD("Cannot find stride in format. Set as frame width.");
489 stride = width;
490 }
491
492 int32_t slice_height = 0;
493 if (!AMediaFormat_getInt32(format, FORMAT_KEY_SLICE_HEIGHT, &slice_height)) {
494 ALOGD("Cannot find slice-height in format. Set as frame height.");
495 slice_height = height;
496 }
497
498 for (const auto& callback : output_format_changed_cbs_) {
499 callback(Size(stride, slice_height),
500 Size(crop_right - crop_left + 1, crop_bottom - crop_top + 1), color_format);
501 }
502 return success;
503 }
504
GetReleaseTimestampNs(size_t frame_order)505 int64_t MediaCodecDecoder::GetReleaseTimestampNs(size_t frame_order) {
506 assert(base_timestamp_ns_ != 0);
507
508 return base_timestamp_ns_ + frame_order * kSecToNs / frame_rate_;
509 }
510
dropped_frame_rate() const511 double MediaCodecDecoder::dropped_frame_rate() const {
512 assert(received_outputs_ > 0);
513
514 return (double)drop_frame_count_ / (double)received_outputs_;
515 }
516
517 } // namespace android
518