blob: 17f379d12b5e913ad37753f498922257e6c0fe7e [file] [log] [blame]
glaznev@webrtc.org18c92472015-02-18 18:42:55 +00001/*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
magjed6d387c02015-10-14 04:02:01 -070029#include <algorithm>
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000030#include <vector>
31
32#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
33#include "talk/app/webrtc/java/jni/androidmediacodeccommon.h"
34#include "talk/app/webrtc/java/jni/classreferenceholder.h"
35#include "talk/app/webrtc/java/jni/native_handle_impl.h"
Per488e75f2015-11-19 10:43:36 +010036#include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000037#include "webrtc/base/bind.h"
38#include "webrtc/base/checks.h"
39#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020040#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000041#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020042#include "webrtc/base/timeutils.h"
kjellander6f8ce062015-11-16 13:52:24 -080043#include "webrtc/common_video/include/i420_buffer_pool.h"
perkj87d58452015-11-23 01:46:27 -080044#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010045#include "webrtc/system_wrappers/include/logcat_trace_context.h"
46#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000047#include "third_party/libyuv/include/libyuv/convert.h"
48#include "third_party/libyuv/include/libyuv/convert_from.h"
49#include "third_party/libyuv/include/libyuv/video_common.h"
50
51using rtc::Bind;
52using rtc::Thread;
53using rtc::ThreadManager;
54using rtc::scoped_ptr;
55
56using webrtc::CodecSpecificInfo;
57using webrtc::DecodedImageCallback;
58using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070059using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000060using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000061using webrtc::TickTime;
62using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000063using webrtc::VideoCodecType;
64using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000065using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080066using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000067
68namespace webrtc_jni {
69
glaznevf4decb52016-01-15 13:49:22 -080070// Logging macros.
71#define TAG_DECODER "MediaCodecVideoDecoder"
72#ifdef TRACK_BUFFER_TIMING
73#define ALOGV(...)
74 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
75#else
76#define ALOGV(...)
77#endif
78#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
79#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
80#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
81
glaznevae95ff32016-02-04 11:47:12 -080082enum { kMaxWarningLogFrames = 2 };
83
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000084class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
85 public rtc::MessageHandler {
86 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070087 explicit MediaCodecVideoDecoder(
88 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000089 virtual ~MediaCodecVideoDecoder();
90
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000091 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
92 override;
93
94 int32_t Decode(
95 const EncodedImage& inputImage, bool missingFrames,
96 const RTPFragmentationHeader* fragmentation,
97 const CodecSpecificInfo* codecSpecificInfo = NULL,
98 int64_t renderTimeMs = -1) override;
99
100 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
101 override;
102
103 int32_t Release() override;
104
perkj796cfaf2015-12-10 09:27:38 -0800105 bool PrefersLateDecoding() const override { return true; }
106
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000107 // rtc::MessageHandler implementation.
108 void OnMessage(rtc::Message* msg) override;
109
Peter Boströmb7d9a972015-12-18 16:01:11 +0100110 const char* ImplementationName() const override;
111
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000112 private:
113 // CHECK-fail if not running on |codec_thread_|.
114 void CheckOnCodecThread();
115
116 int32_t InitDecodeOnCodecThread();
117 int32_t ReleaseOnCodecThread();
118 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
119 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
120 // true on success.
121 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700122 int32_t ProcessHWErrorOnCodecThread();
glaznevae95ff32016-02-04 11:47:12 -0800123 void EnableFrameLogOnWarning();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000124
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000125 // Type of video codec.
126 VideoCodecType codecType_;
127
kjellander60ca31b2016-01-04 10:15:53 -0800128 // Render EGL context - owned by factory, should not be allocated/destroyed
129 // by VideoDecoder.
130 jobject render_egl_context_;
131
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000132 bool key_frame_required_;
133 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700134 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000135 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000136 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200137 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100138 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000139 DecodedImageCallback* callback_;
140 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000141 int frames_decoded_; // Number of frames decoded by decoder.
glaznevae95ff32016-02-04 11:47:12 -0800142 // Number of decoded frames for which log information is displayed.
143 int frames_decoded_logged_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000144 int64_t start_time_ms_; // Start time for statistics.
145 int current_frames_; // Number of frames in the current statistics interval.
146 int current_bytes_; // Encoded bytes in the current statistics interval.
147 int current_decoding_time_ms_; // Overall decoding time in the current second
148 uint32_t max_pending_frames_; // Maximum number of pending input frames
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000149
150 // State that is constant for the lifetime of this object once the ctor
151 // returns.
152 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
153 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
154 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
155 jmethodID j_init_decode_method_;
156 jmethodID j_release_method_;
157 jmethodID j_dequeue_input_buffer_method_;
158 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100159 jmethodID j_dequeue_byte_buffer_method_;
160 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700161 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000162 // MediaCodecVideoDecoder fields.
163 jfieldID j_input_buffers_field_;
164 jfieldID j_output_buffers_field_;
165 jfieldID j_color_format_field_;
166 jfieldID j_width_field_;
167 jfieldID j_height_field_;
168 jfieldID j_stride_field_;
169 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700170 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100171 jfieldID j_texture_id_field_;
172 jfieldID j_transform_matrix_field_;
glaznev94291482016-02-01 13:17:18 -0800173 jfieldID j_texture_presentation_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100174 jfieldID j_texture_timestamp_ms_field_;
175 jfieldID j_texture_ntp_timestamp_ms_field_;
176 jfieldID j_texture_decode_time_ms_field_;
177 jfieldID j_texture_frame_delay_ms_field_;
178 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000179 jfieldID j_info_index_field_;
180 jfieldID j_info_offset_field_;
181 jfieldID j_info_size_field_;
glaznev94291482016-02-01 13:17:18 -0800182 jfieldID j_presentation_timestamp_ms_field_;
183 jfieldID j_timestamp_ms_field_;
184 jfieldID j_ntp_timestamp_ms_field_;
Per488e75f2015-11-19 10:43:36 +0100185 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000186
187 // Global references; must be deleted in Release().
188 std::vector<jobject> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000189};
190
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000191MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700192 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000193 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700194 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000195 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000196 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700197 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000198 codec_thread_(new Thread()),
199 j_media_codec_video_decoder_class_(
200 jni,
201 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
202 j_media_codec_video_decoder_(
203 jni,
204 jni->NewObject(*j_media_codec_video_decoder_class_,
205 GetMethodID(jni,
206 *j_media_codec_video_decoder_class_,
207 "<init>",
208 "()V"))) {
209 ScopedLocalRefFrame local_ref_frame(jni);
210 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700211 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000212
213 j_init_decode_method_ = GetMethodID(
214 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000215 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100216 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000217 j_release_method_ =
218 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
219 j_dequeue_input_buffer_method_ = GetMethodID(
220 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
221 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100222 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
223 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000224 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100225 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
226 j_dequeue_texture_buffer_method_ = GetMethodID(
227 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
228 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700229 j_return_decoded_byte_buffer_method_ =
230 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100231 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000232
233 j_input_buffers_field_ = GetFieldID(
234 jni, *j_media_codec_video_decoder_class_,
235 "inputBuffers", "[Ljava/nio/ByteBuffer;");
236 j_output_buffers_field_ = GetFieldID(
237 jni, *j_media_codec_video_decoder_class_,
238 "outputBuffers", "[Ljava/nio/ByteBuffer;");
239 j_color_format_field_ = GetFieldID(
240 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
241 j_width_field_ = GetFieldID(
242 jni, *j_media_codec_video_decoder_class_, "width", "I");
243 j_height_field_ = GetFieldID(
244 jni, *j_media_codec_video_decoder_class_, "height", "I");
245 j_stride_field_ = GetFieldID(
246 jni, *j_media_codec_video_decoder_class_, "stride", "I");
247 j_slice_height_field_ = GetFieldID(
248 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000249
Per488e75f2015-11-19 10:43:36 +0100250 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700251 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100252 j_texture_id_field_ = GetFieldID(
253 jni, j_decoded_texture_buffer_class, "textureID", "I");
254 j_transform_matrix_field_ = GetFieldID(
255 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
glaznev94291482016-02-01 13:17:18 -0800256 j_texture_presentation_timestamp_ms_field_ = GetFieldID(
257 jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
Per488e75f2015-11-19 10:43:36 +0100258 j_texture_timestamp_ms_field_ = GetFieldID(
259 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
260 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
261 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
262 j_texture_decode_time_ms_field_ = GetFieldID(
263 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
264 j_texture_frame_delay_ms_field_ = GetFieldID(
265 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700266
Per488e75f2015-11-19 10:43:36 +0100267 jclass j_decoded_output_buffer_class = FindClass(jni,
268 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000269 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100270 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000271 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100272 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000273 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100274 jni, j_decoded_output_buffer_class, "size", "I");
glaznev94291482016-02-01 13:17:18 -0800275 j_presentation_timestamp_ms_field_ = GetFieldID(
276 jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
277 j_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100278 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
glaznev94291482016-02-01 13:17:18 -0800279 j_ntp_timestamp_ms_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100280 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
281 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
282 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000283
284 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200285 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700286 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000287 memset(&codec_, 0, sizeof(codec_));
288 AllowBlockingCalls();
289}
290
291MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
292 // Call Release() to ensure no more callbacks to us after we are deleted.
293 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000294}
295
296int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
297 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700298 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000299 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700300 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000301 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
302 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000303 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700304 RTC_CHECK(inst->codecType == codecType_)
305 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000306
Alex Glaznev782671f2015-06-12 16:40:44 -0700307 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700308 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700309 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000310 }
311 // Save VideoCodec instance for later.
312 if (&codec_ != inst) {
313 codec_ = *inst;
314 }
glazneve55c42c2015-10-28 10:30:32 -0700315 // If maxFramerate is not set then assume 30 fps.
316 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000317
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000318 // Call Java init.
319 return codec_thread_->Invoke<int32_t>(
320 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
321}
322
323int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
324 CheckOnCodecThread();
325 JNIEnv* jni = AttachCurrentThreadIfNeeded();
326 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700327 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
328 << codec_.width << " x " << codec_.height << ". Fps: " <<
329 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700330
331 // Release previous codec first if it was allocated before.
332 int ret_val = ReleaseOnCodecThread();
333 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700334 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700335 sw_fallback_required_ = true;
336 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000337 }
338
Alex Glaznev782671f2015-06-12 16:40:44 -0700339 // Always start with a complete key frame.
340 key_frame_required_ = true;
341 frames_received_ = 0;
342 frames_decoded_ = 0;
glaznevae95ff32016-02-04 11:47:12 -0800343 frames_decoded_logged_ = kMaxDecodedLogFrames;
Alex Glaznev782671f2015-06-12 16:40:44 -0700344
perkj88518a22015-12-18 00:37:06 -0800345 jobject java_surface_texture_helper_ = nullptr;
Per488e75f2015-11-19 10:43:36 +0100346 if (use_surface_) {
perkj88518a22015-12-18 00:37:06 -0800347 java_surface_texture_helper_ = jni->CallStaticObjectMethod(
348 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
349 GetStaticMethodID(jni,
350 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
351 "create",
352 "(Lorg/webrtc/EglBase$Context;)"
353 "Lorg/webrtc/SurfaceTextureHelper;"),
354 render_egl_context_);
355 RTC_CHECK(java_surface_texture_helper_ != nullptr);
Per488e75f2015-11-19 10:43:36 +0100356 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
perkj88518a22015-12-18 00:37:06 -0800357 jni, java_surface_texture_helper_);
Per488e75f2015-11-19 10:43:36 +0100358 }
359
Perec2922f2016-01-27 15:25:46 +0100360 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000361 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000362 bool success = jni->CallBooleanMethod(
363 *j_media_codec_video_decoder_,
364 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000365 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000366 codec_.width,
367 codec_.height,
perkj88518a22015-12-18 00:37:06 -0800368 java_surface_texture_helper_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700369 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700370 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700371 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000372 return WEBRTC_VIDEO_CODEC_ERROR;
373 }
374 inited_ = true;
375
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000376 switch (codecType_) {
377 case kVideoCodecVP8:
378 max_pending_frames_ = kMaxPendingFramesVp8;
379 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800380 case kVideoCodecVP9:
381 max_pending_frames_ = kMaxPendingFramesVp9;
382 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000383 case kVideoCodecH264:
384 max_pending_frames_ = kMaxPendingFramesH264;
385 break;
386 default:
387 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000388 }
389 start_time_ms_ = GetCurrentTimeMs();
390 current_frames_ = 0;
391 current_bytes_ = 0;
392 current_decoding_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000393
394 jobjectArray input_buffers = (jobjectArray)GetObjectField(
395 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
396 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700397 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000398 input_buffers_.resize(num_input_buffers);
399 for (size_t i = 0; i < num_input_buffers; ++i) {
400 input_buffers_[i] =
401 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700402 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700403 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700404 sw_fallback_required_ = true;
405 return WEBRTC_VIDEO_CODEC_ERROR;
406 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000407 }
408
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000409 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
410
411 return WEBRTC_VIDEO_CODEC_OK;
412}
413
414int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700415 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000416 return codec_thread_->Invoke<int32_t>(
417 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
418}
419
420int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
421 if (!inited_) {
422 return WEBRTC_VIDEO_CODEC_OK;
423 }
424 CheckOnCodecThread();
425 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700426 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
427 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000428 ScopedLocalRefFrame local_ref_frame(jni);
429 for (size_t i = 0; i < input_buffers_.size(); i++) {
430 jni->DeleteGlobalRef(input_buffers_[i]);
431 }
432 input_buffers_.clear();
433 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100434 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000435 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700436 rtc::MessageQueueManager::Clear(this);
437 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700438 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700439 return WEBRTC_VIDEO_CODEC_ERROR;
440 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700441 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000442 return WEBRTC_VIDEO_CODEC_OK;
443}
444
445void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700446 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000447 << "Running on wrong thread!";
448}
449
glaznevae95ff32016-02-04 11:47:12 -0800450void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
451 // Log next 2 output frames.
452 frames_decoded_logged_ = std::max(
453 frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
454}
455
Alex Glaznev782671f2015-06-12 16:40:44 -0700456int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
457 CheckOnCodecThread();
458 int ret_val = ReleaseOnCodecThread();
459 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700460 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700461 }
462 if (codecType_ == kVideoCodecH264) {
463 // For now there is no SW H.264 which can be used as fallback codec.
464 // So try to restart hw codec for now.
465 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700466 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700467 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
468 // H.264 codec was succesfully reset - return regular error code.
469 return WEBRTC_VIDEO_CODEC_ERROR;
470 } else {
471 // Fail to restart H.264 codec - return error code which should stop the
472 // call.
473 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
474 }
475 } else {
476 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700477 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700478 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
479 }
480}
481
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000482int32_t MediaCodecVideoDecoder::Decode(
483 const EncodedImage& inputImage,
484 bool missingFrames,
485 const RTPFragmentationHeader* fragmentation,
486 const CodecSpecificInfo* codecSpecificInfo,
487 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700488 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700489 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700490 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000491 }
492 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700493 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000494 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
495 }
496 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700497 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000498 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
499 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700500 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700501 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700502 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
503 }
504
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000505 // Check if encoded frame dimension has changed.
506 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
507 (inputImage._encodedWidth != codec_.width ||
508 inputImage._encodedHeight != codec_.height)) {
509 codec_.width = inputImage._encodedWidth;
510 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700511 int32_t ret = InitDecode(&codec_, 1);
512 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700513 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700514 sw_fallback_required_ = true;
515 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
516 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000517 }
518
519 // Always start with a complete key frame.
520 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200521 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700522 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000523 return WEBRTC_VIDEO_CODEC_ERROR;
524 }
525 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700526 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000527 return WEBRTC_VIDEO_CODEC_ERROR;
528 }
529 key_frame_required_ = false;
530 }
531 if (inputImage._length == 0) {
532 return WEBRTC_VIDEO_CODEC_ERROR;
533 }
534
535 return codec_thread_->Invoke<int32_t>(Bind(
536 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
537}
538
539int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
540 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000541 CheckOnCodecThread();
542 JNIEnv* jni = AttachCurrentThreadIfNeeded();
543 ScopedLocalRefFrame local_ref_frame(jni);
544
545 // Try to drain the decoder and wait until output is not too
546 // much behind the input.
glaznevae95ff32016-02-04 11:47:12 -0800547 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
548 ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
549 frames_received_ << ". Decoded: " << frames_decoded_;
550 EnableFrameLogOnWarning();
551 }
Per488e75f2015-11-19 10:43:36 +0100552 const int64 drain_start = GetCurrentTimeMs();
553 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
554 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
Per488e75f2015-11-19 10:43:36 +0100555 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700556 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
557 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700558 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000559 }
Per488e75f2015-11-19 10:43:36 +0100560 }
561 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
562 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
563 frames_received_ << ". Frames decoded: " << frames_decoded_;
564 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000565 }
566
567 // Get input buffer.
glaznevae95ff32016-02-04 11:47:12 -0800568 int j_input_buffer_index = jni->CallIntMethod(
569 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700570 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznevae95ff32016-02-04 11:47:12 -0800571 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
572 ". Retry DeliverPendingOutputs.";
573 EnableFrameLogOnWarning();
574 // Try to drain the decoder.
575 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
576 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
577 frames_received_ << ". Frames decoded: " << frames_decoded_;
578 return ProcessHWErrorOnCodecThread();
579 }
580 // Try dequeue input buffer one last time.
581 j_input_buffer_index = jni->CallIntMethod(
582 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
583 if (CheckException(jni) || j_input_buffer_index < 0) {
584 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
585 return ProcessHWErrorOnCodecThread();
586 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000587 }
588
589 // Copy encoded data to Java ByteBuffer.
590 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200591 uint8_t* buffer =
592 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700593 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200594 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700595 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700596 ALOGE << "Input frame size "<< inputImage._length <<
597 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700598 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000599 }
glaznevae95ff32016-02-04 11:47:12 -0800600 jlong presentation_timestamp_us = static_cast<jlong>(
601 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000602 memcpy(buffer, inputImage._buffer, inputImage._length);
603
glaznevae95ff32016-02-04 11:47:12 -0800604 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800605 ALOGD << "Decoder frame in # " << frames_received_ <<
606 ". Type: " << inputImage._frameType <<
607 ". Buffer # " << j_input_buffer_index <<
glaznevae95ff32016-02-04 11:47:12 -0800608 ". TS: " << presentation_timestamp_us / 1000 <<
glaznev94291482016-02-01 13:17:18 -0800609 ". Size: " << inputImage._length;
610 }
611
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000612 // Save input image timestamps for later output.
613 frames_received_++;
614 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000615
616 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100617 bool success = jni->CallBooleanMethod(
618 *j_media_codec_video_decoder_,
619 j_queue_input_buffer_method_,
620 j_input_buffer_index,
621 inputImage._length,
622 presentation_timestamp_us,
623 static_cast<int64_t> (inputImage._timeStamp),
624 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700625 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700626 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700627 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000628 }
629
630 // Try to drain the decoder
631 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700632 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700633 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000634 }
635
636 return WEBRTC_VIDEO_CODEC_OK;
637}
638
639bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100640 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000641 if (frames_received_ <= frames_decoded_) {
642 // No need to query for output buffers - decoder is drained.
643 return true;
644 }
645 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100646 jobject j_decoder_output_buffer =
647 jni->CallObjectMethod(*j_media_codec_video_decoder_,
648 use_surface_ ? j_dequeue_texture_buffer_method_
649 : j_dequeue_byte_buffer_method_,
650 dequeue_timeout_ms);
651
Alex Glaznev782671f2015-06-12 16:40:44 -0700652 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700653 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700654 return false;
655 }
magjed44bf6f52015-10-03 02:08:00 -0700656 if (IsNull(jni, j_decoder_output_buffer)) {
657 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000658 return true;
659 }
660
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000661 // Get decoded video frame properties.
662 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
663 j_color_format_field_);
664 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
665 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
666 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
667 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
668 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000669
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200670 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
glaznev94291482016-02-01 13:17:18 -0800671 int64_t presentation_timestamps_ms = 0;
Per488e75f2015-11-19 10:43:36 +0100672 int64_t output_timestamps_ms = 0;
673 int64_t output_ntp_timestamps_ms = 0;
674 int decode_time_ms = 0;
675 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200676 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700677 // Extract data from Java DecodedTextureBuffer.
glaznevae95ff32016-02-04 11:47:12 -0800678 presentation_timestamps_ms = GetLongField(
679 jni, j_decoder_output_buffer,
680 j_texture_presentation_timestamp_ms_field_);
681 output_timestamps_ms = GetLongField(
682 jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
683 output_ntp_timestamps_ms = GetLongField(
684 jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
685 decode_time_ms = GetLongField(
686 jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
687
magjed44bf6f52015-10-03 02:08:00 -0700688 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100689 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
690 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
691 const jfloatArray j_transform_matrix =
692 reinterpret_cast<jfloatArray>(GetObjectField(
693 jni, j_decoder_output_buffer, j_transform_matrix_field_));
glaznev94291482016-02-01 13:17:18 -0800694 frame_delayed_ms = GetLongField(
695 jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100696
697 // Create webrtc::VideoFrameBuffer with native texture handle.
698 frame_buffer = surface_texture_helper_->CreateTextureFrame(
699 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
glaznevae95ff32016-02-04 11:47:12 -0800700 } else {
701 EnableFrameLogOnWarning();
Per488e75f2015-11-19 10:43:36 +0100702 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200703 } else {
704 // Extract data from Java ByteBuffer and create output yuv420 frame -
705 // for non surface decoding only.
glaznev94291482016-02-01 13:17:18 -0800706 const int output_buffer_index = GetIntField(
707 jni, j_decoder_output_buffer, j_info_index_field_);
708 const int output_buffer_offset = GetIntField(
709 jni, j_decoder_output_buffer, j_info_offset_field_);
710 const int output_buffer_size = GetIntField(
711 jni, j_decoder_output_buffer, j_info_size_field_);
712 presentation_timestamps_ms = GetLongField(
713 jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
714 output_timestamps_ms = GetLongField(
715 jni, j_decoder_output_buffer, j_timestamp_ms_field_);
716 output_ntp_timestamps_ms = GetLongField(
717 jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
Per488e75f2015-11-19 10:43:36 +0100718
719 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
720 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700721
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000722 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700723 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000724 return false;
725 }
726 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
727 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
728 jobject output_buffer =
729 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
730 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
731 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700732 if (CheckException(jni)) {
733 return false;
734 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000735 payload += output_buffer_offset;
736
737 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200738 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000739 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200740 RTC_CHECK_EQ(0, stride % 2);
741 RTC_CHECK_EQ(0, slice_height % 2);
742 const int uv_stride = stride / 2;
743 const int u_slice_height = slice_height / 2;
744 const uint8_t* y_ptr = payload;
745 const uint8_t* u_ptr = y_ptr + stride * slice_height;
746 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
747 libyuv::I420Copy(y_ptr, stride,
748 u_ptr, uv_stride,
749 v_ptr, uv_stride,
750 frame_buffer->MutableData(webrtc::kYPlane),
751 frame_buffer->stride(webrtc::kYPlane),
752 frame_buffer->MutableData(webrtc::kUPlane),
753 frame_buffer->stride(webrtc::kUPlane),
754 frame_buffer->MutableData(webrtc::kVPlane),
755 frame_buffer->stride(webrtc::kVPlane),
756 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000757 } else {
758 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200759 const uint8_t* y_ptr = payload;
760 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000761 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200762 y_ptr, stride,
763 uv_ptr, stride,
764 frame_buffer->MutableData(webrtc::kYPlane),
765 frame_buffer->stride(webrtc::kYPlane),
766 frame_buffer->MutableData(webrtc::kUPlane),
767 frame_buffer->stride(webrtc::kUPlane),
768 frame_buffer->MutableData(webrtc::kVPlane),
769 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000770 width, height);
771 }
magjed44bf6f52015-10-03 02:08:00 -0700772 // Return output byte buffer back to codec.
773 jni->CallVoidMethod(
774 *j_media_codec_video_decoder_,
775 j_return_decoded_byte_buffer_method_,
776 output_buffer_index);
777 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100778 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700779 return false;
780 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000781 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200782 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
Per488e75f2015-11-19 10:43:36 +0100783 decoded_frame.set_timestamp(output_timestamps_ms);
784 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000785
glaznevae95ff32016-02-04 11:47:12 -0800786 if (frames_decoded_ < frames_decoded_logged_) {
glaznev94291482016-02-01 13:17:18 -0800787 ALOGD << "Decoder frame out # " << frames_decoded_ <<
788 ". " << width << " x " << height <<
789 ". " << stride << " x " << slice_height <<
790 ". Color: " << color_format <<
791 ". TS: " << presentation_timestamps_ms <<
Per488e75f2015-11-19 10:43:36 +0100792 ". DecTime: " << (int)decode_time_ms <<
793 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700794 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000795
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000796 // Calculate and print decoding statistics - every 3 seconds.
797 frames_decoded_++;
798 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100799 current_decoding_time_ms_ += decode_time_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000800 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
801 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
802 current_frames_ > 0) {
glaznev94291482016-02-01 13:17:18 -0800803 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
804 int current_fps =
805 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
806 ALOGD << "Decoded frames: " << frames_decoded_ <<
807 ". Received frames: " << frames_received_ <<
808 ". Bitrate: " << current_bitrate << " kbps" <<
809 ". Fps: " << current_fps <<
810 ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700811 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000812 start_time_ms_ = GetCurrentTimeMs();
813 current_frames_ = 0;
814 current_bytes_ = 0;
815 current_decoding_time_ms_ = 0;
816 }
817
Per488e75f2015-11-19 10:43:36 +0100818 // |.IsZeroSize())| returns true when a frame has been dropped.
819 if (!decoded_frame.IsZeroSize()) {
820 // Callback - output decoded frame.
821 const int32_t callback_status =
822 callback_->Decoded(decoded_frame, decode_time_ms);
823 if (callback_status > 0) {
824 ALOGE << "callback error";
825 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000826 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000827 return true;
828}
829
830int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
831 DecodedImageCallback* callback) {
832 callback_ = callback;
833 return WEBRTC_VIDEO_CODEC_OK;
834}
835
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000836void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
837 JNIEnv* jni = AttachCurrentThreadIfNeeded();
838 ScopedLocalRefFrame local_ref_frame(jni);
839 if (!inited_) {
840 return;
841 }
842 // We only ever send one message to |this| directly (not through a Bind()'d
843 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700844 RTC_CHECK(!msg->message_id) << "Unexpected message!";
845 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000846 CheckOnCodecThread();
847
848 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700849 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700850 ProcessHWErrorOnCodecThread();
851 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000852 }
853 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
854}
855
Perec2922f2016-01-27 15:25:46 +0100856MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700857 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000858 JNIEnv* jni = AttachCurrentThreadIfNeeded();
859 ScopedLocalRefFrame local_ref_frame(jni);
860 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000861 supported_codec_types_.clear();
862
863 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000864 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000865 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700866 if (CheckException(jni)) {
867 is_vp8_hw_supported = false;
868 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000869 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700870 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000871 supported_codec_types_.push_back(kVideoCodecVP8);
872 }
873
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800874 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
875 j_decoder_class,
876 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
877 if (CheckException(jni)) {
878 is_vp9_hw_supported = false;
879 }
880 if (is_vp9_hw_supported) {
881 ALOGD << "VP9 HW Decoder supported.";
882 supported_codec_types_.push_back(kVideoCodecVP9);
883 }
884
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000885 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
886 j_decoder_class,
887 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700888 if (CheckException(jni)) {
889 is_h264_hw_supported = false;
890 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000891 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700892 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000893 supported_codec_types_.push_back(kVideoCodecH264);
894 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000895}
896
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700897MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700898 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700899}
900
901void MediaCodecVideoDecoderFactory::SetEGLContext(
902 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700903 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Perec2922f2016-01-27 15:25:46 +0100904 if (!egl_.CreateEglBase(jni, render_egl_context)) {
905 ALOGW << "Invalid EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700906 }
907}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000908
909webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000910 VideoCodecType type) {
911 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800912 ALOGW << "No HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100913 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000914 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700915 for (VideoCodecType codec_type : supported_codec_types_) {
916 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700917 ALOGD << "Create HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100918 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
919 egl_.egl_base_context());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000920 }
921 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800922 ALOGW << "Can not find HW video decoder for type " << (int)type;
Perec2922f2016-01-27 15:25:46 +0100923 return nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000924}
925
926void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
927 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700928 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000929 delete decoder;
930}
931
Peter Boströmb7d9a972015-12-18 16:01:11 +0100932const char* MediaCodecVideoDecoder::ImplementationName() const {
933 return "MediaCodec";
934}
935
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000936} // namespace webrtc_jni
937