blob: 3793756ec7ca9d6527d8e9217186d47929e3a58a [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"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000035
36using rtc::Bind;
37using rtc::Thread;
38using rtc::ThreadManager;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000039
40using webrtc::CodecSpecificInfo;
41using webrtc::DecodedImageCallback;
42using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070043using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000044using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000045using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000046using webrtc::VideoCodecType;
47using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000048using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080049using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000050
51namespace webrtc_jni {
52
glaznevf4decb52016-01-15 13:49:22 -080053// Logging macros.
54#define TAG_DECODER "MediaCodecVideoDecoder"
55#ifdef TRACK_BUFFER_TIMING
56#define ALOGV(...)
57 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
58#else
59#define ALOGV(...)
60#endif
61#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
62#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
63#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
64
glaznevae95ff32016-02-04 11:47:12 -080065enum { kMaxWarningLogFrames = 2 };
66
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000067class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
68 public rtc::MessageHandler {
69 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070070 explicit MediaCodecVideoDecoder(
71 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000072 virtual ~MediaCodecVideoDecoder();
73
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000074 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
75 override;
76
77 int32_t Decode(
78 const EncodedImage& inputImage, bool missingFrames,
79 const RTPFragmentationHeader* fragmentation,
80 const CodecSpecificInfo* codecSpecificInfo = NULL,
81 int64_t renderTimeMs = -1) override;
82
83 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
84 override;
85
86 int32_t Release() override;
87
perkj796cfaf2015-12-10 09:27:38 -080088 bool PrefersLateDecoding() const override { return true; }
89
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000090 // rtc::MessageHandler implementation.
91 void OnMessage(rtc::Message* msg) override;
92
Peter Boströmb7d9a972015-12-18 16:01:11 +010093 const char* ImplementationName() const override;
94
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000095 private:
96 // CHECK-fail if not running on |codec_thread_|.
97 void CheckOnCodecThread();
98
99 int32_t InitDecodeOnCodecThread();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800100 int32_t ResetDecodeOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000101 int32_t ReleaseOnCodecThread();
102 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
103 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
104 // true on success.
105 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700106 int32_t ProcessHWErrorOnCodecThread();
glaznevae95ff32016-02-04 11:47:12 -0800107 void EnableFrameLogOnWarning();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800108 void ResetVariables();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000109
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000110 // Type of video codec.
111 VideoCodecType codecType_;
112
kjellander60ca31b2016-01-04 10:15:53 -0800113 // Render EGL context - owned by factory, should not be allocated/destroyed
114 // by VideoDecoder.
115 jobject render_egl_context_;
116
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000117 bool key_frame_required_;
118 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700119 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000120 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000121 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200122 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100123 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000124 DecodedImageCallback* callback_;
125 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000126 int frames_decoded_; // Number of frames decoded by decoder.
glaznevae95ff32016-02-04 11:47:12 -0800127 // Number of decoded frames for which log information is displayed.
128 int frames_decoded_logged_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000129 int64_t start_time_ms_; // Start time for statistics.
130 int current_frames_; // Number of frames in the current statistics interval.
131 int current_bytes_; // Encoded bytes in the current statistics interval.
132 int current_decoding_time_ms_; // Overall decoding time in the current second
glaznevfd6706a2016-02-05 14:05:08 -0800133 int current_delay_time_ms_; // Overall delay time in the current second.
134 uint32_t max_pending_frames_; // Maximum number of pending input frames.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000135
136 // State that is constant for the lifetime of this object once the ctor
137 // returns.
kwibergd1fe2812016-04-27 06:47:29 -0700138 std::unique_ptr<Thread>
139 codec_thread_; // Thread on which to operate MediaCodec.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000140 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
141 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
142 jmethodID j_init_decode_method_;
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800143 jmethodID j_reset_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000144 jmethodID j_release_method_;
145 jmethodID j_dequeue_input_buffer_method_;
146 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100147 jmethodID j_dequeue_byte_buffer_method_;
148 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700149 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000150 // MediaCodecVideoDecoder fields.
151 jfieldID j_input_buffers_field_;
152 jfieldID j_output_buffers_field_;
153 jfieldID j_color_format_field_;
154 jfieldID j_width_field_;
155 jfieldID j_height_field_;
156 jfieldID j_stride_field_;
157 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700158 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100159 jfieldID j_texture_id_field_;
160 jfieldID j_transform_matrix_field_;
glaznev94291482016-02-01 13:17:18 -0800161 jfieldID j_texture_presentation_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100162 jfieldID j_texture_timestamp_ms_field_;
163 jfieldID j_texture_ntp_timestamp_ms_field_;
164 jfieldID j_texture_decode_time_ms_field_;
165 jfieldID j_texture_frame_delay_ms_field_;
166 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000167 jfieldID j_info_index_field_;
168 jfieldID j_info_offset_field_;
169 jfieldID j_info_size_field_;
glaznev94291482016-02-01 13:17:18 -0800170 jfieldID j_presentation_timestamp_ms_field_;
171 jfieldID j_timestamp_ms_field_;
172 jfieldID j_ntp_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100173 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000174
175 // Global references; must be deleted in Release().
176 std::vector<jobject> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000177};
178
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000179MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700180 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000181 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700182 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000183 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000184 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700185 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000186 codec_thread_(new Thread()),
187 j_media_codec_video_decoder_class_(
188 jni,
189 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
190 j_media_codec_video_decoder_(
191 jni,
192 jni->NewObject(*j_media_codec_video_decoder_class_,
193 GetMethodID(jni,
194 *j_media_codec_video_decoder_class_,
195 "<init>",
196 "()V"))) {
197 ScopedLocalRefFrame local_ref_frame(jni);
198 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700199 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000200
201 j_init_decode_method_ = GetMethodID(
202 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000203 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100204 "IILorg/webrtc/SurfaceTextureHelper;)Z");
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800205 j_reset_method_ =
206 GetMethodID(jni, *j_media_codec_video_decoder_class_, "reset", "(II)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000207 j_release_method_ =
208 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
209 j_dequeue_input_buffer_method_ = GetMethodID(
210 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
211 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100212 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
213 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000214 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100215 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
216 j_dequeue_texture_buffer_method_ = GetMethodID(
217 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
218 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700219 j_return_decoded_byte_buffer_method_ =
220 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100221 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000222
223 j_input_buffers_field_ = GetFieldID(
224 jni, *j_media_codec_video_decoder_class_,
225 "inputBuffers", "[Ljava/nio/ByteBuffer;");
226 j_output_buffers_field_ = GetFieldID(
227 jni, *j_media_codec_video_decoder_class_,
228 "outputBuffers", "[Ljava/nio/ByteBuffer;");
229 j_color_format_field_ = GetFieldID(
230 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
231 j_width_field_ = GetFieldID(
232 jni, *j_media_codec_video_decoder_class_, "width", "I");
233 j_height_field_ = GetFieldID(
234 jni, *j_media_codec_video_decoder_class_, "height", "I");
235 j_stride_field_ = GetFieldID(
236 jni, *j_media_codec_video_decoder_class_, "stride", "I");
237 j_slice_height_field_ = GetFieldID(
238 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000239
Per488e75f2015-11-19 10:43:36 +0100240 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700241 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100242 j_texture_id_field_ = GetFieldID(
243 jni, j_decoded_texture_buffer_class, "textureID", "I");
244 j_transform_matrix_field_ = GetFieldID(
245 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
glaznev94291482016-02-01 13:17:18 -0800246 j_texture_presentation_timestamp_ms_field_ = GetFieldID(
247 jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
Per488e75f2015-11-19 10:43:36 +0100248 j_texture_timestamp_ms_field_ = GetFieldID(
249 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
250 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
251 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
252 j_texture_decode_time_ms_field_ = GetFieldID(
253 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
254 j_texture_frame_delay_ms_field_ = GetFieldID(
255 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700256
Per488e75f2015-11-19 10:43:36 +0100257 jclass j_decoded_output_buffer_class = FindClass(jni,
258 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000259 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100260 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000261 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100262 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000263 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100264 jni, j_decoded_output_buffer_class, "size", "I");
glaznev94291482016-02-01 13:17:18 -0800265 j_presentation_timestamp_ms_field_ = GetFieldID(
266 jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
267 j_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100268 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
glaznev94291482016-02-01 13:17:18 -0800269 j_ntp_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100270 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
271 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
272 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000273
274 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200275 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700276 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000277 memset(&codec_, 0, sizeof(codec_));
278 AllowBlockingCalls();
279}
280
281MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
282 // Call Release() to ensure no more callbacks to us after we are deleted.
283 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000284}
285
286int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
287 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700288 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000289 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700290 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000291 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
292 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000293 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700294 RTC_CHECK(inst->codecType == codecType_)
295 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000296
Alex Glaznev782671f2015-06-12 16:40:44 -0700297 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700298 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700299 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000300 }
301 // Save VideoCodec instance for later.
302 if (&codec_ != inst) {
303 codec_ = *inst;
304 }
glazneve55c42c2015-10-28 10:30:32 -0700305 // If maxFramerate is not set then assume 30 fps.
306 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000307
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000308 // Call Java init.
309 return codec_thread_->Invoke<int32_t>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700310 RTC_FROM_HERE,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000311 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
312}
313
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800314void MediaCodecVideoDecoder::ResetVariables() {
315 CheckOnCodecThread();
316
317 key_frame_required_ = true;
318 frames_received_ = 0;
319 frames_decoded_ = 0;
320 frames_decoded_logged_ = kMaxDecodedLogFrames;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200321 start_time_ms_ = rtc::TimeMillis();
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800322 current_frames_ = 0;
323 current_bytes_ = 0;
324 current_decoding_time_ms_ = 0;
325 current_delay_time_ms_ = 0;
326}
327
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000328int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
329 CheckOnCodecThread();
330 JNIEnv* jni = AttachCurrentThreadIfNeeded();
331 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700332 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
333 << codec_.width << " x " << codec_.height << ". Fps: " <<
334 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700335
336 // Release previous codec first if it was allocated before.
337 int ret_val = ReleaseOnCodecThread();
338 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700339 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700340 sw_fallback_required_ = true;
341 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000342 }
343
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800344 ResetVariables();
Alex Glaznev782671f2015-06-12 16:40:44 -0700345
Per488e75f2015-11-19 10:43:36 +0100346 if (use_surface_) {
magjed2aa84262016-05-09 08:28:45 -0700347 surface_texture_helper_ = SurfaceTextureHelper::create(
magjed82b750b2016-03-31 00:54:15 -0700348 jni, "Decoder SurfaceTextureHelper", render_egl_context_);
magjed2aa84262016-05-09 08:28:45 -0700349 if (!surface_texture_helper_) {
350 ALOGE << "Couldn't create SurfaceTextureHelper - fallback to SW codec";
351 sw_fallback_required_ = true;
352 return WEBRTC_VIDEO_CODEC_ERROR;
353 }
Per488e75f2015-11-19 10:43:36 +0100354 }
355
Perec2922f2016-01-27 15:25:46 +0100356 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000357 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000358 bool success = jni->CallBooleanMethod(
359 *j_media_codec_video_decoder_,
360 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000361 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000362 codec_.width,
363 codec_.height,
magjed0dc23162016-03-14 03:59:38 -0700364 use_surface_ ? surface_texture_helper_->GetJavaSurfaceTextureHelper()
365 : nullptr);
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800366
Alex Glaznev782671f2015-06-12 16:40:44 -0700367 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700368 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700369 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000370 return WEBRTC_VIDEO_CODEC_ERROR;
371 }
372 inited_ = true;
373
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000374 switch (codecType_) {
375 case kVideoCodecVP8:
376 max_pending_frames_ = kMaxPendingFramesVp8;
377 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800378 case kVideoCodecVP9:
379 max_pending_frames_ = kMaxPendingFramesVp9;
380 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000381 case kVideoCodecH264:
382 max_pending_frames_ = kMaxPendingFramesH264;
383 break;
384 default:
385 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000386 }
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800387 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000388
389 jobjectArray input_buffers = (jobjectArray)GetObjectField(
390 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
391 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
392 input_buffers_.resize(num_input_buffers);
393 for (size_t i = 0; i < num_input_buffers; ++i) {
394 input_buffers_[i] =
395 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700396 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700397 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700398 sw_fallback_required_ = true;
399 return WEBRTC_VIDEO_CODEC_ERROR;
400 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000401 }
402
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700403 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000404
405 return WEBRTC_VIDEO_CODEC_OK;
406}
407
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800408int32_t MediaCodecVideoDecoder::ResetDecodeOnCodecThread() {
409 CheckOnCodecThread();
410 JNIEnv* jni = AttachCurrentThreadIfNeeded();
411 ScopedLocalRefFrame local_ref_frame(jni);
412 ALOGD << "ResetDecodeOnCodecThread Type: " << (int)codecType_ << ". "
413 << codec_.width << " x " << codec_.height;
414 ALOGD << " Frames received: " << frames_received_ <<
415 ". Frames decoded: " << frames_decoded_;
416
417 inited_ = false;
418 rtc::MessageQueueManager::Clear(this);
419 ResetVariables();
420
421 jni->CallVoidMethod(
422 *j_media_codec_video_decoder_,
423 j_reset_method_,
424 codec_.width,
425 codec_.height);
426
427 if (CheckException(jni)) {
428 ALOGE << "Soft reset error - fallback to SW codec.";
429 sw_fallback_required_ = true;
430 return WEBRTC_VIDEO_CODEC_ERROR;
431 }
432 inited_ = true;
433
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700434 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this);
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800435
436 return WEBRTC_VIDEO_CODEC_OK;
437}
438
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000439int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700440 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000441 return codec_thread_->Invoke<int32_t>(
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700442 RTC_FROM_HERE, Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000443}
444
445int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
446 if (!inited_) {
447 return WEBRTC_VIDEO_CODEC_OK;
448 }
449 CheckOnCodecThread();
450 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700451 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
452 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000453 ScopedLocalRefFrame local_ref_frame(jni);
454 for (size_t i = 0; i < input_buffers_.size(); i++) {
455 jni->DeleteGlobalRef(input_buffers_[i]);
456 }
457 input_buffers_.clear();
458 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100459 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000460 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700461 rtc::MessageQueueManager::Clear(this);
462 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700463 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700464 return WEBRTC_VIDEO_CODEC_ERROR;
465 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700466 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000467 return WEBRTC_VIDEO_CODEC_OK;
468}
469
470void MediaCodecVideoDecoder::CheckOnCodecThread() {
kwiberg9708e9c2016-03-29 10:17:42 -0700471 RTC_CHECK(codec_thread_.get() == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000472 << "Running on wrong thread!";
473}
474
glaznevae95ff32016-02-04 11:47:12 -0800475void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
476 // Log next 2 output frames.
477 frames_decoded_logged_ = std::max(
478 frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
479}
480
Alex Glaznev782671f2015-06-12 16:40:44 -0700481int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
482 CheckOnCodecThread();
483 int ret_val = ReleaseOnCodecThread();
484 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700485 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700486 }
487 if (codecType_ == kVideoCodecH264) {
488 // For now there is no SW H.264 which can be used as fallback codec.
489 // So try to restart hw codec for now.
490 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700491 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700492 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
493 // H.264 codec was succesfully reset - return regular error code.
494 return WEBRTC_VIDEO_CODEC_ERROR;
495 } else {
496 // Fail to restart H.264 codec - return error code which should stop the
497 // call.
498 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
499 }
500 } else {
501 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700502 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700503 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
504 }
505}
506
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000507int32_t MediaCodecVideoDecoder::Decode(
508 const EncodedImage& inputImage,
509 bool missingFrames,
510 const RTPFragmentationHeader* fragmentation,
511 const CodecSpecificInfo* codecSpecificInfo,
512 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700513 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700514 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700515 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000516 }
517 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700518 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000519 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
520 }
521 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700522 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000523 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
524 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700525 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700526 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700527 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
528 }
529
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000530 // Check if encoded frame dimension has changed.
531 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
532 (inputImage._encodedWidth != codec_.width ||
533 inputImage._encodedHeight != codec_.height)) {
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800534 ALOGW << "Input resolution changed from " <<
535 codec_.width << " x " << codec_.height << " to " <<
536 inputImage._encodedWidth << " x " << inputImage._encodedHeight;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000537 codec_.width = inputImage._encodedWidth;
538 codec_.height = inputImage._encodedHeight;
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800539 int32_t ret;
Alex Glaznev79299af2016-04-12 16:39:39 -0700540 if (use_surface_ &&
541 (codecType_ == kVideoCodecVP8 || codecType_ == kVideoCodecH264)) {
542 // Soft codec reset - only for surface decoding.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700543 ret = codec_thread_->Invoke<int32_t>(
544 RTC_FROM_HERE,
545 Bind(&MediaCodecVideoDecoder::ResetDecodeOnCodecThread, this));
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800546 } else {
547 // Hard codec reset.
548 ret = InitDecode(&codec_, 1);
549 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700550 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700551 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700552 sw_fallback_required_ = true;
553 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
554 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000555 }
556
557 // Always start with a complete key frame.
558 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200559 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700560 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000561 return WEBRTC_VIDEO_CODEC_ERROR;
562 }
563 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700564 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000565 return WEBRTC_VIDEO_CODEC_ERROR;
566 }
567 key_frame_required_ = false;
568 }
569 if (inputImage._length == 0) {
570 return WEBRTC_VIDEO_CODEC_ERROR;
571 }
572
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700573 return codec_thread_->Invoke<int32_t>(
574 RTC_FROM_HERE,
575 Bind(&MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000576}
577
578int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
579 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000580 CheckOnCodecThread();
581 JNIEnv* jni = AttachCurrentThreadIfNeeded();
582 ScopedLocalRefFrame local_ref_frame(jni);
583
584 // Try to drain the decoder and wait until output is not too
585 // much behind the input.
Alex Glaznev6a4a03c2016-03-04 14:10:50 -0800586 if (codecType_ == kVideoCodecH264 &&
587 frames_received_ > frames_decoded_ + max_pending_frames_) {
588 // Print warning for H.264 only - for VP8/VP9 one frame delay is ok.
glaznevae95ff32016-02-04 11:47:12 -0800589 ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
590 frames_received_ << ". Decoded: " << frames_decoded_;
591 EnableFrameLogOnWarning();
592 }
Niels Möllerd28db7f2016-05-10 16:31:47 +0200593 const int64 drain_start = rtc::TimeMillis();
Per488e75f2015-11-19 10:43:36 +0100594 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
Niels Möllerd28db7f2016-05-10 16:31:47 +0200595 (rtc::TimeMillis() - drain_start) < kMediaCodecTimeoutMs) {
Per488e75f2015-11-19 10:43:36 +0100596 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700597 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
598 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700599 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000600 }
Per488e75f2015-11-19 10:43:36 +0100601 }
602 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
603 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
604 frames_received_ << ". Frames decoded: " << frames_decoded_;
605 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000606 }
607
608 // Get input buffer.
glaznevae95ff32016-02-04 11:47:12 -0800609 int j_input_buffer_index = jni->CallIntMethod(
610 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700611 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznevae95ff32016-02-04 11:47:12 -0800612 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
613 ". Retry DeliverPendingOutputs.";
614 EnableFrameLogOnWarning();
615 // Try to drain the decoder.
616 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
617 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
618 frames_received_ << ". Frames decoded: " << frames_decoded_;
619 return ProcessHWErrorOnCodecThread();
620 }
621 // Try dequeue input buffer one last time.
622 j_input_buffer_index = jni->CallIntMethod(
623 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
624 if (CheckException(jni) || j_input_buffer_index < 0) {
625 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
626 return ProcessHWErrorOnCodecThread();
627 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000628 }
629
630 // Copy encoded data to Java ByteBuffer.
631 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200632 uint8_t* buffer =
633 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700634 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200635 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700636 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700637 ALOGE << "Input frame size "<< inputImage._length <<
638 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700639 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000640 }
glaznevae95ff32016-02-04 11:47:12 -0800641 jlong presentation_timestamp_us = static_cast<jlong>(
642 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000643 memcpy(buffer, inputImage._buffer, inputImage._length);
644
glaznevae95ff32016-02-04 11:47:12 -0800645 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800646 ALOGD << "Decoder frame in # " << frames_received_ <<
647 ". Type: " << inputImage._frameType <<
648 ". Buffer # " << j_input_buffer_index <<
glaznevae95ff32016-02-04 11:47:12 -0800649 ". TS: " << presentation_timestamp_us / 1000 <<
glaznev94291482016-02-01 13:17:18 -0800650 ". Size: " << inputImage._length;
651 }
652
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000653 // Save input image timestamps for later output.
654 frames_received_++;
655 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000656
657 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100658 bool success = jni->CallBooleanMethod(
659 *j_media_codec_video_decoder_,
660 j_queue_input_buffer_method_,
661 j_input_buffer_index,
662 inputImage._length,
663 presentation_timestamp_us,
664 static_cast<int64_t> (inputImage._timeStamp),
665 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700666 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700667 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700668 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000669 }
670
671 // Try to drain the decoder
672 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700673 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700674 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000675 }
676
677 return WEBRTC_VIDEO_CODEC_OK;
678}
679
680bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100681 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000682 if (frames_received_ <= frames_decoded_) {
683 // No need to query for output buffers - decoder is drained.
684 return true;
685 }
686 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100687 jobject j_decoder_output_buffer =
688 jni->CallObjectMethod(*j_media_codec_video_decoder_,
689 use_surface_ ? j_dequeue_texture_buffer_method_
690 : j_dequeue_byte_buffer_method_,
691 dequeue_timeout_ms);
692
Alex Glaznev782671f2015-06-12 16:40:44 -0700693 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700694 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700695 return false;
696 }
magjed44bf6f52015-10-03 02:08:00 -0700697 if (IsNull(jni, j_decoder_output_buffer)) {
698 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000699 return true;
700 }
701
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000702 // Get decoded video frame properties.
703 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
704 j_color_format_field_);
705 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
706 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
707 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
708 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
709 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000710
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200711 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
glaznev94291482016-02-01 13:17:18 -0800712 int64_t presentation_timestamps_ms = 0;
Per488e75f2015-11-19 10:43:36 +0100713 int64_t output_timestamps_ms = 0;
714 int64_t output_ntp_timestamps_ms = 0;
715 int decode_time_ms = 0;
716 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200717 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700718 // Extract data from Java DecodedTextureBuffer.
glaznevae95ff32016-02-04 11:47:12 -0800719 presentation_timestamps_ms = GetLongField(
720 jni, j_decoder_output_buffer,
721 j_texture_presentation_timestamp_ms_field_);
722 output_timestamps_ms = GetLongField(
723 jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
724 output_ntp_timestamps_ms = GetLongField(
725 jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
726 decode_time_ms = GetLongField(
727 jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
728
magjed44bf6f52015-10-03 02:08:00 -0700729 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100730 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
731 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
732 const jfloatArray j_transform_matrix =
733 reinterpret_cast<jfloatArray>(GetObjectField(
734 jni, j_decoder_output_buffer, j_transform_matrix_field_));
glaznev94291482016-02-01 13:17:18 -0800735 frame_delayed_ms = GetLongField(
736 jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100737
738 // Create webrtc::VideoFrameBuffer with native texture handle.
739 frame_buffer = surface_texture_helper_->CreateTextureFrame(
740 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
glaznevae95ff32016-02-04 11:47:12 -0800741 } else {
742 EnableFrameLogOnWarning();
Per488e75f2015-11-19 10:43:36 +0100743 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200744 } else {
745 // Extract data from Java ByteBuffer and create output yuv420 frame -
746 // for non surface decoding only.
glaznev94291482016-02-01 13:17:18 -0800747 const int output_buffer_index = GetIntField(
748 jni, j_decoder_output_buffer, j_info_index_field_);
749 const int output_buffer_offset = GetIntField(
750 jni, j_decoder_output_buffer, j_info_offset_field_);
751 const int output_buffer_size = GetIntField(
752 jni, j_decoder_output_buffer, j_info_size_field_);
753 presentation_timestamps_ms = GetLongField(
754 jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
755 output_timestamps_ms = GetLongField(
756 jni, j_decoder_output_buffer, j_timestamp_ms_field_);
757 output_ntp_timestamps_ms = GetLongField(
758 jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100759
760 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
761 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700762
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000763 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700764 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000765 return false;
766 }
glaznev3816bfd2016-03-08 10:35:33 -0800767 if (output_buffer_size < stride * height * 3 / 2 &&
768 slice_height == height && stride > width) {
769 // Some codecs (Exynos) incorrectly report stride information for
770 // output byte buffer, so actual stride value need to be corrected.
771 stride = output_buffer_size * 2 / (height * 3);
772 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000773 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
774 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
775 jobject output_buffer =
776 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
777 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
778 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700779 if (CheckException(jni)) {
780 return false;
781 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000782 payload += output_buffer_offset;
783
784 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200785 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000786 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200787 RTC_CHECK_EQ(0, stride % 2);
788 RTC_CHECK_EQ(0, slice_height % 2);
789 const int uv_stride = stride / 2;
790 const int u_slice_height = slice_height / 2;
791 const uint8_t* y_ptr = payload;
792 const uint8_t* u_ptr = y_ptr + stride * slice_height;
793 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
794 libyuv::I420Copy(y_ptr, stride,
795 u_ptr, uv_stride,
796 v_ptr, uv_stride,
797 frame_buffer->MutableData(webrtc::kYPlane),
798 frame_buffer->stride(webrtc::kYPlane),
799 frame_buffer->MutableData(webrtc::kUPlane),
800 frame_buffer->stride(webrtc::kUPlane),
801 frame_buffer->MutableData(webrtc::kVPlane),
802 frame_buffer->stride(webrtc::kVPlane),
803 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000804 } else {
805 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200806 const uint8_t* y_ptr = payload;
807 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000808 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200809 y_ptr, stride,
810 uv_ptr, stride,
811 frame_buffer->MutableData(webrtc::kYPlane),
812 frame_buffer->stride(webrtc::kYPlane),
813 frame_buffer->MutableData(webrtc::kUPlane),
814 frame_buffer->stride(webrtc::kUPlane),
815 frame_buffer->MutableData(webrtc::kVPlane),
816 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000817 width, height);
818 }
magjed44bf6f52015-10-03 02:08:00 -0700819 // Return output byte buffer back to codec.
820 jni->CallVoidMethod(
821 *j_media_codec_video_decoder_,
822 j_return_decoded_byte_buffer_method_,
823 output_buffer_index);
824 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100825 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700826 return false;
827 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000828 }
glaznevae95ff32016-02-04 11:47:12 -0800829 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800830 ALOGD << "Decoder frame out # " << frames_decoded_ <<
831 ". " << width << " x " << height <<
832 ". " << stride << " x " << slice_height <<
833 ". Color: " << color_format <<
834 ". TS: " << presentation_timestamps_ms <<
Per488e75f2015-11-19 10:43:36 +0100835 ". DecTime: " << (int)decode_time_ms <<
836 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700837 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000838
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000839 // Calculate and print decoding statistics - every 3 seconds.
840 frames_decoded_++;
841 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100842 current_decoding_time_ms_ += decode_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800843 current_delay_time_ms_ += frame_delayed_ms;
Niels Möllerd28db7f2016-05-10 16:31:47 +0200844 int statistic_time_ms = rtc::TimeMillis() - start_time_ms_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000845 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
846 current_frames_ > 0) {
glaznev94291482016-02-01 13:17:18 -0800847 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
848 int current_fps =
849 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
glaznevfd6706a2016-02-05 14:05:08 -0800850 ALOGD << "Frames decoded: " << frames_decoded_ <<
851 ". Received: " << frames_received_ <<
glaznev94291482016-02-01 13:17:18 -0800852 ". Bitrate: " << current_bitrate << " kbps" <<
853 ". Fps: " << current_fps <<
854 ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
glaznevfd6706a2016-02-05 14:05:08 -0800855 ". DelayTime: " << (current_delay_time_ms_ / current_frames_) <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700856 " for last " << statistic_time_ms << " ms.";
Niels Möllerd28db7f2016-05-10 16:31:47 +0200857 start_time_ms_ = rtc::TimeMillis();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000858 current_frames_ = 0;
859 current_bytes_ = 0;
860 current_decoding_time_ms_ = 0;
glaznevfd6706a2016-02-05 14:05:08 -0800861 current_delay_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000862 }
863
nisse94cd3fa2016-05-23 23:35:54 -0700864 // If the frame was dropped, frame_buffer is left as nullptr.
865 if (frame_buffer) {
866 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
867 decoded_frame.set_timestamp(output_timestamps_ms);
868 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
869
Per488e75f2015-11-19 10:43:36 +0100870 const int32_t callback_status =
871 callback_->Decoded(decoded_frame, decode_time_ms);
872 if (callback_status > 0) {
873 ALOGE << "callback error";
874 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000875 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000876 return true;
877}
878
879int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
880 DecodedImageCallback* callback) {
881 callback_ = callback;
882 return WEBRTC_VIDEO_CODEC_OK;
883}
884
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000885void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
886 JNIEnv* jni = AttachCurrentThreadIfNeeded();
887 ScopedLocalRefFrame local_ref_frame(jni);
888 if (!inited_) {
889 return;
890 }
891 // We only ever send one message to |this| directly (not through a Bind()'d
892 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700893 RTC_CHECK(!msg->message_id) << "Unexpected message!";
894 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000895 CheckOnCodecThread();
896
897 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700898 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700899 ProcessHWErrorOnCodecThread();
900 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000901 }
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700902 codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000903}
904
perkj461121c2016-02-15 06:28:36 -0800905MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory()
906 : egl_context_(nullptr) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700907 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000908 JNIEnv* jni = AttachCurrentThreadIfNeeded();
909 ScopedLocalRefFrame local_ref_frame(jni);
910 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000911 supported_codec_types_.clear();
912
913 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000914 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000915 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700916 if (CheckException(jni)) {
917 is_vp8_hw_supported = false;
918 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000919 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700920 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000921 supported_codec_types_.push_back(kVideoCodecVP8);
922 }
923
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800924 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
925 j_decoder_class,
926 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
927 if (CheckException(jni)) {
928 is_vp9_hw_supported = false;
929 }
930 if (is_vp9_hw_supported) {
931 ALOGD << "VP9 HW Decoder supported.";
932 supported_codec_types_.push_back(kVideoCodecVP9);
933 }
934
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000935 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
936 j_decoder_class,
937 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700938 if (CheckException(jni)) {
939 is_h264_hw_supported = false;
940 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000941 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700942 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000943 supported_codec_types_.push_back(kVideoCodecH264);
944 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000945}
946
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700947MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700948 ALOGD << "MediaCodecVideoDecoderFactory dtor";
perkj461121c2016-02-15 06:28:36 -0800949 if (egl_context_) {
950 JNIEnv* jni = AttachCurrentThreadIfNeeded();
951 jni->DeleteGlobalRef(egl_context_);
952 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700953}
954
955void MediaCodecVideoDecoderFactory::SetEGLContext(
perkj461121c2016-02-15 06:28:36 -0800956 JNIEnv* jni, jobject egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700957 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Perfd22e6c2016-02-18 11:35:48 +0100958 if (egl_context_) {
959 jni->DeleteGlobalRef(egl_context_);
960 egl_context_ = nullptr;
961 }
perkj461121c2016-02-15 06:28:36 -0800962 egl_context_ = jni->NewGlobalRef(egl_context);
963 if (CheckException(jni)) {
964 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700965 }
966}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000967
968webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000969 VideoCodecType type) {
970 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800971 ALOGW << "No HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100972 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000973 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700974 for (VideoCodecType codec_type : supported_codec_types_) {
975 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700976 ALOGD << "Create HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100977 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
perkj461121c2016-02-15 06:28:36 -0800978 egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000979 }
980 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800981 ALOGW << "Can not find HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100982 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000983}
984
985void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
986 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700987 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000988 delete decoder;
989}
990
Peter Boströmb7d9a972015-12-18 16:01:11 +0100991const char* MediaCodecVideoDecoder::ImplementationName() const {
992 return "MediaCodec";
993}
994
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000995} // namespace webrtc_jni