blob: f7966cc44a86c9359d89621c9788b546d9244f27 [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>
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000012#include <vector>
13
kjellandera96e2d72016-02-04 23:52:28 -080014// NOTICE: androidmediadecoder_jni.h must be included before
15// androidmediacodeccommon.h to avoid build errors.
Henrik Kjellander15583c12016-02-10 10:53:12 +010016#include "webrtc/api/java/jni/androidmediadecoder_jni.h"
17
kjellandera96e2d72016-02-04 23:52:28 -080018#include "third_party/libyuv/include/libyuv/convert.h"
19#include "third_party/libyuv/include/libyuv/convert_from.h"
20#include "third_party/libyuv/include/libyuv/video_common.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010021#include "webrtc/api/java/jni/androidmediacodeccommon.h"
22#include "webrtc/api/java/jni/classreferenceholder.h"
23#include "webrtc/api/java/jni/native_handle_impl.h"
24#include "webrtc/api/java/jni/surfacetexturehelper_jni.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000025#include "webrtc/base/bind.h"
26#include "webrtc/base/checks.h"
27#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020028#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000029#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020030#include "webrtc/base/timeutils.h"
kjellander6f8ce062015-11-16 13:52:24 -080031#include "webrtc/common_video/include/i420_buffer_pool.h"
perkj87d58452015-11-23 01:46:27 -080032#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010033#include "webrtc/system_wrappers/include/logcat_trace_context.h"
34#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000035
36using rtc::Bind;
37using rtc::Thread;
38using rtc::ThreadManager;
39using rtc::scoped_ptr;
40
41using webrtc::CodecSpecificInfo;
42using webrtc::DecodedImageCallback;
43using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070044using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000045using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000046using webrtc::TickTime;
47using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000048using webrtc::VideoCodecType;
49using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000050using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080051using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000052
53namespace webrtc_jni {
54
glaznevf4decb52016-01-15 13:49:22 -080055// Logging macros.
56#define TAG_DECODER "MediaCodecVideoDecoder"
57#ifdef TRACK_BUFFER_TIMING
58#define ALOGV(...)
59 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
60#else
61#define ALOGV(...)
62#endif
63#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
64#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
65#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
66
glaznevae95ff32016-02-04 11:47:12 -080067enum { kMaxWarningLogFrames = 2 };
68
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000069class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
70 public rtc::MessageHandler {
71 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070072 explicit MediaCodecVideoDecoder(
73 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000074 virtual ~MediaCodecVideoDecoder();
75
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000076 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
77 override;
78
79 int32_t Decode(
80 const EncodedImage& inputImage, bool missingFrames,
81 const RTPFragmentationHeader* fragmentation,
82 const CodecSpecificInfo* codecSpecificInfo = NULL,
83 int64_t renderTimeMs = -1) override;
84
85 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
86 override;
87
88 int32_t Release() override;
89
perkj796cfaf2015-12-10 09:27:38 -080090 bool PrefersLateDecoding() const override { return true; }
91
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000092 // rtc::MessageHandler implementation.
93 void OnMessage(rtc::Message* msg) override;
94
Peter Boströmb7d9a972015-12-18 16:01:11 +010095 const char* ImplementationName() const override;
96
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000097 private:
98 // CHECK-fail if not running on |codec_thread_|.
99 void CheckOnCodecThread();
100
101 int32_t InitDecodeOnCodecThread();
102 int32_t ReleaseOnCodecThread();
103 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
104 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
105 // true on success.
106 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700107 int32_t ProcessHWErrorOnCodecThread();
glaznevae95ff32016-02-04 11:47:12 -0800108 void EnableFrameLogOnWarning();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000109
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000110 // Type of video codec.
111 VideoCodecType codecType_;
112
kjellander60ca31b2016-01-04 10:15:53 -0800113 // Render EGL context - owned by factory, should not be allocated/destroyed
114 // by VideoDecoder.
115 jobject render_egl_context_;
116
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000117 bool key_frame_required_;
118 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700119 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000120 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000121 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200122 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100123 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000124 DecodedImageCallback* callback_;
125 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000126 int frames_decoded_; // Number of frames decoded by decoder.
glaznevae95ff32016-02-04 11:47:12 -0800127 // Number of decoded frames for which log information is displayed.
128 int frames_decoded_logged_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000129 int64_t start_time_ms_; // Start time for statistics.
130 int current_frames_; // Number of frames in the current statistics interval.
131 int current_bytes_; // Encoded bytes in the current statistics interval.
132 int current_decoding_time_ms_; // Overall decoding time in the current second
glaznevfd6706a2016-02-05 14:05:08 -0800133 int current_delay_time_ms_; // Overall delay time in the current second.
134 uint32_t max_pending_frames_; // Maximum number of pending input frames.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000135
136 // State that is constant for the lifetime of this object once the ctor
137 // returns.
138 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
139 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
140 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
141 jmethodID j_init_decode_method_;
142 jmethodID j_release_method_;
143 jmethodID j_dequeue_input_buffer_method_;
144 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100145 jmethodID j_dequeue_byte_buffer_method_;
146 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700147 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000148 // MediaCodecVideoDecoder fields.
149 jfieldID j_input_buffers_field_;
150 jfieldID j_output_buffers_field_;
151 jfieldID j_color_format_field_;
152 jfieldID j_width_field_;
153 jfieldID j_height_field_;
154 jfieldID j_stride_field_;
155 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700156 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100157 jfieldID j_texture_id_field_;
158 jfieldID j_transform_matrix_field_;
glaznev94291482016-02-01 13:17:18 -0800159 jfieldID j_texture_presentation_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100160 jfieldID j_texture_timestamp_ms_field_;
161 jfieldID j_texture_ntp_timestamp_ms_field_;
162 jfieldID j_texture_decode_time_ms_field_;
163 jfieldID j_texture_frame_delay_ms_field_;
164 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000165 jfieldID j_info_index_field_;
166 jfieldID j_info_offset_field_;
167 jfieldID j_info_size_field_;
glaznev94291482016-02-01 13:17:18 -0800168 jfieldID j_presentation_timestamp_ms_field_;
169 jfieldID j_timestamp_ms_field_;
170 jfieldID j_ntp_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100171 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000172
173 // Global references; must be deleted in Release().
174 std::vector<jobject> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000175};
176
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000177MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700178 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000179 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700180 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000181 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000182 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700183 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000184 codec_thread_(new Thread()),
185 j_media_codec_video_decoder_class_(
186 jni,
187 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
188 j_media_codec_video_decoder_(
189 jni,
190 jni->NewObject(*j_media_codec_video_decoder_class_,
191 GetMethodID(jni,
192 *j_media_codec_video_decoder_class_,
193 "<init>",
194 "()V"))) {
195 ScopedLocalRefFrame local_ref_frame(jni);
196 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700197 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000198
199 j_init_decode_method_ = GetMethodID(
200 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000201 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100202 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000203 j_release_method_ =
204 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
205 j_dequeue_input_buffer_method_ = GetMethodID(
206 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
207 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100208 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
209 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000210 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100211 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
212 j_dequeue_texture_buffer_method_ = GetMethodID(
213 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
214 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700215 j_return_decoded_byte_buffer_method_ =
216 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100217 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000218
219 j_input_buffers_field_ = GetFieldID(
220 jni, *j_media_codec_video_decoder_class_,
221 "inputBuffers", "[Ljava/nio/ByteBuffer;");
222 j_output_buffers_field_ = GetFieldID(
223 jni, *j_media_codec_video_decoder_class_,
224 "outputBuffers", "[Ljava/nio/ByteBuffer;");
225 j_color_format_field_ = GetFieldID(
226 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
227 j_width_field_ = GetFieldID(
228 jni, *j_media_codec_video_decoder_class_, "width", "I");
229 j_height_field_ = GetFieldID(
230 jni, *j_media_codec_video_decoder_class_, "height", "I");
231 j_stride_field_ = GetFieldID(
232 jni, *j_media_codec_video_decoder_class_, "stride", "I");
233 j_slice_height_field_ = GetFieldID(
234 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000235
Per488e75f2015-11-19 10:43:36 +0100236 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700237 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100238 j_texture_id_field_ = GetFieldID(
239 jni, j_decoded_texture_buffer_class, "textureID", "I");
240 j_transform_matrix_field_ = GetFieldID(
241 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
glaznev94291482016-02-01 13:17:18 -0800242 j_texture_presentation_timestamp_ms_field_ = GetFieldID(
243 jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
Per488e75f2015-11-19 10:43:36 +0100244 j_texture_timestamp_ms_field_ = GetFieldID(
245 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
246 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
247 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
248 j_texture_decode_time_ms_field_ = GetFieldID(
249 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
250 j_texture_frame_delay_ms_field_ = GetFieldID(
251 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700252
Per488e75f2015-11-19 10:43:36 +0100253 jclass j_decoded_output_buffer_class = FindClass(jni,
254 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000255 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100256 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000257 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100258 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000259 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100260 jni, j_decoded_output_buffer_class, "size", "I");
glaznev94291482016-02-01 13:17:18 -0800261 j_presentation_timestamp_ms_field_ = GetFieldID(
262 jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
263 j_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100264 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
glaznev94291482016-02-01 13:17:18 -0800265 j_ntp_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100266 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
267 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
268 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000269
270 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200271 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700272 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000273 memset(&codec_, 0, sizeof(codec_));
274 AllowBlockingCalls();
275}
276
277MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
278 // Call Release() to ensure no more callbacks to us after we are deleted.
279 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000280}
281
282int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
283 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700284 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000285 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700286 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000287 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
288 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000289 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700290 RTC_CHECK(inst->codecType == codecType_)
291 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000292
Alex Glaznev782671f2015-06-12 16:40:44 -0700293 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700294 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700295 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000296 }
297 // Save VideoCodec instance for later.
298 if (&codec_ != inst) {
299 codec_ = *inst;
300 }
glazneve55c42c2015-10-28 10:30:32 -0700301 // If maxFramerate is not set then assume 30 fps.
302 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000303
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000304 // Call Java init.
305 return codec_thread_->Invoke<int32_t>(
306 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
307}
308
309int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
310 CheckOnCodecThread();
311 JNIEnv* jni = AttachCurrentThreadIfNeeded();
312 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700313 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
314 << codec_.width << " x " << codec_.height << ". Fps: " <<
315 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700316
317 // Release previous codec first if it was allocated before.
318 int ret_val = ReleaseOnCodecThread();
319 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700320 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700321 sw_fallback_required_ = true;
322 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000323 }
324
Alex Glaznev782671f2015-06-12 16:40:44 -0700325 // Always start with a complete key frame.
326 key_frame_required_ = true;
327 frames_received_ = 0;
328 frames_decoded_ = 0;
glaznevae95ff32016-02-04 11:47:12 -0800329 frames_decoded_logged_ = kMaxDecodedLogFrames;
Alex Glaznev782671f2015-06-12 16:40:44 -0700330
perkj88518a22015-12-18 00:37:06 -0800331 jobject java_surface_texture_helper_ = nullptr;
Per488e75f2015-11-19 10:43:36 +0100332 if (use_surface_) {
perkj88518a22015-12-18 00:37:06 -0800333 java_surface_texture_helper_ = jni->CallStaticObjectMethod(
334 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
335 GetStaticMethodID(jni,
336 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
337 "create",
338 "(Lorg/webrtc/EglBase$Context;)"
339 "Lorg/webrtc/SurfaceTextureHelper;"),
340 render_egl_context_);
341 RTC_CHECK(java_surface_texture_helper_ != nullptr);
Per488e75f2015-11-19 10:43:36 +0100342 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
perkj88518a22015-12-18 00:37:06 -0800343 jni, java_surface_texture_helper_);
Per488e75f2015-11-19 10:43:36 +0100344 }
345
Perec2922f2016-01-27 15:25:46 +0100346 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000347 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000348 bool success = jni->CallBooleanMethod(
349 *j_media_codec_video_decoder_,
350 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000351 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000352 codec_.width,
353 codec_.height,
perkj88518a22015-12-18 00:37:06 -0800354 java_surface_texture_helper_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700355 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700356 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700357 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000358 return WEBRTC_VIDEO_CODEC_ERROR;
359 }
360 inited_ = true;
361
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000362 switch (codecType_) {
363 case kVideoCodecVP8:
364 max_pending_frames_ = kMaxPendingFramesVp8;
365 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800366 case kVideoCodecVP9:
367 max_pending_frames_ = kMaxPendingFramesVp9;
368 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000369 case kVideoCodecH264:
370 max_pending_frames_ = kMaxPendingFramesH264;
371 break;
372 default:
373 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000374 }
375 start_time_ms_ = GetCurrentTimeMs();
376 current_frames_ = 0;
377 current_bytes_ = 0;
378 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800379 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000380
381 jobjectArray input_buffers = (jobjectArray)GetObjectField(
382 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
383 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700384 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000385 input_buffers_.resize(num_input_buffers);
386 for (size_t i = 0; i < num_input_buffers; ++i) {
387 input_buffers_[i] =
388 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700389 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700390 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700391 sw_fallback_required_ = true;
392 return WEBRTC_VIDEO_CODEC_ERROR;
393 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000394 }
395
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000396 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
397
398 return WEBRTC_VIDEO_CODEC_OK;
399}
400
401int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700402 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000403 return codec_thread_->Invoke<int32_t>(
404 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
405}
406
407int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
408 if (!inited_) {
409 return WEBRTC_VIDEO_CODEC_OK;
410 }
411 CheckOnCodecThread();
412 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700413 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
414 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000415 ScopedLocalRefFrame local_ref_frame(jni);
416 for (size_t i = 0; i < input_buffers_.size(); i++) {
417 jni->DeleteGlobalRef(input_buffers_[i]);
418 }
419 input_buffers_.clear();
420 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100421 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000422 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700423 rtc::MessageQueueManager::Clear(this);
424 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700425 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700426 return WEBRTC_VIDEO_CODEC_ERROR;
427 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700428 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000429 return WEBRTC_VIDEO_CODEC_OK;
430}
431
432void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700433 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000434 << "Running on wrong thread!";
435}
436
glaznevae95ff32016-02-04 11:47:12 -0800437void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
438 // Log next 2 output frames.
439 frames_decoded_logged_ = std::max(
440 frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
441}
442
Alex Glaznev782671f2015-06-12 16:40:44 -0700443int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
444 CheckOnCodecThread();
445 int ret_val = ReleaseOnCodecThread();
446 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700447 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700448 }
449 if (codecType_ == kVideoCodecH264) {
450 // For now there is no SW H.264 which can be used as fallback codec.
451 // So try to restart hw codec for now.
452 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700453 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700454 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
455 // H.264 codec was succesfully reset - return regular error code.
456 return WEBRTC_VIDEO_CODEC_ERROR;
457 } else {
458 // Fail to restart H.264 codec - return error code which should stop the
459 // call.
460 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
461 }
462 } else {
463 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700464 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700465 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
466 }
467}
468
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000469int32_t MediaCodecVideoDecoder::Decode(
470 const EncodedImage& inputImage,
471 bool missingFrames,
472 const RTPFragmentationHeader* fragmentation,
473 const CodecSpecificInfo* codecSpecificInfo,
474 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700475 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700476 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700477 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000478 }
479 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700480 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000481 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
482 }
483 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700484 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000485 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
486 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700487 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700488 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700489 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
490 }
491
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000492 // Check if encoded frame dimension has changed.
493 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
494 (inputImage._encodedWidth != codec_.width ||
495 inputImage._encodedHeight != codec_.height)) {
496 codec_.width = inputImage._encodedWidth;
497 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700498 int32_t ret = InitDecode(&codec_, 1);
499 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700500 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700501 sw_fallback_required_ = true;
502 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
503 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000504 }
505
506 // Always start with a complete key frame.
507 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200508 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700509 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000510 return WEBRTC_VIDEO_CODEC_ERROR;
511 }
512 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700513 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000514 return WEBRTC_VIDEO_CODEC_ERROR;
515 }
516 key_frame_required_ = false;
517 }
518 if (inputImage._length == 0) {
519 return WEBRTC_VIDEO_CODEC_ERROR;
520 }
521
522 return codec_thread_->Invoke<int32_t>(Bind(
523 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
524}
525
526int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
527 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000528 CheckOnCodecThread();
529 JNIEnv* jni = AttachCurrentThreadIfNeeded();
530 ScopedLocalRefFrame local_ref_frame(jni);
531
532 // Try to drain the decoder and wait until output is not too
533 // much behind the input.
glaznevae95ff32016-02-04 11:47:12 -0800534 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
535 ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
536 frames_received_ << ". Decoded: " << frames_decoded_;
537 EnableFrameLogOnWarning();
538 }
Per488e75f2015-11-19 10:43:36 +0100539 const int64 drain_start = GetCurrentTimeMs();
540 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
541 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
Per488e75f2015-11-19 10:43:36 +0100542 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700543 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
544 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700545 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000546 }
Per488e75f2015-11-19 10:43:36 +0100547 }
548 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
549 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
550 frames_received_ << ". Frames decoded: " << frames_decoded_;
551 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000552 }
553
554 // Get input buffer.
glaznevae95ff32016-02-04 11:47:12 -0800555 int j_input_buffer_index = jni->CallIntMethod(
556 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700557 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznevae95ff32016-02-04 11:47:12 -0800558 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
559 ". Retry DeliverPendingOutputs.";
560 EnableFrameLogOnWarning();
561 // Try to drain the decoder.
562 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
563 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
564 frames_received_ << ". Frames decoded: " << frames_decoded_;
565 return ProcessHWErrorOnCodecThread();
566 }
567 // Try dequeue input buffer one last time.
568 j_input_buffer_index = jni->CallIntMethod(
569 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
570 if (CheckException(jni) || j_input_buffer_index < 0) {
571 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
572 return ProcessHWErrorOnCodecThread();
573 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000574 }
575
576 // Copy encoded data to Java ByteBuffer.
577 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200578 uint8_t* buffer =
579 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700580 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200581 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700582 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700583 ALOGE << "Input frame size "<< inputImage._length <<
584 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700585 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000586 }
glaznevae95ff32016-02-04 11:47:12 -0800587 jlong presentation_timestamp_us = static_cast<jlong>(
588 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000589 memcpy(buffer, inputImage._buffer, inputImage._length);
590
glaznevae95ff32016-02-04 11:47:12 -0800591 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800592 ALOGD << "Decoder frame in # " << frames_received_ <<
593 ". Type: " << inputImage._frameType <<
594 ". Buffer # " << j_input_buffer_index <<
glaznevae95ff32016-02-04 11:47:12 -0800595 ". TS: " << presentation_timestamp_us / 1000 <<
glaznev94291482016-02-01 13:17:18 -0800596 ". Size: " << inputImage._length;
597 }
598
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000599 // Save input image timestamps for later output.
600 frames_received_++;
601 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000602
603 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100604 bool success = jni->CallBooleanMethod(
605 *j_media_codec_video_decoder_,
606 j_queue_input_buffer_method_,
607 j_input_buffer_index,
608 inputImage._length,
609 presentation_timestamp_us,
610 static_cast<int64_t> (inputImage._timeStamp),
611 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700612 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700613 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700614 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000615 }
616
617 // Try to drain the decoder
618 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700619 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700620 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000621 }
622
623 return WEBRTC_VIDEO_CODEC_OK;
624}
625
626bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100627 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000628 if (frames_received_ <= frames_decoded_) {
629 // No need to query for output buffers - decoder is drained.
630 return true;
631 }
632 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100633 jobject j_decoder_output_buffer =
634 jni->CallObjectMethod(*j_media_codec_video_decoder_,
635 use_surface_ ? j_dequeue_texture_buffer_method_
636 : j_dequeue_byte_buffer_method_,
637 dequeue_timeout_ms);
638
Alex Glaznev782671f2015-06-12 16:40:44 -0700639 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700640 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700641 return false;
642 }
magjed44bf6f52015-10-03 02:08:00 -0700643 if (IsNull(jni, j_decoder_output_buffer)) {
644 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000645 return true;
646 }
647
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000648 // Get decoded video frame properties.
649 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
650 j_color_format_field_);
651 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
652 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
653 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
654 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
655 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000656
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200657 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
glaznev94291482016-02-01 13:17:18 -0800658 int64_t presentation_timestamps_ms = 0;
Per488e75f2015-11-19 10:43:36 +0100659 int64_t output_timestamps_ms = 0;
660 int64_t output_ntp_timestamps_ms = 0;
661 int decode_time_ms = 0;
662 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200663 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700664 // Extract data from Java DecodedTextureBuffer.
glaznevae95ff32016-02-04 11:47:12 -0800665 presentation_timestamps_ms = GetLongField(
666 jni, j_decoder_output_buffer,
667 j_texture_presentation_timestamp_ms_field_);
668 output_timestamps_ms = GetLongField(
669 jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
670 output_ntp_timestamps_ms = GetLongField(
671 jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
672 decode_time_ms = GetLongField(
673 jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
674
magjed44bf6f52015-10-03 02:08:00 -0700675 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100676 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
677 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
678 const jfloatArray j_transform_matrix =
679 reinterpret_cast<jfloatArray>(GetObjectField(
680 jni, j_decoder_output_buffer, j_transform_matrix_field_));
glaznev94291482016-02-01 13:17:18 -0800681 frame_delayed_ms = GetLongField(
682 jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100683
684 // Create webrtc::VideoFrameBuffer with native texture handle.
685 frame_buffer = surface_texture_helper_->CreateTextureFrame(
686 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
glaznevae95ff32016-02-04 11:47:12 -0800687 } else {
688 EnableFrameLogOnWarning();
Per488e75f2015-11-19 10:43:36 +0100689 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200690 } else {
691 // Extract data from Java ByteBuffer and create output yuv420 frame -
692 // for non surface decoding only.
glaznev94291482016-02-01 13:17:18 -0800693 const int output_buffer_index = GetIntField(
694 jni, j_decoder_output_buffer, j_info_index_field_);
695 const int output_buffer_offset = GetIntField(
696 jni, j_decoder_output_buffer, j_info_offset_field_);
697 const int output_buffer_size = GetIntField(
698 jni, j_decoder_output_buffer, j_info_size_field_);
699 presentation_timestamps_ms = GetLongField(
700 jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
701 output_timestamps_ms = GetLongField(
702 jni, j_decoder_output_buffer, j_timestamp_ms_field_);
703 output_ntp_timestamps_ms = GetLongField(
704 jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100705
706 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
707 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700708
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000709 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700710 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000711 return false;
712 }
713 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
714 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
715 jobject output_buffer =
716 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
717 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
718 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700719 if (CheckException(jni)) {
720 return false;
721 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000722 payload += output_buffer_offset;
723
724 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200725 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000726 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200727 RTC_CHECK_EQ(0, stride % 2);
728 RTC_CHECK_EQ(0, slice_height % 2);
729 const int uv_stride = stride / 2;
730 const int u_slice_height = slice_height / 2;
731 const uint8_t* y_ptr = payload;
732 const uint8_t* u_ptr = y_ptr + stride * slice_height;
733 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
734 libyuv::I420Copy(y_ptr, stride,
735 u_ptr, uv_stride,
736 v_ptr, uv_stride,
737 frame_buffer->MutableData(webrtc::kYPlane),
738 frame_buffer->stride(webrtc::kYPlane),
739 frame_buffer->MutableData(webrtc::kUPlane),
740 frame_buffer->stride(webrtc::kUPlane),
741 frame_buffer->MutableData(webrtc::kVPlane),
742 frame_buffer->stride(webrtc::kVPlane),
743 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000744 } else {
745 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200746 const uint8_t* y_ptr = payload;
747 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000748 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200749 y_ptr, stride,
750 uv_ptr, stride,
751 frame_buffer->MutableData(webrtc::kYPlane),
752 frame_buffer->stride(webrtc::kYPlane),
753 frame_buffer->MutableData(webrtc::kUPlane),
754 frame_buffer->stride(webrtc::kUPlane),
755 frame_buffer->MutableData(webrtc::kVPlane),
756 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000757 width, height);
758 }
magjed44bf6f52015-10-03 02:08:00 -0700759 // Return output byte buffer back to codec.
760 jni->CallVoidMethod(
761 *j_media_codec_video_decoder_,
762 j_return_decoded_byte_buffer_method_,
763 output_buffer_index);
764 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100765 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700766 return false;
767 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000768 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200769 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
Per488e75f2015-11-19 10:43:36 +0100770 decoded_frame.set_timestamp(output_timestamps_ms);
771 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000772
glaznevae95ff32016-02-04 11:47:12 -0800773 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800774 ALOGD << "Decoder frame out # " << frames_decoded_ <<
775 ". " << width << " x " << height <<
776 ". " << stride << " x " << slice_height <<
777 ". Color: " << color_format <<
778 ". TS: " << presentation_timestamps_ms <<
Per488e75f2015-11-19 10:43:36 +0100779 ". DecTime: " << (int)decode_time_ms <<
780 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700781 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000782
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000783 // Calculate and print decoding statistics - every 3 seconds.
784 frames_decoded_++;
785 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100786 current_decoding_time_ms_ += decode_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800787 current_delay_time_ms_ += frame_delayed_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000788 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
789 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
790 current_frames_ > 0) {
glaznev94291482016-02-01 13:17:18 -0800791 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
792 int current_fps =
793 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800794 ALOGD << "Frames decoded: " << frames_decoded_ <<
795 ". Received: " << frames_received_ <<
glaznev94291482016-02-01 13:17:18 -0800796 ". Bitrate: " << current_bitrate << " kbps" <<
797 ". Fps: " << current_fps <<
798 ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
glaznevfd6706a2016-02-05 14:05:08 -0800799 ". DelayTime: " << (current_delay_time_ms_ / current_frames_) <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700800 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000801 start_time_ms_ = GetCurrentTimeMs();
802 current_frames_ = 0;
803 current_bytes_ = 0;
804 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800805 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000806 }
807
Per488e75f2015-11-19 10:43:36 +0100808 // |.IsZeroSize())| returns true when a frame has been dropped.
809 if (!decoded_frame.IsZeroSize()) {
810 // Callback - output decoded frame.
811 const int32_t callback_status =
812 callback_->Decoded(decoded_frame, decode_time_ms);
813 if (callback_status > 0) {
814 ALOGE << "callback error";
815 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000816 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000817 return true;
818}
819
820int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
821 DecodedImageCallback* callback) {
822 callback_ = callback;
823 return WEBRTC_VIDEO_CODEC_OK;
824}
825
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000826void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
827 JNIEnv* jni = AttachCurrentThreadIfNeeded();
828 ScopedLocalRefFrame local_ref_frame(jni);
829 if (!inited_) {
830 return;
831 }
832 // We only ever send one message to |this| directly (not through a Bind()'d
833 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700834 RTC_CHECK(!msg->message_id) << "Unexpected message!";
835 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000836 CheckOnCodecThread();
837
838 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700839 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700840 ProcessHWErrorOnCodecThread();
841 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000842 }
843 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
844}
845
perkj461121c2016-02-15 06:28:36 -0800846MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory()
847 : egl_context_(nullptr) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700848 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000849 JNIEnv* jni = AttachCurrentThreadIfNeeded();
850 ScopedLocalRefFrame local_ref_frame(jni);
851 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000852 supported_codec_types_.clear();
853
854 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000855 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000856 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700857 if (CheckException(jni)) {
858 is_vp8_hw_supported = false;
859 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000860 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700861 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000862 supported_codec_types_.push_back(kVideoCodecVP8);
863 }
864
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800865 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
866 j_decoder_class,
867 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
868 if (CheckException(jni)) {
869 is_vp9_hw_supported = false;
870 }
871 if (is_vp9_hw_supported) {
872 ALOGD << "VP9 HW Decoder supported.";
873 supported_codec_types_.push_back(kVideoCodecVP9);
874 }
875
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000876 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
877 j_decoder_class,
878 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700879 if (CheckException(jni)) {
880 is_h264_hw_supported = false;
881 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000882 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700883 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000884 supported_codec_types_.push_back(kVideoCodecH264);
885 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000886}
887
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700888MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700889 ALOGD << "MediaCodecVideoDecoderFactory dtor";
perkj461121c2016-02-15 06:28:36 -0800890 if (egl_context_) {
891 JNIEnv* jni = AttachCurrentThreadIfNeeded();
892 jni->DeleteGlobalRef(egl_context_);
893 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700894}
895
896void MediaCodecVideoDecoderFactory::SetEGLContext(
perkj461121c2016-02-15 06:28:36 -0800897 JNIEnv* jni, jobject egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700898 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
perkj461121c2016-02-15 06:28:36 -0800899 RTC_DCHECK(!egl_context_);
900 egl_context_ = jni->NewGlobalRef(egl_context);
901 if (CheckException(jni)) {
902 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700903 }
904}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000905
906webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000907 VideoCodecType type) {
908 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800909 ALOGW << "No HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100910 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000911 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700912 for (VideoCodecType codec_type : supported_codec_types_) {
913 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700914 ALOGD << "Create HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100915 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
perkj461121c2016-02-15 06:28:36 -0800916 egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000917 }
918 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800919 ALOGW << "Can not find HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100920 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000921}
922
923void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
924 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700925 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000926 delete decoder;
927}
928
Peter Boströmb7d9a972015-12-18 16:01:11 +0100929const char* MediaCodecVideoDecoder::ImplementationName() const {
930 return "MediaCodec";
931}
932
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000933} // namespace webrtc_jni
934