blob: e506bc3ab3b9f8c87fc5ffcd7539908c977fc64b [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"
perkj9cb89822015-11-11 03:27:01 -080036#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"
Henrik Kjellander98f53512015-10-28 18:17:40 +010045#include "webrtc/system_wrappers/include/logcat_trace_context.h"
46#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000047#include "third_party/libyuv/include/libyuv/convert.h"
48#include "third_party/libyuv/include/libyuv/convert_from.h"
49#include "third_party/libyuv/include/libyuv/video_common.h"
50
51using rtc::Bind;
52using rtc::Thread;
53using rtc::ThreadManager;
54using rtc::scoped_ptr;
55
56using webrtc::CodecSpecificInfo;
57using webrtc::DecodedImageCallback;
58using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070059using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000060using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000061using webrtc::TickTime;
62using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000063using webrtc::VideoCodecType;
64using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000065using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080066using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000067
68namespace webrtc_jni {
69
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000070class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
71 public rtc::MessageHandler {
72 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070073 explicit MediaCodecVideoDecoder(
74 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000075 virtual ~MediaCodecVideoDecoder();
76
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000077 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
78 override;
79
80 int32_t Decode(
81 const EncodedImage& inputImage, bool missingFrames,
82 const RTPFragmentationHeader* fragmentation,
83 const CodecSpecificInfo* codecSpecificInfo = NULL,
84 int64_t renderTimeMs = -1) override;
85
86 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
87 override;
88
89 int32_t Release() override;
90
91 int32_t Reset() override;
92 // rtc::MessageHandler implementation.
93 void OnMessage(rtc::Message* msg) override;
94
95 private:
96 // CHECK-fail if not running on |codec_thread_|.
97 void CheckOnCodecThread();
98
99 int32_t InitDecodeOnCodecThread();
100 int32_t ReleaseOnCodecThread();
101 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
102 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
103 // true on success.
104 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700105 int32_t ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000106
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000107 // Type of video codec.
108 VideoCodecType codecType_;
109
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000110 bool key_frame_required_;
111 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700112 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000113 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000114 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200115 webrtc::I420BufferPool decoded_frame_pool_;
perkj9cb89822015-11-11 03:27:01 -0800116 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000117 DecodedImageCallback* callback_;
118 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000119 int frames_decoded_; // Number of frames decoded by decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000120 int64_t start_time_ms_; // Start time for statistics.
121 int current_frames_; // Number of frames in the current statistics interval.
122 int current_bytes_; // Encoded bytes in the current statistics interval.
123 int current_decoding_time_ms_; // Overall decoding time in the current second
124 uint32_t max_pending_frames_; // Maximum number of pending input frames
125 std::vector<int32_t> timestamps_;
126 std::vector<int64_t> ntp_times_ms_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000127
128 // State that is constant for the lifetime of this object once the ctor
129 // returns.
130 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
131 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
132 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
133 jmethodID j_init_decode_method_;
134 jmethodID j_release_method_;
135 jmethodID j_dequeue_input_buffer_method_;
136 jmethodID j_queue_input_buffer_method_;
perkj9cb89822015-11-11 03:27:01 -0800137 jmethodID j_dequeue_byte_buffer_method_;
138 jmethodID j_dequeue_texture_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.
perkj9cb89822015-11-11 03:27:01 -0800149 jfieldID j_texture_id_field_;
150 jfieldID j_transform_matrix_field_;
magjed543b6ca2015-10-15 05:45:07 -0700151 jfieldID j_texture_presentation_timestamp_us_field_;
perkj9cb89822015-11-11 03:27:01 -0800152 jfieldID j_texture_decode_time_ms_field_;
153 jfieldID j_texture_frame_delay_ms_field_;
154 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000155 jfieldID j_info_index_field_;
156 jfieldID j_info_offset_field_;
157 jfieldID j_info_size_field_;
158 jfieldID j_info_presentation_timestamp_us_field_;
perkj9cb89822015-11-11 03:27:01 -0800159 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000160
161 // Global references; must be deleted in Release().
162 std::vector<jobject> input_buffers_;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700163
164 // Render EGL context - owned by factory, should not be allocated/destroyed
165 // by VideoDecoder.
166 jobject render_egl_context_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000167};
168
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000169MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700170 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000171 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700172 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000173 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000174 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700175 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000176 codec_thread_(new Thread()),
177 j_media_codec_video_decoder_class_(
178 jni,
179 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
180 j_media_codec_video_decoder_(
181 jni,
182 jni->NewObject(*j_media_codec_video_decoder_class_,
183 GetMethodID(jni,
184 *j_media_codec_video_decoder_class_,
185 "<init>",
186 "()V"))) {
187 ScopedLocalRefFrame local_ref_frame(jni);
188 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700189 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000190
191 j_init_decode_method_ = GetMethodID(
192 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000193 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
perkj9cb89822015-11-11 03:27:01 -0800194 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000195 j_release_method_ =
196 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
197 j_dequeue_input_buffer_method_ = GetMethodID(
198 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
199 j_queue_input_buffer_method_ = GetMethodID(
200 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
perkj9cb89822015-11-11 03:27:01 -0800201 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000202 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
perkj9cb89822015-11-11 03:27:01 -0800203 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
204 j_dequeue_texture_buffer_method_ = GetMethodID(
205 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
206 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700207 j_return_decoded_byte_buffer_method_ =
208 GetMethodID(jni, *j_media_codec_video_decoder_class_,
perkj9cb89822015-11-11 03:27:01 -0800209 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000210
211 j_input_buffers_field_ = GetFieldID(
212 jni, *j_media_codec_video_decoder_class_,
213 "inputBuffers", "[Ljava/nio/ByteBuffer;");
214 j_output_buffers_field_ = GetFieldID(
215 jni, *j_media_codec_video_decoder_class_,
216 "outputBuffers", "[Ljava/nio/ByteBuffer;");
217 j_color_format_field_ = GetFieldID(
218 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
219 j_width_field_ = GetFieldID(
220 jni, *j_media_codec_video_decoder_class_, "width", "I");
221 j_height_field_ = GetFieldID(
222 jni, *j_media_codec_video_decoder_class_, "height", "I");
223 j_stride_field_ = GetFieldID(
224 jni, *j_media_codec_video_decoder_class_, "stride", "I");
225 j_slice_height_field_ = GetFieldID(
226 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000227
perkj9cb89822015-11-11 03:27:01 -0800228 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700229 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
perkj9cb89822015-11-11 03:27:01 -0800230 j_texture_id_field_ = GetFieldID(
231 jni, j_decoded_texture_buffer_class, "textureID", "I");
232 j_transform_matrix_field_ = GetFieldID(
233 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
234 j_texture_presentation_timestamp_us_field_ = GetFieldID(
235 jni, j_decoded_texture_buffer_class, "presentationTimestampUs", "J");
236 j_texture_decode_time_ms_field_ = GetFieldID(
237 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
238 j_texture_frame_delay_ms_field_ = GetFieldID(
239 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700240
perkj9cb89822015-11-11 03:27:01 -0800241 jclass j_decoded_output_buffer_class = FindClass(jni,
242 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000243 j_info_index_field_ = GetFieldID(
perkj9cb89822015-11-11 03:27:01 -0800244 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000245 j_info_offset_field_ = GetFieldID(
perkj9cb89822015-11-11 03:27:01 -0800246 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000247 j_info_size_field_ = GetFieldID(
perkj9cb89822015-11-11 03:27:01 -0800248 jni, j_decoded_output_buffer_class, "size", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000249 j_info_presentation_timestamp_us_field_ = GetFieldID(
perkj9cb89822015-11-11 03:27:01 -0800250 jni, j_decoded_output_buffer_class, "presentationTimestampUs", "J");
251 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
252 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000253
254 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200255 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700256 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000257 memset(&codec_, 0, sizeof(codec_));
258 AllowBlockingCalls();
259}
260
261MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
262 // Call Release() to ensure no more callbacks to us after we are deleted.
263 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000264}
265
266int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
267 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700268 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000269 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700270 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000271 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
272 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000273 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700274 RTC_CHECK(inst->codecType == codecType_)
275 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000276
Alex Glaznev782671f2015-06-12 16:40:44 -0700277 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700278 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700279 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000280 }
281 // Save VideoCodec instance for later.
282 if (&codec_ != inst) {
283 codec_ = *inst;
284 }
glazneve55c42c2015-10-28 10:30:32 -0700285 // If maxFramerate is not set then assume 30 fps.
286 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000287
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000288 // Call Java init.
289 return codec_thread_->Invoke<int32_t>(
290 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
291}
292
293int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
294 CheckOnCodecThread();
295 JNIEnv* jni = AttachCurrentThreadIfNeeded();
296 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700297 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
298 << codec_.width << " x " << codec_.height << ". Fps: " <<
299 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700300
301 // Release previous codec first if it was allocated before.
302 int ret_val = ReleaseOnCodecThread();
303 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700304 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700305 sw_fallback_required_ = true;
306 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000307 }
308
Alex Glaznev782671f2015-06-12 16:40:44 -0700309 // Always start with a complete key frame.
310 key_frame_required_ = true;
311 frames_received_ = 0;
312 frames_decoded_ = 0;
313
perkj9cb89822015-11-11 03:27:01 -0800314 if (use_surface_) {
315 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
316 jni, render_egl_context_);
317 }
318
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000319 jobject j_video_codec_enum = JavaEnumFromIndex(
320 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000321 bool success = jni->CallBooleanMethod(
322 *j_media_codec_video_decoder_,
323 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000324 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000325 codec_.width,
326 codec_.height,
perkj9cb89822015-11-11 03:27:01 -0800327 use_surface_ ? surface_texture_helper_->GetJavaSurfaceTextureHelper()
328 : nullptr);
Alex Glaznev782671f2015-06-12 16:40:44 -0700329 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700330 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700331 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000332 return WEBRTC_VIDEO_CODEC_ERROR;
333 }
334 inited_ = true;
335
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000336 switch (codecType_) {
337 case kVideoCodecVP8:
338 max_pending_frames_ = kMaxPendingFramesVp8;
339 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800340 case kVideoCodecVP9:
341 max_pending_frames_ = kMaxPendingFramesVp9;
342 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000343 case kVideoCodecH264:
344 max_pending_frames_ = kMaxPendingFramesH264;
345 break;
346 default:
347 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000348 }
349 start_time_ms_ = GetCurrentTimeMs();
350 current_frames_ = 0;
351 current_bytes_ = 0;
352 current_decoding_time_ms_ = 0;
353 timestamps_.clear();
354 ntp_times_ms_.clear();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000355
356 jobjectArray input_buffers = (jobjectArray)GetObjectField(
357 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
358 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700359 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000360 input_buffers_.resize(num_input_buffers);
361 for (size_t i = 0; i < num_input_buffers; ++i) {
362 input_buffers_[i] =
363 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700364 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700365 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700366 sw_fallback_required_ = true;
367 return WEBRTC_VIDEO_CODEC_ERROR;
368 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000369 }
370
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000371 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
372
373 return WEBRTC_VIDEO_CODEC_OK;
374}
375
376int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700377 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000378 return codec_thread_->Invoke<int32_t>(
379 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
380}
381
382int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
383 if (!inited_) {
384 return WEBRTC_VIDEO_CODEC_OK;
385 }
386 CheckOnCodecThread();
387 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700388 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
389 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000390 ScopedLocalRefFrame local_ref_frame(jni);
391 for (size_t i = 0; i < input_buffers_.size(); i++) {
392 jni->DeleteGlobalRef(input_buffers_[i]);
393 }
394 input_buffers_.clear();
395 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
perkj9cb89822015-11-11 03:27:01 -0800396 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000397 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700398 rtc::MessageQueueManager::Clear(this);
399 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700400 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700401 return WEBRTC_VIDEO_CODEC_ERROR;
402 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700403 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000404 return WEBRTC_VIDEO_CODEC_OK;
405}
406
407void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700408 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000409 << "Running on wrong thread!";
410}
411
Alex Glaznev782671f2015-06-12 16:40:44 -0700412int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
413 CheckOnCodecThread();
414 int ret_val = ReleaseOnCodecThread();
415 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700416 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700417 }
418 if (codecType_ == kVideoCodecH264) {
419 // For now there is no SW H.264 which can be used as fallback codec.
420 // So try to restart hw codec for now.
421 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700422 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700423 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
424 // H.264 codec was succesfully reset - return regular error code.
425 return WEBRTC_VIDEO_CODEC_ERROR;
426 } else {
427 // Fail to restart H.264 codec - return error code which should stop the
428 // call.
429 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
430 }
431 } else {
432 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700433 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700434 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
435 }
436}
437
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000438int32_t MediaCodecVideoDecoder::Decode(
439 const EncodedImage& inputImage,
440 bool missingFrames,
441 const RTPFragmentationHeader* fragmentation,
442 const CodecSpecificInfo* codecSpecificInfo,
443 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700444 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700445 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700446 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000447 }
448 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700449 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000450 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
451 }
452 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700453 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000454 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
455 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700456 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700457 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700458 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
459 }
460
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000461 // Check if encoded frame dimension has changed.
462 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
463 (inputImage._encodedWidth != codec_.width ||
464 inputImage._encodedHeight != codec_.height)) {
465 codec_.width = inputImage._encodedWidth;
466 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700467 int32_t ret = InitDecode(&codec_, 1);
468 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700469 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700470 sw_fallback_required_ = true;
471 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
472 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000473 }
474
475 // Always start with a complete key frame.
476 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200477 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700478 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000479 return WEBRTC_VIDEO_CODEC_ERROR;
480 }
481 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700482 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000483 return WEBRTC_VIDEO_CODEC_ERROR;
484 }
485 key_frame_required_ = false;
486 }
487 if (inputImage._length == 0) {
488 return WEBRTC_VIDEO_CODEC_ERROR;
489 }
490
491 return codec_thread_->Invoke<int32_t>(Bind(
492 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
493}
494
495int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
496 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000497 CheckOnCodecThread();
498 JNIEnv* jni = AttachCurrentThreadIfNeeded();
499 ScopedLocalRefFrame local_ref_frame(jni);
500
501 // Try to drain the decoder and wait until output is not too
502 // much behind the input.
503 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000504 ALOGV("Received: %d. Decoded: %d. Wait for output...",
505 frames_received_, frames_decoded_);
perkj9cb89822015-11-11 03:27:01 -0800506 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700507 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
508 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700509 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000510 }
511 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glazneve55c42c2015-10-28 10:30:32 -0700512 ALOGE << "Output buffer dequeue timeout. 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 }
517
518 // Get input buffer.
519 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
520 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700521 if (CheckException(jni) || j_input_buffer_index < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700522 ALOGE << "dequeueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700523 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000524 }
525
526 // Copy encoded data to Java ByteBuffer.
527 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200528 uint8_t* buffer =
529 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700530 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200531 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700532 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700533 ALOGE << "Input frame size "<< inputImage._length <<
534 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700535 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000536 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000537 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
glazneve55c42c2015-10-28 10:30:32 -0700538 if (frames_decoded_ < kMaxDecodedLogFrames) {
539 ALOGD << "Decoder frame in # " << frames_received_ << ". Type: "
540 << inputImage._frameType << ". Buffer # " <<
541 j_input_buffer_index << ". TS: " << (int)(timestamp_us / 1000)
542 << ". Size: " << inputImage._length;
543 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000544 memcpy(buffer, inputImage._buffer, inputImage._length);
545
546 // Save input image timestamps for later output.
547 frames_received_++;
548 current_bytes_ += inputImage._length;
549 timestamps_.push_back(inputImage._timeStamp);
550 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000551
552 // Feed input to decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000553 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
554 j_queue_input_buffer_method_,
555 j_input_buffer_index,
556 inputImage._length,
557 timestamp_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700558 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700559 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700560 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000561 }
562
563 // Try to drain the decoder
564 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700565 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700566 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000567 }
568
569 return WEBRTC_VIDEO_CODEC_OK;
570}
571
572bool MediaCodecVideoDecoder::DeliverPendingOutputs(
perkj9cb89822015-11-11 03:27:01 -0800573 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000574 if (frames_received_ <= frames_decoded_) {
575 // No need to query for output buffers - decoder is drained.
576 return true;
577 }
578 // Get decoder output.
perkj9cb89822015-11-11 03:27:01 -0800579 jobject j_decoder_output_buffer =
580 jni->CallObjectMethod(*j_media_codec_video_decoder_,
581 use_surface_ ? j_dequeue_texture_buffer_method_
582 : j_dequeue_byte_buffer_method_,
583 dequeue_timeout_ms);
584
Alex Glaznev782671f2015-06-12 16:40:44 -0700585 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700586 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700587 return false;
588 }
magjed44bf6f52015-10-03 02:08:00 -0700589 if (IsNull(jni, j_decoder_output_buffer)) {
590 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000591 return true;
592 }
593
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000594 // Get decoded video frame properties.
595 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
596 j_color_format_field_);
597 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
598 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
599 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
600 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
601 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000602
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200603 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
perkj9cb89822015-11-11 03:27:01 -0800604 int64_t output_timestamps_ms = 0;
605 int decode_time_ms = 0;
606 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200607 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700608 // Extract data from Java DecodedTextureBuffer.
609 const int texture_id =
perkj9cb89822015-11-11 03:27:01 -0800610 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
611 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
612 const jfloatArray j_transform_matrix =
613 reinterpret_cast<jfloatArray>(GetObjectField(
614 jni, j_decoder_output_buffer, j_transform_matrix_field_));
615 const int64_t timestamp_us =
616 GetLongField(jni, j_decoder_output_buffer,
617 j_texture_presentation_timestamp_us_field_);
618 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
619 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
620 j_texture_decode_time_ms_field_);
621 frame_delayed_ms = GetLongField(jni, j_decoder_output_buffer,
622 j_texture_frame_delay_ms_field_);
623
624 // Create webrtc::VideoFrameBuffer with native texture handle.
625 frame_buffer = surface_texture_helper_->CreateTextureFrame(
626 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
627 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200628 } else {
629 // Extract data from Java ByteBuffer and create output yuv420 frame -
630 // for non surface decoding only.
magjed44bf6f52015-10-03 02:08:00 -0700631 const int output_buffer_index =
632 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_);
633 const int output_buffer_offset =
634 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_);
635 const int output_buffer_size =
636 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_);
637 const int64_t timestamp_us = GetLongField(
638 jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_);
639 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
perkj9cb89822015-11-11 03:27:01 -0800640 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
641 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700642
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000643 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700644 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000645 return false;
646 }
647 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
648 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
649 jobject output_buffer =
650 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
651 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
652 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700653 if (CheckException(jni)) {
654 return false;
655 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000656 payload += output_buffer_offset;
657
658 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200659 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000660 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200661 RTC_CHECK_EQ(0, stride % 2);
662 RTC_CHECK_EQ(0, slice_height % 2);
663 const int uv_stride = stride / 2;
664 const int u_slice_height = slice_height / 2;
665 const uint8_t* y_ptr = payload;
666 const uint8_t* u_ptr = y_ptr + stride * slice_height;
667 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
668 libyuv::I420Copy(y_ptr, stride,
669 u_ptr, uv_stride,
670 v_ptr, uv_stride,
671 frame_buffer->MutableData(webrtc::kYPlane),
672 frame_buffer->stride(webrtc::kYPlane),
673 frame_buffer->MutableData(webrtc::kUPlane),
674 frame_buffer->stride(webrtc::kUPlane),
675 frame_buffer->MutableData(webrtc::kVPlane),
676 frame_buffer->stride(webrtc::kVPlane),
677 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000678 } else {
679 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200680 const uint8_t* y_ptr = payload;
681 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000682 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200683 y_ptr, stride,
684 uv_ptr, stride,
685 frame_buffer->MutableData(webrtc::kYPlane),
686 frame_buffer->stride(webrtc::kYPlane),
687 frame_buffer->MutableData(webrtc::kUPlane),
688 frame_buffer->stride(webrtc::kUPlane),
689 frame_buffer->MutableData(webrtc::kVPlane),
690 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000691 width, height);
692 }
magjed44bf6f52015-10-03 02:08:00 -0700693 // Return output byte buffer back to codec.
694 jni->CallVoidMethod(
695 *j_media_codec_video_decoder_,
696 j_return_decoded_byte_buffer_method_,
697 output_buffer_index);
698 if (CheckException(jni)) {
perkj9cb89822015-11-11 03:27:01 -0800699 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700700 return false;
701 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000702 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200703 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000704
705 // Get frame timestamps from a queue.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000706 if (timestamps_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200707 decoded_frame.set_timestamp(timestamps_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000708 timestamps_.erase(timestamps_.begin());
709 }
710 if (ntp_times_ms_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200711 decoded_frame.set_ntp_time_ms(ntp_times_ms_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000712 ntp_times_ms_.erase(ntp_times_ms_.begin());
713 }
perkj9cb89822015-11-11 03:27:01 -0800714
glazneve55c42c2015-10-28 10:30:32 -0700715 if (frames_decoded_ < kMaxDecodedLogFrames) {
716 ALOGD << "Decoder frame out # " << frames_decoded_ << ". " << width <<
717 " x " << height << ". " << stride << " x " << slice_height <<
718 ". Color: " << color_format << ". TS:" << (int)output_timestamps_ms <<
perkj9cb89822015-11-11 03:27:01 -0800719 ". DecTime: " << (int)decode_time_ms <<
720 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700721 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000722
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000723 // Calculate and print decoding statistics - every 3 seconds.
724 frames_decoded_++;
725 current_frames_++;
perkj9cb89822015-11-11 03:27:01 -0800726 current_decoding_time_ms_ += decode_time_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000727 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
728 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
729 current_frames_ > 0) {
perkj9cb89822015-11-11 03:27:01 -0800730 ALOGD << "Decoded frames: " << frames_decoded_ << ". Received frames: "
731 << frames_received_ << ". Bitrate: " <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700732 (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " <<
733 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
734 << ". decTime: " << (current_decoding_time_ms_ / current_frames_) <<
735 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000736 start_time_ms_ = GetCurrentTimeMs();
737 current_frames_ = 0;
738 current_bytes_ = 0;
739 current_decoding_time_ms_ = 0;
740 }
741
perkj9cb89822015-11-11 03:27:01 -0800742 // |.IsZeroSize())| returns true when a frame has been dropped.
743 if (!decoded_frame.IsZeroSize()) {
744 // Callback - output decoded frame.
745 const int32_t callback_status =
746 callback_->Decoded(decoded_frame, decode_time_ms);
747 if (callback_status > 0) {
748 ALOGE << "callback error";
749 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000750 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000751 return true;
752}
753
754int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
755 DecodedImageCallback* callback) {
756 callback_ = callback;
757 return WEBRTC_VIDEO_CODEC_OK;
758}
759
760int32_t MediaCodecVideoDecoder::Reset() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700761 ALOGD << "DecoderReset";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000762 if (!inited_) {
763 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
764 }
765 return InitDecode(&codec_, 1);
766}
767
768void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
769 JNIEnv* jni = AttachCurrentThreadIfNeeded();
770 ScopedLocalRefFrame local_ref_frame(jni);
771 if (!inited_) {
772 return;
773 }
774 // We only ever send one message to |this| directly (not through a Bind()'d
775 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700776 RTC_CHECK(!msg->message_id) << "Unexpected message!";
777 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000778 CheckOnCodecThread();
779
780 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700781 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700782 ProcessHWErrorOnCodecThread();
783 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000784 }
785 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
786}
787
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700788MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
789 render_egl_context_(NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700790 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000791 JNIEnv* jni = AttachCurrentThreadIfNeeded();
792 ScopedLocalRefFrame local_ref_frame(jni);
793 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000794 supported_codec_types_.clear();
795
796 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000797 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000798 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700799 if (CheckException(jni)) {
800 is_vp8_hw_supported = false;
801 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000802 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700803 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000804 supported_codec_types_.push_back(kVideoCodecVP8);
805 }
806
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800807 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
808 j_decoder_class,
809 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
810 if (CheckException(jni)) {
811 is_vp9_hw_supported = false;
812 }
813 if (is_vp9_hw_supported) {
814 ALOGD << "VP9 HW Decoder supported.";
815 supported_codec_types_.push_back(kVideoCodecVP9);
816 }
817
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000818 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
819 j_decoder_class,
820 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700821 if (CheckException(jni)) {
822 is_h264_hw_supported = false;
823 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000824 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700825 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000826 supported_codec_types_.push_back(kVideoCodecH264);
827 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000828}
829
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700830MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700831 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700832 if (render_egl_context_) {
833 JNIEnv* jni = AttachCurrentThreadIfNeeded();
834 jni->DeleteGlobalRef(render_egl_context_);
835 render_egl_context_ = NULL;
836 }
837}
838
839void MediaCodecVideoDecoderFactory::SetEGLContext(
840 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700841 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700842 if (render_egl_context_) {
843 jni->DeleteGlobalRef(render_egl_context_);
844 render_egl_context_ = NULL;
845 }
846 if (!IsNull(jni, render_egl_context)) {
847 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
848 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700849 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700850 render_egl_context_ = NULL;
851 } else {
magjed8c425aa2015-10-22 16:52:39 -0700852 jclass j_egl_context_class =
853 FindClass(jni, "javax/microedition/khronos/egl/EGLContext");
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700854 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700855 ALOGE << "Wrong EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700856 jni->DeleteGlobalRef(render_egl_context_);
857 render_egl_context_ = NULL;
858 }
859 }
860 }
861 if (render_egl_context_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700862 ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700863 }
864}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000865
866webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000867 VideoCodecType type) {
868 if (supported_codec_types_.empty()) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700869 ALOGE << "No HW video decoder for type " << (int)type;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000870 return NULL;
871 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700872 for (VideoCodecType codec_type : supported_codec_types_) {
873 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700874 ALOGD << "Create HW video decoder for type " << (int)type;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700875 return new MediaCodecVideoDecoder(
876 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000877 }
878 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700879 ALOGE << "Can not find HW video decoder for type " << (int)type;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000880 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000881}
882
883void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
884 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700885 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000886 delete decoder;
887}
888
889} // namespace webrtc_jni
890