blob: 3bfad6885fc9eeda1b85f4509b710aa71d08a9f2 [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"
36#include "webrtc/base/bind.h"
37#include "webrtc/base/checks.h"
38#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020039#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000040#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020041#include "webrtc/base/timeutils.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020042#include "webrtc/common_video/interface/i420_buffer_pool.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000043#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010044#include "webrtc/system_wrappers/include/logcat_trace_context.h"
45#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000046#include "third_party/libyuv/include/libyuv/convert.h"
47#include "third_party/libyuv/include/libyuv/convert_from.h"
48#include "third_party/libyuv/include/libyuv/video_common.h"
49
50using rtc::Bind;
51using rtc::Thread;
52using rtc::ThreadManager;
53using rtc::scoped_ptr;
54
55using webrtc::CodecSpecificInfo;
56using webrtc::DecodedImageCallback;
57using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070058using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000059using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000060using webrtc::TickTime;
61using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000062using webrtc::VideoCodecType;
63using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000064using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080065using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000066
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_;
Perc01c2542015-11-13 16:58:26 +0100115 NativeHandleImpl native_handle_;
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_;
Perc01c2542015-11-13 16:58:26 +0100126 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
127 // decoder input.
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_;
Perc01c2542015-11-13 16:58:26 +0100138 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_;
Perc01c2542015-11-13 16:58:26 +0100148 jfieldID j_surface_texture_field_;
magjed44bf6f52015-10-03 02:08:00 -0700149 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Perc01c2542015-11-13 16:58:26 +0100150 jfieldID j_textureID_field_;
magjed543b6ca2015-10-15 05:45:07 -0700151 jfieldID j_texture_presentation_timestamp_us_field_;
Perc01c2542015-11-13 16:58:26 +0100152 // 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_;
Perc01c2542015-11-13 16:58:26 +0100160 jobject surface_texture_;
161 jobject previous_surface_texture_;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700162
163 // Render EGL context - owned by factory, should not be allocated/destroyed
164 // by VideoDecoder.
165 jobject render_egl_context_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000166};
167
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000168MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700169 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000170 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700171 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000172 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000173 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700174 sw_fallback_required_(false),
Perc01c2542015-11-13 16:58:26 +0100175 surface_texture_(NULL),
176 previous_surface_texture_(NULL),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000177 codec_thread_(new Thread()),
178 j_media_codec_video_decoder_class_(
179 jni,
180 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
181 j_media_codec_video_decoder_(
182 jni,
183 jni->NewObject(*j_media_codec_video_decoder_class_,
184 GetMethodID(jni,
185 *j_media_codec_video_decoder_class_,
186 "<init>",
187 "()V"))) {
188 ScopedLocalRefFrame local_ref_frame(jni);
189 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700190 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000191
192 j_init_decode_method_ = GetMethodID(
193 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000194 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Perc01c2542015-11-13 16:58:26 +0100195 "IILjavax/microedition/khronos/egl/EGLContext;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000196 j_release_method_ =
197 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
198 j_dequeue_input_buffer_method_ = GetMethodID(
199 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
200 j_queue_input_buffer_method_ = GetMethodID(
201 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
Perc01c2542015-11-13 16:58:26 +0100202 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000203 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Perc01c2542015-11-13 16:58:26 +0100204 "(I)Ljava/lang/Object;");
magjed44bf6f52015-10-03 02:08:00 -0700205 j_return_decoded_byte_buffer_method_ =
206 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Perc01c2542015-11-13 16:58:26 +0100207 "returnDecodedByteBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000208
209 j_input_buffers_field_ = GetFieldID(
210 jni, *j_media_codec_video_decoder_class_,
211 "inputBuffers", "[Ljava/nio/ByteBuffer;");
212 j_output_buffers_field_ = GetFieldID(
213 jni, *j_media_codec_video_decoder_class_,
214 "outputBuffers", "[Ljava/nio/ByteBuffer;");
215 j_color_format_field_ = GetFieldID(
216 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
217 j_width_field_ = GetFieldID(
218 jni, *j_media_codec_video_decoder_class_, "width", "I");
219 j_height_field_ = GetFieldID(
220 jni, *j_media_codec_video_decoder_class_, "height", "I");
221 j_stride_field_ = GetFieldID(
222 jni, *j_media_codec_video_decoder_class_, "stride", "I");
223 j_slice_height_field_ = GetFieldID(
224 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
Perc01c2542015-11-13 16:58:26 +0100225 j_surface_texture_field_ = GetFieldID(
226 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
227 "Landroid/graphics/SurfaceTexture;");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000228
Perc01c2542015-11-13 16:58:26 +0100229 jclass j_decoder_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700230 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Perc01c2542015-11-13 16:58:26 +0100231 j_textureID_field_ = GetFieldID(
232 jni, j_decoder_decoded_texture_buffer_class, "textureID", "I");
233 j_texture_presentation_timestamp_us_field_ =
234 GetFieldID(jni, j_decoder_decoded_texture_buffer_class,
235 "presentationTimestampUs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700236
Perc01c2542015-11-13 16:58:26 +0100237 jclass j_decoder_decoded_byte_buffer_class = FindClass(jni,
238 "org/webrtc/MediaCodecVideoDecoder$DecodedByteBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000239 j_info_index_field_ = GetFieldID(
Perc01c2542015-11-13 16:58:26 +0100240 jni, j_decoder_decoded_byte_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000241 j_info_offset_field_ = GetFieldID(
Perc01c2542015-11-13 16:58:26 +0100242 jni, j_decoder_decoded_byte_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000243 j_info_size_field_ = GetFieldID(
Perc01c2542015-11-13 16:58:26 +0100244 jni, j_decoder_decoded_byte_buffer_class, "size", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000245 j_info_presentation_timestamp_us_field_ = GetFieldID(
Perc01c2542015-11-13 16:58:26 +0100246 jni, j_decoder_decoded_byte_buffer_class, "presentationTimestampUs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000247
248 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200249 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700250 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000251 memset(&codec_, 0, sizeof(codec_));
252 AllowBlockingCalls();
253}
254
255MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
256 // Call Release() to ensure no more callbacks to us after we are deleted.
257 Release();
Perc01c2542015-11-13 16:58:26 +0100258 // Delete global references.
259 JNIEnv* jni = AttachCurrentThreadIfNeeded();
260 if (previous_surface_texture_ != NULL) {
261 jni->DeleteGlobalRef(previous_surface_texture_);
262 }
263 if (surface_texture_ != NULL) {
264 jni->DeleteGlobalRef(surface_texture_);
265 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000266}
267
268int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
269 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700270 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000271 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700272 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000273 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
274 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000275 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700276 RTC_CHECK(inst->codecType == codecType_)
277 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000278
Alex Glaznev782671f2015-06-12 16:40:44 -0700279 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700280 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700281 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000282 }
283 // Save VideoCodec instance for later.
284 if (&codec_ != inst) {
285 codec_ = *inst;
286 }
glazneve55c42c2015-10-28 10:30:32 -0700287 // If maxFramerate is not set then assume 30 fps.
288 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000289
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000290 // Call Java init.
291 return codec_thread_->Invoke<int32_t>(
292 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
293}
294
295int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
296 CheckOnCodecThread();
297 JNIEnv* jni = AttachCurrentThreadIfNeeded();
298 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700299 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
300 << codec_.width << " x " << codec_.height << ". Fps: " <<
301 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700302
303 // Release previous codec first if it was allocated before.
304 int ret_val = ReleaseOnCodecThread();
305 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700306 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700307 sw_fallback_required_ = true;
308 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000309 }
310
Alex Glaznev782671f2015-06-12 16:40:44 -0700311 // Always start with a complete key frame.
312 key_frame_required_ = true;
313 frames_received_ = 0;
314 frames_decoded_ = 0;
315
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000316 jobject j_video_codec_enum = JavaEnumFromIndex(
317 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000318 bool success = jni->CallBooleanMethod(
319 *j_media_codec_video_decoder_,
320 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000321 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000322 codec_.width,
323 codec_.height,
Perc01c2542015-11-13 16:58:26 +0100324 use_surface_ ? render_egl_context_ : nullptr);
Alex Glaznev782671f2015-06-12 16:40:44 -0700325 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700326 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700327 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000328 return WEBRTC_VIDEO_CODEC_ERROR;
329 }
330 inited_ = true;
331
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000332 switch (codecType_) {
333 case kVideoCodecVP8:
334 max_pending_frames_ = kMaxPendingFramesVp8;
335 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800336 case kVideoCodecVP9:
337 max_pending_frames_ = kMaxPendingFramesVp9;
338 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000339 case kVideoCodecH264:
340 max_pending_frames_ = kMaxPendingFramesH264;
341 break;
342 default:
343 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000344 }
345 start_time_ms_ = GetCurrentTimeMs();
346 current_frames_ = 0;
347 current_bytes_ = 0;
348 current_decoding_time_ms_ = 0;
349 timestamps_.clear();
350 ntp_times_ms_.clear();
Perc01c2542015-11-13 16:58:26 +0100351 frame_rtc_times_ms_.clear();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000352
353 jobjectArray input_buffers = (jobjectArray)GetObjectField(
354 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
355 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700356 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000357 input_buffers_.resize(num_input_buffers);
358 for (size_t i = 0; i < num_input_buffers; ++i) {
359 input_buffers_[i] =
360 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700361 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700362 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700363 sw_fallback_required_ = true;
364 return WEBRTC_VIDEO_CODEC_ERROR;
365 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000366 }
367
Perc01c2542015-11-13 16:58:26 +0100368 if (use_surface_) {
369 jobject surface_texture = GetObjectField(
370 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
371 if (previous_surface_texture_ != NULL) {
372 jni->DeleteGlobalRef(previous_surface_texture_);
373 }
374 previous_surface_texture_ = surface_texture_;
375 surface_texture_ = jni->NewGlobalRef(surface_texture);
376 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000377 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
378
379 return WEBRTC_VIDEO_CODEC_OK;
380}
381
382int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700383 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000384 return codec_thread_->Invoke<int32_t>(
385 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
386}
387
388int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
389 if (!inited_) {
390 return WEBRTC_VIDEO_CODEC_OK;
391 }
392 CheckOnCodecThread();
393 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700394 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
395 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000396 ScopedLocalRefFrame local_ref_frame(jni);
397 for (size_t i = 0; i < input_buffers_.size(); i++) {
398 jni->DeleteGlobalRef(input_buffers_[i]);
399 }
400 input_buffers_.clear();
401 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000402 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700403 rtc::MessageQueueManager::Clear(this);
404 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700405 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700406 return WEBRTC_VIDEO_CODEC_ERROR;
407 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700408 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000409 return WEBRTC_VIDEO_CODEC_OK;
410}
411
412void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700413 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000414 << "Running on wrong thread!";
415}
416
Alex Glaznev782671f2015-06-12 16:40:44 -0700417int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
418 CheckOnCodecThread();
419 int ret_val = ReleaseOnCodecThread();
420 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700421 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700422 }
423 if (codecType_ == kVideoCodecH264) {
424 // For now there is no SW H.264 which can be used as fallback codec.
425 // So try to restart hw codec for now.
426 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700427 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700428 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
429 // H.264 codec was succesfully reset - return regular error code.
430 return WEBRTC_VIDEO_CODEC_ERROR;
431 } else {
432 // Fail to restart H.264 codec - return error code which should stop the
433 // call.
434 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
435 }
436 } else {
437 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700438 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700439 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
440 }
441}
442
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000443int32_t MediaCodecVideoDecoder::Decode(
444 const EncodedImage& inputImage,
445 bool missingFrames,
446 const RTPFragmentationHeader* fragmentation,
447 const CodecSpecificInfo* codecSpecificInfo,
448 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700449 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700450 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700451 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000452 }
453 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700454 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000455 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
456 }
457 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700458 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000459 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
460 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700461 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700462 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700463 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
464 }
465
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000466 // Check if encoded frame dimension has changed.
467 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
468 (inputImage._encodedWidth != codec_.width ||
469 inputImage._encodedHeight != codec_.height)) {
470 codec_.width = inputImage._encodedWidth;
471 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700472 int32_t ret = InitDecode(&codec_, 1);
473 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700474 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700475 sw_fallback_required_ = true;
476 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
477 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000478 }
479
480 // Always start with a complete key frame.
481 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200482 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700483 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000484 return WEBRTC_VIDEO_CODEC_ERROR;
485 }
486 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700487 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000488 return WEBRTC_VIDEO_CODEC_ERROR;
489 }
490 key_frame_required_ = false;
491 }
492 if (inputImage._length == 0) {
493 return WEBRTC_VIDEO_CODEC_ERROR;
494 }
495
496 return codec_thread_->Invoke<int32_t>(Bind(
497 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
498}
499
500int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
501 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000502 CheckOnCodecThread();
503 JNIEnv* jni = AttachCurrentThreadIfNeeded();
504 ScopedLocalRefFrame local_ref_frame(jni);
505
506 // Try to drain the decoder and wait until output is not too
507 // much behind the input.
508 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000509 ALOGV("Received: %d. Decoded: %d. Wait for output...",
510 frames_received_, frames_decoded_);
Perc01c2542015-11-13 16:58:26 +0100511 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glazneve55c42c2015-10-28 10:30:32 -0700512 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
513 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700514 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000515 }
516 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glazneve55c42c2015-10-28 10:30:32 -0700517 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
518 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700519 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000520 }
521 }
522
523 // Get input buffer.
524 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
525 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700526 if (CheckException(jni) || j_input_buffer_index < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700527 ALOGE << "dequeueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700528 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000529 }
530
531 // Copy encoded data to Java ByteBuffer.
532 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200533 uint8_t* buffer =
534 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700535 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200536 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700537 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700538 ALOGE << "Input frame size "<< inputImage._length <<
539 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700540 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000541 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000542 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
glazneve55c42c2015-10-28 10:30:32 -0700543 if (frames_decoded_ < kMaxDecodedLogFrames) {
544 ALOGD << "Decoder frame in # " << frames_received_ << ". Type: "
545 << inputImage._frameType << ". Buffer # " <<
546 j_input_buffer_index << ". TS: " << (int)(timestamp_us / 1000)
547 << ". Size: " << inputImage._length;
548 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000549 memcpy(buffer, inputImage._buffer, inputImage._length);
550
551 // Save input image timestamps for later output.
552 frames_received_++;
553 current_bytes_ += inputImage._length;
554 timestamps_.push_back(inputImage._timeStamp);
555 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
Perc01c2542015-11-13 16:58:26 +0100556 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000557
558 // Feed input to decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000559 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
560 j_queue_input_buffer_method_,
561 j_input_buffer_index,
562 inputImage._length,
563 timestamp_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700564 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700565 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700566 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000567 }
568
569 // Try to drain the decoder
570 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700571 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700572 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000573 }
574
575 return WEBRTC_VIDEO_CODEC_OK;
576}
577
578bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Perc01c2542015-11-13 16:58:26 +0100579 JNIEnv* jni, int dequeue_timeout_us) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000580 if (frames_received_ <= frames_decoded_) {
581 // No need to query for output buffers - decoder is drained.
582 return true;
583 }
584 // Get decoder output.
Perc01c2542015-11-13 16:58:26 +0100585 jobject j_decoder_output_buffer = jni->CallObjectMethod(
586 *j_media_codec_video_decoder_,
587 j_dequeue_output_buffer_method_,
588 dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700589 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700590 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700591 return false;
592 }
magjed44bf6f52015-10-03 02:08:00 -0700593 if (IsNull(jni, j_decoder_output_buffer)) {
594 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000595 return true;
596 }
597
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000598 // Get decoded video frame properties.
599 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
600 j_color_format_field_);
601 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
602 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
603 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
604 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
605 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000606
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200607 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
Perc01c2542015-11-13 16:58:26 +0100608 long output_timestamps_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200609 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700610 // Extract data from Java DecodedTextureBuffer.
611 const int texture_id =
Perc01c2542015-11-13 16:58:26 +0100612 GetIntField(jni, j_decoder_output_buffer, j_textureID_field_);
613 const int64_t timestamp_us =
614 GetLongField(jni, j_decoder_output_buffer,
615 j_texture_presentation_timestamp_us_field_);
616 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
617 // Create webrtc::VideoFrameBuffer with native texture handle.
618 native_handle_.SetTextureObject(surface_texture_, texture_id);
619 frame_buffer = new rtc::RefCountedObject<JniNativeHandleBuffer>(
620 &native_handle_, width, height);
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200621 } else {
622 // Extract data from Java ByteBuffer and create output yuv420 frame -
623 // for non surface decoding only.
magjed44bf6f52015-10-03 02:08:00 -0700624 const int output_buffer_index =
625 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_);
626 const int output_buffer_offset =
627 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_);
628 const int output_buffer_size =
629 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_);
630 const int64_t timestamp_us = GetLongField(
631 jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_);
632 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
633
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000634 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700635 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000636 return false;
637 }
638 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
639 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
640 jobject output_buffer =
641 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
642 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
643 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700644 if (CheckException(jni)) {
645 return false;
646 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000647 payload += output_buffer_offset;
648
649 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200650 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000651 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200652 RTC_CHECK_EQ(0, stride % 2);
653 RTC_CHECK_EQ(0, slice_height % 2);
654 const int uv_stride = stride / 2;
655 const int u_slice_height = slice_height / 2;
656 const uint8_t* y_ptr = payload;
657 const uint8_t* u_ptr = y_ptr + stride * slice_height;
658 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
659 libyuv::I420Copy(y_ptr, stride,
660 u_ptr, uv_stride,
661 v_ptr, uv_stride,
662 frame_buffer->MutableData(webrtc::kYPlane),
663 frame_buffer->stride(webrtc::kYPlane),
664 frame_buffer->MutableData(webrtc::kUPlane),
665 frame_buffer->stride(webrtc::kUPlane),
666 frame_buffer->MutableData(webrtc::kVPlane),
667 frame_buffer->stride(webrtc::kVPlane),
668 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000669 } else {
670 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200671 const uint8_t* y_ptr = payload;
672 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000673 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200674 y_ptr, stride,
675 uv_ptr, stride,
676 frame_buffer->MutableData(webrtc::kYPlane),
677 frame_buffer->stride(webrtc::kYPlane),
678 frame_buffer->MutableData(webrtc::kUPlane),
679 frame_buffer->stride(webrtc::kUPlane),
680 frame_buffer->MutableData(webrtc::kVPlane),
681 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000682 width, height);
683 }
magjed44bf6f52015-10-03 02:08:00 -0700684 // Return output byte buffer back to codec.
685 jni->CallVoidMethod(
686 *j_media_codec_video_decoder_,
687 j_return_decoded_byte_buffer_method_,
688 output_buffer_index);
689 if (CheckException(jni)) {
Perc01c2542015-11-13 16:58:26 +0100690 ALOGE << "returnDecodedByteBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700691 return false;
692 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000693 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200694 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000695
696 // Get frame timestamps from a queue.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000697 if (timestamps_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200698 decoded_frame.set_timestamp(timestamps_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000699 timestamps_.erase(timestamps_.begin());
700 }
701 if (ntp_times_ms_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200702 decoded_frame.set_ntp_time_ms(ntp_times_ms_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000703 ntp_times_ms_.erase(ntp_times_ms_.begin());
704 }
Perc01c2542015-11-13 16:58:26 +0100705 int64_t frame_decoding_time_ms = 0;
706 if (frame_rtc_times_ms_.size() > 0) {
707 frame_decoding_time_ms = GetCurrentTimeMs() - frame_rtc_times_ms_.front();
708 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
709 }
glazneve55c42c2015-10-28 10:30:32 -0700710 if (frames_decoded_ < kMaxDecodedLogFrames) {
711 ALOGD << "Decoder frame out # " << frames_decoded_ << ". " << width <<
712 " x " << height << ". " << stride << " x " << slice_height <<
713 ". Color: " << color_format << ". TS:" << (int)output_timestamps_ms <<
Perc01c2542015-11-13 16:58:26 +0100714 ". DecTime: " << (int)frame_decoding_time_ms;
glazneve55c42c2015-10-28 10:30:32 -0700715 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000716
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000717 // Calculate and print decoding statistics - every 3 seconds.
718 frames_decoded_++;
719 current_frames_++;
Perc01c2542015-11-13 16:58:26 +0100720 current_decoding_time_ms_ += frame_decoding_time_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000721 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
722 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
723 current_frames_ > 0) {
Perc01c2542015-11-13 16:58:26 +0100724 ALOGD << "Decoded frames: " << frames_decoded_ << ". Bitrate: " <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700725 (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " <<
726 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
727 << ". decTime: " << (current_decoding_time_ms_ / current_frames_) <<
728 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000729 start_time_ms_ = GetCurrentTimeMs();
730 current_frames_ = 0;
731 current_bytes_ = 0;
732 current_decoding_time_ms_ = 0;
733 }
734
Perc01c2542015-11-13 16:58:26 +0100735 // Callback - output decoded frame.
736 const int32_t callback_status = callback_->Decoded(decoded_frame);
737 if (callback_status > 0) {
738 ALOGE << "callback error";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000739 }
Perc01c2542015-11-13 16:58:26 +0100740
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000741 return true;
742}
743
744int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
745 DecodedImageCallback* callback) {
746 callback_ = callback;
747 return WEBRTC_VIDEO_CODEC_OK;
748}
749
750int32_t MediaCodecVideoDecoder::Reset() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700751 ALOGD << "DecoderReset";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000752 if (!inited_) {
753 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
754 }
755 return InitDecode(&codec_, 1);
756}
757
758void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
759 JNIEnv* jni = AttachCurrentThreadIfNeeded();
760 ScopedLocalRefFrame local_ref_frame(jni);
761 if (!inited_) {
762 return;
763 }
764 // We only ever send one message to |this| directly (not through a Bind()'d
765 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700766 RTC_CHECK(!msg->message_id) << "Unexpected message!";
767 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000768 CheckOnCodecThread();
769
770 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700771 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700772 ProcessHWErrorOnCodecThread();
773 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000774 }
775 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
776}
777
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700778MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
779 render_egl_context_(NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700780 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000781 JNIEnv* jni = AttachCurrentThreadIfNeeded();
782 ScopedLocalRefFrame local_ref_frame(jni);
783 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000784 supported_codec_types_.clear();
785
786 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000787 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000788 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700789 if (CheckException(jni)) {
790 is_vp8_hw_supported = false;
791 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000792 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700793 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000794 supported_codec_types_.push_back(kVideoCodecVP8);
795 }
796
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800797 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
798 j_decoder_class,
799 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
800 if (CheckException(jni)) {
801 is_vp9_hw_supported = false;
802 }
803 if (is_vp9_hw_supported) {
804 ALOGD << "VP9 HW Decoder supported.";
805 supported_codec_types_.push_back(kVideoCodecVP9);
806 }
807
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000808 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
809 j_decoder_class,
810 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700811 if (CheckException(jni)) {
812 is_h264_hw_supported = false;
813 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000814 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700815 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000816 supported_codec_types_.push_back(kVideoCodecH264);
817 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000818}
819
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700820MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700821 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700822 if (render_egl_context_) {
823 JNIEnv* jni = AttachCurrentThreadIfNeeded();
824 jni->DeleteGlobalRef(render_egl_context_);
825 render_egl_context_ = NULL;
826 }
827}
828
829void MediaCodecVideoDecoderFactory::SetEGLContext(
830 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700831 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700832 if (render_egl_context_) {
833 jni->DeleteGlobalRef(render_egl_context_);
834 render_egl_context_ = NULL;
835 }
836 if (!IsNull(jni, render_egl_context)) {
837 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
838 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700839 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700840 render_egl_context_ = NULL;
841 } else {
magjed8c425aa2015-10-22 16:52:39 -0700842 jclass j_egl_context_class =
843 FindClass(jni, "javax/microedition/khronos/egl/EGLContext");
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700844 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700845 ALOGE << "Wrong EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700846 jni->DeleteGlobalRef(render_egl_context_);
847 render_egl_context_ = NULL;
848 }
849 }
850 }
851 if (render_egl_context_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700852 ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700853 }
854}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000855
856webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000857 VideoCodecType type) {
858 if (supported_codec_types_.empty()) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700859 ALOGE << "No HW video decoder for type " << (int)type;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000860 return NULL;
861 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700862 for (VideoCodecType codec_type : supported_codec_types_) {
863 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700864 ALOGD << "Create HW video decoder for type " << (int)type;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700865 return new MediaCodecVideoDecoder(
866 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000867 }
868 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700869 ALOGE << "Can not find HW video decoder for type " << (int)type;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000870 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000871}
872
873void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
874 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700875 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000876 delete decoder;
877}
878
879} // namespace webrtc_jni
880