blob: ed5ba0b478edd0df334db0e1eca929e101312415 [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"
Magnus Jedvert91b348c2015-10-07 22:57:06 +020036#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"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020043#include "webrtc/common_video/interface/i420_buffer_pool.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000044#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
45#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
46#include "webrtc/system_wrappers/interface/tick_util.h"
47#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;
66
67namespace webrtc_jni {
68
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000069class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
70 public rtc::MessageHandler {
71 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070072 explicit MediaCodecVideoDecoder(
73 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000074 virtual ~MediaCodecVideoDecoder();
75
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000076 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
77 override;
78
79 int32_t Decode(
80 const EncodedImage& inputImage, bool missingFrames,
81 const RTPFragmentationHeader* fragmentation,
82 const CodecSpecificInfo* codecSpecificInfo = NULL,
83 int64_t renderTimeMs = -1) override;
84
85 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
86 override;
87
88 int32_t Release() override;
89
90 int32_t Reset() override;
91 // rtc::MessageHandler implementation.
92 void OnMessage(rtc::Message* msg) override;
93
94 private:
95 // CHECK-fail if not running on |codec_thread_|.
96 void CheckOnCodecThread();
97
98 int32_t InitDecodeOnCodecThread();
99 int32_t ReleaseOnCodecThread();
100 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
101 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
102 // true on success.
103 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700104 int32_t ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000105
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000106 // Type of video codec.
107 VideoCodecType codecType_;
108
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000109 bool key_frame_required_;
110 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700111 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000112 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000113 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200114 webrtc::I420BufferPool decoded_frame_pool_;
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200115 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000116 DecodedImageCallback* callback_;
117 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000118 int frames_decoded_; // Number of frames decoded by decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000119 int64_t start_time_ms_; // Start time for statistics.
120 int current_frames_; // Number of frames in the current statistics interval.
121 int current_bytes_; // Encoded bytes in the current statistics interval.
122 int current_decoding_time_ms_; // Overall decoding time in the current second
123 uint32_t max_pending_frames_; // Maximum number of pending input frames
124 std::vector<int32_t> timestamps_;
125 std::vector<int64_t> ntp_times_ms_;
126 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
127 // decoder input.
128
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_;
138 jmethodID j_dequeue_output_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700139 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000140 // MediaCodecVideoDecoder fields.
141 jfieldID j_input_buffers_field_;
142 jfieldID j_output_buffers_field_;
143 jfieldID j_color_format_field_;
144 jfieldID j_width_field_;
145 jfieldID j_height_field_;
146 jfieldID j_stride_field_;
147 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700148 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000149 jfieldID j_textureID_field_;
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200150 jfieldID j_transform_matrix_field_;
151 jfieldID j_texture_timestamp_ns_field_;
magjed44bf6f52015-10-03 02:08:00 -0700152 // MediaCodecVideoDecoder.DecodedByteBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000153 jfieldID j_info_index_field_;
154 jfieldID j_info_offset_field_;
155 jfieldID j_info_size_field_;
156 jfieldID j_info_presentation_timestamp_us_field_;
157
158 // Global references; must be deleted in Release().
159 std::vector<jobject> input_buffers_;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700160
161 // Render EGL context - owned by factory, should not be allocated/destroyed
162 // by VideoDecoder.
163 jobject render_egl_context_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000164};
165
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000166MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700167 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000168 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700169 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000170 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000171 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700172 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000173 codec_thread_(new Thread()),
174 j_media_codec_video_decoder_class_(
175 jni,
176 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
177 j_media_codec_video_decoder_(
178 jni,
179 jni->NewObject(*j_media_codec_video_decoder_class_,
180 GetMethodID(jni,
181 *j_media_codec_video_decoder_class_,
182 "<init>",
183 "()V"))) {
184 ScopedLocalRefFrame local_ref_frame(jni);
185 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700186 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000187
188 j_init_decode_method_ = GetMethodID(
189 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000190 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200191 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000192 j_release_method_ =
193 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
194 j_dequeue_input_buffer_method_ = GetMethodID(
195 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
196 j_queue_input_buffer_method_ = GetMethodID(
197 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
198 j_dequeue_output_buffer_method_ = GetMethodID(
199 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
magjed44bf6f52015-10-03 02:08:00 -0700200 "(I)Ljava/lang/Object;");
201 j_return_decoded_byte_buffer_method_ =
202 GetMethodID(jni, *j_media_codec_video_decoder_class_,
203 "returnDecodedByteBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000204
205 j_input_buffers_field_ = GetFieldID(
206 jni, *j_media_codec_video_decoder_class_,
207 "inputBuffers", "[Ljava/nio/ByteBuffer;");
208 j_output_buffers_field_ = GetFieldID(
209 jni, *j_media_codec_video_decoder_class_,
210 "outputBuffers", "[Ljava/nio/ByteBuffer;");
211 j_color_format_field_ = GetFieldID(
212 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
213 j_width_field_ = GetFieldID(
214 jni, *j_media_codec_video_decoder_class_, "width", "I");
215 j_height_field_ = GetFieldID(
216 jni, *j_media_codec_video_decoder_class_, "height", "I");
217 j_stride_field_ = GetFieldID(
218 jni, *j_media_codec_video_decoder_class_, "stride", "I");
219 j_slice_height_field_ = GetFieldID(
220 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000221
magjed44bf6f52015-10-03 02:08:00 -0700222 jclass j_decoder_decoded_texture_buffer_class = FindClass(jni,
223 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
224 j_textureID_field_ = GetFieldID(
225 jni, j_decoder_decoded_texture_buffer_class, "textureID", "I");
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200226 j_transform_matrix_field_ = GetFieldID(
227 jni, j_decoder_decoded_texture_buffer_class, "transformMatrix", "[F");
228 j_texture_timestamp_ns_field_ = GetFieldID(
229 jni, j_decoder_decoded_texture_buffer_class, "timestampNs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700230
231 jclass j_decoder_decoded_byte_buffer_class = FindClass(jni,
232 "org/webrtc/MediaCodecVideoDecoder$DecodedByteBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000233 j_info_index_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700234 jni, j_decoder_decoded_byte_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000235 j_info_offset_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700236 jni, j_decoder_decoded_byte_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000237 j_info_size_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700238 jni, j_decoder_decoded_byte_buffer_class, "size", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000239 j_info_presentation_timestamp_us_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700240 jni, j_decoder_decoded_byte_buffer_class, "presentationTimestampUs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000241
242 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200243 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700244 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000245 memset(&codec_, 0, sizeof(codec_));
246 AllowBlockingCalls();
247}
248
249MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
250 // Call Release() to ensure no more callbacks to us after we are deleted.
251 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000252}
253
254int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
255 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700256 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000257 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700258 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000259 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
260 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000261 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700262 RTC_CHECK(inst->codecType == codecType_)
263 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000264
Alex Glaznev782671f2015-06-12 16:40:44 -0700265 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700266 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700267 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000268 }
269 // Save VideoCodec instance for later.
270 if (&codec_ != inst) {
271 codec_ = *inst;
272 }
273 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
274
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000275 // Call Java init.
276 return codec_thread_->Invoke<int32_t>(
277 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
278}
279
280int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
281 CheckOnCodecThread();
282 JNIEnv* jni = AttachCurrentThreadIfNeeded();
283 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700284 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
285 << codec_.width << " x " << codec_.height << ". Fps: " <<
286 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700287
288 // Release previous codec first if it was allocated before.
289 int ret_val = ReleaseOnCodecThread();
290 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700291 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700292 sw_fallback_required_ = true;
293 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000294 }
295
Alex Glaznev782671f2015-06-12 16:40:44 -0700296 // Always start with a complete key frame.
297 key_frame_required_ = true;
298 frames_received_ = 0;
299 frames_decoded_ = 0;
300
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200301 if (use_surface_) {
302 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
303 jni, render_egl_context_);
304 }
305
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000306 jobject j_video_codec_enum = JavaEnumFromIndex(
307 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000308 bool success = jni->CallBooleanMethod(
309 *j_media_codec_video_decoder_,
310 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000311 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000312 codec_.width,
313 codec_.height,
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200314 use_surface_ ? surface_texture_helper_->GetJavaSurfaceTextureHelper()
315 : nullptr);
Alex Glaznev782671f2015-06-12 16:40:44 -0700316 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700317 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700318 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000319 return WEBRTC_VIDEO_CODEC_ERROR;
320 }
321 inited_ = true;
322
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000323 switch (codecType_) {
324 case kVideoCodecVP8:
325 max_pending_frames_ = kMaxPendingFramesVp8;
326 break;
327 case kVideoCodecH264:
328 max_pending_frames_ = kMaxPendingFramesH264;
329 break;
330 default:
331 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000332 }
333 start_time_ms_ = GetCurrentTimeMs();
334 current_frames_ = 0;
335 current_bytes_ = 0;
336 current_decoding_time_ms_ = 0;
337 timestamps_.clear();
338 ntp_times_ms_.clear();
339 frame_rtc_times_ms_.clear();
340
341 jobjectArray input_buffers = (jobjectArray)GetObjectField(
342 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
343 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
magjed6d387c02015-10-14 04:02:01 -0700344 max_pending_frames_ =
345 std::min(max_pending_frames_, static_cast<uint32_t>(num_input_buffers));
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000346 input_buffers_.resize(num_input_buffers);
347 for (size_t i = 0; i < num_input_buffers; ++i) {
348 input_buffers_[i] =
349 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700350 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700351 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700352 sw_fallback_required_ = true;
353 return WEBRTC_VIDEO_CODEC_ERROR;
354 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000355 }
356
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000357 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
358
359 return WEBRTC_VIDEO_CODEC_OK;
360}
361
362int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700363 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000364 return codec_thread_->Invoke<int32_t>(
365 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
366}
367
368int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
369 if (!inited_) {
370 return WEBRTC_VIDEO_CODEC_OK;
371 }
372 CheckOnCodecThread();
373 JNIEnv* jni = AttachCurrentThreadIfNeeded();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700374 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " << frames_received_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000375 ScopedLocalRefFrame local_ref_frame(jni);
376 for (size_t i = 0; i < input_buffers_.size(); i++) {
377 jni->DeleteGlobalRef(input_buffers_[i]);
378 }
379 input_buffers_.clear();
380 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200381 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000382 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700383 rtc::MessageQueueManager::Clear(this);
384 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700385 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700386 return WEBRTC_VIDEO_CODEC_ERROR;
387 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700388 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000389 return WEBRTC_VIDEO_CODEC_OK;
390}
391
392void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700393 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000394 << "Running on wrong thread!";
395}
396
Alex Glaznev782671f2015-06-12 16:40:44 -0700397int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
398 CheckOnCodecThread();
399 int ret_val = ReleaseOnCodecThread();
400 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700401 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700402 }
403 if (codecType_ == kVideoCodecH264) {
404 // For now there is no SW H.264 which can be used as fallback codec.
405 // So try to restart hw codec for now.
406 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700407 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700408 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
409 // H.264 codec was succesfully reset - return regular error code.
410 return WEBRTC_VIDEO_CODEC_ERROR;
411 } else {
412 // Fail to restart H.264 codec - return error code which should stop the
413 // call.
414 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
415 }
416 } else {
417 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700418 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700419 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
420 }
421}
422
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000423int32_t MediaCodecVideoDecoder::Decode(
424 const EncodedImage& inputImage,
425 bool missingFrames,
426 const RTPFragmentationHeader* fragmentation,
427 const CodecSpecificInfo* codecSpecificInfo,
428 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700429 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700430 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700431 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000432 }
433 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700434 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000435 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
436 }
437 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700438 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000439 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
440 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700441 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700442 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700443 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
444 }
445
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000446 // Check if encoded frame dimension has changed.
447 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
448 (inputImage._encodedWidth != codec_.width ||
449 inputImage._encodedHeight != codec_.height)) {
450 codec_.width = inputImage._encodedWidth;
451 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700452 int32_t ret = InitDecode(&codec_, 1);
453 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700454 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700455 sw_fallback_required_ = true;
456 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
457 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000458 }
459
460 // Always start with a complete key frame.
461 if (key_frame_required_) {
462 if (inputImage._frameType != webrtc::kKeyFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700463 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000464 return WEBRTC_VIDEO_CODEC_ERROR;
465 }
466 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700467 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000468 return WEBRTC_VIDEO_CODEC_ERROR;
469 }
470 key_frame_required_ = false;
471 }
472 if (inputImage._length == 0) {
473 return WEBRTC_VIDEO_CODEC_ERROR;
474 }
475
476 return codec_thread_->Invoke<int32_t>(Bind(
477 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
478}
479
480int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
481 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000482 CheckOnCodecThread();
483 JNIEnv* jni = AttachCurrentThreadIfNeeded();
484 ScopedLocalRefFrame local_ref_frame(jni);
485
486 // Try to drain the decoder and wait until output is not too
487 // much behind the input.
488 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000489 ALOGV("Received: %d. Decoded: %d. Wait for output...",
490 frames_received_, frames_decoded_);
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200491 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700492 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700493 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000494 }
495 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700496 ALOGE << "Output buffer dequeue timeout";
Alex Glaznev782671f2015-06-12 16:40:44 -0700497 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000498 }
499 }
500
501 // Get input buffer.
502 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
503 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700504 if (CheckException(jni) || j_input_buffer_index < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700505 ALOGE << "dequeueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700506 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000507 }
508
509 // Copy encoded data to Java ByteBuffer.
510 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200511 uint8_t* buffer =
512 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700513 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200514 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700515 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700516 ALOGE << "Input frame size "<< inputImage._length <<
517 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700518 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000519 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000520 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
521 ALOGV("Decoder frame in # %d. Type: %d. Buffer # %d. TS: %lld. Size: %d",
522 frames_received_, inputImage._frameType, j_input_buffer_index,
523 timestamp_us / 1000, inputImage._length);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000524 memcpy(buffer, inputImage._buffer, inputImage._length);
525
526 // Save input image timestamps for later output.
527 frames_received_++;
528 current_bytes_ += inputImage._length;
529 timestamps_.push_back(inputImage._timeStamp);
530 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
531 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
532
533 // Feed input to decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000534 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
535 j_queue_input_buffer_method_,
536 j_input_buffer_index,
537 inputImage._length,
538 timestamp_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700539 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700540 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700541 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000542 }
543
544 // Try to drain the decoder
545 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700546 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700547 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000548 }
549
550 return WEBRTC_VIDEO_CODEC_OK;
551}
552
553bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200554 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000555 if (frames_received_ <= frames_decoded_) {
556 // No need to query for output buffers - decoder is drained.
557 return true;
558 }
559 // Get decoder output.
magjed44bf6f52015-10-03 02:08:00 -0700560 jobject j_decoder_output_buffer = jni->CallObjectMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000561 *j_media_codec_video_decoder_,
562 j_dequeue_output_buffer_method_,
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200563 dequeue_timeout_ms);
Alex Glaznev782671f2015-06-12 16:40:44 -0700564 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700565 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700566 return false;
567 }
magjed44bf6f52015-10-03 02:08:00 -0700568 if (IsNull(jni, j_decoder_output_buffer)) {
569 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000570 return true;
571 }
572
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000573 // Get decoded video frame properties.
574 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
575 j_color_format_field_);
576 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
577 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
578 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
579 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
580 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000581
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200582 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
magjed44bf6f52015-10-03 02:08:00 -0700583 long output_timestamps_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200584 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700585 // Extract data from Java DecodedTextureBuffer.
586 const int texture_id =
587 GetIntField(jni, j_decoder_output_buffer, j_textureID_field_);
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200588 const jfloatArray j_transform_matrix =
589 reinterpret_cast<jfloatArray>(GetObjectField(
590 jni, j_decoder_output_buffer, j_transform_matrix_field_));
591 const int64_t timestamp_ns = GetLongField(jni, j_decoder_output_buffer,
592 j_texture_timestamp_ns_field_);
593 output_timestamps_ms = timestamp_ns / rtc::kNumNanosecsPerMillisec;
magjed44bf6f52015-10-03 02:08:00 -0700594 // Create webrtc::VideoFrameBuffer with native texture handle.
Magnus Jedvert91b348c2015-10-07 22:57:06 +0200595 frame_buffer = surface_texture_helper_->CreateTextureFrame(
596 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200597 } else {
598 // Extract data from Java ByteBuffer and create output yuv420 frame -
599 // for non surface decoding only.
magjed44bf6f52015-10-03 02:08:00 -0700600 const int output_buffer_index =
601 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_);
602 const int output_buffer_offset =
603 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_);
604 const int output_buffer_size =
605 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_);
606 const int64_t timestamp_us = GetLongField(
607 jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_);
608 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
609
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000610 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700611 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000612 return false;
613 }
614 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
615 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
616 jobject output_buffer =
617 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
618 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
619 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700620 if (CheckException(jni)) {
621 return false;
622 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000623 payload += output_buffer_offset;
624
625 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200626 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000627 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200628 RTC_CHECK_EQ(0, stride % 2);
629 RTC_CHECK_EQ(0, slice_height % 2);
630 const int uv_stride = stride / 2;
631 const int u_slice_height = slice_height / 2;
632 const uint8_t* y_ptr = payload;
633 const uint8_t* u_ptr = y_ptr + stride * slice_height;
634 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
635 libyuv::I420Copy(y_ptr, stride,
636 u_ptr, uv_stride,
637 v_ptr, uv_stride,
638 frame_buffer->MutableData(webrtc::kYPlane),
639 frame_buffer->stride(webrtc::kYPlane),
640 frame_buffer->MutableData(webrtc::kUPlane),
641 frame_buffer->stride(webrtc::kUPlane),
642 frame_buffer->MutableData(webrtc::kVPlane),
643 frame_buffer->stride(webrtc::kVPlane),
644 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000645 } else {
646 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200647 const uint8_t* y_ptr = payload;
648 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000649 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200650 y_ptr, stride,
651 uv_ptr, stride,
652 frame_buffer->MutableData(webrtc::kYPlane),
653 frame_buffer->stride(webrtc::kYPlane),
654 frame_buffer->MutableData(webrtc::kUPlane),
655 frame_buffer->stride(webrtc::kUPlane),
656 frame_buffer->MutableData(webrtc::kVPlane),
657 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000658 width, height);
659 }
magjed44bf6f52015-10-03 02:08:00 -0700660 // Return output byte buffer back to codec.
661 jni->CallVoidMethod(
662 *j_media_codec_video_decoder_,
663 j_return_decoded_byte_buffer_method_,
664 output_buffer_index);
665 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700666 ALOGE << "returnDecodedByteBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700667 return false;
668 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000669 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200670 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000671
672 // Get frame timestamps from a queue.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000673 if (timestamps_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200674 decoded_frame.set_timestamp(timestamps_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000675 timestamps_.erase(timestamps_.begin());
676 }
677 if (ntp_times_ms_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200678 decoded_frame.set_ntp_time_ms(ntp_times_ms_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000679 ntp_times_ms_.erase(ntp_times_ms_.begin());
680 }
681 int64_t frame_decoding_time_ms = 0;
682 if (frame_rtc_times_ms_.size() > 0) {
683 frame_decoding_time_ms = GetCurrentTimeMs() - frame_rtc_times_ms_.front();
684 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
685 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000686 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. TS: %ld."
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000687 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000688 color_format, output_timestamps_ms, frame_decoding_time_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000689
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000690 // Calculate and print decoding statistics - every 3 seconds.
691 frames_decoded_++;
692 current_frames_++;
693 current_decoding_time_ms_ += frame_decoding_time_ms;
694 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
695 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
696 current_frames_ > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700697 ALOGD << "Decoded frames: " << frames_decoded_ << ". Bitrate: " <<
698 (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " <<
699 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
700 << ". decTime: " << (current_decoding_time_ms_ / current_frames_) <<
701 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000702 start_time_ms_ = GetCurrentTimeMs();
703 current_frames_ = 0;
704 current_bytes_ = 0;
705 current_decoding_time_ms_ = 0;
706 }
707
708 // Callback - output decoded frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200709 const int32_t callback_status = callback_->Decoded(decoded_frame);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000710 if (callback_status > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700711 ALOGE << "callback error";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000712 }
713
714 return true;
715}
716
717int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
718 DecodedImageCallback* callback) {
719 callback_ = callback;
720 return WEBRTC_VIDEO_CODEC_OK;
721}
722
723int32_t MediaCodecVideoDecoder::Reset() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700724 ALOGD << "DecoderReset";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000725 if (!inited_) {
726 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
727 }
728 return InitDecode(&codec_, 1);
729}
730
731void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
732 JNIEnv* jni = AttachCurrentThreadIfNeeded();
733 ScopedLocalRefFrame local_ref_frame(jni);
734 if (!inited_) {
735 return;
736 }
737 // We only ever send one message to |this| directly (not through a Bind()'d
738 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700739 RTC_CHECK(!msg->message_id) << "Unexpected message!";
740 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000741 CheckOnCodecThread();
742
743 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700744 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700745 ProcessHWErrorOnCodecThread();
746 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000747 }
748 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
749}
750
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700751MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
752 render_egl_context_(NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700753 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000754 JNIEnv* jni = AttachCurrentThreadIfNeeded();
755 ScopedLocalRefFrame local_ref_frame(jni);
756 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000757 supported_codec_types_.clear();
758
759 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000760 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000761 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700762 if (CheckException(jni)) {
763 is_vp8_hw_supported = false;
764 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000765 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700766 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000767 supported_codec_types_.push_back(kVideoCodecVP8);
768 }
769
770 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
771 j_decoder_class,
772 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700773 if (CheckException(jni)) {
774 is_h264_hw_supported = false;
775 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000776 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700777 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000778 supported_codec_types_.push_back(kVideoCodecH264);
779 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000780}
781
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700782MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700783 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700784 if (render_egl_context_) {
785 JNIEnv* jni = AttachCurrentThreadIfNeeded();
786 jni->DeleteGlobalRef(render_egl_context_);
787 render_egl_context_ = NULL;
788 }
789}
790
791void MediaCodecVideoDecoderFactory::SetEGLContext(
792 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700793 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700794 if (render_egl_context_) {
795 jni->DeleteGlobalRef(render_egl_context_);
796 render_egl_context_ = NULL;
797 }
798 if (!IsNull(jni, render_egl_context)) {
799 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
800 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700801 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700802 render_egl_context_ = NULL;
803 } else {
804 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
805 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700806 ALOGE << "Wrong EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700807 jni->DeleteGlobalRef(render_egl_context_);
808 render_egl_context_ = NULL;
809 }
810 }
811 }
812 if (render_egl_context_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700813 ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700814 }
815}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000816
817webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000818 VideoCodecType type) {
819 if (supported_codec_types_.empty()) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700820 ALOGE << "No HW video decoder for type " << (int)type;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000821 return NULL;
822 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700823 for (VideoCodecType codec_type : supported_codec_types_) {
824 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700825 ALOGD << "Create HW video decoder for type " << (int)type;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700826 return new MediaCodecVideoDecoder(
827 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000828 }
829 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700830 ALOGE << "Can not find HW video decoder for type " << (int)type;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000831 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000832}
833
834void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
835 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700836 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000837 delete decoder;
838}
839
840} // namespace webrtc_jni
841