blob: a0e5579c37c32aea84ba74293b4a8a5d6bec1ab4 [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>
kwibergd1fe2812016-04-27 06:47:29 -070012#include <memory>
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000013#include <vector>
14
kjellandera96e2d72016-02-04 23:52:28 -080015// NOTICE: androidmediadecoder_jni.h must be included before
16// androidmediacodeccommon.h to avoid build errors.
Henrik Kjellander15583c12016-02-10 10:53:12 +010017#include "webrtc/api/java/jni/androidmediadecoder_jni.h"
18
kjellandera96e2d72016-02-04 23:52:28 -080019#include "third_party/libyuv/include/libyuv/convert.h"
20#include "third_party/libyuv/include/libyuv/convert_from.h"
21#include "third_party/libyuv/include/libyuv/video_common.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010022#include "webrtc/api/java/jni/androidmediacodeccommon.h"
23#include "webrtc/api/java/jni/classreferenceholder.h"
24#include "webrtc/api/java/jni/native_handle_impl.h"
25#include "webrtc/api/java/jni/surfacetexturehelper_jni.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000026#include "webrtc/base/bind.h"
27#include "webrtc/base/checks.h"
28#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020029#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000030#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020031#include "webrtc/base/timeutils.h"
kjellander6f8ce062015-11-16 13:52:24 -080032#include "webrtc/common_video/include/i420_buffer_pool.h"
perkj87d58452015-11-23 01:46:27 -080033#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010034#include "webrtc/system_wrappers/include/logcat_trace_context.h"
35#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000036
37using rtc::Bind;
38using rtc::Thread;
39using rtc::ThreadManager;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000040
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();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800102 int32_t ResetDecodeOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000103 int32_t ReleaseOnCodecThread();
104 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
105 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
106 // true on success.
107 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700108 int32_t ProcessHWErrorOnCodecThread();
glaznevae95ff32016-02-04 11:47:12 -0800109 void EnableFrameLogOnWarning();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800110 void ResetVariables();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000111
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000112 // Type of video codec.
113 VideoCodecType codecType_;
114
kjellander60ca31b2016-01-04 10:15:53 -0800115 // Render EGL context - owned by factory, should not be allocated/destroyed
116 // by VideoDecoder.
117 jobject render_egl_context_;
118
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000119 bool key_frame_required_;
120 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700121 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000122 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000123 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200124 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100125 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000126 DecodedImageCallback* callback_;
127 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000128 int frames_decoded_; // Number of frames decoded by decoder.
glaznevae95ff32016-02-04 11:47:12 -0800129 // Number of decoded frames for which log information is displayed.
130 int frames_decoded_logged_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000131 int64_t start_time_ms_; // Start time for statistics.
132 int current_frames_; // Number of frames in the current statistics interval.
133 int current_bytes_; // Encoded bytes in the current statistics interval.
134 int current_decoding_time_ms_; // Overall decoding time in the current second
glaznevfd6706a2016-02-05 14:05:08 -0800135 int current_delay_time_ms_; // Overall delay time in the current second.
136 uint32_t max_pending_frames_; // Maximum number of pending input frames.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000137
138 // State that is constant for the lifetime of this object once the ctor
139 // returns.
kwibergd1fe2812016-04-27 06:47:29 -0700140 std::unique_ptr<Thread>
141 codec_thread_; // Thread on which to operate MediaCodec.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000142 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
143 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
144 jmethodID j_init_decode_method_;
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800145 jmethodID j_reset_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000146 jmethodID j_release_method_;
147 jmethodID j_dequeue_input_buffer_method_;
148 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100149 jmethodID j_dequeue_byte_buffer_method_;
150 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700151 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000152 // MediaCodecVideoDecoder fields.
153 jfieldID j_input_buffers_field_;
154 jfieldID j_output_buffers_field_;
155 jfieldID j_color_format_field_;
156 jfieldID j_width_field_;
157 jfieldID j_height_field_;
158 jfieldID j_stride_field_;
159 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700160 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100161 jfieldID j_texture_id_field_;
162 jfieldID j_transform_matrix_field_;
glaznev94291482016-02-01 13:17:18 -0800163 jfieldID j_texture_presentation_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100164 jfieldID j_texture_timestamp_ms_field_;
165 jfieldID j_texture_ntp_timestamp_ms_field_;
166 jfieldID j_texture_decode_time_ms_field_;
167 jfieldID j_texture_frame_delay_ms_field_;
168 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000169 jfieldID j_info_index_field_;
170 jfieldID j_info_offset_field_;
171 jfieldID j_info_size_field_;
glaznev94291482016-02-01 13:17:18 -0800172 jfieldID j_presentation_timestamp_ms_field_;
173 jfieldID j_timestamp_ms_field_;
174 jfieldID j_ntp_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100175 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000176
177 // Global references; must be deleted in Release().
178 std::vector<jobject> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000179};
180
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000181MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700182 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000183 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700184 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000185 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000186 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700187 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000188 codec_thread_(new Thread()),
189 j_media_codec_video_decoder_class_(
190 jni,
191 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
192 j_media_codec_video_decoder_(
193 jni,
194 jni->NewObject(*j_media_codec_video_decoder_class_,
195 GetMethodID(jni,
196 *j_media_codec_video_decoder_class_,
197 "<init>",
198 "()V"))) {
199 ScopedLocalRefFrame local_ref_frame(jni);
200 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700201 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000202
203 j_init_decode_method_ = GetMethodID(
204 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000205 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100206 "IILorg/webrtc/SurfaceTextureHelper;)Z");
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800207 j_reset_method_ =
208 GetMethodID(jni, *j_media_codec_video_decoder_class_, "reset", "(II)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000209 j_release_method_ =
210 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
211 j_dequeue_input_buffer_method_ = GetMethodID(
212 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
213 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100214 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
215 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000216 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100217 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
218 j_dequeue_texture_buffer_method_ = GetMethodID(
219 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
220 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700221 j_return_decoded_byte_buffer_method_ =
222 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100223 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000224
225 j_input_buffers_field_ = GetFieldID(
226 jni, *j_media_codec_video_decoder_class_,
227 "inputBuffers", "[Ljava/nio/ByteBuffer;");
228 j_output_buffers_field_ = GetFieldID(
229 jni, *j_media_codec_video_decoder_class_,
230 "outputBuffers", "[Ljava/nio/ByteBuffer;");
231 j_color_format_field_ = GetFieldID(
232 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
233 j_width_field_ = GetFieldID(
234 jni, *j_media_codec_video_decoder_class_, "width", "I");
235 j_height_field_ = GetFieldID(
236 jni, *j_media_codec_video_decoder_class_, "height", "I");
237 j_stride_field_ = GetFieldID(
238 jni, *j_media_codec_video_decoder_class_, "stride", "I");
239 j_slice_height_field_ = GetFieldID(
240 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000241
Per488e75f2015-11-19 10:43:36 +0100242 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700243 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100244 j_texture_id_field_ = GetFieldID(
245 jni, j_decoded_texture_buffer_class, "textureID", "I");
246 j_transform_matrix_field_ = GetFieldID(
247 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
glaznev94291482016-02-01 13:17:18 -0800248 j_texture_presentation_timestamp_ms_field_ = GetFieldID(
249 jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
Per488e75f2015-11-19 10:43:36 +0100250 j_texture_timestamp_ms_field_ = GetFieldID(
251 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
252 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
253 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
254 j_texture_decode_time_ms_field_ = GetFieldID(
255 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
256 j_texture_frame_delay_ms_field_ = GetFieldID(
257 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700258
Per488e75f2015-11-19 10:43:36 +0100259 jclass j_decoded_output_buffer_class = FindClass(jni,
260 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000261 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100262 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000263 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100264 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000265 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100266 jni, j_decoded_output_buffer_class, "size", "I");
glaznev94291482016-02-01 13:17:18 -0800267 j_presentation_timestamp_ms_field_ = GetFieldID(
268 jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
269 j_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100270 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
glaznev94291482016-02-01 13:17:18 -0800271 j_ntp_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100272 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
273 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
274 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000275
276 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200277 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700278 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000279 memset(&codec_, 0, sizeof(codec_));
280 AllowBlockingCalls();
281}
282
283MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
284 // Call Release() to ensure no more callbacks to us after we are deleted.
285 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000286}
287
288int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
289 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700290 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000291 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700292 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000293 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
294 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000295 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700296 RTC_CHECK(inst->codecType == codecType_)
297 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000298
Alex Glaznev782671f2015-06-12 16:40:44 -0700299 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700300 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700301 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000302 }
303 // Save VideoCodec instance for later.
304 if (&codec_ != inst) {
305 codec_ = *inst;
306 }
glazneve55c42c2015-10-28 10:30:32 -0700307 // If maxFramerate is not set then assume 30 fps.
308 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000309
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000310 // Call Java init.
311 return codec_thread_->Invoke<int32_t>(
312 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
313}
314
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800315void MediaCodecVideoDecoder::ResetVariables() {
316 CheckOnCodecThread();
317
318 key_frame_required_ = true;
319 frames_received_ = 0;
320 frames_decoded_ = 0;
321 frames_decoded_logged_ = kMaxDecodedLogFrames;
322 start_time_ms_ = GetCurrentTimeMs();
323 current_frames_ = 0;
324 current_bytes_ = 0;
325 current_decoding_time_ms_ = 0;
326 current_delay_time_ms_ = 0;
327}
328
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000329int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
330 CheckOnCodecThread();
331 JNIEnv* jni = AttachCurrentThreadIfNeeded();
332 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700333 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
334 << codec_.width << " x " << codec_.height << ". Fps: " <<
335 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700336
337 // Release previous codec first if it was allocated before.
338 int ret_val = ReleaseOnCodecThread();
339 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700340 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700341 sw_fallback_required_ = true;
342 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000343 }
344
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800345 ResetVariables();
Alex Glaznev782671f2015-06-12 16:40:44 -0700346
Per488e75f2015-11-19 10:43:36 +0100347 if (use_surface_) {
348 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
magjed82b750b2016-03-31 00:54:15 -0700349 jni, "Decoder SurfaceTextureHelper", render_egl_context_);
Per488e75f2015-11-19 10:43:36 +0100350 }
351
Perec2922f2016-01-27 15:25:46 +0100352 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000353 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000354 bool success = jni->CallBooleanMethod(
355 *j_media_codec_video_decoder_,
356 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000357 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000358 codec_.width,
359 codec_.height,
magjed0dc23162016-03-14 03:59:38 -0700360 use_surface_ ? surface_texture_helper_->GetJavaSurfaceTextureHelper()
361 : nullptr);
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800362
Alex Glaznev782671f2015-06-12 16:40:44 -0700363 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700364 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700365 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000366 return WEBRTC_VIDEO_CODEC_ERROR;
367 }
368 inited_ = true;
369
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000370 switch (codecType_) {
371 case kVideoCodecVP8:
372 max_pending_frames_ = kMaxPendingFramesVp8;
373 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800374 case kVideoCodecVP9:
375 max_pending_frames_ = kMaxPendingFramesVp9;
376 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000377 case kVideoCodecH264:
378 max_pending_frames_ = kMaxPendingFramesH264;
379 break;
380 default:
381 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000382 }
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800383 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000384
385 jobjectArray input_buffers = (jobjectArray)GetObjectField(
386 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
387 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
388 input_buffers_.resize(num_input_buffers);
389 for (size_t i = 0; i < num_input_buffers; ++i) {
390 input_buffers_[i] =
391 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700392 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700393 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700394 sw_fallback_required_ = true;
395 return WEBRTC_VIDEO_CODEC_ERROR;
396 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000397 }
398
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000399 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
400
401 return WEBRTC_VIDEO_CODEC_OK;
402}
403
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800404int32_t MediaCodecVideoDecoder::ResetDecodeOnCodecThread() {
405 CheckOnCodecThread();
406 JNIEnv* jni = AttachCurrentThreadIfNeeded();
407 ScopedLocalRefFrame local_ref_frame(jni);
408 ALOGD << "ResetDecodeOnCodecThread Type: " << (int)codecType_ << ". "
409 << codec_.width << " x " << codec_.height;
410 ALOGD << " Frames received: " << frames_received_ <<
411 ". Frames decoded: " << frames_decoded_;
412
413 inited_ = false;
414 rtc::MessageQueueManager::Clear(this);
415 ResetVariables();
416
417 jni->CallVoidMethod(
418 *j_media_codec_video_decoder_,
419 j_reset_method_,
420 codec_.width,
421 codec_.height);
422
423 if (CheckException(jni)) {
424 ALOGE << "Soft reset error - fallback to SW codec.";
425 sw_fallback_required_ = true;
426 return WEBRTC_VIDEO_CODEC_ERROR;
427 }
428 inited_ = true;
429
430 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
431
432 return WEBRTC_VIDEO_CODEC_OK;
433}
434
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000435int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700436 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000437 return codec_thread_->Invoke<int32_t>(
438 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
439}
440
441int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
442 if (!inited_) {
443 return WEBRTC_VIDEO_CODEC_OK;
444 }
445 CheckOnCodecThread();
446 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700447 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
448 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000449 ScopedLocalRefFrame local_ref_frame(jni);
450 for (size_t i = 0; i < input_buffers_.size(); i++) {
451 jni->DeleteGlobalRef(input_buffers_[i]);
452 }
453 input_buffers_.clear();
454 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100455 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000456 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700457 rtc::MessageQueueManager::Clear(this);
458 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700459 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700460 return WEBRTC_VIDEO_CODEC_ERROR;
461 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700462 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000463 return WEBRTC_VIDEO_CODEC_OK;
464}
465
466void MediaCodecVideoDecoder::CheckOnCodecThread() {
kwiberg9708e9c2016-03-29 10:17:42 -0700467 RTC_CHECK(codec_thread_.get() == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000468 << "Running on wrong thread!";
469}
470
glaznevae95ff32016-02-04 11:47:12 -0800471void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
472 // Log next 2 output frames.
473 frames_decoded_logged_ = std::max(
474 frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
475}
476
Alex Glaznev782671f2015-06-12 16:40:44 -0700477int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
478 CheckOnCodecThread();
479 int ret_val = ReleaseOnCodecThread();
480 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700481 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700482 }
483 if (codecType_ == kVideoCodecH264) {
484 // For now there is no SW H.264 which can be used as fallback codec.
485 // So try to restart hw codec for now.
486 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700487 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700488 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
489 // H.264 codec was succesfully reset - return regular error code.
490 return WEBRTC_VIDEO_CODEC_ERROR;
491 } else {
492 // Fail to restart H.264 codec - return error code which should stop the
493 // call.
494 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
495 }
496 } else {
497 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700498 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700499 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
500 }
501}
502
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000503int32_t MediaCodecVideoDecoder::Decode(
504 const EncodedImage& inputImage,
505 bool missingFrames,
506 const RTPFragmentationHeader* fragmentation,
507 const CodecSpecificInfo* codecSpecificInfo,
508 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700509 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700510 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700511 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000512 }
513 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700514 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000515 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
516 }
517 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700518 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000519 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
520 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700521 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700522 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700523 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
524 }
525
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000526 // Check if encoded frame dimension has changed.
527 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
528 (inputImage._encodedWidth != codec_.width ||
529 inputImage._encodedHeight != codec_.height)) {
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800530 ALOGW << "Input resolution changed from " <<
531 codec_.width << " x " << codec_.height << " to " <<
532 inputImage._encodedWidth << " x " << inputImage._encodedHeight;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000533 codec_.width = inputImage._encodedWidth;
534 codec_.height = inputImage._encodedHeight;
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800535 int32_t ret;
Alex Glaznev79299af2016-04-12 16:39:39 -0700536 if (use_surface_ &&
537 (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecH264)) {
538 // Soft codec reset - only for surface decoding.
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800539 ret = codec_thread_->Invoke<int32_t>(Bind(
540 &MediaCodecVideoDecoder::ResetDecodeOnCodecThread, this));
541 } else {
542 // Hard codec reset.
543 ret = InitDecode(&codec_, 1);
544 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700545 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700546 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700547 sw_fallback_required_ = true;
548 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
549 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000550 }
551
552 // Always start with a complete key frame.
553 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200554 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700555 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000556 return WEBRTC_VIDEO_CODEC_ERROR;
557 }
558 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700559 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000560 return WEBRTC_VIDEO_CODEC_ERROR;
561 }
562 key_frame_required_ = false;
563 }
564 if (inputImage._length == 0) {
565 return WEBRTC_VIDEO_CODEC_ERROR;
566 }
567
568 return codec_thread_->Invoke<int32_t>(Bind(
569 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
570}
571
572int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
573 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000574 CheckOnCodecThread();
575 JNIEnv* jni = AttachCurrentThreadIfNeeded();
576 ScopedLocalRefFrame local_ref_frame(jni);
577
578 // Try to drain the decoder and wait until output is not too
579 // much behind the input.
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800580 if (codecType_ == kVideoCodecH264 &&
581 frames_received_ > frames_decoded_ + max_pending_frames_) {
582 // Print warning for H.264 only - for VP8/VP9 one frame delay is ok.
glaznevae95ff32016-02-04 11:47:12 -0800583 ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
584 frames_received_ << ". Decoded: " << frames_decoded_;
585 EnableFrameLogOnWarning();
586 }
Per488e75f2015-11-19 10:43:36 +0100587 const int64 drain_start = GetCurrentTimeMs();
588 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
589 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
Per488e75f2015-11-19 10:43:36 +0100590 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700591 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
592 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700593 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000594 }
Per488e75f2015-11-19 10:43:36 +0100595 }
596 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
597 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
598 frames_received_ << ". Frames decoded: " << frames_decoded_;
599 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000600 }
601
602 // Get input buffer.
glaznevae95ff32016-02-04 11:47:12 -0800603 int j_input_buffer_index = jni->CallIntMethod(
604 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700605 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznevae95ff32016-02-04 11:47:12 -0800606 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
607 ". Retry DeliverPendingOutputs.";
608 EnableFrameLogOnWarning();
609 // Try to drain the decoder.
610 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
611 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
612 frames_received_ << ". Frames decoded: " << frames_decoded_;
613 return ProcessHWErrorOnCodecThread();
614 }
615 // Try dequeue input buffer one last time.
616 j_input_buffer_index = jni->CallIntMethod(
617 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
618 if (CheckException(jni) || j_input_buffer_index < 0) {
619 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
620 return ProcessHWErrorOnCodecThread();
621 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000622 }
623
624 // Copy encoded data to Java ByteBuffer.
625 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200626 uint8_t* buffer =
627 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700628 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200629 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700630 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700631 ALOGE << "Input frame size "<< inputImage._length <<
632 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700633 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000634 }
glaznevae95ff32016-02-04 11:47:12 -0800635 jlong presentation_timestamp_us = static_cast<jlong>(
636 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000637 memcpy(buffer, inputImage._buffer, inputImage._length);
638
glaznevae95ff32016-02-04 11:47:12 -0800639 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800640 ALOGD << "Decoder frame in # " << frames_received_ <<
641 ". Type: " << inputImage._frameType <<
642 ". Buffer # " << j_input_buffer_index <<
glaznevae95ff32016-02-04 11:47:12 -0800643 ". TS: " << presentation_timestamp_us / 1000 <<
glaznev94291482016-02-01 13:17:18 -0800644 ". Size: " << inputImage._length;
645 }
646
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000647 // Save input image timestamps for later output.
648 frames_received_++;
649 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000650
651 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100652 bool success = jni->CallBooleanMethod(
653 *j_media_codec_video_decoder_,
654 j_queue_input_buffer_method_,
655 j_input_buffer_index,
656 inputImage._length,
657 presentation_timestamp_us,
658 static_cast<int64_t> (inputImage._timeStamp),
659 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700660 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700661 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700662 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000663 }
664
665 // Try to drain the decoder
666 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700667 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700668 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000669 }
670
671 return WEBRTC_VIDEO_CODEC_OK;
672}
673
674bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100675 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000676 if (frames_received_ <= frames_decoded_) {
677 // No need to query for output buffers - decoder is drained.
678 return true;
679 }
680 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100681 jobject j_decoder_output_buffer =
682 jni->CallObjectMethod(*j_media_codec_video_decoder_,
683 use_surface_ ? j_dequeue_texture_buffer_method_
684 : j_dequeue_byte_buffer_method_,
685 dequeue_timeout_ms);
686
Alex Glaznev782671f2015-06-12 16:40:44 -0700687 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700688 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700689 return false;
690 }
magjed44bf6f52015-10-03 02:08:00 -0700691 if (IsNull(jni, j_decoder_output_buffer)) {
692 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000693 return true;
694 }
695
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000696 // Get decoded video frame properties.
697 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
698 j_color_format_field_);
699 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
700 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
701 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
702 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
703 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000704
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200705 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
glaznev94291482016-02-01 13:17:18 -0800706 int64_t presentation_timestamps_ms = 0;
Per488e75f2015-11-19 10:43:36 +0100707 int64_t output_timestamps_ms = 0;
708 int64_t output_ntp_timestamps_ms = 0;
709 int decode_time_ms = 0;
710 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200711 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700712 // Extract data from Java DecodedTextureBuffer.
glaznevae95ff32016-02-04 11:47:12 -0800713 presentation_timestamps_ms = GetLongField(
714 jni, j_decoder_output_buffer,
715 j_texture_presentation_timestamp_ms_field_);
716 output_timestamps_ms = GetLongField(
717 jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
718 output_ntp_timestamps_ms = GetLongField(
719 jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
720 decode_time_ms = GetLongField(
721 jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
722
magjed44bf6f52015-10-03 02:08:00 -0700723 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100724 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
725 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
726 const jfloatArray j_transform_matrix =
727 reinterpret_cast<jfloatArray>(GetObjectField(
728 jni, j_decoder_output_buffer, j_transform_matrix_field_));
glaznev94291482016-02-01 13:17:18 -0800729 frame_delayed_ms = GetLongField(
730 jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100731
732 // Create webrtc::VideoFrameBuffer with native texture handle.
733 frame_buffer = surface_texture_helper_->CreateTextureFrame(
734 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
glaznevae95ff32016-02-04 11:47:12 -0800735 } else {
736 EnableFrameLogOnWarning();
Per488e75f2015-11-19 10:43:36 +0100737 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200738 } else {
739 // Extract data from Java ByteBuffer and create output yuv420 frame -
740 // for non surface decoding only.
glaznev94291482016-02-01 13:17:18 -0800741 const int output_buffer_index = GetIntField(
742 jni, j_decoder_output_buffer, j_info_index_field_);
743 const int output_buffer_offset = GetIntField(
744 jni, j_decoder_output_buffer, j_info_offset_field_);
745 const int output_buffer_size = GetIntField(
746 jni, j_decoder_output_buffer, j_info_size_field_);
747 presentation_timestamps_ms = GetLongField(
748 jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
749 output_timestamps_ms = GetLongField(
750 jni, j_decoder_output_buffer, j_timestamp_ms_field_);
751 output_ntp_timestamps_ms = GetLongField(
752 jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100753
754 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
755 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700756
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000757 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700758 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000759 return false;
760 }
glaznev3816bfd2016-03-08 10:35:33 -0800761 if (output_buffer_size < stride * height * 3 / 2 &&
762 slice_height == height && stride > width) {
763 // Some codecs (Exynos) incorrectly report stride information for
764 // output byte buffer, so actual stride value need to be corrected.
765 stride = output_buffer_size * 2 / (height * 3);
766 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000767 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
768 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
769 jobject output_buffer =
770 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
771 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
772 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700773 if (CheckException(jni)) {
774 return false;
775 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000776 payload += output_buffer_offset;
777
778 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200779 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000780 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200781 RTC_CHECK_EQ(0, stride % 2);
782 RTC_CHECK_EQ(0, slice_height % 2);
783 const int uv_stride = stride / 2;
784 const int u_slice_height = slice_height / 2;
785 const uint8_t* y_ptr = payload;
786 const uint8_t* u_ptr = y_ptr + stride * slice_height;
787 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
788 libyuv::I420Copy(y_ptr, stride,
789 u_ptr, uv_stride,
790 v_ptr, uv_stride,
791 frame_buffer->MutableData(webrtc::kYPlane),
792 frame_buffer->stride(webrtc::kYPlane),
793 frame_buffer->MutableData(webrtc::kUPlane),
794 frame_buffer->stride(webrtc::kUPlane),
795 frame_buffer->MutableData(webrtc::kVPlane),
796 frame_buffer->stride(webrtc::kVPlane),
797 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000798 } else {
799 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200800 const uint8_t* y_ptr = payload;
801 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000802 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200803 y_ptr, stride,
804 uv_ptr, stride,
805 frame_buffer->MutableData(webrtc::kYPlane),
806 frame_buffer->stride(webrtc::kYPlane),
807 frame_buffer->MutableData(webrtc::kUPlane),
808 frame_buffer->stride(webrtc::kUPlane),
809 frame_buffer->MutableData(webrtc::kVPlane),
810 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000811 width, height);
812 }
magjed44bf6f52015-10-03 02:08:00 -0700813 // Return output byte buffer back to codec.
814 jni->CallVoidMethod(
815 *j_media_codec_video_decoder_,
816 j_return_decoded_byte_buffer_method_,
817 output_buffer_index);
818 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100819 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700820 return false;
821 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000822 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200823 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
Per488e75f2015-11-19 10:43:36 +0100824 decoded_frame.set_timestamp(output_timestamps_ms);
825 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000826
glaznevae95ff32016-02-04 11:47:12 -0800827 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800828 ALOGD << "Decoder frame out # " << frames_decoded_ <<
829 ". " << width << " x " << height <<
830 ". " << stride << " x " << slice_height <<
831 ". Color: " << color_format <<
832 ". TS: " << presentation_timestamps_ms <<
Per488e75f2015-11-19 10:43:36 +0100833 ". DecTime: " << (int)decode_time_ms <<
834 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700835 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000836
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000837 // Calculate and print decoding statistics - every 3 seconds.
838 frames_decoded_++;
839 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100840 current_decoding_time_ms_ += decode_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800841 current_delay_time_ms_ += frame_delayed_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000842 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
843 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
844 current_frames_ > 0) {
glaznev94291482016-02-01 13:17:18 -0800845 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
846 int current_fps =
847 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800848 ALOGD << "Frames decoded: " << frames_decoded_ <<
849 ". Received: " << frames_received_ <<
glaznev94291482016-02-01 13:17:18 -0800850 ". Bitrate: " << current_bitrate << " kbps" <<
851 ". Fps: " << current_fps <<
852 ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
glaznevfd6706a2016-02-05 14:05:08 -0800853 ". DelayTime: " << (current_delay_time_ms_ / current_frames_) <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700854 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000855 start_time_ms_ = GetCurrentTimeMs();
856 current_frames_ = 0;
857 current_bytes_ = 0;
858 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800859 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000860 }
861
Per488e75f2015-11-19 10:43:36 +0100862 // |.IsZeroSize())| returns true when a frame has been dropped.
863 if (!decoded_frame.IsZeroSize()) {
864 // Callback - output decoded frame.
865 const int32_t callback_status =
866 callback_->Decoded(decoded_frame, decode_time_ms);
867 if (callback_status > 0) {
868 ALOGE << "callback error";
869 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000870 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000871 return true;
872}
873
874int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
875 DecodedImageCallback* callback) {
876 callback_ = callback;
877 return WEBRTC_VIDEO_CODEC_OK;
878}
879
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000880void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
881 JNIEnv* jni = AttachCurrentThreadIfNeeded();
882 ScopedLocalRefFrame local_ref_frame(jni);
883 if (!inited_) {
884 return;
885 }
886 // We only ever send one message to |this| directly (not through a Bind()'d
887 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700888 RTC_CHECK(!msg->message_id) << "Unexpected message!";
889 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000890 CheckOnCodecThread();
891
892 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700893 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700894 ProcessHWErrorOnCodecThread();
895 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000896 }
897 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
898}
899
perkj461121c2016-02-15 06:28:36 -0800900MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory()
901 : egl_context_(nullptr) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700902 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000903 JNIEnv* jni = AttachCurrentThreadIfNeeded();
904 ScopedLocalRefFrame local_ref_frame(jni);
905 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000906 supported_codec_types_.clear();
907
908 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000909 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000910 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700911 if (CheckException(jni)) {
912 is_vp8_hw_supported = false;
913 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000914 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700915 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000916 supported_codec_types_.push_back(kVideoCodecVP8);
917 }
918
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800919 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
920 j_decoder_class,
921 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
922 if (CheckException(jni)) {
923 is_vp9_hw_supported = false;
924 }
925 if (is_vp9_hw_supported) {
926 ALOGD << "VP9 HW Decoder supported.";
927 supported_codec_types_.push_back(kVideoCodecVP9);
928 }
929
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000930 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
931 j_decoder_class,
932 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700933 if (CheckException(jni)) {
934 is_h264_hw_supported = false;
935 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000936 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700937 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000938 supported_codec_types_.push_back(kVideoCodecH264);
939 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000940}
941
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700942MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700943 ALOGD << "MediaCodecVideoDecoderFactory dtor";
perkj461121c2016-02-15 06:28:36 -0800944 if (egl_context_) {
945 JNIEnv* jni = AttachCurrentThreadIfNeeded();
946 jni->DeleteGlobalRef(egl_context_);
947 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700948}
949
950void MediaCodecVideoDecoderFactory::SetEGLContext(
perkj461121c2016-02-15 06:28:36 -0800951 JNIEnv* jni, jobject egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700952 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Perfd22e6c2016-02-18 11:35:48 +0100953 if (egl_context_) {
954 jni->DeleteGlobalRef(egl_context_);
955 egl_context_ = nullptr;
956 }
perkj461121c2016-02-15 06:28:36 -0800957 egl_context_ = jni->NewGlobalRef(egl_context);
958 if (CheckException(jni)) {
959 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700960 }
961}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000962
963webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000964 VideoCodecType type) {
965 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800966 ALOGW << "No HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100967 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000968 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700969 for (VideoCodecType codec_type : supported_codec_types_) {
970 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700971 ALOGD << "Create HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100972 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
perkj461121c2016-02-15 06:28:36 -0800973 egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000974 }
975 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800976 ALOGW << "Can not find HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100977 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000978}
979
980void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
981 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700982 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000983 delete decoder;
984}
985
Peter Boströmb7d9a972015-12-18 16:01:11 +0100986const char* MediaCodecVideoDecoder::ImplementationName() const {
987 return "MediaCodec";
988}
989
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000990} // namespace webrtc_jni
991