• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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