blob: b9973be01e2e1bf266594c991083efd8c2cd211b [file] [log] [blame]
glaznev@webrtc.org18c92472015-02-18 18:42:55 +00001/*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
magjed6d387c02015-10-14 04:02:01 -070029#include <algorithm>
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000030#include <vector>
31
kjellandera96e2d72016-02-04 23:52:28 -080032// NOTICE: androidmediadecoder_jni.h must be included before
33// androidmediacodeccommon.h to avoid build errors.
Henrik Kjellander15583c12016-02-10 10:53:12 +010034#include "webrtc/api/java/jni/androidmediadecoder_jni.h"
35
kjellandera96e2d72016-02-04 23:52:28 -080036#include "third_party/libyuv/include/libyuv/convert.h"
37#include "third_party/libyuv/include/libyuv/convert_from.h"
38#include "third_party/libyuv/include/libyuv/video_common.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010039#include "webrtc/api/java/jni/androidmediacodeccommon.h"
40#include "webrtc/api/java/jni/classreferenceholder.h"
41#include "webrtc/api/java/jni/native_handle_impl.h"
42#include "webrtc/api/java/jni/surfacetexturehelper_jni.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000043#include "webrtc/base/bind.h"
44#include "webrtc/base/checks.h"
45#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020046#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000047#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020048#include "webrtc/base/timeutils.h"
kjellander6f8ce062015-11-16 13:52:24 -080049#include "webrtc/common_video/include/i420_buffer_pool.h"
perkj87d58452015-11-23 01:46:27 -080050#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010051#include "webrtc/system_wrappers/include/logcat_trace_context.h"
52#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000053
54using rtc::Bind;
55using rtc::Thread;
56using rtc::ThreadManager;
57using rtc::scoped_ptr;
58
59using webrtc::CodecSpecificInfo;
60using webrtc::DecodedImageCallback;
61using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070062using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000063using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000064using webrtc::TickTime;
65using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000066using webrtc::VideoCodecType;
67using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000068using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080069using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000070
71namespace webrtc_jni {
72
glaznevf4decb52016-01-15 13:49:22 -080073// Logging macros.
74#define TAG_DECODER "MediaCodecVideoDecoder"
75#ifdef TRACK_BUFFER_TIMING
76#define ALOGV(...)
77 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
78#else
79#define ALOGV(...)
80#endif
81#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
82#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
83#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
84
glaznevae95ff32016-02-04 11:47:12 -080085enum { kMaxWarningLogFrames = 2 };
86
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000087class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
88 public rtc::MessageHandler {
89 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070090 explicit MediaCodecVideoDecoder(
91 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000092 virtual ~MediaCodecVideoDecoder();
93
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000094 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
95 override;
96
97 int32_t Decode(
98 const EncodedImage& inputImage, bool missingFrames,
99 const RTPFragmentationHeader* fragmentation,
100 const CodecSpecificInfo* codecSpecificInfo = NULL,
101 int64_t renderTimeMs = -1) override;
102
103 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
104 override;
105
106 int32_t Release() override;
107
perkj796cfaf2015-12-10 09:27:38 -0800108 bool PrefersLateDecoding() const override { return true; }
109
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000110 // rtc::MessageHandler implementation.
111 void OnMessage(rtc::Message* msg) override;
112
Peter Boströmb7d9a972015-12-18 16:01:11 +0100113 const char* ImplementationName() const override;
114
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000115 private:
116 // CHECK-fail if not running on |codec_thread_|.
117 void CheckOnCodecThread();
118
119 int32_t InitDecodeOnCodecThread();
120 int32_t ReleaseOnCodecThread();
121 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
122 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
123 // true on success.
124 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700125 int32_t ProcessHWErrorOnCodecThread();
glaznevae95ff32016-02-04 11:47:12 -0800126 void EnableFrameLogOnWarning();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000127
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000128 // Type of video codec.
129 VideoCodecType codecType_;
130
kjellander60ca31b2016-01-04 10:15:53 -0800131 // Render EGL context - owned by factory, should not be allocated/destroyed
132 // by VideoDecoder.
133 jobject render_egl_context_;
134
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000135 bool key_frame_required_;
136 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700137 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000138 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000139 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200140 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100141 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000142 DecodedImageCallback* callback_;
143 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000144 int frames_decoded_; // Number of frames decoded by decoder.
glaznevae95ff32016-02-04 11:47:12 -0800145 // Number of decoded frames for which log information is displayed.
146 int frames_decoded_logged_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000147 int64_t start_time_ms_; // Start time for statistics.
148 int current_frames_; // Number of frames in the current statistics interval.
149 int current_bytes_; // Encoded bytes in the current statistics interval.
150 int current_decoding_time_ms_; // Overall decoding time in the current second
glaznevfd6706a2016-02-05 14:05:08 -0800151 int current_delay_time_ms_; // Overall delay time in the current second.
152 uint32_t max_pending_frames_; // Maximum number of pending input frames.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000153
154 // State that is constant for the lifetime of this object once the ctor
155 // returns.
156 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
157 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
158 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
159 jmethodID j_init_decode_method_;
160 jmethodID j_release_method_;
161 jmethodID j_dequeue_input_buffer_method_;
162 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100163 jmethodID j_dequeue_byte_buffer_method_;
164 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700165 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000166 // MediaCodecVideoDecoder fields.
167 jfieldID j_input_buffers_field_;
168 jfieldID j_output_buffers_field_;
169 jfieldID j_color_format_field_;
170 jfieldID j_width_field_;
171 jfieldID j_height_field_;
172 jfieldID j_stride_field_;
173 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700174 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100175 jfieldID j_texture_id_field_;
176 jfieldID j_transform_matrix_field_;
glaznev94291482016-02-01 13:17:18 -0800177 jfieldID j_texture_presentation_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100178 jfieldID j_texture_timestamp_ms_field_;
179 jfieldID j_texture_ntp_timestamp_ms_field_;
180 jfieldID j_texture_decode_time_ms_field_;
181 jfieldID j_texture_frame_delay_ms_field_;
182 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000183 jfieldID j_info_index_field_;
184 jfieldID j_info_offset_field_;
185 jfieldID j_info_size_field_;
glaznev94291482016-02-01 13:17:18 -0800186 jfieldID j_presentation_timestamp_ms_field_;
187 jfieldID j_timestamp_ms_field_;
188 jfieldID j_ntp_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100189 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000190
191 // Global references; must be deleted in Release().
192 std::vector<jobject> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000193};
194
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000195MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700196 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000197 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700198 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000199 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000200 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700201 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000202 codec_thread_(new Thread()),
203 j_media_codec_video_decoder_class_(
204 jni,
205 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
206 j_media_codec_video_decoder_(
207 jni,
208 jni->NewObject(*j_media_codec_video_decoder_class_,
209 GetMethodID(jni,
210 *j_media_codec_video_decoder_class_,
211 "<init>",
212 "()V"))) {
213 ScopedLocalRefFrame local_ref_frame(jni);
214 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700215 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000216
217 j_init_decode_method_ = GetMethodID(
218 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000219 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100220 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000221 j_release_method_ =
222 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
223 j_dequeue_input_buffer_method_ = GetMethodID(
224 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
225 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100226 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
227 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000228 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100229 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
230 j_dequeue_texture_buffer_method_ = GetMethodID(
231 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
232 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700233 j_return_decoded_byte_buffer_method_ =
234 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100235 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000236
237 j_input_buffers_field_ = GetFieldID(
238 jni, *j_media_codec_video_decoder_class_,
239 "inputBuffers", "[Ljava/nio/ByteBuffer;");
240 j_output_buffers_field_ = GetFieldID(
241 jni, *j_media_codec_video_decoder_class_,
242 "outputBuffers", "[Ljava/nio/ByteBuffer;");
243 j_color_format_field_ = GetFieldID(
244 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
245 j_width_field_ = GetFieldID(
246 jni, *j_media_codec_video_decoder_class_, "width", "I");
247 j_height_field_ = GetFieldID(
248 jni, *j_media_codec_video_decoder_class_, "height", "I");
249 j_stride_field_ = GetFieldID(
250 jni, *j_media_codec_video_decoder_class_, "stride", "I");
251 j_slice_height_field_ = GetFieldID(
252 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000253
Per488e75f2015-11-19 10:43:36 +0100254 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700255 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100256 j_texture_id_field_ = GetFieldID(
257 jni, j_decoded_texture_buffer_class, "textureID", "I");
258 j_transform_matrix_field_ = GetFieldID(
259 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
glaznev94291482016-02-01 13:17:18 -0800260 j_texture_presentation_timestamp_ms_field_ = GetFieldID(
261 jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
Per488e75f2015-11-19 10:43:36 +0100262 j_texture_timestamp_ms_field_ = GetFieldID(
263 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
264 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
265 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
266 j_texture_decode_time_ms_field_ = GetFieldID(
267 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
268 j_texture_frame_delay_ms_field_ = GetFieldID(
269 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700270
Per488e75f2015-11-19 10:43:36 +0100271 jclass j_decoded_output_buffer_class = FindClass(jni,
272 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000273 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100274 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000275 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100276 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000277 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100278 jni, j_decoded_output_buffer_class, "size", "I");
glaznev94291482016-02-01 13:17:18 -0800279 j_presentation_timestamp_ms_field_ = GetFieldID(
280 jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
281 j_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100282 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
glaznev94291482016-02-01 13:17:18 -0800283 j_ntp_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100284 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
285 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
286 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000287
288 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200289 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700290 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000291 memset(&codec_, 0, sizeof(codec_));
292 AllowBlockingCalls();
293}
294
295MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
296 // Call Release() to ensure no more callbacks to us after we are deleted.
297 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000298}
299
300int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
301 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700302 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000303 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700304 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000305 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
306 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000307 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700308 RTC_CHECK(inst->codecType == codecType_)
309 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000310
Alex Glaznev782671f2015-06-12 16:40:44 -0700311 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700312 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700313 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000314 }
315 // Save VideoCodec instance for later.
316 if (&codec_ != inst) {
317 codec_ = *inst;
318 }
glazneve55c42c2015-10-28 10:30:32 -0700319 // If maxFramerate is not set then assume 30 fps.
320 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000321
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000322 // Call Java init.
323 return codec_thread_->Invoke<int32_t>(
324 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
325}
326
327int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
328 CheckOnCodecThread();
329 JNIEnv* jni = AttachCurrentThreadIfNeeded();
330 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700331 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
332 << codec_.width << " x " << codec_.height << ". Fps: " <<
333 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700334
335 // Release previous codec first if it was allocated before.
336 int ret_val = ReleaseOnCodecThread();
337 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700338 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700339 sw_fallback_required_ = true;
340 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000341 }
342
Alex Glaznev782671f2015-06-12 16:40:44 -0700343 // Always start with a complete key frame.
344 key_frame_required_ = true;
345 frames_received_ = 0;
346 frames_decoded_ = 0;
glaznevae95ff32016-02-04 11:47:12 -0800347 frames_decoded_logged_ = kMaxDecodedLogFrames;
Alex Glaznev782671f2015-06-12 16:40:44 -0700348
perkj88518a22015-12-18 00:37:06 -0800349 jobject java_surface_texture_helper_ = nullptr;
Per488e75f2015-11-19 10:43:36 +0100350 if (use_surface_) {
perkj88518a22015-12-18 00:37:06 -0800351 java_surface_texture_helper_ = jni->CallStaticObjectMethod(
352 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
353 GetStaticMethodID(jni,
354 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
355 "create",
356 "(Lorg/webrtc/EglBase$Context;)"
357 "Lorg/webrtc/SurfaceTextureHelper;"),
358 render_egl_context_);
359 RTC_CHECK(java_surface_texture_helper_ != nullptr);
Per488e75f2015-11-19 10:43:36 +0100360 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
perkj88518a22015-12-18 00:37:06 -0800361 jni, java_surface_texture_helper_);
Per488e75f2015-11-19 10:43:36 +0100362 }
363
Perec2922f2016-01-27 15:25:46 +0100364 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000365 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000366 bool success = jni->CallBooleanMethod(
367 *j_media_codec_video_decoder_,
368 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000369 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000370 codec_.width,
371 codec_.height,
perkj88518a22015-12-18 00:37:06 -0800372 java_surface_texture_helper_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700373 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700374 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700375 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000376 return WEBRTC_VIDEO_CODEC_ERROR;
377 }
378 inited_ = true;
379
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000380 switch (codecType_) {
381 case kVideoCodecVP8:
382 max_pending_frames_ = kMaxPendingFramesVp8;
383 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800384 case kVideoCodecVP9:
385 max_pending_frames_ = kMaxPendingFramesVp9;
386 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000387 case kVideoCodecH264:
388 max_pending_frames_ = kMaxPendingFramesH264;
389 break;
390 default:
391 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000392 }
393 start_time_ms_ = GetCurrentTimeMs();
394 current_frames_ = 0;
395 current_bytes_ = 0;
396 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800397 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000398
399 jobjectArray input_buffers = (jobjectArray)GetObjectField(
400 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
401 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700402 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000403 input_buffers_.resize(num_input_buffers);
404 for (size_t i = 0; i < num_input_buffers; ++i) {
405 input_buffers_[i] =
406 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700407 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700408 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700409 sw_fallback_required_ = true;
410 return WEBRTC_VIDEO_CODEC_ERROR;
411 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000412 }
413
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000414 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
415
416 return WEBRTC_VIDEO_CODEC_OK;
417}
418
419int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700420 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000421 return codec_thread_->Invoke<int32_t>(
422 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
423}
424
425int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
426 if (!inited_) {
427 return WEBRTC_VIDEO_CODEC_OK;
428 }
429 CheckOnCodecThread();
430 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700431 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
432 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000433 ScopedLocalRefFrame local_ref_frame(jni);
434 for (size_t i = 0; i < input_buffers_.size(); i++) {
435 jni->DeleteGlobalRef(input_buffers_[i]);
436 }
437 input_buffers_.clear();
438 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100439 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000440 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700441 rtc::MessageQueueManager::Clear(this);
442 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700443 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700444 return WEBRTC_VIDEO_CODEC_ERROR;
445 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700446 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000447 return WEBRTC_VIDEO_CODEC_OK;
448}
449
450void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700451 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000452 << "Running on wrong thread!";
453}
454
glaznevae95ff32016-02-04 11:47:12 -0800455void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
456 // Log next 2 output frames.
457 frames_decoded_logged_ = std::max(
458 frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
459}
460
Alex Glaznev782671f2015-06-12 16:40:44 -0700461int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
462 CheckOnCodecThread();
463 int ret_val = ReleaseOnCodecThread();
464 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700465 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700466 }
467 if (codecType_ == kVideoCodecH264) {
468 // For now there is no SW H.264 which can be used as fallback codec.
469 // So try to restart hw codec for now.
470 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700471 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700472 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
473 // H.264 codec was succesfully reset - return regular error code.
474 return WEBRTC_VIDEO_CODEC_ERROR;
475 } else {
476 // Fail to restart H.264 codec - return error code which should stop the
477 // call.
478 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
479 }
480 } else {
481 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700482 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700483 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
484 }
485}
486
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000487int32_t MediaCodecVideoDecoder::Decode(
488 const EncodedImage& inputImage,
489 bool missingFrames,
490 const RTPFragmentationHeader* fragmentation,
491 const CodecSpecificInfo* codecSpecificInfo,
492 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700493 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700494 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700495 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000496 }
497 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700498 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000499 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
500 }
501 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700502 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000503 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
504 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700505 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700506 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700507 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
508 }
509
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000510 // Check if encoded frame dimension has changed.
511 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
512 (inputImage._encodedWidth != codec_.width ||
513 inputImage._encodedHeight != codec_.height)) {
514 codec_.width = inputImage._encodedWidth;
515 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700516 int32_t ret = InitDecode(&codec_, 1);
517 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700518 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700519 sw_fallback_required_ = true;
520 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
521 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000522 }
523
524 // Always start with a complete key frame.
525 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200526 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700527 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000528 return WEBRTC_VIDEO_CODEC_ERROR;
529 }
530 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700531 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000532 return WEBRTC_VIDEO_CODEC_ERROR;
533 }
534 key_frame_required_ = false;
535 }
536 if (inputImage._length == 0) {
537 return WEBRTC_VIDEO_CODEC_ERROR;
538 }
539
540 return codec_thread_->Invoke<int32_t>(Bind(
541 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
542}
543
544int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
545 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000546 CheckOnCodecThread();
547 JNIEnv* jni = AttachCurrentThreadIfNeeded();
548 ScopedLocalRefFrame local_ref_frame(jni);
549
550 // Try to drain the decoder and wait until output is not too
551 // much behind the input.
glaznevae95ff32016-02-04 11:47:12 -0800552 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
553 ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
554 frames_received_ << ". Decoded: " << frames_decoded_;
555 EnableFrameLogOnWarning();
556 }
Per488e75f2015-11-19 10:43:36 +0100557 const int64 drain_start = GetCurrentTimeMs();
558 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
559 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
Per488e75f2015-11-19 10:43:36 +0100560 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700561 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
562 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700563 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000564 }
Per488e75f2015-11-19 10:43:36 +0100565 }
566 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
567 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
568 frames_received_ << ". Frames decoded: " << frames_decoded_;
569 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000570 }
571
572 // Get input buffer.
glaznevae95ff32016-02-04 11:47:12 -0800573 int j_input_buffer_index = jni->CallIntMethod(
574 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700575 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznevae95ff32016-02-04 11:47:12 -0800576 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
577 ". Retry DeliverPendingOutputs.";
578 EnableFrameLogOnWarning();
579 // Try to drain the decoder.
580 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
581 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
582 frames_received_ << ". Frames decoded: " << frames_decoded_;
583 return ProcessHWErrorOnCodecThread();
584 }
585 // Try dequeue input buffer one last time.
586 j_input_buffer_index = jni->CallIntMethod(
587 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
588 if (CheckException(jni) || j_input_buffer_index < 0) {
589 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
590 return ProcessHWErrorOnCodecThread();
591 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000592 }
593
594 // Copy encoded data to Java ByteBuffer.
595 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200596 uint8_t* buffer =
597 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700598 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200599 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700600 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700601 ALOGE << "Input frame size "<< inputImage._length <<
602 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700603 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000604 }
glaznevae95ff32016-02-04 11:47:12 -0800605 jlong presentation_timestamp_us = static_cast<jlong>(
606 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000607 memcpy(buffer, inputImage._buffer, inputImage._length);
608
glaznevae95ff32016-02-04 11:47:12 -0800609 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800610 ALOGD << "Decoder frame in # " << frames_received_ <<
611 ". Type: " << inputImage._frameType <<
612 ". Buffer # " << j_input_buffer_index <<
glaznevae95ff32016-02-04 11:47:12 -0800613 ". TS: " << presentation_timestamp_us / 1000 <<
glaznev94291482016-02-01 13:17:18 -0800614 ". Size: " << inputImage._length;
615 }
616
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000617 // Save input image timestamps for later output.
618 frames_received_++;
619 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000620
621 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100622 bool success = jni->CallBooleanMethod(
623 *j_media_codec_video_decoder_,
624 j_queue_input_buffer_method_,
625 j_input_buffer_index,
626 inputImage._length,
627 presentation_timestamp_us,
628 static_cast<int64_t> (inputImage._timeStamp),
629 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700630 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700631 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700632 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000633 }
634
635 // Try to drain the decoder
636 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700637 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700638 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000639 }
640
641 return WEBRTC_VIDEO_CODEC_OK;
642}
643
644bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100645 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000646 if (frames_received_ <= frames_decoded_) {
647 // No need to query for output buffers - decoder is drained.
648 return true;
649 }
650 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100651 jobject j_decoder_output_buffer =
652 jni->CallObjectMethod(*j_media_codec_video_decoder_,
653 use_surface_ ? j_dequeue_texture_buffer_method_
654 : j_dequeue_byte_buffer_method_,
655 dequeue_timeout_ms);
656
Alex Glaznev782671f2015-06-12 16:40:44 -0700657 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700658 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700659 return false;
660 }
magjed44bf6f52015-10-03 02:08:00 -0700661 if (IsNull(jni, j_decoder_output_buffer)) {
662 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000663 return true;
664 }
665
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000666 // Get decoded video frame properties.
667 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
668 j_color_format_field_);
669 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
670 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
671 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
672 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
673 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000674
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200675 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
glaznev94291482016-02-01 13:17:18 -0800676 int64_t presentation_timestamps_ms = 0;
Per488e75f2015-11-19 10:43:36 +0100677 int64_t output_timestamps_ms = 0;
678 int64_t output_ntp_timestamps_ms = 0;
679 int decode_time_ms = 0;
680 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200681 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700682 // Extract data from Java DecodedTextureBuffer.
glaznevae95ff32016-02-04 11:47:12 -0800683 presentation_timestamps_ms = GetLongField(
684 jni, j_decoder_output_buffer,
685 j_texture_presentation_timestamp_ms_field_);
686 output_timestamps_ms = GetLongField(
687 jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
688 output_ntp_timestamps_ms = GetLongField(
689 jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
690 decode_time_ms = GetLongField(
691 jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
692
magjed44bf6f52015-10-03 02:08:00 -0700693 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100694 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
695 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
696 const jfloatArray j_transform_matrix =
697 reinterpret_cast<jfloatArray>(GetObjectField(
698 jni, j_decoder_output_buffer, j_transform_matrix_field_));
glaznev94291482016-02-01 13:17:18 -0800699 frame_delayed_ms = GetLongField(
700 jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100701
702 // Create webrtc::VideoFrameBuffer with native texture handle.
703 frame_buffer = surface_texture_helper_->CreateTextureFrame(
704 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
glaznevae95ff32016-02-04 11:47:12 -0800705 } else {
706 EnableFrameLogOnWarning();
Per488e75f2015-11-19 10:43:36 +0100707 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200708 } else {
709 // Extract data from Java ByteBuffer and create output yuv420 frame -
710 // for non surface decoding only.
glaznev94291482016-02-01 13:17:18 -0800711 const int output_buffer_index = GetIntField(
712 jni, j_decoder_output_buffer, j_info_index_field_);
713 const int output_buffer_offset = GetIntField(
714 jni, j_decoder_output_buffer, j_info_offset_field_);
715 const int output_buffer_size = GetIntField(
716 jni, j_decoder_output_buffer, j_info_size_field_);
717 presentation_timestamps_ms = GetLongField(
718 jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
719 output_timestamps_ms = GetLongField(
720 jni, j_decoder_output_buffer, j_timestamp_ms_field_);
721 output_ntp_timestamps_ms = GetLongField(
722 jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100723
724 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
725 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700726
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000727 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700728 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000729 return false;
730 }
731 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
732 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
733 jobject output_buffer =
734 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
735 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
736 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700737 if (CheckException(jni)) {
738 return false;
739 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000740 payload += output_buffer_offset;
741
742 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200743 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000744 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200745 RTC_CHECK_EQ(0, stride % 2);
746 RTC_CHECK_EQ(0, slice_height % 2);
747 const int uv_stride = stride / 2;
748 const int u_slice_height = slice_height / 2;
749 const uint8_t* y_ptr = payload;
750 const uint8_t* u_ptr = y_ptr + stride * slice_height;
751 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
752 libyuv::I420Copy(y_ptr, stride,
753 u_ptr, uv_stride,
754 v_ptr, uv_stride,
755 frame_buffer->MutableData(webrtc::kYPlane),
756 frame_buffer->stride(webrtc::kYPlane),
757 frame_buffer->MutableData(webrtc::kUPlane),
758 frame_buffer->stride(webrtc::kUPlane),
759 frame_buffer->MutableData(webrtc::kVPlane),
760 frame_buffer->stride(webrtc::kVPlane),
761 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000762 } else {
763 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200764 const uint8_t* y_ptr = payload;
765 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000766 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200767 y_ptr, stride,
768 uv_ptr, stride,
769 frame_buffer->MutableData(webrtc::kYPlane),
770 frame_buffer->stride(webrtc::kYPlane),
771 frame_buffer->MutableData(webrtc::kUPlane),
772 frame_buffer->stride(webrtc::kUPlane),
773 frame_buffer->MutableData(webrtc::kVPlane),
774 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000775 width, height);
776 }
magjed44bf6f52015-10-03 02:08:00 -0700777 // Return output byte buffer back to codec.
778 jni->CallVoidMethod(
779 *j_media_codec_video_decoder_,
780 j_return_decoded_byte_buffer_method_,
781 output_buffer_index);
782 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100783 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700784 return false;
785 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000786 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200787 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
Per488e75f2015-11-19 10:43:36 +0100788 decoded_frame.set_timestamp(output_timestamps_ms);
789 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000790
glaznevae95ff32016-02-04 11:47:12 -0800791 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800792 ALOGD << "Decoder frame out # " << frames_decoded_ <<
793 ". " << width << " x " << height <<
794 ". " << stride << " x " << slice_height <<
795 ". Color: " << color_format <<
796 ". TS: " << presentation_timestamps_ms <<
Per488e75f2015-11-19 10:43:36 +0100797 ". DecTime: " << (int)decode_time_ms <<
798 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700799 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000800
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000801 // Calculate and print decoding statistics - every 3 seconds.
802 frames_decoded_++;
803 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100804 current_decoding_time_ms_ += decode_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800805 current_delay_time_ms_ += frame_delayed_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000806 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
807 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
808 current_frames_ > 0) {
glaznev94291482016-02-01 13:17:18 -0800809 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
810 int current_fps =
811 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800812 ALOGD << "Frames decoded: " << frames_decoded_ <<
813 ". Received: " << frames_received_ <<
glaznev94291482016-02-01 13:17:18 -0800814 ". Bitrate: " << current_bitrate << " kbps" <<
815 ". Fps: " << current_fps <<
816 ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
glaznevfd6706a2016-02-05 14:05:08 -0800817 ". DelayTime: " << (current_delay_time_ms_ / current_frames_) <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700818 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000819 start_time_ms_ = GetCurrentTimeMs();
820 current_frames_ = 0;
821 current_bytes_ = 0;
822 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800823 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000824 }
825
Per488e75f2015-11-19 10:43:36 +0100826 // |.IsZeroSize())| returns true when a frame has been dropped.
827 if (!decoded_frame.IsZeroSize()) {
828 // Callback - output decoded frame.
829 const int32_t callback_status =
830 callback_->Decoded(decoded_frame, decode_time_ms);
831 if (callback_status > 0) {
832 ALOGE << "callback error";
833 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000834 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000835 return true;
836}
837
838int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
839 DecodedImageCallback* callback) {
840 callback_ = callback;
841 return WEBRTC_VIDEO_CODEC_OK;
842}
843
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000844void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
845 JNIEnv* jni = AttachCurrentThreadIfNeeded();
846 ScopedLocalRefFrame local_ref_frame(jni);
847 if (!inited_) {
848 return;
849 }
850 // We only ever send one message to |this| directly (not through a Bind()'d
851 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700852 RTC_CHECK(!msg->message_id) << "Unexpected message!";
853 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000854 CheckOnCodecThread();
855
856 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700857 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700858 ProcessHWErrorOnCodecThread();
859 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000860 }
861 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
862}
863
Perec2922f2016-01-27 15:25:46 +0100864MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700865 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000866 JNIEnv* jni = AttachCurrentThreadIfNeeded();
867 ScopedLocalRefFrame local_ref_frame(jni);
868 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000869 supported_codec_types_.clear();
870
871 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000872 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000873 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700874 if (CheckException(jni)) {
875 is_vp8_hw_supported = false;
876 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000877 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700878 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000879 supported_codec_types_.push_back(kVideoCodecVP8);
880 }
881
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800882 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
883 j_decoder_class,
884 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
885 if (CheckException(jni)) {
886 is_vp9_hw_supported = false;
887 }
888 if (is_vp9_hw_supported) {
889 ALOGD << "VP9 HW Decoder supported.";
890 supported_codec_types_.push_back(kVideoCodecVP9);
891 }
892
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000893 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
894 j_decoder_class,
895 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700896 if (CheckException(jni)) {
897 is_h264_hw_supported = false;
898 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000899 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700900 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000901 supported_codec_types_.push_back(kVideoCodecH264);
902 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000903}
904
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700905MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700906 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700907}
908
909void MediaCodecVideoDecoderFactory::SetEGLContext(
910 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700911 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Perec2922f2016-01-27 15:25:46 +0100912 if (!egl_.CreateEglBase(jni, render_egl_context)) {
913 ALOGW << "Invalid EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700914 }
915}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000916
917webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000918 VideoCodecType type) {
919 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800920 ALOGW << "No HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100921 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000922 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700923 for (VideoCodecType codec_type : supported_codec_types_) {
924 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700925 ALOGD << "Create HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100926 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
927 egl_.egl_base_context());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000928 }
929 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800930 ALOGW << "Can not find HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100931 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000932}
933
934void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
935 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700936 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000937 delete decoder;
938}
939
Peter Boströmb7d9a972015-12-18 16:01:11 +0100940const char* MediaCodecVideoDecoder::ImplementationName() const {
941 return "MediaCodec";
942}
943
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000944} // namespace webrtc_jni
945