blob: 1f6313119e8d0d5b2726a75f38417102b5887147 [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
29#include <vector>
30
31#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
32#include "talk/app/webrtc/java/jni/androidmediacodeccommon.h"
33#include "talk/app/webrtc/java/jni/classreferenceholder.h"
34#include "talk/app/webrtc/java/jni/native_handle_impl.h"
35#include "webrtc/base/bind.h"
36#include "webrtc/base/checks.h"
37#include "webrtc/base/logging.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020038#include "webrtc/base/scoped_ref_ptr.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000039#include "webrtc/base/thread.h"
Magnus Jedvert7e319372015-10-02 15:49:38 +020040#include "webrtc/base/timeutils.h"
Magnus Jedvertbbda54e2015-09-30 16:06:37 +020041#include "webrtc/common_video/interface/i420_buffer_pool.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000042#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
43#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
44#include "webrtc/system_wrappers/interface/tick_util.h"
45#include "third_party/libyuv/include/libyuv/convert.h"
46#include "third_party/libyuv/include/libyuv/convert_from.h"
47#include "third_party/libyuv/include/libyuv/video_common.h"
48
49using rtc::Bind;
50using rtc::Thread;
51using rtc::ThreadManager;
52using rtc::scoped_ptr;
53
54using webrtc::CodecSpecificInfo;
55using webrtc::DecodedImageCallback;
56using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070057using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000058using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000059using webrtc::TickTime;
60using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000061using webrtc::VideoCodecType;
62using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000063using webrtc::kVideoCodecVP8;
64
65namespace webrtc_jni {
66
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000067class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
68 public rtc::MessageHandler {
69 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070070 explicit MediaCodecVideoDecoder(
71 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000072 virtual ~MediaCodecVideoDecoder();
73
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000074 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
75 override;
76
77 int32_t Decode(
78 const EncodedImage& inputImage, bool missingFrames,
79 const RTPFragmentationHeader* fragmentation,
80 const CodecSpecificInfo* codecSpecificInfo = NULL,
81 int64_t renderTimeMs = -1) override;
82
83 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
84 override;
85
86 int32_t Release() override;
87
88 int32_t Reset() override;
89 // rtc::MessageHandler implementation.
90 void OnMessage(rtc::Message* msg) override;
91
92 private:
93 // CHECK-fail if not running on |codec_thread_|.
94 void CheckOnCodecThread();
95
96 int32_t InitDecodeOnCodecThread();
97 int32_t ReleaseOnCodecThread();
98 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
99 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
100 // true on success.
101 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700102 int32_t ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000103
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000104 // Type of video codec.
105 VideoCodecType codecType_;
106
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000107 bool key_frame_required_;
108 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700109 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000110 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000111 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200112 webrtc::I420BufferPool decoded_frame_pool_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000113 NativeHandleImpl native_handle_;
114 DecodedImageCallback* callback_;
115 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000116 int frames_decoded_; // Number of frames decoded by decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000117 int64_t start_time_ms_; // Start time for statistics.
118 int current_frames_; // Number of frames in the current statistics interval.
119 int current_bytes_; // Encoded bytes in the current statistics interval.
120 int current_decoding_time_ms_; // Overall decoding time in the current second
121 uint32_t max_pending_frames_; // Maximum number of pending input frames
122 std::vector<int32_t> timestamps_;
123 std::vector<int64_t> ntp_times_ms_;
124 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
125 // decoder input.
126
127 // State that is constant for the lifetime of this object once the ctor
128 // returns.
129 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
130 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
131 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
132 jmethodID j_init_decode_method_;
133 jmethodID j_release_method_;
134 jmethodID j_dequeue_input_buffer_method_;
135 jmethodID j_queue_input_buffer_method_;
136 jmethodID j_dequeue_output_buffer_method_;
magjed44bf6f52015-10-03 02:08:00 -0700137 jmethodID j_return_decoded_byte_buffer_method_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000138 // MediaCodecVideoDecoder fields.
139 jfieldID j_input_buffers_field_;
140 jfieldID j_output_buffers_field_;
141 jfieldID j_color_format_field_;
142 jfieldID j_width_field_;
143 jfieldID j_height_field_;
144 jfieldID j_stride_field_;
145 jfieldID j_slice_height_field_;
146 jfieldID j_surface_texture_field_;
magjed44bf6f52015-10-03 02:08:00 -0700147 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000148 jfieldID j_textureID_field_;
magjed44bf6f52015-10-03 02:08:00 -0700149 jfieldID j_texture_presentation_timestamp_us_field_;
150 // MediaCodecVideoDecoder.DecodedByteBuffer fields.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000151 jfieldID j_info_index_field_;
152 jfieldID j_info_offset_field_;
153 jfieldID j_info_size_field_;
154 jfieldID j_info_presentation_timestamp_us_field_;
155
156 // Global references; must be deleted in Release().
157 std::vector<jobject> input_buffers_;
158 jobject surface_texture_;
159 jobject previous_surface_texture_;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700160
161 // Render EGL context - owned by factory, should not be allocated/destroyed
162 // by VideoDecoder.
163 jobject render_egl_context_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000164};
165
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000166MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700167 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000168 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700169 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000170 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000171 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700172 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000173 surface_texture_(NULL),
174 previous_surface_texture_(NULL),
175 codec_thread_(new Thread()),
176 j_media_codec_video_decoder_class_(
177 jni,
178 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
179 j_media_codec_video_decoder_(
180 jni,
181 jni->NewObject(*j_media_codec_video_decoder_class_,
182 GetMethodID(jni,
183 *j_media_codec_video_decoder_class_,
184 "<init>",
185 "()V"))) {
186 ScopedLocalRefFrame local_ref_frame(jni);
187 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700188 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000189
190 j_init_decode_method_ = GetMethodID(
191 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000192 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Magnus Jedvert207370f2015-09-16 12:32:21 +0200193 "IILandroid/opengl/EGLContext;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000194 j_release_method_ =
195 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
196 j_dequeue_input_buffer_method_ = GetMethodID(
197 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
198 j_queue_input_buffer_method_ = GetMethodID(
199 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
200 j_dequeue_output_buffer_method_ = GetMethodID(
201 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
magjed44bf6f52015-10-03 02:08:00 -0700202 "(I)Ljava/lang/Object;");
203 j_return_decoded_byte_buffer_method_ =
204 GetMethodID(jni, *j_media_codec_video_decoder_class_,
205 "returnDecodedByteBuffer", "(I)V");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000206
207 j_input_buffers_field_ = GetFieldID(
208 jni, *j_media_codec_video_decoder_class_,
209 "inputBuffers", "[Ljava/nio/ByteBuffer;");
210 j_output_buffers_field_ = GetFieldID(
211 jni, *j_media_codec_video_decoder_class_,
212 "outputBuffers", "[Ljava/nio/ByteBuffer;");
213 j_color_format_field_ = GetFieldID(
214 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
215 j_width_field_ = GetFieldID(
216 jni, *j_media_codec_video_decoder_class_, "width", "I");
217 j_height_field_ = GetFieldID(
218 jni, *j_media_codec_video_decoder_class_, "height", "I");
219 j_stride_field_ = GetFieldID(
220 jni, *j_media_codec_video_decoder_class_, "stride", "I");
221 j_slice_height_field_ = GetFieldID(
222 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000223 j_surface_texture_field_ = GetFieldID(
224 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
225 "Landroid/graphics/SurfaceTexture;");
226
magjed44bf6f52015-10-03 02:08:00 -0700227 jclass j_decoder_decoded_texture_buffer_class = FindClass(jni,
228 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
229 j_textureID_field_ = GetFieldID(
230 jni, j_decoder_decoded_texture_buffer_class, "textureID", "I");
231 j_texture_presentation_timestamp_us_field_ =
232 GetFieldID(jni, j_decoder_decoded_texture_buffer_class,
233 "presentationTimestampUs", "J");
234
235 jclass j_decoder_decoded_byte_buffer_class = FindClass(jni,
236 "org/webrtc/MediaCodecVideoDecoder$DecodedByteBuffer");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000237 j_info_index_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700238 jni, j_decoder_decoded_byte_buffer_class, "index", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000239 j_info_offset_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700240 jni, j_decoder_decoded_byte_buffer_class, "offset", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000241 j_info_size_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700242 jni, j_decoder_decoded_byte_buffer_class, "size", "I");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000243 j_info_presentation_timestamp_us_field_ = GetFieldID(
magjed44bf6f52015-10-03 02:08:00 -0700244 jni, j_decoder_decoded_byte_buffer_class, "presentationTimestampUs", "J");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000245
246 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200247 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700248 ALOGD("MediaCodecVideoDecoder ctor. Use surface: %d", use_surface_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000249 memset(&codec_, 0, sizeof(codec_));
250 AllowBlockingCalls();
251}
252
253MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
254 // Call Release() to ensure no more callbacks to us after we are deleted.
255 Release();
256 // Delete global references.
257 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000258 if (previous_surface_texture_ != NULL) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000259 jni->DeleteGlobalRef(previous_surface_texture_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000260 }
261 if (surface_texture_ != NULL) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000262 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000263 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000264}
265
266int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
267 int32_t numberOfCores) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700268 ALOGD("InitDecode.");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000269 if (inst == NULL) {
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000270 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_) {
278 ALOGE("InitDecode() - fallback to SW decoder");
279 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 }
285 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
286
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000287 // Call Java init.
288 return codec_thread_->Invoke<int32_t>(
289 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
290}
291
292int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
293 CheckOnCodecThread();
294 JNIEnv* jni = AttachCurrentThreadIfNeeded();
295 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznev782671f2015-06-12 16:40:44 -0700296 ALOGD("InitDecodeOnCodecThread Type: %d. %d x %d. Fps: %d.",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000297 (int)codecType_, codec_.width, codec_.height,
Alex Glaznev782671f2015-06-12 16:40:44 -0700298 codec_.maxFramerate);
299
300 // Release previous codec first if it was allocated before.
301 int ret_val = ReleaseOnCodecThread();
302 if (ret_val < 0) {
303 ALOGE("Release failure: %d - fallback to SW codec", ret_val);
304 sw_fallback_required_ = true;
305 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000306 }
307
Alex Glaznev782671f2015-06-12 16:40:44 -0700308 // Always start with a complete key frame.
309 key_frame_required_ = true;
310 frames_received_ = 0;
311 frames_decoded_ = 0;
312
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000313 jobject j_video_codec_enum = JavaEnumFromIndex(
314 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000315 bool success = jni->CallBooleanMethod(
316 *j_media_codec_video_decoder_,
317 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000318 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000319 codec_.width,
320 codec_.height,
Magnus Jedvert207370f2015-09-16 12:32:21 +0200321 use_surface_ ? render_egl_context_ : nullptr);
Alex Glaznev782671f2015-06-12 16:40:44 -0700322 if (CheckException(jni) || !success) {
323 ALOGE("Codec initialization error - fallback to SW codec.");
324 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000325 return WEBRTC_VIDEO_CODEC_ERROR;
326 }
327 inited_ = true;
328
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000329 switch (codecType_) {
330 case kVideoCodecVP8:
331 max_pending_frames_ = kMaxPendingFramesVp8;
332 break;
333 case kVideoCodecH264:
334 max_pending_frames_ = kMaxPendingFramesH264;
335 break;
336 default:
337 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000338 }
339 start_time_ms_ = GetCurrentTimeMs();
340 current_frames_ = 0;
341 current_bytes_ = 0;
342 current_decoding_time_ms_ = 0;
343 timestamps_.clear();
344 ntp_times_ms_.clear();
345 frame_rtc_times_ms_.clear();
346
347 jobjectArray input_buffers = (jobjectArray)GetObjectField(
348 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
349 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
350 input_buffers_.resize(num_input_buffers);
351 for (size_t i = 0; i < num_input_buffers; ++i) {
352 input_buffers_[i] =
353 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700354 if (CheckException(jni)) {
355 ALOGE("NewGlobalRef error - fallback to SW codec.");
356 sw_fallback_required_ = true;
357 return WEBRTC_VIDEO_CODEC_ERROR;
358 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000359 }
360
361 if (use_surface_) {
362 jobject surface_texture = GetObjectField(
363 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
364 if (previous_surface_texture_ != NULL) {
365 jni->DeleteGlobalRef(previous_surface_texture_);
366 }
367 previous_surface_texture_ = surface_texture_;
368 surface_texture_ = jni->NewGlobalRef(surface_texture);
369 }
370 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
371
372 return WEBRTC_VIDEO_CODEC_OK;
373}
374
375int32_t MediaCodecVideoDecoder::Release() {
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000376 ALOGD("DecoderRelease request");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000377 return codec_thread_->Invoke<int32_t>(
378 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
379}
380
381int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
382 if (!inited_) {
383 return WEBRTC_VIDEO_CODEC_OK;
384 }
385 CheckOnCodecThread();
386 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000387 ALOGD("DecoderReleaseOnCodecThread: Frames received: %d.", frames_received_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000388 ScopedLocalRefFrame local_ref_frame(jni);
389 for (size_t i = 0; i < input_buffers_.size(); i++) {
390 jni->DeleteGlobalRef(input_buffers_[i]);
391 }
392 input_buffers_.clear();
393 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000394 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700395 rtc::MessageQueueManager::Clear(this);
396 if (CheckException(jni)) {
397 ALOGE("Decoder release exception");
398 return WEBRTC_VIDEO_CODEC_ERROR;
399 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000400 return WEBRTC_VIDEO_CODEC_OK;
401}
402
403void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700404 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000405 << "Running on wrong thread!";
406}
407
Alex Glaznev782671f2015-06-12 16:40:44 -0700408int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
409 CheckOnCodecThread();
410 int ret_val = ReleaseOnCodecThread();
411 if (ret_val < 0) {
412 ALOGE("ProcessHWError: Release failure");
413 }
414 if (codecType_ == kVideoCodecH264) {
415 // For now there is no SW H.264 which can be used as fallback codec.
416 // So try to restart hw codec for now.
417 ret_val = InitDecodeOnCodecThread();
418 ALOGE("Reset H.264 codec done. Status: %d", ret_val);
419 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
420 // H.264 codec was succesfully reset - return regular error code.
421 return WEBRTC_VIDEO_CODEC_ERROR;
422 } else {
423 // Fail to restart H.264 codec - return error code which should stop the
424 // call.
425 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
426 }
427 } else {
428 sw_fallback_required_ = true;
429 ALOGE("Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE");
430 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
431 }
432}
433
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000434int32_t MediaCodecVideoDecoder::Decode(
435 const EncodedImage& inputImage,
436 bool missingFrames,
437 const RTPFragmentationHeader* fragmentation,
438 const CodecSpecificInfo* codecSpecificInfo,
439 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700440 if (sw_fallback_required_) {
441 ALOGE("Decode() - fallback to SW codec");
442 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000443 }
444 if (callback_ == NULL) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700445 ALOGE("Decode() - callback_ is NULL");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000446 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
447 }
448 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700449 ALOGE("Decode() - inputImage is incorrect");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000450 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
451 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700452 if (!inited_) {
453 ALOGE("Decode() - decoder is not initialized");
454 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
455 }
456
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000457 // Check if encoded frame dimension has changed.
458 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
459 (inputImage._encodedWidth != codec_.width ||
460 inputImage._encodedHeight != codec_.height)) {
461 codec_.width = inputImage._encodedWidth;
462 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700463 int32_t ret = InitDecode(&codec_, 1);
464 if (ret < 0) {
465 ALOGE("InitDecode failure: %d - fallback to SW codec", ret);
466 sw_fallback_required_ = true;
467 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
468 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000469 }
470
471 // Always start with a complete key frame.
472 if (key_frame_required_) {
473 if (inputImage._frameType != webrtc::kKeyFrame) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700474 ALOGE("Decode() - key frame is required");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000475 return WEBRTC_VIDEO_CODEC_ERROR;
476 }
477 if (!inputImage._completeFrame) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700478 ALOGE("Decode() - complete frame is required");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000479 return WEBRTC_VIDEO_CODEC_ERROR;
480 }
481 key_frame_required_ = false;
482 }
483 if (inputImage._length == 0) {
484 return WEBRTC_VIDEO_CODEC_ERROR;
485 }
486
487 return codec_thread_->Invoke<int32_t>(Bind(
488 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
489}
490
491int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
492 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000493 CheckOnCodecThread();
494 JNIEnv* jni = AttachCurrentThreadIfNeeded();
495 ScopedLocalRefFrame local_ref_frame(jni);
496
497 // Try to drain the decoder and wait until output is not too
498 // much behind the input.
499 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000500 ALOGV("Received: %d. Decoded: %d. Wait for output...",
501 frames_received_, frames_decoded_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000502 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700503 ALOGE("DeliverPendingOutputs error");
504 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000505 }
506 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
507 ALOGE("Output buffer dequeue timeout");
Alex Glaznev782671f2015-06-12 16:40:44 -0700508 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000509 }
510 }
511
512 // Get input buffer.
513 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
514 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700515 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000516 ALOGE("dequeueInputBuffer error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700517 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000518 }
519
520 // Copy encoded data to Java ByteBuffer.
521 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
Peter Boström0c4e06b2015-10-07 12:23:21 +0200522 uint8_t* buffer =
523 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700524 RTC_CHECK(buffer) << "Indirect buffer??";
Peter Boström0c4e06b2015-10-07 12:23:21 +0200525 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700526 if (CheckException(jni) || buffer_capacity < inputImage._length) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000527 ALOGE("Input frame size %d is bigger than buffer size %d.",
528 inputImage._length, buffer_capacity);
Alex Glaznev782671f2015-06-12 16:40:44 -0700529 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000530 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000531 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
532 ALOGV("Decoder frame in # %d. Type: %d. Buffer # %d. TS: %lld. Size: %d",
533 frames_received_, inputImage._frameType, j_input_buffer_index,
534 timestamp_us / 1000, inputImage._length);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000535 memcpy(buffer, inputImage._buffer, inputImage._length);
536
537 // Save input image timestamps for later output.
538 frames_received_++;
539 current_bytes_ += inputImage._length;
540 timestamps_.push_back(inputImage._timeStamp);
541 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
542 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
543
544 // Feed input to decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000545 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
546 j_queue_input_buffer_method_,
547 j_input_buffer_index,
548 inputImage._length,
549 timestamp_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700550 if (CheckException(jni) || !success) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000551 ALOGE("queueInputBuffer error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700552 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000553 }
554
555 // Try to drain the decoder
556 if (!DeliverPendingOutputs(jni, 0)) {
557 ALOGE("DeliverPendingOutputs error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700558 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000559 }
560
561 return WEBRTC_VIDEO_CODEC_OK;
562}
563
564bool MediaCodecVideoDecoder::DeliverPendingOutputs(
565 JNIEnv* jni, int dequeue_timeout_us) {
566 if (frames_received_ <= frames_decoded_) {
567 // No need to query for output buffers - decoder is drained.
568 return true;
569 }
570 // Get decoder output.
magjed44bf6f52015-10-03 02:08:00 -0700571 jobject j_decoder_output_buffer = jni->CallObjectMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000572 *j_media_codec_video_decoder_,
573 j_dequeue_output_buffer_method_,
574 dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700575 if (CheckException(jni)) {
magjed44bf6f52015-10-03 02:08:00 -0700576 ALOGE("dequeueOutputBuffer() error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700577 return false;
578 }
magjed44bf6f52015-10-03 02:08:00 -0700579 if (IsNull(jni, j_decoder_output_buffer)) {
580 // No decoded frame ready.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000581 return true;
582 }
583
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000584 // Get decoded video frame properties.
585 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
586 j_color_format_field_);
587 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
588 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
589 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
590 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
591 j_slice_height_field_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000592
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200593 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
magjed44bf6f52015-10-03 02:08:00 -0700594 long output_timestamps_ms = 0;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200595 if (use_surface_) {
magjed44bf6f52015-10-03 02:08:00 -0700596 // Extract data from Java DecodedTextureBuffer.
597 const int texture_id =
598 GetIntField(jni, j_decoder_output_buffer, j_textureID_field_);
599 const int64_t timestamp_us =
600 GetLongField(jni, j_decoder_output_buffer,
601 j_texture_presentation_timestamp_us_field_);
602 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
603 // Create webrtc::VideoFrameBuffer with native texture handle.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200604 native_handle_.SetTextureObject(surface_texture_, texture_id);
605 frame_buffer = new rtc::RefCountedObject<JniNativeHandleBuffer>(
606 &native_handle_, width, height);
607 } else {
608 // Extract data from Java ByteBuffer and create output yuv420 frame -
609 // for non surface decoding only.
magjed44bf6f52015-10-03 02:08:00 -0700610 const int output_buffer_index =
611 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_);
612 const int output_buffer_offset =
613 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_);
614 const int output_buffer_size =
615 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_);
616 const int64_t timestamp_us = GetLongField(
617 jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_);
618 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec;
619
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000620 if (output_buffer_size < width * height * 3 / 2) {
621 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
622 return false;
623 }
624 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
625 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
626 jobject output_buffer =
627 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
628 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
629 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700630 if (CheckException(jni)) {
631 return false;
632 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000633 payload += output_buffer_offset;
634
635 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200636 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000637 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200638 RTC_CHECK_EQ(0, stride % 2);
639 RTC_CHECK_EQ(0, slice_height % 2);
640 const int uv_stride = stride / 2;
641 const int u_slice_height = slice_height / 2;
642 const uint8_t* y_ptr = payload;
643 const uint8_t* u_ptr = y_ptr + stride * slice_height;
644 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
645 libyuv::I420Copy(y_ptr, stride,
646 u_ptr, uv_stride,
647 v_ptr, uv_stride,
648 frame_buffer->MutableData(webrtc::kYPlane),
649 frame_buffer->stride(webrtc::kYPlane),
650 frame_buffer->MutableData(webrtc::kUPlane),
651 frame_buffer->stride(webrtc::kUPlane),
652 frame_buffer->MutableData(webrtc::kVPlane),
653 frame_buffer->stride(webrtc::kVPlane),
654 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000655 } else {
656 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200657 const uint8_t* y_ptr = payload;
658 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000659 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200660 y_ptr, stride,
661 uv_ptr, stride,
662 frame_buffer->MutableData(webrtc::kYPlane),
663 frame_buffer->stride(webrtc::kYPlane),
664 frame_buffer->MutableData(webrtc::kUPlane),
665 frame_buffer->stride(webrtc::kUPlane),
666 frame_buffer->MutableData(webrtc::kVPlane),
667 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000668 width, height);
669 }
magjed44bf6f52015-10-03 02:08:00 -0700670 // Return output byte buffer back to codec.
671 jni->CallVoidMethod(
672 *j_media_codec_video_decoder_,
673 j_return_decoded_byte_buffer_method_,
674 output_buffer_index);
675 if (CheckException(jni)) {
676 ALOGE("returnDecodedByteBuffer error");
677 return false;
678 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000679 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200680 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000681
682 // Get frame timestamps from a queue.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000683 if (timestamps_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200684 decoded_frame.set_timestamp(timestamps_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000685 timestamps_.erase(timestamps_.begin());
686 }
687 if (ntp_times_ms_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200688 decoded_frame.set_ntp_time_ms(ntp_times_ms_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000689 ntp_times_ms_.erase(ntp_times_ms_.begin());
690 }
691 int64_t frame_decoding_time_ms = 0;
692 if (frame_rtc_times_ms_.size() > 0) {
693 frame_decoding_time_ms = GetCurrentTimeMs() - frame_rtc_times_ms_.front();
694 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
695 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000696 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. TS: %ld."
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000697 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000698 color_format, output_timestamps_ms, frame_decoding_time_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000699
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000700 // Calculate and print decoding statistics - every 3 seconds.
701 frames_decoded_++;
702 current_frames_++;
703 current_decoding_time_ms_ += frame_decoding_time_ms;
704 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
705 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
706 current_frames_ > 0) {
707 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
708 current_bytes_ * 8 / statistic_time_ms,
709 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
710 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
711 start_time_ms_ = GetCurrentTimeMs();
712 current_frames_ = 0;
713 current_bytes_ = 0;
714 current_decoding_time_ms_ = 0;
715 }
716
717 // Callback - output decoded frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200718 const int32_t callback_status = callback_->Decoded(decoded_frame);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000719 if (callback_status > 0) {
720 ALOGE("callback error");
721 }
722
723 return true;
724}
725
726int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
727 DecodedImageCallback* callback) {
728 callback_ = callback;
729 return WEBRTC_VIDEO_CODEC_OK;
730}
731
732int32_t MediaCodecVideoDecoder::Reset() {
733 ALOGD("DecoderReset");
734 if (!inited_) {
735 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
736 }
737 return InitDecode(&codec_, 1);
738}
739
740void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
741 JNIEnv* jni = AttachCurrentThreadIfNeeded();
742 ScopedLocalRefFrame local_ref_frame(jni);
743 if (!inited_) {
744 return;
745 }
746 // We only ever send one message to |this| directly (not through a Bind()'d
747 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700748 RTC_CHECK(!msg->message_id) << "Unexpected message!";
749 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000750 CheckOnCodecThread();
751
752 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700753 ALOGE("OnMessage: DeliverPendingOutputs error");
754 ProcessHWErrorOnCodecThread();
755 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000756 }
757 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
758}
759
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700760MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
761 render_egl_context_(NULL) {
762 ALOGD("MediaCodecVideoDecoderFactory ctor");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000763 JNIEnv* jni = AttachCurrentThreadIfNeeded();
764 ScopedLocalRefFrame local_ref_frame(jni);
765 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000766 supported_codec_types_.clear();
767
768 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000769 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000770 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700771 if (CheckException(jni)) {
772 is_vp8_hw_supported = false;
773 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000774 if (is_vp8_hw_supported) {
775 ALOGD("VP8 HW Decoder supported.");
776 supported_codec_types_.push_back(kVideoCodecVP8);
777 }
778
779 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
780 j_decoder_class,
781 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700782 if (CheckException(jni)) {
783 is_h264_hw_supported = false;
784 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000785 if (is_h264_hw_supported) {
786 ALOGD("H264 HW Decoder supported.");
787 supported_codec_types_.push_back(kVideoCodecH264);
788 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000789}
790
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700791MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
792 ALOGD("MediaCodecVideoDecoderFactory dtor");
793 if (render_egl_context_) {
794 JNIEnv* jni = AttachCurrentThreadIfNeeded();
795 jni->DeleteGlobalRef(render_egl_context_);
796 render_egl_context_ = NULL;
797 }
798}
799
800void MediaCodecVideoDecoderFactory::SetEGLContext(
801 JNIEnv* jni, jobject render_egl_context) {
802 ALOGD("MediaCodecVideoDecoderFactory::SetEGLContext");
803 if (render_egl_context_) {
804 jni->DeleteGlobalRef(render_egl_context_);
805 render_egl_context_ = NULL;
806 }
807 if (!IsNull(jni, render_egl_context)) {
808 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
809 if (CheckException(jni)) {
810 ALOGE("error calling NewGlobalRef for EGL Context.");
811 render_egl_context_ = NULL;
812 } else {
813 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
814 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
815 ALOGE("Wrong EGL Context.");
816 jni->DeleteGlobalRef(render_egl_context_);
817 render_egl_context_ = NULL;
818 }
819 }
820 }
821 if (render_egl_context_ == NULL) {
822 ALOGW("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
823 }
824}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000825
826webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000827 VideoCodecType type) {
828 if (supported_codec_types_.empty()) {
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700829 ALOGE("No HW video decoder for type %d.", (int)type);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000830 return NULL;
831 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700832 for (VideoCodecType codec_type : supported_codec_types_) {
833 if (codec_type == type) {
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000834 ALOGD("Create HW video decoder for type %d.", (int)type);
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700835 return new MediaCodecVideoDecoder(
836 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000837 }
838 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700839 ALOGE("Can not find HW video decoder for type %d.", (int)type);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000840 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000841}
842
843void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
844 webrtc::VideoDecoder* decoder) {
845 delete decoder;
846}
847
848} // namespace webrtc_jni
849