blob: 96fc748bb92979623c352e6665c12798e12ce08e [file] [log] [blame]
glaznev@webrtc.org18c92472015-02-18 18:42:55 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2015 The WebRTC project authors. All Rights Reserved.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +00009 */
10
magjed6d387c02015-10-14 04:02:01 -070011#include <algorithm>
sakal9c997a32017-02-17 03:26:10 -080012#include <deque>
kwibergd1fe2812016-04-27 06:47:29 -070013#include <memory>
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000014#include <vector>
15
kjellandera96e2d72016-02-04 23:52:28 -080016// NOTICE: androidmediadecoder_jni.h must be included before
17// androidmediacodeccommon.h to avoid build errors.
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "sdk/android/src/jni/androidmediadecoder_jni.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010019
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "common_video/h264/h264_bitstream_parser.h"
21#include "common_video/include/i420_buffer_pool.h"
22#include "modules/video_coding/include/video_codec_interface.h"
23#include "modules/video_coding/utility/vp8_header_parser.h"
24#include "rtc_base/bind.h"
25#include "rtc_base/checks.h"
26#include "rtc_base/logging.h"
Mirko Bonadeiab55c342018-06-01 14:54:29 +020027#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/scoped_ref_ptr.h"
29#include "rtc_base/thread.h"
30#include "rtc_base/timeutils.h"
Magnus Jedvert655e1962017-12-08 11:05:22 +010031#include "sdk/android/generated_video_jni/jni/MediaCodecVideoDecoder_jni.h"
Sami Kalliomäki82f96e62018-01-29 13:18:57 +010032#include "sdk/android/native_api/jni/java_types.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "sdk/android/src/jni/androidmediacodeccommon.h"
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +010034#include "sdk/android/src/jni/videoframe.h"
35#include "third_party/libyuv/include/libyuv/convert.h"
36#include "third_party/libyuv/include/libyuv/convert_from.h"
37#include "third_party/libyuv/include/libyuv/video_common.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000038
39using rtc::Bind;
40using rtc::Thread;
41using rtc::ThreadManager;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000042
magjeda3d4f682017-08-28 16:24:06 -070043namespace webrtc {
44namespace jni {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000045
guidouc3372582017-04-04 07:16:21 -070046// Logging macros.
47#define TAG_DECODER "MediaCodecVideoDecoder"
48#ifdef TRACK_BUFFER_TIMING
tommie7251592017-07-14 14:44:46 -070049#define ALOGV(...) \
guidouc3372582017-04-04 07:16:21 -070050 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
51#else
52#define ALOGV(...)
53#endif
Mirko Bonadei675513b2017-11-09 11:09:25 +010054#define ALOGD RTC_LOG_TAG(rtc::LS_INFO, TAG_DECODER)
55#define ALOGW RTC_LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
56#define ALOGE RTC_LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
guidouc3372582017-04-04 07:16:21 -070057
58enum { kMaxWarningLogFrames = 2 };
59
magjeda3d4f682017-08-28 16:24:06 -070060class MediaCodecVideoDecoder : public VideoDecoder, public rtc::MessageHandler {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000061 public:
Yves Gerey665174f2018-06-19 15:03:05 +020062 explicit MediaCodecVideoDecoder(JNIEnv* jni,
63 VideoCodecType codecType,
64 jobject render_egl_context);
Paulina Hensmana680a6a2018-04-05 11:42:24 +020065 ~MediaCodecVideoDecoder() override;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000066
Yves Gerey665174f2018-06-19 15:03:05 +020067 int32_t InitDecode(const VideoCodec* codecSettings,
68 int32_t numberOfCores) override;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000069
Yves Gerey665174f2018-06-19 15:03:05 +020070 int32_t Decode(const EncodedImage& inputImage,
71 bool missingFrames,
72 const CodecSpecificInfo* codecSpecificInfo = NULL,
73 int64_t renderTimeMs = -1) override;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000074
Yves Gerey665174f2018-06-19 15:03:05 +020075 int32_t RegisterDecodeCompleteCallback(
76 DecodedImageCallback* callback) override;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000077
78 int32_t Release() override;
79
perkj796cfaf2015-12-10 09:27:38 -080080 bool PrefersLateDecoding() const override { return true; }
81
guidouc3372582017-04-04 07:16:21 -070082 // rtc::MessageHandler implementation.
83 void OnMessage(rtc::Message* msg) override;
84
Peter Boströmb7d9a972015-12-18 16:01:11 +010085 const char* ImplementationName() const override;
86
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000087 private:
guidouc3372582017-04-04 07:16:21 -070088 // CHECK-fail if not running on |codec_thread_|.
89 void CheckOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000090
91 int32_t InitDecodeOnCodecThread();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -080092 int32_t ResetDecodeOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000093 int32_t ReleaseOnCodecThread();
guidouc3372582017-04-04 07:16:21 -070094 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000095 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
96 // true on success.
guidouc3372582017-04-04 07:16:21 -070097 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -070098 int32_t ProcessHWErrorOnCodecThread();
glaznevae95ff32016-02-04 11:47:12 -080099 void EnableFrameLogOnWarning();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800100 void ResetVariables();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000101
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000102 // Type of video codec.
103 VideoCodecType codecType_;
104
kjellander60ca31b2016-01-04 10:15:53 -0800105 // Render EGL context - owned by factory, should not be allocated/destroyed
106 // by VideoDecoder.
107 jobject render_egl_context_;
108
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000109 bool key_frame_required_;
110 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700111 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000112 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000113 VideoCodec codec_;
magjeda3d4f682017-08-28 16:24:06 -0700114 I420BufferPool decoded_frame_pool_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000115 DecodedImageCallback* callback_;
116 int frames_received_; // Number of frames received by decoder.
Yves Gerey665174f2018-06-19 15:03:05 +0200117 int frames_decoded_; // Number of frames decoded by decoder.
glaznevae95ff32016-02-04 11:47:12 -0800118 // Number of decoded frames for which log information is displayed.
119 int frames_decoded_logged_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000120 int64_t start_time_ms_; // Start time for statistics.
121 int current_frames_; // Number of frames in the current statistics interval.
Yves Gerey665174f2018-06-19 15:03:05 +0200122 int current_bytes_; // Encoded bytes in the current statistics interval.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000123 int current_decoding_time_ms_; // Overall decoding time in the current second
Yves Gerey665174f2018-06-19 15:03:05 +0200124 int current_delay_time_ms_; // Overall delay time in the current second.
125 int32_t max_pending_frames_; // Maximum number of pending input frames.
magjeda3d4f682017-08-28 16:24:06 -0700126 H264BitstreamParser h264_bitstream_parser_;
Danil Chapovalov196100e2018-06-21 10:17:24 +0200127 std::deque<absl::optional<uint8_t>> pending_frame_qps_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000128
129 // State that is constant for the lifetime of this object once the ctor
130 // returns.
kwibergd1fe2812016-04-27 06:47:29 -0700131 std::unique_ptr<Thread>
132 codec_thread_; // Thread on which to operate MediaCodec.
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100133 ScopedJavaGlobalRef<jobject> j_media_codec_video_decoder_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000134
135 // Global references; must be deleted in Release().
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100136 std::vector<ScopedJavaGlobalRef<jobject>> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000137};
138
tommie7251592017-07-14 14:44:46 -0700139MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni,
140 VideoCodecType codecType,
141 jobject render_egl_context)
142 : codecType_(codecType),
143 render_egl_context_(render_egl_context),
144 key_frame_required_(true),
145 inited_(false),
146 sw_fallback_required_(false),
147 codec_thread_(Thread::Create()),
tommie7251592017-07-14 14:44:46 -0700148 j_media_codec_video_decoder_(
149 jni,
Magnus Jedvert655e1962017-12-08 11:05:22 +0100150 Java_MediaCodecVideoDecoder_Constructor(jni)) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000151 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
guidouc3372582017-04-04 07:16:21 -0700152 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000153
Magnus Jedvert207370f2015-09-16 12:32:21 +0200154 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700155 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000156 memset(&codec_, 0, sizeof(codec_));
157 AllowBlockingCalls();
158}
159
160MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
161 // Call Release() to ensure no more callbacks to us after we are deleted.
162 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000163}
164
165int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
Yves Gerey665174f2018-06-19 15:03:05 +0200166 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700167 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000168 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700169 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000170 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
171 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000172 // Factory should guard against other codecs being used with us.
guidouc3372582017-04-04 07:16:21 -0700173 RTC_CHECK(inst->codecType == codecType_)
henrikg91d6ede2015-09-17 00:24:34 -0700174 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000175
Alex Glaznev782671f2015-06-12 16:40:44 -0700176 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700177 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700178 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000179 }
180 // Save VideoCodec instance for later.
181 if (&codec_ != inst) {
182 codec_ = *inst;
183 }
glazneve55c42c2015-10-28 10:30:32 -0700184 // If maxFramerate is not set then assume 30 fps.
185 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000186
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000187 // Call Java init.
188 return codec_thread_->Invoke<int32_t>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700189 RTC_FROM_HERE,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000190 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
191}
192
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800193void MediaCodecVideoDecoder::ResetVariables() {
guidouc3372582017-04-04 07:16:21 -0700194 CheckOnCodecThread();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800195
196 key_frame_required_ = true;
197 frames_received_ = 0;
198 frames_decoded_ = 0;
199 frames_decoded_logged_ = kMaxDecodedLogFrames;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200200 start_time_ms_ = rtc::TimeMillis();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800201 current_frames_ = 0;
202 current_bytes_ = 0;
203 current_decoding_time_ms_ = 0;
204 current_delay_time_ms_ = 0;
sakal9c997a32017-02-17 03:26:10 -0800205 pending_frame_qps_.clear();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800206}
207
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000208int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
guidouc3372582017-04-04 07:16:21 -0700209 CheckOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000210 JNIEnv* jni = AttachCurrentThreadIfNeeded();
211 ScopedLocalRefFrame local_ref_frame(jni);
Magnus Jedvert9060eb12017-12-12 12:52:54 +0100212 ALOGD << "InitDecodeOnCodecThread Type: " << static_cast<int>(codecType_)
213 << ". " << codec_.width << " x " << codec_.height
214 << ". Fps: " << static_cast<int>(codec_.maxFramerate);
Alex Glaznev782671f2015-06-12 16:40:44 -0700215
216 // Release previous codec first if it was allocated before.
217 int ret_val = ReleaseOnCodecThread();
218 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700219 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700220 sw_fallback_required_ = true;
221 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000222 }
223
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800224 ResetVariables();
Alex Glaznev782671f2015-06-12 16:40:44 -0700225
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100226 ScopedJavaLocalRef<jobject> j_video_codec_enum =
Magnus Jedvert655e1962017-12-08 11:05:22 +0100227 Java_VideoCodecType_fromNativeIndex(jni, codecType_);
Magnus Jedvertb9ac1212018-04-23 11:29:05 +0200228 jobject j_egl_context = use_surface_ ? render_egl_context_ : nullptr;
Magnus Jedvert655e1962017-12-08 11:05:22 +0100229 bool success = Java_MediaCodecVideoDecoder_initDecode(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100230 jni, j_media_codec_video_decoder_, j_video_codec_enum, codec_.width,
Magnus Jedvertb9ac1212018-04-23 11:29:05 +0200231 codec_.height, JavaParamRef<jobject>(j_egl_context));
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800232
Alex Glaznev782671f2015-06-12 16:40:44 -0700233 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700234 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700235 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000236 return WEBRTC_VIDEO_CODEC_ERROR;
237 }
238 inited_ = true;
239
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000240 switch (codecType_) {
241 case kVideoCodecVP8:
242 max_pending_frames_ = kMaxPendingFramesVp8;
243 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800244 case kVideoCodecVP9:
245 max_pending_frames_ = kMaxPendingFramesVp9;
246 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000247 case kVideoCodecH264:
248 max_pending_frames_ = kMaxPendingFramesH264;
249 break;
250 default:
251 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000252 }
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800253 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000254
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100255 ScopedJavaLocalRef<jobjectArray> input_buffers =
256 Java_MediaCodecVideoDecoder_getInputBuffers(jni,
257 j_media_codec_video_decoder_);
258 input_buffers_ = JavaToNativeVector<ScopedJavaGlobalRef<jobject>>(
259 jni, input_buffers, [](JNIEnv* env, const JavaRef<jobject>& o) {
260 return ScopedJavaGlobalRef<jobject>(env, o);
261 });
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000262
guidouc3372582017-04-04 07:16:21 -0700263 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this);
264
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000265 return WEBRTC_VIDEO_CODEC_OK;
266}
267
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800268int32_t MediaCodecVideoDecoder::ResetDecodeOnCodecThread() {
guidouc3372582017-04-04 07:16:21 -0700269 CheckOnCodecThread();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800270 JNIEnv* jni = AttachCurrentThreadIfNeeded();
271 ScopedLocalRefFrame local_ref_frame(jni);
Magnus Jedvert9060eb12017-12-12 12:52:54 +0100272 ALOGD << "ResetDecodeOnCodecThread Type: " << static_cast<int>(codecType_)
273 << ". " << codec_.width << " x " << codec_.height;
Yves Gerey665174f2018-06-19 15:03:05 +0200274 ALOGD << " Frames received: " << frames_received_
275 << ". Frames decoded: " << frames_decoded_;
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800276
277 inited_ = false;
guidouc3372582017-04-04 07:16:21 -0700278 rtc::MessageQueueManager::Clear(this);
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800279 ResetVariables();
280
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100281 Java_MediaCodecVideoDecoder_reset(jni, j_media_codec_video_decoder_,
Magnus Jedvert655e1962017-12-08 11:05:22 +0100282 codec_.width, codec_.height);
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800283
284 if (CheckException(jni)) {
285 ALOGE << "Soft reset error - fallback to SW codec.";
286 sw_fallback_required_ = true;
287 return WEBRTC_VIDEO_CODEC_ERROR;
288 }
289 inited_ = true;
290
guidouc3372582017-04-04 07:16:21 -0700291 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this);
292
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800293 return WEBRTC_VIDEO_CODEC_OK;
294}
295
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000296int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700297 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000298 return codec_thread_->Invoke<int32_t>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700299 RTC_FROM_HERE, Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000300}
301
302int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
303 if (!inited_) {
304 return WEBRTC_VIDEO_CODEC_OK;
305 }
guidouc3372582017-04-04 07:16:21 -0700306 CheckOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000307 JNIEnv* jni = AttachCurrentThreadIfNeeded();
Yves Gerey665174f2018-06-19 15:03:05 +0200308 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " << frames_received_
309 << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000310 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000311 input_buffers_.clear();
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100312 Java_MediaCodecVideoDecoder_release(jni, j_media_codec_video_decoder_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000313 inited_ = false;
guidouc3372582017-04-04 07:16:21 -0700314 rtc::MessageQueueManager::Clear(this);
Alex Glaznev782671f2015-06-12 16:40:44 -0700315 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700316 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700317 return WEBRTC_VIDEO_CODEC_ERROR;
318 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700319 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000320 return WEBRTC_VIDEO_CODEC_OK;
321}
322
guidouc3372582017-04-04 07:16:21 -0700323void MediaCodecVideoDecoder::CheckOnCodecThread() {
324 RTC_CHECK(codec_thread_.get() == ThreadManager::Instance()->CurrentThread())
325 << "Running on wrong thread!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000326}
327
glaznevae95ff32016-02-04 11:47:12 -0800328void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
329 // Log next 2 output frames.
Yves Gerey665174f2018-06-19 15:03:05 +0200330 frames_decoded_logged_ =
331 std::max(frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
glaznevae95ff32016-02-04 11:47:12 -0800332}
333
Alex Glaznev782671f2015-06-12 16:40:44 -0700334int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
guidouc3372582017-04-04 07:16:21 -0700335 CheckOnCodecThread();
Alex Glaznev782671f2015-06-12 16:40:44 -0700336 int ret_val = ReleaseOnCodecThread();
337 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700338 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700339 }
340 if (codecType_ == kVideoCodecH264) {
341 // For now there is no SW H.264 which can be used as fallback codec.
342 // So try to restart hw codec for now.
343 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700344 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700345 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
346 // H.264 codec was succesfully reset - return regular error code.
347 return WEBRTC_VIDEO_CODEC_ERROR;
348 } else {
349 // Fail to restart H.264 codec - return error code which should stop the
350 // call.
351 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
352 }
353 } else {
354 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700355 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700356 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
357 }
358}
359
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000360int32_t MediaCodecVideoDecoder::Decode(
361 const EncodedImage& inputImage,
362 bool missingFrames,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000363 const CodecSpecificInfo* codecSpecificInfo,
364 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700365 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700366 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700367 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000368 }
guidouc3372582017-04-04 07:16:21 -0700369 if (callback_ == NULL) {
370 ALOGE << "Decode() - callback_ is NULL";
371 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
372 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000373 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700374 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000375 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
376 }
guidouc3372582017-04-04 07:16:21 -0700377 if (!inited_) {
378 ALOGE << "Decode() - decoder is not initialized";
379 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
380 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700381
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000382 // Check if encoded frame dimension has changed.
383 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
Danil Chapovalov350531e2018-06-08 11:04:04 +0000384 (inputImage._encodedWidth != codec_.width ||
Yves Gerey665174f2018-06-19 15:03:05 +0200385 inputImage._encodedHeight != codec_.height)) {
386 ALOGW << "Input resolution changed from " << codec_.width << " x "
387 << codec_.height << " to " << inputImage._encodedWidth << " x "
388 << inputImage._encodedHeight;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000389 codec_.width = inputImage._encodedWidth;
390 codec_.height = inputImage._encodedHeight;
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800391 int32_t ret;
Alex Glaznev79299af2016-04-12 16:39:39 -0700392 if (use_surface_ &&
393 (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecH264)) {
394 // Soft codec reset - only for surface decoding.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700395 ret = codec_thread_->Invoke<int32_t>(
396 RTC_FROM_HERE,
397 Bind(&MediaCodecVideoDecoder::ResetDecodeOnCodecThread, this));
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800398 } else {
399 // Hard codec reset.
400 ret = InitDecode(&codec_, 1);
401 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700402 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700403 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700404 sw_fallback_required_ = true;
405 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
406 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000407 }
408
409 // Always start with a complete key frame.
410 if (key_frame_required_) {
magjeda3d4f682017-08-28 16:24:06 -0700411 if (inputImage._frameType != kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700412 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000413 return WEBRTC_VIDEO_CODEC_ERROR;
414 }
415 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700416 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000417 return WEBRTC_VIDEO_CODEC_ERROR;
418 }
419 key_frame_required_ = false;
420 }
421 if (inputImage._length == 0) {
422 return WEBRTC_VIDEO_CODEC_ERROR;
423 }
424
guidouc3372582017-04-04 07:16:21 -0700425 return codec_thread_->Invoke<int32_t>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700426 RTC_FROM_HERE,
guidouc3372582017-04-04 07:16:21 -0700427 Bind(&MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000428}
429
430int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
guidouc3372582017-04-04 07:16:21 -0700431 const EncodedImage& inputImage) {
432 CheckOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000433 JNIEnv* jni = AttachCurrentThreadIfNeeded();
434 ScopedLocalRefFrame local_ref_frame(jni);
435
436 // Try to drain the decoder and wait until output is not too
437 // much behind the input.
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800438 if (codecType_ == kVideoCodecH264 &&
439 frames_received_ > frames_decoded_ + max_pending_frames_) {
440 // Print warning for H.264 only - for VP8/VP9 one frame delay is ok.
Yves Gerey665174f2018-06-19 15:03:05 +0200441 ALOGW << "Decoder is too far behind. Try to drain. Received: "
442 << frames_received_ << ". Decoded: " << frames_decoded_;
glaznevae95ff32016-02-04 11:47:12 -0800443 EnableFrameLogOnWarning();
444 }
Mirko Bonadei4d131e42018-07-09 21:41:33 +0200445 const int64_t drain_start = rtc::TimeMillis();
Per488e75f2015-11-19 10:43:36 +0100446 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
Niels Möllerd28db7f2016-05-10 16:31:47 +0200447 (rtc::TimeMillis() - drain_start) < kMediaCodecTimeoutMs) {
guidouc3372582017-04-04 07:16:21 -0700448 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
Yves Gerey665174f2018-06-19 15:03:05 +0200449 ALOGE << "DeliverPendingOutputs error. Frames received: "
450 << frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700451 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000452 }
Per488e75f2015-11-19 10:43:36 +0100453 }
454 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
Yves Gerey665174f2018-06-19 15:03:05 +0200455 ALOGE << "Output buffer dequeue timeout. Frames received: "
456 << frames_received_ << ". Frames decoded: " << frames_decoded_;
Per488e75f2015-11-19 10:43:36 +0100457 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000458 }
459
460 // Get input buffer.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100461 int j_input_buffer_index = Java_MediaCodecVideoDecoder_dequeueInputBuffer(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100462 jni, j_media_codec_video_decoder_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700463 if (CheckException(jni) || j_input_buffer_index < 0) {
Yves Gerey665174f2018-06-19 15:03:05 +0200464 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index
465 << ". Retry DeliverPendingOutputs.";
glaznevae95ff32016-02-04 11:47:12 -0800466 EnableFrameLogOnWarning();
467 // Try to drain the decoder.
guidouc3372582017-04-04 07:16:21 -0700468 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
Yves Gerey665174f2018-06-19 15:03:05 +0200469 ALOGE << "DeliverPendingOutputs error. Frames received: "
470 << frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznevae95ff32016-02-04 11:47:12 -0800471 return ProcessHWErrorOnCodecThread();
472 }
473 // Try dequeue input buffer one last time.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100474 j_input_buffer_index = Java_MediaCodecVideoDecoder_dequeueInputBuffer(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100475 jni, j_media_codec_video_decoder_);
glaznevae95ff32016-02-04 11:47:12 -0800476 if (CheckException(jni) || j_input_buffer_index < 0) {
477 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
478 return ProcessHWErrorOnCodecThread();
479 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000480 }
481
482 // Copy encoded data to Java ByteBuffer.
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100483 jobject j_input_buffer = input_buffers_[j_input_buffer_index].obj();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200484 uint8_t* buffer =
485 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
guidouc3372582017-04-04 07:16:21 -0700486 RTC_CHECK(buffer) << "Indirect buffer??";
Yves Gerey665174f2018-06-19 15:03:05 +0200487 size_t buffer_capacity =
488 rtc::dchecked_cast<size_t>(jni->GetDirectBufferCapacity(j_input_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700489 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Yves Gerey665174f2018-06-19 15:03:05 +0200490 ALOGE << "Input frame size " << inputImage._length
491 << " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700492 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000493 }
glaznevae95ff32016-02-04 11:47:12 -0800494 jlong presentation_timestamp_us = static_cast<jlong>(
495 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000496 memcpy(buffer, inputImage._buffer, inputImage._length);
497
glaznevae95ff32016-02-04 11:47:12 -0800498 if (frames_decoded_ < frames_decoded_logged_) {
Yves Gerey665174f2018-06-19 15:03:05 +0200499 ALOGD << "Decoder frame in # " << frames_received_
500 << ". Type: " << inputImage._frameType << ". Buffer # "
501 << j_input_buffer_index
502 << ". TS: " << presentation_timestamp_us / 1000
503 << ". Size: " << inputImage._length;
glaznev94291482016-02-01 13:17:18 -0800504 }
505
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000506 // Save input image timestamps for later output.
507 frames_received_++;
508 current_bytes_ += inputImage._length;
Danil Chapovalov196100e2018-06-21 10:17:24 +0200509 absl::optional<uint8_t> qp;
sakal9c997a32017-02-17 03:26:10 -0800510 if (codecType_ == kVideoCodecVP8) {
511 int qp_int;
magjeda3d4f682017-08-28 16:24:06 -0700512 if (vp8::GetQp(inputImage._buffer, inputImage._length, &qp_int)) {
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100513 qp = qp_int;
sakal9c997a32017-02-17 03:26:10 -0800514 }
515 } else if (codecType_ == kVideoCodecH264) {
516 h264_bitstream_parser_.ParseBitstream(inputImage._buffer,
517 inputImage._length);
518 int qp_int;
519 if (h264_bitstream_parser_.GetLastSliceQp(&qp_int)) {
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100520 qp = qp_int;
sakal9c997a32017-02-17 03:26:10 -0800521 }
522 }
523 pending_frame_qps_.push_back(qp);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000524
525 // Feed input to decoder.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100526 bool success = Java_MediaCodecVideoDecoder_queueInputBuffer(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100527 jni, j_media_codec_video_decoder_, j_input_buffer_index,
Magnus Jedvert8a483be2018-05-08 10:51:00 +0200528 static_cast<int>(inputImage._length), presentation_timestamp_us,
Magnus Jedvert655e1962017-12-08 11:05:22 +0100529 static_cast<int64_t>(inputImage._timeStamp), inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700530 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700531 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700532 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000533 }
534
535 // Try to drain the decoder
guidouc3372582017-04-04 07:16:21 -0700536 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700537 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700538 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000539 }
540
541 return WEBRTC_VIDEO_CODEC_OK;
542}
543
Yves Gerey665174f2018-06-19 15:03:05 +0200544bool MediaCodecVideoDecoder::DeliverPendingOutputs(JNIEnv* jni,
545 int dequeue_timeout_ms) {
guidouc3372582017-04-04 07:16:21 -0700546 CheckOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000547 if (frames_received_ <= frames_decoded_) {
548 // No need to query for output buffers - decoder is drained.
549 return true;
550 }
551 // Get decoder output.
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100552 ScopedJavaLocalRef<jobject> j_decoder_output_buffer =
Magnus Jedvert655e1962017-12-08 11:05:22 +0100553 (use_surface_ ? &Java_MediaCodecVideoDecoder_dequeueTextureBuffer
554 : &Java_MediaCodecVideoDecoder_dequeueOutputBuffer)(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100555 jni, j_media_codec_video_decoder_, dequeue_timeout_ms);
Alex Glaznev782671f2015-06-12 16:40:44 -0700556 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700557 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700558 return false;
559 }
magjed44bf6f52015-10-03 02:08:00 -0700560 if (IsNull(jni, j_decoder_output_buffer)) {
561 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000562 return true;
563 }
564
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000565 // Get decoded video frame properties.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100566 int color_format = Java_MediaCodecVideoDecoder_getColorFormat(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100567 jni, j_media_codec_video_decoder_);
Magnus Jedvert655e1962017-12-08 11:05:22 +0100568 int width =
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100569 Java_MediaCodecVideoDecoder_getWidth(jni, j_media_codec_video_decoder_);
Magnus Jedvert655e1962017-12-08 11:05:22 +0100570 int height =
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100571 Java_MediaCodecVideoDecoder_getHeight(jni, j_media_codec_video_decoder_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000572
magjeda3d4f682017-08-28 16:24:06 -0700573 rtc::scoped_refptr<VideoFrameBuffer> frame_buffer;
glaznev94291482016-02-01 13:17:18 -0800574 int64_t presentation_timestamps_ms = 0;
Per488e75f2015-11-19 10:43:36 +0100575 int64_t output_timestamps_ms = 0;
576 int64_t output_ntp_timestamps_ms = 0;
577 int decode_time_ms = 0;
578 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200579 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700580 // Extract data from Java DecodedTextureBuffer.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100581 presentation_timestamps_ms =
582 Java_DecodedTextureBuffer_getPresentationTimestampMs(
583 jni, j_decoder_output_buffer);
584 output_timestamps_ms =
585 Java_DecodedTextureBuffer_getTimeStampMs(jni, j_decoder_output_buffer);
586 output_ntp_timestamps_ms = Java_DecodedTextureBuffer_getNtpTimestampMs(
587 jni, j_decoder_output_buffer);
588 decode_time_ms =
589 Java_DecodedTextureBuffer_getDecodeTimeMs(jni, j_decoder_output_buffer);
glaznevae95ff32016-02-04 11:47:12 -0800590
Magnus Jedvertb9ac1212018-04-23 11:29:05 +0200591 ScopedJavaLocalRef<jobject> j_video_frame_buffer =
592 Java_DecodedTextureBuffer_getVideoFrameBuffer(jni,
593 j_decoder_output_buffer);
594 // |video_frame_buffer| == null represents a dropped frame.
595 if (!j_video_frame_buffer.is_null()) {
Magnus Jedvert655e1962017-12-08 11:05:22 +0100596 frame_delayed_ms = Java_DecodedTextureBuffer_getFrameDelayMs(
597 jni, j_decoder_output_buffer);
Magnus Jedvertb9ac1212018-04-23 11:29:05 +0200598 frame_buffer = AndroidVideoBuffer::Adopt(jni, j_video_frame_buffer);
glaznevae95ff32016-02-04 11:47:12 -0800599 } else {
600 EnableFrameLogOnWarning();
Per488e75f2015-11-19 10:43:36 +0100601 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200602 } else {
603 // Extract data from Java ByteBuffer and create output yuv420 frame -
604 // for non surface decoding only.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100605 int stride = Java_MediaCodecVideoDecoder_getStride(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100606 jni, j_media_codec_video_decoder_);
Magnus Jedvert655e1962017-12-08 11:05:22 +0100607 const int slice_height = Java_MediaCodecVideoDecoder_getSliceHeight(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100608 jni, j_media_codec_video_decoder_);
Magnus Jedvert655e1962017-12-08 11:05:22 +0100609 const int output_buffer_index =
610 Java_DecodedOutputBuffer_getIndex(jni, j_decoder_output_buffer);
611 const int output_buffer_offset =
612 Java_DecodedOutputBuffer_getOffset(jni, j_decoder_output_buffer);
613 const int output_buffer_size =
614 Java_DecodedOutputBuffer_getSize(jni, j_decoder_output_buffer);
615 presentation_timestamps_ms =
616 Java_DecodedOutputBuffer_getPresentationTimestampMs(
617 jni, j_decoder_output_buffer);
618 output_timestamps_ms =
619 Java_DecodedOutputBuffer_getTimestampMs(jni, j_decoder_output_buffer);
620 output_ntp_timestamps_ms = Java_DecodedOutputBuffer_getNtpTimestampMs(
621 jni, j_decoder_output_buffer);
Per488e75f2015-11-19 10:43:36 +0100622
Magnus Jedvert655e1962017-12-08 11:05:22 +0100623 decode_time_ms =
624 Java_DecodedOutputBuffer_getDecodeTimeMs(jni, j_decoder_output_buffer);
magjedd1587ad2017-03-06 05:20:49 -0800625 RTC_CHECK_GE(slice_height, height);
magjed44bf6f52015-10-03 02:08:00 -0700626
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000627 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700628 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000629 return false;
630 }
glaznev3816bfd2016-03-08 10:35:33 -0800631 if (output_buffer_size < stride * height * 3 / 2 &&
632 slice_height == height && stride > width) {
633 // Some codecs (Exynos) incorrectly report stride information for
634 // output byte buffer, so actual stride value need to be corrected.
635 stride = output_buffer_size * 2 / (height * 3);
636 }
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100637 ScopedJavaLocalRef<jobjectArray> output_buffers =
638 Java_MediaCodecVideoDecoder_getOutputBuffers(
639 jni, j_media_codec_video_decoder_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000640 jobject output_buffer =
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100641 jni->GetObjectArrayElement(output_buffers.obj(), output_buffer_index);
Yves Gerey665174f2018-06-19 15:03:05 +0200642 uint8_t* payload =
643 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700644 if (CheckException(jni)) {
645 return false;
646 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000647 payload += output_buffer_offset;
648
649 // Create yuv420 frame.
magjeda3d4f682017-08-28 16:24:06 -0700650 rtc::scoped_refptr<I420Buffer> i420_buffer =
magjed0e22a4c2017-02-23 07:11:32 -0800651 decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000652 if (color_format == COLOR_FormatYUV420Planar) {
guidouc3372582017-04-04 07:16:21 -0700653 RTC_CHECK_EQ(0, stride % 2);
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200654 const int uv_stride = stride / 2;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200655 const uint8_t* y_ptr = payload;
656 const uint8_t* u_ptr = y_ptr + stride * slice_height;
magjed0e22a4c2017-02-23 07:11:32 -0800657
658 // Note that the case with odd |slice_height| is handled in a special way.
659 // The chroma height contained in the payload is rounded down instead of
660 // up, making it one row less than what we expect in WebRTC. Therefore, we
661 // have to duplicate the last chroma rows for this case. Also, the offset
662 // between the Y plane and the U plane is unintuitive for this case. See
663 // http://bugs.webrtc.org/6651 for more info.
664 const int chroma_width = (width + 1) / 2;
665 const int chroma_height =
666 (slice_height % 2 == 0) ? (height + 1) / 2 : height / 2;
667 const int u_offset = uv_stride * slice_height / 2;
668 const uint8_t* v_ptr = u_ptr + u_offset;
Yves Gerey665174f2018-06-19 15:03:05 +0200669 libyuv::CopyPlane(y_ptr, stride, i420_buffer->MutableDataY(),
670 i420_buffer->StrideY(), width, height);
671 libyuv::CopyPlane(u_ptr, uv_stride, i420_buffer->MutableDataU(),
672 i420_buffer->StrideU(), chroma_width, chroma_height);
673 libyuv::CopyPlane(v_ptr, uv_stride, i420_buffer->MutableDataV(),
674 i420_buffer->StrideV(), chroma_width, chroma_height);
magjed0e22a4c2017-02-23 07:11:32 -0800675 if (slice_height % 2 == 1) {
guidouc3372582017-04-04 07:16:21 -0700676 RTC_CHECK_EQ(height, slice_height);
magjed0e22a4c2017-02-23 07:11:32 -0800677 // Duplicate the last chroma rows.
678 uint8_t* u_last_row_ptr = i420_buffer->MutableDataU() +
679 chroma_height * i420_buffer->StrideU();
680 memcpy(u_last_row_ptr, u_last_row_ptr - i420_buffer->StrideU(),
681 i420_buffer->StrideU());
682 uint8_t* v_last_row_ptr = i420_buffer->MutableDataV() +
683 chroma_height * i420_buffer->StrideV();
684 memcpy(v_last_row_ptr, v_last_row_ptr - i420_buffer->StrideV(),
685 i420_buffer->StrideV());
686 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000687 } else {
688 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200689 const uint8_t* y_ptr = payload;
690 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
nissecbae0b42016-09-14 05:45:06 -0700691 libyuv::NV12ToI420(y_ptr, stride, uv_ptr, stride,
692 i420_buffer->MutableDataY(), i420_buffer->StrideY(),
693 i420_buffer->MutableDataU(), i420_buffer->StrideU(),
694 i420_buffer->MutableDataV(), i420_buffer->StrideV(),
695 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000696 }
nissecbae0b42016-09-14 05:45:06 -0700697 frame_buffer = i420_buffer;
698
magjed44bf6f52015-10-03 02:08:00 -0700699 // Return output byte buffer back to codec.
Magnus Jedvert655e1962017-12-08 11:05:22 +0100700 Java_MediaCodecVideoDecoder_returnDecodedOutputBuffer(
Magnus Jedvert84d8ae52017-12-20 15:12:10 +0100701 jni, j_media_codec_video_decoder_, output_buffer_index);
magjed44bf6f52015-10-03 02:08:00 -0700702 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100703 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700704 return false;
705 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000706 }
glaznevae95ff32016-02-04 11:47:12 -0800707 if (frames_decoded_ < frames_decoded_logged_) {
Yves Gerey665174f2018-06-19 15:03:05 +0200708 ALOGD << "Decoder frame out # " << frames_decoded_ << ". " << width << " x "
709 << height << ". Color: " << color_format
710 << ". TS: " << presentation_timestamps_ms
711 << ". DecTime: " << static_cast<int>(decode_time_ms)
712 << ". DelayTime: " << static_cast<int>(frame_delayed_ms);
glazneve55c42c2015-10-28 10:30:32 -0700713 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000714
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000715 // Calculate and print decoding statistics - every 3 seconds.
716 frames_decoded_++;
717 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100718 current_decoding_time_ms_ += decode_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800719 current_delay_time_ms_ += frame_delayed_ms;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200720 int statistic_time_ms = rtc::TimeMillis() - start_time_ms_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000721 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
722 current_frames_ > 0) {
glaznev94291482016-02-01 13:17:18 -0800723 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
724 int current_fps =
725 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
Yves Gerey665174f2018-06-19 15:03:05 +0200726 ALOGD << "Frames decoded: " << frames_decoded_
727 << ". Received: " << frames_received_
728 << ". Bitrate: " << current_bitrate << " kbps"
729 << ". Fps: " << current_fps
730 << ". DecTime: " << (current_decoding_time_ms_ / current_frames_)
731 << ". DelayTime: " << (current_delay_time_ms_ / current_frames_)
732 << " for last " << statistic_time_ms << " ms.";
Niels Möllerd28db7f2016-05-10 16:31:47 +0200733 start_time_ms_ = rtc::TimeMillis();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000734 current_frames_ = 0;
735 current_bytes_ = 0;
736 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800737 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000738 }
739
nisse94cd3fa2016-05-23 23:35:54 -0700740 // If the frame was dropped, frame_buffer is left as nullptr.
741 if (frame_buffer) {
magjeda3d4f682017-08-28 16:24:06 -0700742 VideoFrame decoded_frame(frame_buffer, 0, 0, kVideoRotation_0);
nisse94cd3fa2016-05-23 23:35:54 -0700743 decoded_frame.set_timestamp(output_timestamps_ms);
744 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
745
Danil Chapovalov196100e2018-06-21 10:17:24 +0200746 absl::optional<uint8_t> qp = pending_frame_qps_.front();
sakal9c997a32017-02-17 03:26:10 -0800747 pending_frame_qps_.pop_front();
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100748 callback_->Decoded(decoded_frame, decode_time_ms, qp);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000749 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000750 return true;
751}
752
753int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
754 DecodedImageCallback* callback) {
755 callback_ = callback;
756 return WEBRTC_VIDEO_CODEC_OK;
757}
758
guidouc3372582017-04-04 07:16:21 -0700759void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
760 JNIEnv* jni = AttachCurrentThreadIfNeeded();
761 ScopedLocalRefFrame local_ref_frame(jni);
762 if (!inited_) {
763 return;
764 }
765 // We only ever send one message to |this| directly (not through a Bind()'d
766 // functor), so expect no ID/data.
767 RTC_CHECK(!msg->message_id) << "Unexpected message!";
768 RTC_CHECK(!msg->pdata) << "Unexpected message!";
769 CheckOnCodecThread();
770
771 if (!DeliverPendingOutputs(jni, 0)) {
772 ALOGE << "OnMessage: DeliverPendingOutputs error";
773 ProcessHWErrorOnCodecThread();
774 return;
775 }
776 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this);
777}
778
perkj461121c2016-02-15 06:28:36 -0800779MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory()
780 : egl_context_(nullptr) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700781 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000782 JNIEnv* jni = AttachCurrentThreadIfNeeded();
783 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000784 supported_codec_types_.clear();
785
Magnus Jedvert655e1962017-12-08 11:05:22 +0100786 if (Java_MediaCodecVideoDecoder_isVp8HwSupported(jni) &&
787 !CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700788 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000789 supported_codec_types_.push_back(kVideoCodecVP8);
790 }
791
Magnus Jedvert655e1962017-12-08 11:05:22 +0100792 if (Java_MediaCodecVideoDecoder_isVp9HwSupported(jni) &&
793 !CheckException(jni)) {
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800794 ALOGD << "VP9 HW Decoder supported.";
795 supported_codec_types_.push_back(kVideoCodecVP9);
796 }
797
Magnus Jedvert655e1962017-12-08 11:05:22 +0100798 if (Java_MediaCodecVideoDecoder_isH264HwSupported(jni) &&
799 !CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700800 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000801 supported_codec_types_.push_back(kVideoCodecH264);
802 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000803}
804
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700805MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700806 ALOGD << "MediaCodecVideoDecoderFactory dtor";
perkj461121c2016-02-15 06:28:36 -0800807 if (egl_context_) {
808 JNIEnv* jni = AttachCurrentThreadIfNeeded();
809 jni->DeleteGlobalRef(egl_context_);
810 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700811}
812
Yves Gerey665174f2018-06-19 15:03:05 +0200813void MediaCodecVideoDecoderFactory::SetEGLContext(JNIEnv* jni,
814 jobject egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700815 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Perfd22e6c2016-02-18 11:35:48 +0100816 if (egl_context_) {
817 jni->DeleteGlobalRef(egl_context_);
818 egl_context_ = nullptr;
819 }
perkj461121c2016-02-15 06:28:36 -0800820 egl_context_ = jni->NewGlobalRef(egl_context);
821 if (CheckException(jni)) {
822 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700823 }
824}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000825
magjeda3d4f682017-08-28 16:24:06 -0700826VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000827 VideoCodecType type) {
828 if (supported_codec_types_.empty()) {
Magnus Jedvert9060eb12017-12-12 12:52:54 +0100829 ALOGW << "No HW video decoder for type " << static_cast<int>(type);
Perec2922f2016-01-27 15:25:46 +0100830 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000831 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700832 for (VideoCodecType codec_type : supported_codec_types_) {
833 if (codec_type == type) {
Magnus Jedvert9060eb12017-12-12 12:52:54 +0100834 ALOGD << "Create HW video decoder for type " << static_cast<int>(type);
magjede4cd15d2017-03-30 01:08:36 -0700835 JNIEnv* jni = AttachCurrentThreadIfNeeded();
836 ScopedLocalRefFrame local_ref_frame(jni);
837 return new MediaCodecVideoDecoder(jni, type, egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000838 }
839 }
Magnus Jedvert9060eb12017-12-12 12:52:54 +0100840 ALOGW << "Can not find HW video decoder for type " << static_cast<int>(type);
Perec2922f2016-01-27 15:25:46 +0100841 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000842}
843
magjeda3d4f682017-08-28 16:24:06 -0700844void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700845 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000846 delete decoder;
847}
848
Magnus Jedvert655e1962017-12-08 11:05:22 +0100849bool MediaCodecVideoDecoderFactory::IsH264HighProfileSupported(JNIEnv* env) {
850 return Java_MediaCodecVideoDecoder_isH264HighProfileHwSupported(env);
851}
852
Peter Boströmb7d9a972015-12-18 16:01:11 +0100853const char* MediaCodecVideoDecoder::ImplementationName() const {
854 return "MediaCodec";
855}
856
magjeda3d4f682017-08-28 16:24:06 -0700857} // namespace jni
858} // namespace webrtc