blob: e46750fe6c45c1508b20a149d9af4ba733f45ead [file] [log] [blame]
glaznev@webrtc.org18c92472015-02-18 18:42:55 +00001/*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
magjed6d387c02015-10-14 04:02:01 -070029#include <algorithm>
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000030#include <vector>
31
32#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
33#include "talk/app/webrtc/java/jni/androidmediacodeccommon.h"
34#include "talk/app/webrtc/java/jni/classreferenceholder.h"
35#include "talk/app/webrtc/java/jni/native_handle_impl.h"
Per488e75f2015-11-19 10:43:36 +010036#include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000037#include "webrtc/base/bind.h"
38#include "webrtc/base/checks.h"
39#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020040#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000041#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020042#include "webrtc/base/timeutils.h"
kjellander6f8ce062015-11-16 13:52:24 -080043#include "webrtc/common_video/include/i420_buffer_pool.h"
perkj87d58452015-11-23 01:46:27 -080044#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010045#include "webrtc/system_wrappers/include/logcat_trace_context.h"
46#include "webrtc/system_wrappers/include/tick_util.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000047#include "third_party/libyuv/include/libyuv/convert.h"
48#include "third_party/libyuv/include/libyuv/convert_from.h"
49#include "third_party/libyuv/include/libyuv/video_common.h"
50
51using rtc::Bind;
52using rtc::Thread;
53using rtc::ThreadManager;
54using rtc::scoped_ptr;
55
56using webrtc::CodecSpecificInfo;
57using webrtc::DecodedImageCallback;
58using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070059using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000060using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000061using webrtc::TickTime;
62using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000063using webrtc::VideoCodecType;
64using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000065using webrtc::kVideoCodecVP8;
Alex Glaznev69a7fd52015-11-10 10:25:40 -080066using webrtc::kVideoCodecVP9;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000067
68namespace webrtc_jni {
69
glaznevf4decb52016-01-15 13:49:22 -080070// Logging macros.
71#define TAG_DECODER "MediaCodecVideoDecoder"
72#ifdef TRACK_BUFFER_TIMING
73#define ALOGV(...)
74 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
75#else
76#define ALOGV(...)
77#endif
78#define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
79#define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
80#define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
81
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000082class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
83 public rtc::MessageHandler {
84 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070085 explicit MediaCodecVideoDecoder(
86 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000087 virtual ~MediaCodecVideoDecoder();
88
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000089 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
90 override;
91
92 int32_t Decode(
93 const EncodedImage& inputImage, bool missingFrames,
94 const RTPFragmentationHeader* fragmentation,
95 const CodecSpecificInfo* codecSpecificInfo = NULL,
96 int64_t renderTimeMs = -1) override;
97
98 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
99 override;
100
101 int32_t Release() override;
102
103 int32_t Reset() override;
perkj796cfaf2015-12-10 09:27:38 -0800104
105 bool PrefersLateDecoding() const override { return true; }
106
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000107 // rtc::MessageHandler implementation.
108 void OnMessage(rtc::Message* msg) override;
109
Peter Boströmb7d9a972015-12-18 16:01:11 +0100110 const char* ImplementationName() const override;
111
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000112 private:
113 // CHECK-fail if not running on |codec_thread_|.
114 void CheckOnCodecThread();
115
116 int32_t InitDecodeOnCodecThread();
117 int32_t ReleaseOnCodecThread();
118 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
119 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
120 // true on success.
121 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700122 int32_t ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000123
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000124 // Type of video codec.
125 VideoCodecType codecType_;
126
kjellander60ca31b2016-01-04 10:15:53 -0800127 // Render EGL context - owned by factory, should not be allocated/destroyed
128 // by VideoDecoder.
129 jobject render_egl_context_;
130
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000131 bool key_frame_required_;
132 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700133 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000134 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000135 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200136 webrtc::I420BufferPool decoded_frame_pool_;
Per488e75f2015-11-19 10:43:36 +0100137 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000138 DecodedImageCallback* callback_;
139 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000140 int frames_decoded_; // Number of frames decoded by decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000141 int64_t start_time_ms_; // Start time for statistics.
142 int current_frames_; // Number of frames in the current statistics interval.
143 int current_bytes_; // Encoded bytes in the current statistics interval.
144 int current_decoding_time_ms_; // Overall decoding time in the current second
145 uint32_t max_pending_frames_; // Maximum number of pending input frames
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000146
147 // State that is constant for the lifetime of this object once the ctor
148 // returns.
149 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
150 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
151 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
152 jmethodID j_init_decode_method_;
153 jmethodID j_release_method_;
154 jmethodID j_dequeue_input_buffer_method_;
155 jmethodID j_queue_input_buffer_method_;
Per488e75f2015-11-19 10:43:36 +0100156 jmethodID j_dequeue_byte_buffer_method_;
157 jmethodID j_dequeue_texture_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700158 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000159 // MediaCodecVideoDecoder fields.
160 jfieldID j_input_buffers_field_;
161 jfieldID j_output_buffers_field_;
162 jfieldID j_color_format_field_;
163 jfieldID j_width_field_;
164 jfieldID j_height_field_;
165 jfieldID j_stride_field_;
166 jfieldID j_slice_height_field_;
magjed44bf6f52015-10-03 02:08:00 -0700167 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
Per488e75f2015-11-19 10:43:36 +0100168 jfieldID j_texture_id_field_;
169 jfieldID j_transform_matrix_field_;
170 jfieldID j_texture_timestamp_ms_field_;
171 jfieldID j_texture_ntp_timestamp_ms_field_;
172 jfieldID j_texture_decode_time_ms_field_;
173 jfieldID j_texture_frame_delay_ms_field_;
174 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000175 jfieldID j_info_index_field_;
176 jfieldID j_info_offset_field_;
177 jfieldID j_info_size_field_;
Per488e75f2015-11-19 10:43:36 +0100178 jfieldID j_info_timestamp_ms_field_;
179 jfieldID j_info_ntp_timestamp_ms_field_;
180 jfieldID j_byte_buffer_decode_time_ms_field_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000181
182 // Global references; must be deleted in Release().
183 std::vector<jobject> input_buffers_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000184};
185
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000186MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700187 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000188 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700189 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000190 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000191 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700192 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000193 codec_thread_(new Thread()),
194 j_media_codec_video_decoder_class_(
195 jni,
196 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
197 j_media_codec_video_decoder_(
198 jni,
199 jni->NewObject(*j_media_codec_video_decoder_class_,
200 GetMethodID(jni,
201 *j_media_codec_video_decoder_class_,
202 "<init>",
203 "()V"))) {
204 ScopedLocalRefFrame local_ref_frame(jni);
205 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700206 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000207
208 j_init_decode_method_ = GetMethodID(
209 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000210 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Per488e75f2015-11-19 10:43:36 +0100211 "IILorg/webrtc/SurfaceTextureHelper;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000212 j_release_method_ =
213 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
214 j_dequeue_input_buffer_method_ = GetMethodID(
215 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
216 j_queue_input_buffer_method_ = GetMethodID(
Per488e75f2015-11-19 10:43:36 +0100217 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
218 j_dequeue_byte_buffer_method_ = GetMethodID(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000219 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
Per488e75f2015-11-19 10:43:36 +0100220 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
221 j_dequeue_texture_buffer_method_ = GetMethodID(
222 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
223 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
magjed44bf6f52015-10-03 02:08:00 -0700224 j_return_decoded_byte_buffer_method_ =
225 GetMethodID(jni, *j_media_codec_video_decoder_class_,
Per488e75f2015-11-19 10:43:36 +0100226 "returnDecodedOutputBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000227
228 j_input_buffers_field_ = GetFieldID(
229 jni, *j_media_codec_video_decoder_class_,
230 "inputBuffers", "[Ljava/nio/ByteBuffer;");
231 j_output_buffers_field_ = GetFieldID(
232 jni, *j_media_codec_video_decoder_class_,
233 "outputBuffers", "[Ljava/nio/ByteBuffer;");
234 j_color_format_field_ = GetFieldID(
235 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
236 j_width_field_ = GetFieldID(
237 jni, *j_media_codec_video_decoder_class_, "width", "I");
238 j_height_field_ = GetFieldID(
239 jni, *j_media_codec_video_decoder_class_, "height", "I");
240 j_stride_field_ = GetFieldID(
241 jni, *j_media_codec_video_decoder_class_, "stride", "I");
242 j_slice_height_field_ = GetFieldID(
243 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000244
Per488e75f2015-11-19 10:43:36 +0100245 jclass j_decoded_texture_buffer_class = FindClass(jni,
magjed44bf6f52015-10-03 02:08:00 -0700246 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
Per488e75f2015-11-19 10:43:36 +0100247 j_texture_id_field_ = GetFieldID(
248 jni, j_decoded_texture_buffer_class, "textureID", "I");
249 j_transform_matrix_field_ = GetFieldID(
250 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
251 j_texture_timestamp_ms_field_ = GetFieldID(
252 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
253 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
254 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
255 j_texture_decode_time_ms_field_ = GetFieldID(
256 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
257 j_texture_frame_delay_ms_field_ = GetFieldID(
258 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
magjed44bf6f52015-10-03 02:08:00 -0700259
Per488e75f2015-11-19 10:43:36 +0100260 jclass j_decoded_output_buffer_class = FindClass(jni,
261 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000262 j_info_index_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100263 jni, j_decoded_output_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000264 j_info_offset_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100265 jni, j_decoded_output_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000266 j_info_size_field_ = GetFieldID(
Per488e75f2015-11-19 10:43:36 +0100267 jni, j_decoded_output_buffer_class, "size", "I");
268 j_info_timestamp_ms_field_ = GetFieldID(
269 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
270 j_info_ntp_timestamp_ms_field_ = GetFieldID(
271 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
272 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
273 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000274
275 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200276 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700277 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000278 memset(&codec_, 0, sizeof(codec_));
279 AllowBlockingCalls();
280}
281
282MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
283 // Call Release() to ensure no more callbacks to us after we are deleted.
284 Release();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000285}
286
287int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
288 int32_t numberOfCores) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700289 ALOGD << "InitDecode.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000290 if (inst == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700291 ALOGE << "NULL VideoCodec instance";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000292 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
293 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000294 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700295 RTC_CHECK(inst->codecType == codecType_)
296 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000297
Alex Glaznev782671f2015-06-12 16:40:44 -0700298 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700299 ALOGE << "InitDecode() - fallback to SW decoder";
Alex Glaznev782671f2015-06-12 16:40:44 -0700300 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000301 }
302 // Save VideoCodec instance for later.
303 if (&codec_ != inst) {
304 codec_ = *inst;
305 }
glazneve55c42c2015-10-28 10:30:32 -0700306 // If maxFramerate is not set then assume 30 fps.
307 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000308
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000309 // Call Java init.
310 return codec_thread_->Invoke<int32_t>(
311 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
312}
313
314int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
315 CheckOnCodecThread();
316 JNIEnv* jni = AttachCurrentThreadIfNeeded();
317 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700318 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
319 << codec_.width << " x " << codec_.height << ". Fps: " <<
320 (int)codec_.maxFramerate;
Alex Glaznev782671f2015-06-12 16:40:44 -0700321
322 // Release previous codec first if it was allocated before.
323 int ret_val = ReleaseOnCodecThread();
324 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700325 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700326 sw_fallback_required_ = true;
327 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000328 }
329
Alex Glaznev782671f2015-06-12 16:40:44 -0700330 // Always start with a complete key frame.
331 key_frame_required_ = true;
332 frames_received_ = 0;
333 frames_decoded_ = 0;
334
perkj88518a22015-12-18 00:37:06 -0800335 jobject java_surface_texture_helper_ = nullptr;
Per488e75f2015-11-19 10:43:36 +0100336 if (use_surface_) {
perkj88518a22015-12-18 00:37:06 -0800337 java_surface_texture_helper_ = jni->CallStaticObjectMethod(
338 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
339 GetStaticMethodID(jni,
340 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
341 "create",
342 "(Lorg/webrtc/EglBase$Context;)"
343 "Lorg/webrtc/SurfaceTextureHelper;"),
344 render_egl_context_);
345 RTC_CHECK(java_surface_texture_helper_ != nullptr);
Per488e75f2015-11-19 10:43:36 +0100346 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
perkj88518a22015-12-18 00:37:06 -0800347 jni, java_surface_texture_helper_);
Per488e75f2015-11-19 10:43:36 +0100348 }
349
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000350 jobject j_video_codec_enum = JavaEnumFromIndex(
351 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000352 bool success = jni->CallBooleanMethod(
353 *j_media_codec_video_decoder_,
354 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000355 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000356 codec_.width,
357 codec_.height,
perkj88518a22015-12-18 00:37:06 -0800358 java_surface_texture_helper_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700359 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700360 ALOGE << "Codec initialization error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700361 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000362 return WEBRTC_VIDEO_CODEC_ERROR;
363 }
364 inited_ = true;
365
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000366 switch (codecType_) {
367 case kVideoCodecVP8:
368 max_pending_frames_ = kMaxPendingFramesVp8;
369 break;
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800370 case kVideoCodecVP9:
371 max_pending_frames_ = kMaxPendingFramesVp9;
372 break;
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000373 case kVideoCodecH264:
374 max_pending_frames_ = kMaxPendingFramesH264;
375 break;
376 default:
377 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000378 }
379 start_time_ms_ = GetCurrentTimeMs();
380 current_frames_ = 0;
381 current_bytes_ = 0;
382 current_decoding_time_ms_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000383
384 jobjectArray input_buffers = (jobjectArray)GetObjectField(
385 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
386 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glazneve55c42c2015-10-28 10:30:32 -0700387 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000388 input_buffers_.resize(num_input_buffers);
389 for (size_t i = 0; i < num_input_buffers; ++i) {
390 input_buffers_[i] =
391 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700392 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700393 ALOGE << "NewGlobalRef error - fallback to SW codec.";
Alex Glaznev782671f2015-06-12 16:40:44 -0700394 sw_fallback_required_ = true;
395 return WEBRTC_VIDEO_CODEC_ERROR;
396 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000397 }
398
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000399 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
400
401 return WEBRTC_VIDEO_CODEC_OK;
402}
403
404int32_t MediaCodecVideoDecoder::Release() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700405 ALOGD << "DecoderRelease request";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000406 return codec_thread_->Invoke<int32_t>(
407 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
408}
409
410int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
411 if (!inited_) {
412 return WEBRTC_VIDEO_CODEC_OK;
413 }
414 CheckOnCodecThread();
415 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glazneve55c42c2015-10-28 10:30:32 -0700416 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
417 frames_received_ << ". Frames decoded: " << frames_decoded_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000418 ScopedLocalRefFrame local_ref_frame(jni);
419 for (size_t i = 0; i < input_buffers_.size(); i++) {
420 jni->DeleteGlobalRef(input_buffers_[i]);
421 }
422 input_buffers_.clear();
423 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
Per488e75f2015-11-19 10:43:36 +0100424 surface_texture_helper_ = nullptr;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000425 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700426 rtc::MessageQueueManager::Clear(this);
427 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700428 ALOGE << "Decoder release exception";
Alex Glaznev782671f2015-06-12 16:40:44 -0700429 return WEBRTC_VIDEO_CODEC_ERROR;
430 }
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700431 ALOGD << "DecoderReleaseOnCodecThread done";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000432 return WEBRTC_VIDEO_CODEC_OK;
433}
434
435void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700436 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000437 << "Running on wrong thread!";
438}
439
Alex Glaznev782671f2015-06-12 16:40:44 -0700440int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
441 CheckOnCodecThread();
442 int ret_val = ReleaseOnCodecThread();
443 if (ret_val < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700444 ALOGE << "ProcessHWError: Release failure";
Alex Glaznev782671f2015-06-12 16:40:44 -0700445 }
446 if (codecType_ == kVideoCodecH264) {
447 // For now there is no SW H.264 which can be used as fallback codec.
448 // So try to restart hw codec for now.
449 ret_val = InitDecodeOnCodecThread();
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700450 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
Alex Glaznev782671f2015-06-12 16:40:44 -0700451 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
452 // H.264 codec was succesfully reset - return regular error code.
453 return WEBRTC_VIDEO_CODEC_ERROR;
454 } else {
455 // Fail to restart H.264 codec - return error code which should stop the
456 // call.
457 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
458 }
459 } else {
460 sw_fallback_required_ = true;
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700461 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
Alex Glaznev782671f2015-06-12 16:40:44 -0700462 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
463 }
464}
465
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000466int32_t MediaCodecVideoDecoder::Decode(
467 const EncodedImage& inputImage,
468 bool missingFrames,
469 const RTPFragmentationHeader* fragmentation,
470 const CodecSpecificInfo* codecSpecificInfo,
471 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700472 if (sw_fallback_required_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700473 ALOGE << "Decode() - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700474 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000475 }
476 if (callback_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700477 ALOGE << "Decode() - callback_ is NULL";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000478 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
479 }
480 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700481 ALOGE << "Decode() - inputImage is incorrect";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000482 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
483 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700484 if (!inited_) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700485 ALOGE << "Decode() - decoder is not initialized";
Alex Glaznev782671f2015-06-12 16:40:44 -0700486 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
487 }
488
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000489 // Check if encoded frame dimension has changed.
490 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
491 (inputImage._encodedWidth != codec_.width ||
492 inputImage._encodedHeight != codec_.height)) {
493 codec_.width = inputImage._encodedWidth;
494 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700495 int32_t ret = InitDecode(&codec_, 1);
496 if (ret < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700497 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
Alex Glaznev782671f2015-06-12 16:40:44 -0700498 sw_fallback_required_ = true;
499 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
500 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000501 }
502
503 // Always start with a complete key frame.
504 if (key_frame_required_) {
Peter Boström49e196a2015-10-23 15:58:18 +0200505 if (inputImage._frameType != webrtc::kVideoFrameKey) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700506 ALOGE << "Decode() - key frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000507 return WEBRTC_VIDEO_CODEC_ERROR;
508 }
509 if (!inputImage._completeFrame) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700510 ALOGE << "Decode() - complete frame is required";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000511 return WEBRTC_VIDEO_CODEC_ERROR;
512 }
513 key_frame_required_ = false;
514 }
515 if (inputImage._length == 0) {
516 return WEBRTC_VIDEO_CODEC_ERROR;
517 }
518
519 return codec_thread_->Invoke<int32_t>(Bind(
520 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
521}
522
523int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
524 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000525 CheckOnCodecThread();
526 JNIEnv* jni = AttachCurrentThreadIfNeeded();
527 ScopedLocalRefFrame local_ref_frame(jni);
528
529 // Try to drain the decoder and wait until output is not too
530 // much behind the input.
Per488e75f2015-11-19 10:43:36 +0100531 const int64 drain_start = GetCurrentTimeMs();
532 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
533 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000534 ALOGV("Received: %d. Decoded: %d. Wait for output...",
535 frames_received_, frames_decoded_);
Per488e75f2015-11-19 10:43:36 +0100536 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
glazneve55c42c2015-10-28 10:30:32 -0700537 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
538 frames_received_ << ". Frames decoded: " << frames_decoded_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700539 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000540 }
Per488e75f2015-11-19 10:43:36 +0100541 }
542 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
543 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
544 frames_received_ << ". Frames decoded: " << frames_decoded_;
545 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000546 }
547
548 // Get input buffer.
549 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
550 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700551 if (CheckException(jni) || j_input_buffer_index < 0) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700552 ALOGE << "dequeueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700553 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000554 }
555
556 // Copy encoded data to Java ByteBuffer.
557 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200558 uint8_t* buffer =
559 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700560 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200561 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700562 if (CheckException(jni) || buffer_capacity < inputImage._length) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700563 ALOGE << "Input frame size "<< inputImage._length <<
564 " is bigger than buffer size " << buffer_capacity;
Alex Glaznev782671f2015-06-12 16:40:44 -0700565 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000566 }
Per488e75f2015-11-19 10:43:36 +0100567 jlong presentation_timestamp_us =
568 (frames_received_ * 1000000) / codec_.maxFramerate;
glazneve55c42c2015-10-28 10:30:32 -0700569 if (frames_decoded_ < kMaxDecodedLogFrames) {
570 ALOGD << "Decoder frame in # " << frames_received_ << ". Type: "
571 << inputImage._frameType << ". Buffer # " <<
perkj87d58452015-11-23 01:46:27 -0800572 j_input_buffer_index << ". pTS: "
Per488e75f2015-11-19 10:43:36 +0100573 << (int)(presentation_timestamp_us / 1000)
perkj87d58452015-11-23 01:46:27 -0800574 << ". TS: " << inputImage._timeStamp
glazneve55c42c2015-10-28 10:30:32 -0700575 << ". Size: " << inputImage._length;
576 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000577 memcpy(buffer, inputImage._buffer, inputImage._length);
578
579 // Save input image timestamps for later output.
580 frames_received_++;
581 current_bytes_ += inputImage._length;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000582
583 // Feed input to decoder.
Per488e75f2015-11-19 10:43:36 +0100584 bool success = jni->CallBooleanMethod(
585 *j_media_codec_video_decoder_,
586 j_queue_input_buffer_method_,
587 j_input_buffer_index,
588 inputImage._length,
589 presentation_timestamp_us,
590 static_cast<int64_t> (inputImage._timeStamp),
591 inputImage.ntp_time_ms_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700592 if (CheckException(jni) || !success) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700593 ALOGE << "queueInputBuffer error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700594 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000595 }
596
597 // Try to drain the decoder
598 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700599 ALOGE << "DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700600 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000601 }
602
603 return WEBRTC_VIDEO_CODEC_OK;
604}
605
606bool MediaCodecVideoDecoder::DeliverPendingOutputs(
Per488e75f2015-11-19 10:43:36 +0100607 JNIEnv* jni, int dequeue_timeout_ms) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000608 if (frames_received_ <= frames_decoded_) {
609 // No need to query for output buffers - decoder is drained.
610 return true;
611 }
612 // Get decoder output.
Per488e75f2015-11-19 10:43:36 +0100613 jobject j_decoder_output_buffer =
614 jni->CallObjectMethod(*j_media_codec_video_decoder_,
615 use_surface_ ? j_dequeue_texture_buffer_method_
616 : j_dequeue_byte_buffer_method_,
617 dequeue_timeout_ms);
618
Alex Glaznev782671f2015-06-12 16:40:44 -0700619 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700620 ALOGE << "dequeueOutputBuffer() error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700621 return false;
622 }
magjed44bf6f52015-10-03 02:08:00 -0700623 if (IsNull(jni, j_decoder_output_buffer)) {
624 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000625 return true;
626 }
627
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000628 // Get decoded video frame properties.
629 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
630 j_color_format_field_);
631 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
632 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
633 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
634 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
635 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000636
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200637 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
Per488e75f2015-11-19 10:43:36 +0100638 int64_t output_timestamps_ms = 0;
639 int64_t output_ntp_timestamps_ms = 0;
640 int decode_time_ms = 0;
641 int64_t frame_delayed_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200642 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700643 // Extract data from Java DecodedTextureBuffer.
644 const int texture_id =
Per488e75f2015-11-19 10:43:36 +0100645 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
646 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
647 const jfloatArray j_transform_matrix =
648 reinterpret_cast<jfloatArray>(GetObjectField(
649 jni, j_decoder_output_buffer, j_transform_matrix_field_));
650 const int64_t timestamp_us =
651 GetLongField(jni, j_decoder_output_buffer,
652 j_texture_timestamp_ms_field_);
653 output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer,
654 j_texture_timestamp_ms_field_);
655 output_ntp_timestamps_ms =
656 GetLongField(jni, j_decoder_output_buffer,
657 j_texture_ntp_timestamp_ms_field_);
658 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
659 j_texture_decode_time_ms_field_);
660 frame_delayed_ms = GetLongField(jni, j_decoder_output_buffer,
661 j_texture_frame_delay_ms_field_);
662
663 // Create webrtc::VideoFrameBuffer with native texture handle.
664 frame_buffer = surface_texture_helper_->CreateTextureFrame(
665 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
666 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200667 } else {
668 // Extract data from Java ByteBuffer and create output yuv420 frame -
669 // for non surface decoding only.
magjed44bf6f52015-10-03 02:08:00 -0700670 const int output_buffer_index =
671 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_);
672 const int output_buffer_offset =
673 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_);
674 const int output_buffer_size =
675 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_);
Per488e75f2015-11-19 10:43:36 +0100676 output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer,
677 j_info_timestamp_ms_field_);
678 output_ntp_timestamps_ms =
679 GetLongField(jni, j_decoder_output_buffer,
680 j_info_ntp_timestamp_ms_field_);
681
682 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
683 j_byte_buffer_decode_time_ms_field_);
magjed44bf6f52015-10-03 02:08:00 -0700684
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000685 if (output_buffer_size < width * height * 3 / 2) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700686 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000687 return false;
688 }
689 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
690 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
691 jobject output_buffer =
692 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
693 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
694 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700695 if (CheckException(jni)) {
696 return false;
697 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000698 payload += output_buffer_offset;
699
700 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200701 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000702 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200703 RTC_CHECK_EQ(0, stride % 2);
704 RTC_CHECK_EQ(0, slice_height % 2);
705 const int uv_stride = stride / 2;
706 const int u_slice_height = slice_height / 2;
707 const uint8_t* y_ptr = payload;
708 const uint8_t* u_ptr = y_ptr + stride * slice_height;
709 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
710 libyuv::I420Copy(y_ptr, stride,
711 u_ptr, uv_stride,
712 v_ptr, uv_stride,
713 frame_buffer->MutableData(webrtc::kYPlane),
714 frame_buffer->stride(webrtc::kYPlane),
715 frame_buffer->MutableData(webrtc::kUPlane),
716 frame_buffer->stride(webrtc::kUPlane),
717 frame_buffer->MutableData(webrtc::kVPlane),
718 frame_buffer->stride(webrtc::kVPlane),
719 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000720 } else {
721 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200722 const uint8_t* y_ptr = payload;
723 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000724 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200725 y_ptr, stride,
726 uv_ptr, stride,
727 frame_buffer->MutableData(webrtc::kYPlane),
728 frame_buffer->stride(webrtc::kYPlane),
729 frame_buffer->MutableData(webrtc::kUPlane),
730 frame_buffer->stride(webrtc::kUPlane),
731 frame_buffer->MutableData(webrtc::kVPlane),
732 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000733 width, height);
734 }
magjed44bf6f52015-10-03 02:08:00 -0700735 // Return output byte buffer back to codec.
736 jni->CallVoidMethod(
737 *j_media_codec_video_decoder_,
738 j_return_decoded_byte_buffer_method_,
739 output_buffer_index);
740 if (CheckException(jni)) {
Per488e75f2015-11-19 10:43:36 +0100741 ALOGE << "returnDecodedOutputBuffer error";
magjed44bf6f52015-10-03 02:08:00 -0700742 return false;
743 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000744 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200745 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
Per488e75f2015-11-19 10:43:36 +0100746 decoded_frame.set_timestamp(output_timestamps_ms);
747 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000748
glazneve55c42c2015-10-28 10:30:32 -0700749 if (frames_decoded_ < kMaxDecodedLogFrames) {
750 ALOGD << "Decoder frame out # " << frames_decoded_ << ". " << width <<
751 " x " << height << ". " << stride << " x " << slice_height <<
perkj87d58452015-11-23 01:46:27 -0800752 ". Color: " << color_format << ". TS:" << decoded_frame.timestamp() <<
Per488e75f2015-11-19 10:43:36 +0100753 ". DecTime: " << (int)decode_time_ms <<
754 ". DelayTime: " << (int)frame_delayed_ms;
glazneve55c42c2015-10-28 10:30:32 -0700755 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000756
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000757 // Calculate and print decoding statistics - every 3 seconds.
758 frames_decoded_++;
759 current_frames_++;
Per488e75f2015-11-19 10:43:36 +0100760 current_decoding_time_ms_ += decode_time_ms;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000761 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
762 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
763 current_frames_ > 0) {
Per488e75f2015-11-19 10:43:36 +0100764 ALOGD << "Decoded frames: " << frames_decoded_ << ". Received frames: "
765 << frames_received_ << ". Bitrate: " <<
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700766 (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " <<
767 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms)
768 << ". decTime: " << (current_decoding_time_ms_ / current_frames_) <<
769 " for last " << statistic_time_ms << " ms.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000770 start_time_ms_ = GetCurrentTimeMs();
771 current_frames_ = 0;
772 current_bytes_ = 0;
773 current_decoding_time_ms_ = 0;
774 }
775
Per488e75f2015-11-19 10:43:36 +0100776 // |.IsZeroSize())| returns true when a frame has been dropped.
777 if (!decoded_frame.IsZeroSize()) {
778 // Callback - output decoded frame.
779 const int32_t callback_status =
780 callback_->Decoded(decoded_frame, decode_time_ms);
781 if (callback_status > 0) {
782 ALOGE << "callback error";
783 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000784 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000785 return true;
786}
787
788int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
789 DecodedImageCallback* callback) {
790 callback_ = callback;
791 return WEBRTC_VIDEO_CODEC_OK;
792}
793
794int32_t MediaCodecVideoDecoder::Reset() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700795 ALOGD << "DecoderReset";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000796 if (!inited_) {
797 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
798 }
799 return InitDecode(&codec_, 1);
800}
801
802void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
803 JNIEnv* jni = AttachCurrentThreadIfNeeded();
804 ScopedLocalRefFrame local_ref_frame(jni);
805 if (!inited_) {
806 return;
807 }
808 // We only ever send one message to |this| directly (not through a Bind()'d
809 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700810 RTC_CHECK(!msg->message_id) << "Unexpected message!";
811 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000812 CheckOnCodecThread();
813
814 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700815 ALOGE << "OnMessage: DeliverPendingOutputs error";
Alex Glaznev782671f2015-06-12 16:40:44 -0700816 ProcessHWErrorOnCodecThread();
817 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000818 }
819 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
820}
821
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700822MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
823 render_egl_context_(NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700824 ALOGD << "MediaCodecVideoDecoderFactory ctor";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000825 JNIEnv* jni = AttachCurrentThreadIfNeeded();
826 ScopedLocalRefFrame local_ref_frame(jni);
827 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000828 supported_codec_types_.clear();
829
830 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000831 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000832 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700833 if (CheckException(jni)) {
834 is_vp8_hw_supported = false;
835 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000836 if (is_vp8_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700837 ALOGD << "VP8 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000838 supported_codec_types_.push_back(kVideoCodecVP8);
839 }
840
Alex Glaznev69a7fd52015-11-10 10:25:40 -0800841 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
842 j_decoder_class,
843 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
844 if (CheckException(jni)) {
845 is_vp9_hw_supported = false;
846 }
847 if (is_vp9_hw_supported) {
848 ALOGD << "VP9 HW Decoder supported.";
849 supported_codec_types_.push_back(kVideoCodecVP9);
850 }
851
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000852 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
853 j_decoder_class,
854 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700855 if (CheckException(jni)) {
856 is_h264_hw_supported = false;
857 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000858 if (is_h264_hw_supported) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700859 ALOGD << "H264 HW Decoder supported.";
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000860 supported_codec_types_.push_back(kVideoCodecH264);
861 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000862}
863
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700864MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700865 ALOGD << "MediaCodecVideoDecoderFactory dtor";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700866 if (render_egl_context_) {
867 JNIEnv* jni = AttachCurrentThreadIfNeeded();
868 jni->DeleteGlobalRef(render_egl_context_);
869 render_egl_context_ = NULL;
870 }
871}
872
873void MediaCodecVideoDecoderFactory::SetEGLContext(
874 JNIEnv* jni, jobject render_egl_context) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700875 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700876 if (render_egl_context_) {
877 jni->DeleteGlobalRef(render_egl_context_);
878 render_egl_context_ = NULL;
879 }
880 if (!IsNull(jni, render_egl_context)) {
881 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
882 if (CheckException(jni)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700883 ALOGE << "error calling NewGlobalRef for EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700884 render_egl_context_ = NULL;
885 } else {
magjed8c425aa2015-10-22 16:52:39 -0700886 jclass j_egl_context_class =
perkj40455d62015-12-02 01:07:18 -0800887 FindClass(jni, "org/webrtc/EglBase$Context");
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700888 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700889 ALOGE << "Wrong EGL Context.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700890 jni->DeleteGlobalRef(render_egl_context_);
891 render_egl_context_ = NULL;
892 }
893 }
894 }
895 if (render_egl_context_ == NULL) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700896 ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled.";
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700897 }
898}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000899
900webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000901 VideoCodecType type) {
902 if (supported_codec_types_.empty()) {
Alex Glaznevad948c42015-11-18 13:06:42 -0800903 ALOGW << "No HW video decoder for type " << (int)type;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000904 return NULL;
905 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700906 for (VideoCodecType codec_type : supported_codec_types_) {
907 if (codec_type == type) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700908 ALOGD << "Create HW video decoder for type " << (int)type;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700909 return new MediaCodecVideoDecoder(
910 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000911 }
912 }
Alex Glaznevad948c42015-11-18 13:06:42 -0800913 ALOGW << "Can not find HW video decoder for type " << (int)type;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000914 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000915}
916
917void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
918 webrtc::VideoDecoder* decoder) {
Alex Glaznevfddf6e52015-10-07 16:51:02 -0700919 ALOGD << "Destroy video decoder.";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000920 delete decoder;
921}
922
Peter Boströmb7d9a972015-12-18 16:01:11 +0100923const char* MediaCodecVideoDecoder::ImplementationName() const {
924 return "MediaCodec";
925}
926
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000927} // namespace webrtc_jni
928