blob: 49b84aa58522268d65c176373595e0f4bda1dbaf [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
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000070class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
71 public rtc::MessageHandler {
72 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070073 explicit MediaCodecVideoDecoder(
74 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000075 virtual ~MediaCodecVideoDecoder();
76
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000077 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
78 override;
79
80 int32_t Decode(
81 const EncodedImage& inputImage, bool missingFrames,
82 const RTPFragmentationHeader* fragmentation,
83 const CodecSpecificInfo* codecSpecificInfo = NULL,
84 int64_t renderTimeMs = -1) override;
85
86 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
87 override;
88
89 int32_t Release() override;
90
91 int32_t Reset() override;
perkj796cfaf2015-12-10 09:27:38 -080092
93 bool PrefersLateDecoding() const override { return true; }
94
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000095 // rtc::MessageHandler implementation.
96 void OnMessage(rtc::Message* msg) override;
97
98 private:
99 // CHECK-fail if not running on |codec_thread_|.
100 void CheckOnCodecThread();
101
102 int32_t InitDecodeOnCodecThread();
103 int32_t ReleaseOnCodecThread();
104 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
105 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
106 // true on success.
107 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700108 int32_t ProcessHWErrorOnCodecThread();
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
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000113 bool key_frame_required_;
114 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700115 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000116 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000117 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200118 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100119 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000120 DecodedImageCallback* callback_;
121 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000122 int frames_decoded_; // Number of frames decoded by decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000123 int64_t start_time_ms_; // Start time for statistics.
124 int current_frames_; // Number of frames in the current statistics interval.
125 int current_bytes_; // Encoded bytes in the current statistics interval.
126 int current_decoding_time_ms_; // Overall decoding time in the current second
127 uint32_t max_pending_frames_; // Maximum number of pending input frames
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000128
129 // State that is constant for the lifetime of this object once the ctor
130 // returns.
131 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
132 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
133 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
134 jmethodID j_init_decode_method_;
135 jmethodID j_release_method_;
136 jmethodID j_dequeue_input_buffer_method_;
137 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100138 jmethodID j_dequeue_byte_buffer_method_;
139 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700140 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000141 // MediaCodecVideoDecoder fields.
142 jfieldID j_input_buffers_field_;
143 jfieldID j_output_buffers_field_;
144 jfieldID j_color_format_field_;
145 jfieldID j_width_field_;
146 jfieldID j_height_field_;
147 jfieldID j_stride_field_;
148 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700149 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100150 jfieldID j_texture_id_field_;
151 jfieldID j_transform_matrix_field_;
152 jfieldID j_texture_timestamp_ms_field_;
153 jfieldID j_texture_ntp_timestamp_ms_field_;
154 jfieldID j_texture_decode_time_ms_field_;
155 jfieldID j_texture_frame_delay_ms_field_;
156 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000157 jfieldID j_info_index_field_;
158 jfieldID j_info_offset_field_;
159 jfieldID j_info_size_field_;
Per488e75f2015-11-19 10:43:36 +0100160 jfieldID j_info_timestamp_ms_field_;
161 jfieldID j_info_ntp_timestamp_ms_field_;
162 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000163
164 // Global references; must be deleted in Release().
165 std::vector<jobject> input_buffers_;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700166
167 // Render EGL context - owned by factory, should not be allocated/destroyed
168 // by VideoDecoder.
169 jobject render_egl_context_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000170};
171
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000172MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700173 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000174 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700175 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000176 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000177 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700178 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000179 codec_thread_(new Thread()),
180 j_media_codec_video_decoder_class_(
181 jni,
182 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
183 j_media_codec_video_decoder_(
184 jni,
185 jni->NewObject(*j_media_codec_video_decoder_class_,
186 GetMethodID(jni,
187 *j_media_codec_video_decoder_class_,
188 "<init>",
189 "()V"))) {
190 ScopedLocalRefFrame local_ref_frame(jni);
191 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700192 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000193
194 j_init_decode_method_ = GetMethodID(
195 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000196 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100197 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000198 j_release_method_ =
199 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
200 j_dequeue_input_buffer_method_ = GetMethodID(
201 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
202 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100203 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
204 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000205 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100206 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
207 j_dequeue_texture_buffer_method_ = GetMethodID(
208 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
209 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700210 j_return_decoded_byte_buffer_method_ =
211 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100212 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000213
214 j_input_buffers_field_ = GetFieldID(
215 jni, *j_media_codec_video_decoder_class_,
216 "inputBuffers", "[Ljava/nio/ByteBuffer;");
217 j_output_buffers_field_ = GetFieldID(
218 jni, *j_media_codec_video_decoder_class_,
219 "outputBuffers", "[Ljava/nio/ByteBuffer;");
220 j_color_format_field_ = GetFieldID(
221 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
222 j_width_field_ = GetFieldID(
223 jni, *j_media_codec_video_decoder_class_, "width", "I");
224 j_height_field_ = GetFieldID(
225 jni, *j_media_codec_video_decoder_class_, "height", "I");
226 j_stride_field_ = GetFieldID(
227 jni, *j_media_codec_video_decoder_class_, "stride", "I");
228 j_slice_height_field_ = GetFieldID(
229 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000230
Per488e75f2015-11-19 10:43:36 +0100231 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700232 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100233 j_texture_id_field_ = GetFieldID(
234 jni, j_decoded_texture_buffer_class, "textureID", "I");
235 j_transform_matrix_field_ = GetFieldID(
236 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
237 j_texture_timestamp_ms_field_ = GetFieldID(
238 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
239 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
240 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
241 j_texture_decode_time_ms_field_ = GetFieldID(
242 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
243 j_texture_frame_delay_ms_field_ = GetFieldID(
244 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700245
Per488e75f2015-11-19 10:43:36 +0100246 jclass j_decoded_output_buffer_class = FindClass(jni,
247 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000248 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100249 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000250 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100251 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000252 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100253 jni, j_decoded_output_buffer_class, "size", "I");
254 j_info_timestamp_ms_field_ = GetFieldID(
255 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
256 j_info_ntp_timestamp_ms_field_ = GetFieldID(
257 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
258 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
259 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000260
261 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200262 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700263 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000264 memset(&codec_, 0, sizeof(codec_));
265 AllowBlockingCalls();
266}
267
268MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
269 // Call Release() to ensure no more callbacks to us after we are deleted.
270 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000271}
272
273int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
274 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700275 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000276 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700277 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000278 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
279 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000280 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700281 RTC_CHECK(inst->codecType == codecType_)
282 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000283
Alex Glaznev782671f2015-06-12 16:40:44 -0700284 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700285 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700286 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000287 }
288 // Save VideoCodec instance for later.
289 if (&codec_ != inst) {
290 codec_ = *inst;
291 }
glazneve55c42c2015-10-28 10:30:32 -0700292 // If maxFramerate is not set then assume 30 fps.
293 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000294
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000295 // Call Java init.
296 return codec_thread_->Invoke<int32_t>(
297 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
298}
299
300int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
301 CheckOnCodecThread();
302 JNIEnv* jni = AttachCurrentThreadIfNeeded();
303 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700304 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
305 << codec_.width << " x " << codec_.height << ". Fps: " <<
306 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700307
308 // Release previous codec first if it was allocated before.
309 int ret_val = ReleaseOnCodecThread();
310 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700311 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700312 sw_fallback_required_ = true;
313 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000314 }
315
Alex Glaznev782671f2015-06-12 16:40:44 -0700316 // Always start with a complete key frame.
317 key_frame_required_ = true;
318 frames_received_ = 0;
319 frames_decoded_ = 0;
320
perkj88518a22015-12-18 00:37:06 -0800321 jobject java_surface_texture_helper_ = nullptr;
Per488e75f2015-11-19 10:43:36 +0100322 if (use_surface_) {
perkj88518a22015-12-18 00:37:06 -0800323 java_surface_texture_helper_ = jni->CallStaticObjectMethod(
324 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
325 GetStaticMethodID(jni,
326 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
327 "create",
328 "(Lorg/webrtc/EglBase$Context;)"
329 "Lorg/webrtc/SurfaceTextureHelper;"),
330 render_egl_context_);
331 RTC_CHECK(java_surface_texture_helper_ != nullptr);
Per488e75f2015-11-19 10:43:36 +0100332 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
perkj88518a22015-12-18 00:37:06 -0800333 jni, java_surface_texture_helper_);
Per488e75f2015-11-19 10:43:36 +0100334 }
335
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000336 jobject j_video_codec_enum = JavaEnumFromIndex(
337 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000338 bool success = jni->CallBooleanMethod(
339 *j_media_codec_video_decoder_,
340 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000341 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000342 codec_.width,
343 codec_.height,
perkj88518a22015-12-18 00:37:06 -0800344 java_surface_texture_helper_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700345 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700346 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700347 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000348 return WEBRTC_VIDEO_CODEC_ERROR;
349 }
350 inited_ = true;
351
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000352 switch (codecType_) {
353 case kVideoCodecVP8:
354 max_pending_frames_ = kMaxPendingFramesVp8;
355 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800356 case kVideoCodecVP9:
357 max_pending_frames_ = kMaxPendingFramesVp9;
358 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000359 case kVideoCodecH264:
360 max_pending_frames_ = kMaxPendingFramesH264;
361 break;
362 default:
363 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000364 }
365 start_time_ms_ = GetCurrentTimeMs();
366 current_frames_ = 0;
367 current_bytes_ = 0;
368 current_decoding_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000369
370 jobjectArray input_buffers = (jobjectArray)GetObjectField(
371 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
372 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700373 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000374 input_buffers_.resize(num_input_buffers);
375 for (size_t i = 0; i < num_input_buffers; ++i) {
376 input_buffers_[i] =
377 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700378 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700379 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700380 sw_fallback_required_ = true;
381 return WEBRTC_VIDEO_CODEC_ERROR;
382 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000383 }
384
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000385 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
386
387 return WEBRTC_VIDEO_CODEC_OK;
388}
389
390int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700391 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000392 return codec_thread_->Invoke<int32_t>(
393 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
394}
395
396int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
397 if (!inited_) {
398 return WEBRTC_VIDEO_CODEC_OK;
399 }
400 CheckOnCodecThread();
401 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700402 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
403 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000404 ScopedLocalRefFrame local_ref_frame(jni);
405 for (size_t i = 0; i < input_buffers_.size(); i++) {
406 jni->DeleteGlobalRef(input_buffers_[i]);
407 }
408 input_buffers_.clear();
409 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100410 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000411 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700412 rtc::MessageQueueManager::Clear(this);
413 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700414 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700415 return WEBRTC_VIDEO_CODEC_ERROR;
416 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700417 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000418 return WEBRTC_VIDEO_CODEC_OK;
419}
420
421void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700422 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000423 << "Running on wrong thread!";
424}
425
Alex Glaznev782671f2015-06-12 16:40:44 -0700426int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
427 CheckOnCodecThread();
428 int ret_val = ReleaseOnCodecThread();
429 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700430 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700431 }
432 if (codecType_ == kVideoCodecH264) {
433 // For now there is no SW H.264 which can be used as fallback codec.
434 // So try to restart hw codec for now.
435 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700436 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700437 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
438 // H.264 codec was succesfully reset - return regular error code.
439 return WEBRTC_VIDEO_CODEC_ERROR;
440 } else {
441 // Fail to restart H.264 codec - return error code which should stop the
442 // call.
443 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
444 }
445 } else {
446 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700447 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700448 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
449 }
450}
451
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000452int32_t MediaCodecVideoDecoder::Decode(
453 const EncodedImage& inputImage,
454 bool missingFrames,
455 const RTPFragmentationHeader* fragmentation,
456 const CodecSpecificInfo* codecSpecificInfo,
457 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700458 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700459 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700460 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000461 }
462 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700463 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000464 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
465 }
466 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700467 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000468 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
469 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700470 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700471 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700472 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
473 }
474
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000475 // Check if encoded frame dimension has changed.
476 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
477 (inputImage._encodedWidth != codec_.width ||
478 inputImage._encodedHeight != codec_.height)) {
479 codec_.width = inputImage._encodedWidth;
480 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700481 int32_t ret = InitDecode(&codec_, 1);
482 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700483 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700484 sw_fallback_required_ = true;
485 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
486 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000487 }
488
489 // Always start with a complete key frame.
490 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200491 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700492 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000493 return WEBRTC_VIDEO_CODEC_ERROR;
494 }
495 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700496 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000497 return WEBRTC_VIDEO_CODEC_ERROR;
498 }
499 key_frame_required_ = false;
500 }
501 if (inputImage._length == 0) {
502 return WEBRTC_VIDEO_CODEC_ERROR;
503 }
504
505 return codec_thread_->Invoke<int32_t>(Bind(
506 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
507}
508
509int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
510 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000511 CheckOnCodecThread();
512 JNIEnv* jni = AttachCurrentThreadIfNeeded();
513 ScopedLocalRefFrame local_ref_frame(jni);
514
515 // Try to drain the decoder and wait until output is not too
516 // much behind the input.
Per488e75f2015-11-19 10:43:36 +0100517 const int64 drain_start = GetCurrentTimeMs();
518 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
519 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000520 ALOGV("Received: %d. Decoded: %d. Wait for output...",
521 frames_received_, frames_decoded_);
Per488e75f2015-11-19 10:43:36 +0100522 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700523 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
524 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700525 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000526 }
Per488e75f2015-11-19 10:43:36 +0100527 }
528 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
529 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
530 frames_received_ << ". Frames decoded: " << frames_decoded_;
531 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000532 }
533
534 // Get input buffer.
535 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
536 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700537 if (CheckException(jni) || j_input_buffer_index < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700538 ALOGE << "dequeueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700539 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000540 }
541
542 // Copy encoded data to Java ByteBuffer.
543 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200544 uint8_t* buffer =
545 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700546 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200547 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700548 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700549 ALOGE << "Input frame size "<< inputImage._length <<
550 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700551 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000552 }
Per488e75f2015-11-19 10:43:36 +0100553 jlong presentation_timestamp_us =
554 (frames_received_ * 1000000) / codec_.maxFramerate;
glazneve55c42c2015-10-28 10:30:32 -0700555 if (frames_decoded_ < kMaxDecodedLogFrames) {
556 ALOGD << "Decoder frame in # " << frames_received_ << ". Type: "
557 << inputImage._frameType << ". Buffer # " <<
perkj87d58452015-11-23 01:46:27 -0800558 j_input_buffer_index << ". pTS: "
Per488e75f2015-11-19 10:43:36 +0100559 << (int)(presentation_timestamp_us / 1000)
perkj87d58452015-11-23 01:46:27 -0800560 << ". TS: " << inputImage._timeStamp
glazneve55c42c2015-10-28 10:30:32 -0700561 << ". Size: " << inputImage._length;
562 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000563 memcpy(buffer, inputImage._buffer, inputImage._length);
564
565 // Save input image timestamps for later output.
566 frames_received_++;
567 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000568
569 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100570 bool success = jni->CallBooleanMethod(
571 *j_media_codec_video_decoder_,
572 j_queue_input_buffer_method_,
573 j_input_buffer_index,
574 inputImage._length,
575 presentation_timestamp_us,
576 static_cast<int64_t> (inputImage._timeStamp),
577 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700578 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700579 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700580 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000581 }
582
583 // Try to drain the decoder
584 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700585 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700586 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000587 }
588
589 return WEBRTC_VIDEO_CODEC_OK;
590}
591
592bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100593 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000594 if (frames_received_ <= frames_decoded_) {
595 // No need to query for output buffers - decoder is drained.
596 return true;
597 }
598 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100599 jobject j_decoder_output_buffer =
600 jni->CallObjectMethod(*j_media_codec_video_decoder_,
601 use_surface_ ? j_dequeue_texture_buffer_method_
602 : j_dequeue_byte_buffer_method_,
603 dequeue_timeout_ms);
604
Alex Glaznev782671f2015-06-12 16:40:44 -0700605 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700606 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700607 return false;
608 }
magjed44bf6f52015-10-03 02:08:00 -0700609 if (IsNull(jni, j_decoder_output_buffer)) {
610 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000611 return true;
612 }
613
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000614 // Get decoded video frame properties.
615 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
616 j_color_format_field_);
617 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
618 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
619 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
620 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
621 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000622
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200623 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
Per488e75f2015-11-19 10:43:36 +0100624 int64_t output_timestamps_ms = 0;
625 int64_t output_ntp_timestamps_ms = 0;
626 int decode_time_ms = 0;
627 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200628 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700629 // Extract data from Java DecodedTextureBuffer.
630 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100631 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
632 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
633 const jfloatArray j_transform_matrix =
634 reinterpret_cast<jfloatArray>(GetObjectField(
635 jni, j_decoder_output_buffer, j_transform_matrix_field_));
636 const int64_t timestamp_us =
637 GetLongField(jni, j_decoder_output_buffer,
638 j_texture_timestamp_ms_field_);
639 output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer,
640 j_texture_timestamp_ms_field_);
641 output_ntp_timestamps_ms =
642 GetLongField(jni, j_decoder_output_buffer,
643 j_texture_ntp_timestamp_ms_field_);
644 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
645 j_texture_decode_time_ms_field_);
646 frame_delayed_ms = GetLongField(jni, j_decoder_output_buffer,
647 j_texture_frame_delay_ms_field_);
648
649 // Create webrtc::VideoFrameBuffer with native texture handle.
650 frame_buffer = surface_texture_helper_->CreateTextureFrame(
651 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
652 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200653 } else {
654 // Extract data from Java ByteBuffer and create output yuv420 frame -
655 // for non surface decoding only.
magjed44bf6f52015-10-03 02:08:00 -0700656 const int output_buffer_index =
657 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_);
658 const int output_buffer_offset =
659 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_);
660 const int output_buffer_size =
661 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_);
Per488e75f2015-11-19 10:43:36 +0100662 output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer,
663 j_info_timestamp_ms_field_);
664 output_ntp_timestamps_ms =
665 GetLongField(jni, j_decoder_output_buffer,
666 j_info_ntp_timestamp_ms_field_);
667
668 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
669 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700670
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000671 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700672 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000673 return false;
674 }
675 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
676 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
677 jobject output_buffer =
678 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
679 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
680 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700681 if (CheckException(jni)) {
682 return false;
683 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000684 payload += output_buffer_offset;
685
686 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200687 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000688 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200689 RTC_CHECK_EQ(0, stride % 2);
690 RTC_CHECK_EQ(0, slice_height % 2);
691 const int uv_stride = stride / 2;
692 const int u_slice_height = slice_height / 2;
693 const uint8_t* y_ptr = payload;
694 const uint8_t* u_ptr = y_ptr + stride * slice_height;
695 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
696 libyuv::I420Copy(y_ptr, stride,
697 u_ptr, uv_stride,
698 v_ptr, uv_stride,
699 frame_buffer->MutableData(webrtc::kYPlane),
700 frame_buffer->stride(webrtc::kYPlane),
701 frame_buffer->MutableData(webrtc::kUPlane),
702 frame_buffer->stride(webrtc::kUPlane),
703 frame_buffer->MutableData(webrtc::kVPlane),
704 frame_buffer->stride(webrtc::kVPlane),
705 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000706 } else {
707 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200708 const uint8_t* y_ptr = payload;
709 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000710 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200711 y_ptr, stride,
712 uv_ptr, stride,
713 frame_buffer->MutableData(webrtc::kYPlane),
714 frame_buffer->stride(webrtc::kYPlane),
715 frame_buffer->MutableData(webrtc::kUPlane),
716 frame_buffer->stride(webrtc::kUPlane),
717 frame_buffer->MutableData(webrtc::kVPlane),
718 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000719 width, height);
720 }
magjed44bf6f52015-10-03 02:08:00 -0700721 // Return output byte buffer back to codec.
722 jni->CallVoidMethod(
723 *j_media_codec_video_decoder_,
724 j_return_decoded_byte_buffer_method_,
725 output_buffer_index);
726 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100727 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700728 return false;
729 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000730 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200731 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
Per488e75f2015-11-19 10:43:36 +0100732 decoded_frame.set_timestamp(output_timestamps_ms);
733 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000734
glazneve55c42c2015-10-28 10:30:32 -0700735 if (frames_decoded_ < kMaxDecodedLogFrames) {
736 ALOGD << "Decoder frame out # " << frames_decoded_ << ". " << width <<
737 " x " << height << ". " << stride << " x " << slice_height <<
perkj87d58452015-11-23 01:46:27 -0800738 ". Color: " << color_format << ". TS:" << decoded_frame.timestamp() <<
Per488e75f2015-11-19 10:43:36 +0100739 ". DecTime: " << (int)decode_time_ms <<
740 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700741 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000742
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000743 // Calculate and print decoding statistics - every 3 seconds.
744 frames_decoded_++;
745 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100746 current_decoding_time_ms_ += decode_time_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000747 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
748 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
749 current_frames_ > 0) {
Per488e75f2015-11-19 10:43:36 +0100750 ALOGD << "Decoded frames: " << frames_decoded_ << ". Received frames: "
751 << frames_received_ << ". Bitrate: " <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700752 (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " <<
753 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
754 << ". decTime: " << (current_decoding_time_ms_ / current_frames_) <<
755 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000756 start_time_ms_ = GetCurrentTimeMs();
757 current_frames_ = 0;
758 current_bytes_ = 0;
759 current_decoding_time_ms_ = 0;
760 }
761
Per488e75f2015-11-19 10:43:36 +0100762 // |.IsZeroSize())| returns true when a frame has been dropped.
763 if (!decoded_frame.IsZeroSize()) {
764 // Callback - output decoded frame.
765 const int32_t callback_status =
766 callback_->Decoded(decoded_frame, decode_time_ms);
767 if (callback_status > 0) {
768 ALOGE << "callback error";
769 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000770 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000771 return true;
772}
773
774int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
775 DecodedImageCallback* callback) {
776 callback_ = callback;
777 return WEBRTC_VIDEO_CODEC_OK;
778}
779
780int32_t MediaCodecVideoDecoder::Reset() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700781 ALOGD << "DecoderReset";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000782 if (!inited_) {
783 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
784 }
785 return InitDecode(&codec_, 1);
786}
787
788void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
789 JNIEnv* jni = AttachCurrentThreadIfNeeded();
790 ScopedLocalRefFrame local_ref_frame(jni);
791 if (!inited_) {
792 return;
793 }
794 // We only ever send one message to |this| directly (not through a Bind()'d
795 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700796 RTC_CHECK(!msg->message_id) << "Unexpected message!";
797 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000798 CheckOnCodecThread();
799
800 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700801 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700802 ProcessHWErrorOnCodecThread();
803 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000804 }
805 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
806}
807
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700808MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
809 render_egl_context_(NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700810 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000811 JNIEnv* jni = AttachCurrentThreadIfNeeded();
812 ScopedLocalRefFrame local_ref_frame(jni);
813 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000814 supported_codec_types_.clear();
815
816 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000817 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000818 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700819 if (CheckException(jni)) {
820 is_vp8_hw_supported = false;
821 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000822 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700823 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000824 supported_codec_types_.push_back(kVideoCodecVP8);
825 }
826
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800827 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
828 j_decoder_class,
829 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
830 if (CheckException(jni)) {
831 is_vp9_hw_supported = false;
832 }
833 if (is_vp9_hw_supported) {
834 ALOGD << "VP9 HW Decoder supported.";
835 supported_codec_types_.push_back(kVideoCodecVP9);
836 }
837
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000838 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
839 j_decoder_class,
840 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700841 if (CheckException(jni)) {
842 is_h264_hw_supported = false;
843 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000844 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700845 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000846 supported_codec_types_.push_back(kVideoCodecH264);
847 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000848}
849
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700850MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700851 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700852 if (render_egl_context_) {
853 JNIEnv* jni = AttachCurrentThreadIfNeeded();
854 jni->DeleteGlobalRef(render_egl_context_);
855 render_egl_context_ = NULL;
856 }
857}
858
859void MediaCodecVideoDecoderFactory::SetEGLContext(
860 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700861 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700862 if (render_egl_context_) {
863 jni->DeleteGlobalRef(render_egl_context_);
864 render_egl_context_ = NULL;
865 }
866 if (!IsNull(jni, render_egl_context)) {
867 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
868 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700869 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700870 render_egl_context_ = NULL;
871 } else {
magjed8c425aa2015-10-22 16:52:39 -0700872 jclass j_egl_context_class =
perkj40455d62015-12-02 01:07:18 -0800873 FindClass(jni, "org/webrtc/EglBase$Context");
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700874 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700875 ALOGE << "Wrong EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700876 jni->DeleteGlobalRef(render_egl_context_);
877 render_egl_context_ = NULL;
878 }
879 }
880 }
881 if (render_egl_context_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700882 ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700883 }
884}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000885
886webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000887 VideoCodecType type) {
888 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800889 ALOGW << "No HW video decoder for type " << (int)type;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000890 return NULL;
891 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700892 for (VideoCodecType codec_type : supported_codec_types_) {
893 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700894 ALOGD << "Create HW video decoder for type " << (int)type;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700895 return new MediaCodecVideoDecoder(
896 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000897 }
898 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800899 ALOGW << "Can not find HW video decoder for type " << (int)type;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000900 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000901}
902
903void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
904 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700905 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000906 delete decoder;
907}
908
909} // namespace webrtc_jni
910