blob: 4f7445ef4317ad8fcd0a7541b92ebea84dfaab8e [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 Jedvertbbda54e2015-09-30 16:06:37 +020040#include "webrtc/common_video/interface/i420_buffer_pool.h"
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000041#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
42#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
43#include "webrtc/system_wrappers/interface/tick_util.h"
44#include "third_party/libyuv/include/libyuv/convert.h"
45#include "third_party/libyuv/include/libyuv/convert_from.h"
46#include "third_party/libyuv/include/libyuv/video_common.h"
47
48using rtc::Bind;
49using rtc::Thread;
50using rtc::ThreadManager;
51using rtc::scoped_ptr;
52
53using webrtc::CodecSpecificInfo;
54using webrtc::DecodedImageCallback;
55using webrtc::EncodedImage;
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070056using webrtc::VideoFrame;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000057using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000058using webrtc::TickTime;
59using webrtc::VideoCodec;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +000060using webrtc::VideoCodecType;
61using webrtc::kVideoCodecH264;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000062using webrtc::kVideoCodecVP8;
63
64namespace webrtc_jni {
65
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000066class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
67 public rtc::MessageHandler {
68 public:
Alex Glaznev4d2f4d12015-09-01 15:04:13 -070069 explicit MediaCodecVideoDecoder(
70 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000071 virtual ~MediaCodecVideoDecoder();
72
glaznev@webrtc.org18c92472015-02-18 18:42:55 +000073 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
74 override;
75
76 int32_t Decode(
77 const EncodedImage& inputImage, bool missingFrames,
78 const RTPFragmentationHeader* fragmentation,
79 const CodecSpecificInfo* codecSpecificInfo = NULL,
80 int64_t renderTimeMs = -1) override;
81
82 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
83 override;
84
85 int32_t Release() override;
86
87 int32_t Reset() override;
88 // rtc::MessageHandler implementation.
89 void OnMessage(rtc::Message* msg) override;
90
91 private:
92 // CHECK-fail if not running on |codec_thread_|.
93 void CheckOnCodecThread();
94
95 int32_t InitDecodeOnCodecThread();
96 int32_t ReleaseOnCodecThread();
97 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
98 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
99 // true on success.
100 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700101 int32_t ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000102
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000103 // Type of video codec.
104 VideoCodecType codecType_;
105
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000106 bool key_frame_required_;
107 bool inited_;
Alex Glaznev782671f2015-06-12 16:40:44 -0700108 bool sw_fallback_required_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000109 bool use_surface_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000110 VideoCodec codec_;
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200111 webrtc::I420BufferPool decoded_frame_pool_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000112 NativeHandleImpl native_handle_;
113 DecodedImageCallback* callback_;
114 int frames_received_; // Number of frames received by decoder.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000115 int frames_decoded_; // Number of frames decoded by decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000116 int64_t start_time_ms_; // Start time for statistics.
117 int current_frames_; // Number of frames in the current statistics interval.
118 int current_bytes_; // Encoded bytes in the current statistics interval.
119 int current_decoding_time_ms_; // Overall decoding time in the current second
120 uint32_t max_pending_frames_; // Maximum number of pending input frames
121 std::vector<int32_t> timestamps_;
122 std::vector<int64_t> ntp_times_ms_;
123 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
124 // decoder input.
125
126 // State that is constant for the lifetime of this object once the ctor
127 // returns.
128 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
129 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
130 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
131 jmethodID j_init_decode_method_;
132 jmethodID j_release_method_;
133 jmethodID j_dequeue_input_buffer_method_;
134 jmethodID j_queue_input_buffer_method_;
135 jmethodID j_dequeue_output_buffer_method_;
136 jmethodID j_release_output_buffer_method_;
137 // MediaCodecVideoDecoder fields.
138 jfieldID j_input_buffers_field_;
139 jfieldID j_output_buffers_field_;
140 jfieldID j_color_format_field_;
141 jfieldID j_width_field_;
142 jfieldID j_height_field_;
143 jfieldID j_stride_field_;
144 jfieldID j_slice_height_field_;
145 jfieldID j_surface_texture_field_;
146 jfieldID j_textureID_field_;
147 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
148 jfieldID j_info_index_field_;
149 jfieldID j_info_offset_field_;
150 jfieldID j_info_size_field_;
151 jfieldID j_info_presentation_timestamp_us_field_;
152
153 // Global references; must be deleted in Release().
154 std::vector<jobject> input_buffers_;
155 jobject surface_texture_;
156 jobject previous_surface_texture_;
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700157
158 // Render EGL context - owned by factory, should not be allocated/destroyed
159 // by VideoDecoder.
160 jobject render_egl_context_;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000161};
162
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000163MediaCodecVideoDecoder::MediaCodecVideoDecoder(
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700164 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000165 codecType_(codecType),
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700166 render_egl_context_(render_egl_context),
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000167 key_frame_required_(true),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000168 inited_(false),
Alex Glaznev782671f2015-06-12 16:40:44 -0700169 sw_fallback_required_(false),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000170 surface_texture_(NULL),
171 previous_surface_texture_(NULL),
172 codec_thread_(new Thread()),
173 j_media_codec_video_decoder_class_(
174 jni,
175 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
176 j_media_codec_video_decoder_(
177 jni,
178 jni->NewObject(*j_media_codec_video_decoder_class_,
179 GetMethodID(jni,
180 *j_media_codec_video_decoder_class_,
181 "<init>",
182 "()V"))) {
183 ScopedLocalRefFrame local_ref_frame(jni);
184 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
henrikg91d6ede2015-09-17 00:24:34 -0700185 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000186
187 j_init_decode_method_ = GetMethodID(
188 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000189 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
Magnus Jedvert207370f2015-09-16 12:32:21 +0200190 "IILandroid/opengl/EGLContext;)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000191 j_release_method_ =
192 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
193 j_dequeue_input_buffer_method_ = GetMethodID(
194 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
195 j_queue_input_buffer_method_ = GetMethodID(
196 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
197 j_dequeue_output_buffer_method_ = GetMethodID(
198 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
199 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
200 j_release_output_buffer_method_ = GetMethodID(
Magnus Jedvert207370f2015-09-16 12:32:21 +0200201 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(I)Z");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000202
203 j_input_buffers_field_ = GetFieldID(
204 jni, *j_media_codec_video_decoder_class_,
205 "inputBuffers", "[Ljava/nio/ByteBuffer;");
206 j_output_buffers_field_ = GetFieldID(
207 jni, *j_media_codec_video_decoder_class_,
208 "outputBuffers", "[Ljava/nio/ByteBuffer;");
209 j_color_format_field_ = GetFieldID(
210 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
211 j_width_field_ = GetFieldID(
212 jni, *j_media_codec_video_decoder_class_, "width", "I");
213 j_height_field_ = GetFieldID(
214 jni, *j_media_codec_video_decoder_class_, "height", "I");
215 j_stride_field_ = GetFieldID(
216 jni, *j_media_codec_video_decoder_class_, "stride", "I");
217 j_slice_height_field_ = GetFieldID(
218 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
219 j_textureID_field_ = GetFieldID(
220 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
221 j_surface_texture_field_ = GetFieldID(
222 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
223 "Landroid/graphics/SurfaceTexture;");
224
225 jclass j_decoder_output_buffer_info_class = FindClass(jni,
226 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
227 j_info_index_field_ = GetFieldID(
228 jni, j_decoder_output_buffer_info_class, "index", "I");
229 j_info_offset_field_ = GetFieldID(
230 jni, j_decoder_output_buffer_info_class, "offset", "I");
231 j_info_size_field_ = GetFieldID(
232 jni, j_decoder_output_buffer_info_class, "size", "I");
233 j_info_presentation_timestamp_us_field_ = GetFieldID(
234 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
235
236 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
Magnus Jedvert207370f2015-09-16 12:32:21 +0200237 use_surface_ = (render_egl_context_ != NULL);
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700238 ALOGD("MediaCodecVideoDecoder ctor. Use surface: %d", use_surface_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000239 memset(&codec_, 0, sizeof(codec_));
240 AllowBlockingCalls();
241}
242
243MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
244 // Call Release() to ensure no more callbacks to us after we are deleted.
245 Release();
246 // Delete global references.
247 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000248 if (previous_surface_texture_ != NULL) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000249 jni->DeleteGlobalRef(previous_surface_texture_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000250 }
251 if (surface_texture_ != NULL) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000252 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000253 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000254}
255
256int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
257 int32_t numberOfCores) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700258 ALOGD("InitDecode.");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000259 if (inst == NULL) {
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000260 ALOGE("NULL VideoCodec instance");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000261 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
262 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000263 // Factory should guard against other codecs being used with us.
henrikg91d6ede2015-09-17 00:24:34 -0700264 RTC_CHECK(inst->codecType == codecType_)
265 << "Unsupported codec " << inst->codecType << " for " << codecType_;
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000266
Alex Glaznev782671f2015-06-12 16:40:44 -0700267 if (sw_fallback_required_) {
268 ALOGE("InitDecode() - fallback to SW decoder");
269 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000270 }
271 // Save VideoCodec instance for later.
272 if (&codec_ != inst) {
273 codec_ = *inst;
274 }
275 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
276
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000277 // Call Java init.
278 return codec_thread_->Invoke<int32_t>(
279 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
280}
281
282int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
283 CheckOnCodecThread();
284 JNIEnv* jni = AttachCurrentThreadIfNeeded();
285 ScopedLocalRefFrame local_ref_frame(jni);
Alex Glaznev782671f2015-06-12 16:40:44 -0700286 ALOGD("InitDecodeOnCodecThread Type: %d. %d x %d. Fps: %d.",
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000287 (int)codecType_, codec_.width, codec_.height,
Alex Glaznev782671f2015-06-12 16:40:44 -0700288 codec_.maxFramerate);
289
290 // Release previous codec first if it was allocated before.
291 int ret_val = ReleaseOnCodecThread();
292 if (ret_val < 0) {
293 ALOGE("Release failure: %d - fallback to SW codec", ret_val);
294 sw_fallback_required_ = true;
295 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000296 }
297
Alex Glaznev782671f2015-06-12 16:40:44 -0700298 // Always start with a complete key frame.
299 key_frame_required_ = true;
300 frames_received_ = 0;
301 frames_decoded_ = 0;
302
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000303 jobject j_video_codec_enum = JavaEnumFromIndex(
304 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000305 bool success = jni->CallBooleanMethod(
306 *j_media_codec_video_decoder_,
307 j_init_decode_method_,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000308 j_video_codec_enum,
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000309 codec_.width,
310 codec_.height,
Magnus Jedvert207370f2015-09-16 12:32:21 +0200311 use_surface_ ? render_egl_context_ : nullptr);
Alex Glaznev782671f2015-06-12 16:40:44 -0700312 if (CheckException(jni) || !success) {
313 ALOGE("Codec initialization error - fallback to SW codec.");
314 sw_fallback_required_ = true;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000315 return WEBRTC_VIDEO_CODEC_ERROR;
316 }
317 inited_ = true;
318
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000319 switch (codecType_) {
320 case kVideoCodecVP8:
321 max_pending_frames_ = kMaxPendingFramesVp8;
322 break;
323 case kVideoCodecH264:
324 max_pending_frames_ = kMaxPendingFramesH264;
325 break;
326 default:
327 max_pending_frames_ = 0;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000328 }
329 start_time_ms_ = GetCurrentTimeMs();
330 current_frames_ = 0;
331 current_bytes_ = 0;
332 current_decoding_time_ms_ = 0;
333 timestamps_.clear();
334 ntp_times_ms_.clear();
335 frame_rtc_times_ms_.clear();
336
337 jobjectArray input_buffers = (jobjectArray)GetObjectField(
338 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
339 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
340 input_buffers_.resize(num_input_buffers);
341 for (size_t i = 0; i < num_input_buffers; ++i) {
342 input_buffers_[i] =
343 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
Alex Glaznev782671f2015-06-12 16:40:44 -0700344 if (CheckException(jni)) {
345 ALOGE("NewGlobalRef error - fallback to SW codec.");
346 sw_fallback_required_ = true;
347 return WEBRTC_VIDEO_CODEC_ERROR;
348 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000349 }
350
351 if (use_surface_) {
352 jobject surface_texture = GetObjectField(
353 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
354 if (previous_surface_texture_ != NULL) {
355 jni->DeleteGlobalRef(previous_surface_texture_);
356 }
357 previous_surface_texture_ = surface_texture_;
358 surface_texture_ = jni->NewGlobalRef(surface_texture);
359 }
360 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
361
362 return WEBRTC_VIDEO_CODEC_OK;
363}
364
365int32_t MediaCodecVideoDecoder::Release() {
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000366 ALOGD("DecoderRelease request");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000367 return codec_thread_->Invoke<int32_t>(
368 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
369}
370
371int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
372 if (!inited_) {
373 return WEBRTC_VIDEO_CODEC_OK;
374 }
375 CheckOnCodecThread();
376 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000377 ALOGD("DecoderReleaseOnCodecThread: Frames received: %d.", frames_received_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000378 ScopedLocalRefFrame local_ref_frame(jni);
379 for (size_t i = 0; i < input_buffers_.size(); i++) {
380 jni->DeleteGlobalRef(input_buffers_[i]);
381 }
382 input_buffers_.clear();
383 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000384 inited_ = false;
Alex Glaznev782671f2015-06-12 16:40:44 -0700385 rtc::MessageQueueManager::Clear(this);
386 if (CheckException(jni)) {
387 ALOGE("Decoder release exception");
388 return WEBRTC_VIDEO_CODEC_ERROR;
389 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000390 return WEBRTC_VIDEO_CODEC_OK;
391}
392
393void MediaCodecVideoDecoder::CheckOnCodecThread() {
henrikg91d6ede2015-09-17 00:24:34 -0700394 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000395 << "Running on wrong thread!";
396}
397
Alex Glaznev782671f2015-06-12 16:40:44 -0700398int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
399 CheckOnCodecThread();
400 int ret_val = ReleaseOnCodecThread();
401 if (ret_val < 0) {
402 ALOGE("ProcessHWError: Release failure");
403 }
404 if (codecType_ == kVideoCodecH264) {
405 // For now there is no SW H.264 which can be used as fallback codec.
406 // So try to restart hw codec for now.
407 ret_val = InitDecodeOnCodecThread();
408 ALOGE("Reset H.264 codec done. Status: %d", ret_val);
409 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
410 // H.264 codec was succesfully reset - return regular error code.
411 return WEBRTC_VIDEO_CODEC_ERROR;
412 } else {
413 // Fail to restart H.264 codec - return error code which should stop the
414 // call.
415 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
416 }
417 } else {
418 sw_fallback_required_ = true;
419 ALOGE("Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE");
420 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
421 }
422}
423
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000424int32_t MediaCodecVideoDecoder::Decode(
425 const EncodedImage& inputImage,
426 bool missingFrames,
427 const RTPFragmentationHeader* fragmentation,
428 const CodecSpecificInfo* codecSpecificInfo,
429 int64_t renderTimeMs) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700430 if (sw_fallback_required_) {
431 ALOGE("Decode() - fallback to SW codec");
432 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000433 }
434 if (callback_ == NULL) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700435 ALOGE("Decode() - callback_ is NULL");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000436 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
437 }
438 if (inputImage._buffer == NULL && inputImage._length > 0) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700439 ALOGE("Decode() - inputImage is incorrect");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000440 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
441 }
Alex Glaznev782671f2015-06-12 16:40:44 -0700442 if (!inited_) {
443 ALOGE("Decode() - decoder is not initialized");
444 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
445 }
446
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000447 // Check if encoded frame dimension has changed.
448 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
449 (inputImage._encodedWidth != codec_.width ||
450 inputImage._encodedHeight != codec_.height)) {
451 codec_.width = inputImage._encodedWidth;
452 codec_.height = inputImage._encodedHeight;
Alex Glaznev782671f2015-06-12 16:40:44 -0700453 int32_t ret = InitDecode(&codec_, 1);
454 if (ret < 0) {
455 ALOGE("InitDecode failure: %d - fallback to SW codec", ret);
456 sw_fallback_required_ = true;
457 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
458 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000459 }
460
461 // Always start with a complete key frame.
462 if (key_frame_required_) {
463 if (inputImage._frameType != webrtc::kKeyFrame) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700464 ALOGE("Decode() - key frame is required");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000465 return WEBRTC_VIDEO_CODEC_ERROR;
466 }
467 if (!inputImage._completeFrame) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700468 ALOGE("Decode() - complete frame is required");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000469 return WEBRTC_VIDEO_CODEC_ERROR;
470 }
471 key_frame_required_ = false;
472 }
473 if (inputImage._length == 0) {
474 return WEBRTC_VIDEO_CODEC_ERROR;
475 }
476
477 return codec_thread_->Invoke<int32_t>(Bind(
478 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
479}
480
481int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
482 const EncodedImage& inputImage) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000483 CheckOnCodecThread();
484 JNIEnv* jni = AttachCurrentThreadIfNeeded();
485 ScopedLocalRefFrame local_ref_frame(jni);
486
487 // Try to drain the decoder and wait until output is not too
488 // much behind the input.
489 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000490 ALOGV("Received: %d. Decoded: %d. Wait for output...",
491 frames_received_, frames_decoded_);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000492 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700493 ALOGE("DeliverPendingOutputs error");
494 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000495 }
496 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
497 ALOGE("Output buffer dequeue timeout");
Alex Glaznev782671f2015-06-12 16:40:44 -0700498 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000499 }
500 }
501
502 // Get input buffer.
503 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
504 j_dequeue_input_buffer_method_);
Alex Glaznev782671f2015-06-12 16:40:44 -0700505 if (CheckException(jni) || j_input_buffer_index < 0) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000506 ALOGE("dequeueInputBuffer error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700507 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000508 }
509
510 // Copy encoded data to Java ByteBuffer.
511 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
512 uint8* buffer =
513 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
henrikg91d6ede2015-09-17 00:24:34 -0700514 RTC_CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000515 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
Alex Glaznev782671f2015-06-12 16:40:44 -0700516 if (CheckException(jni) || buffer_capacity < inputImage._length) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000517 ALOGE("Input frame size %d is bigger than buffer size %d.",
518 inputImage._length, buffer_capacity);
Alex Glaznev782671f2015-06-12 16:40:44 -0700519 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000520 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000521 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
522 ALOGV("Decoder frame in # %d. Type: %d. Buffer # %d. TS: %lld. Size: %d",
523 frames_received_, inputImage._frameType, j_input_buffer_index,
524 timestamp_us / 1000, inputImage._length);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000525 memcpy(buffer, inputImage._buffer, inputImage._length);
526
527 // Save input image timestamps for later output.
528 frames_received_++;
529 current_bytes_ += inputImage._length;
530 timestamps_.push_back(inputImage._timeStamp);
531 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
532 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
533
534 // Feed input to decoder.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000535 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
536 j_queue_input_buffer_method_,
537 j_input_buffer_index,
538 inputImage._length,
539 timestamp_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700540 if (CheckException(jni) || !success) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000541 ALOGE("queueInputBuffer error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700542 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000543 }
544
545 // Try to drain the decoder
546 if (!DeliverPendingOutputs(jni, 0)) {
547 ALOGE("DeliverPendingOutputs error");
Alex Glaznev782671f2015-06-12 16:40:44 -0700548 return ProcessHWErrorOnCodecThread();
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000549 }
550
551 return WEBRTC_VIDEO_CODEC_OK;
552}
553
554bool MediaCodecVideoDecoder::DeliverPendingOutputs(
555 JNIEnv* jni, int dequeue_timeout_us) {
556 if (frames_received_ <= frames_decoded_) {
557 // No need to query for output buffers - decoder is drained.
558 return true;
559 }
560 // Get decoder output.
561 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
562 *j_media_codec_video_decoder_,
563 j_dequeue_output_buffer_method_,
564 dequeue_timeout_us);
Alex Glaznev782671f2015-06-12 16:40:44 -0700565 if (CheckException(jni)) {
566 return false;
567 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000568 if (IsNull(jni, j_decoder_output_buffer_info)) {
569 return true;
570 }
571
572 // Extract output buffer info from Java DecoderOutputBufferInfo.
573 int output_buffer_index =
574 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
575 if (output_buffer_index < 0) {
576 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
577 return false;
578 }
579 int output_buffer_offset =
580 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
581 int output_buffer_size =
582 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000583 long output_timestamps_ms = GetLongField(jni, j_decoder_output_buffer_info,
584 j_info_presentation_timestamp_us_field_) / 1000;
Alex Glaznev782671f2015-06-12 16:40:44 -0700585 if (CheckException(jni)) {
586 return false;
587 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000588
589 // Get decoded video frame properties.
590 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
591 j_color_format_field_);
592 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
593 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
594 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
595 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
596 j_slice_height_field_);
597 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
598 j_textureID_field_);
599
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200600 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
601 if (use_surface_) {
602 native_handle_.SetTextureObject(surface_texture_, texture_id);
603 frame_buffer = new rtc::RefCountedObject<JniNativeHandleBuffer>(
604 &native_handle_, width, height);
605 } else {
606 // Extract data from Java ByteBuffer and create output yuv420 frame -
607 // for non surface decoding only.
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000608 if (output_buffer_size < width * height * 3 / 2) {
609 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
610 return false;
611 }
612 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
613 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
614 jobject output_buffer =
615 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
616 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
617 output_buffer));
Alex Glaznev782671f2015-06-12 16:40:44 -0700618 if (CheckException(jni)) {
619 return false;
620 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000621 payload += output_buffer_offset;
622
623 // Create yuv420 frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200624 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000625 if (color_format == COLOR_FormatYUV420Planar) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200626 RTC_CHECK_EQ(0, stride % 2);
627 RTC_CHECK_EQ(0, slice_height % 2);
628 const int uv_stride = stride / 2;
629 const int u_slice_height = slice_height / 2;
630 const uint8_t* y_ptr = payload;
631 const uint8_t* u_ptr = y_ptr + stride * slice_height;
632 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
633 libyuv::I420Copy(y_ptr, stride,
634 u_ptr, uv_stride,
635 v_ptr, uv_stride,
636 frame_buffer->MutableData(webrtc::kYPlane),
637 frame_buffer->stride(webrtc::kYPlane),
638 frame_buffer->MutableData(webrtc::kUPlane),
639 frame_buffer->stride(webrtc::kUPlane),
640 frame_buffer->MutableData(webrtc::kVPlane),
641 frame_buffer->stride(webrtc::kVPlane),
642 width, height);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000643 } else {
644 // All other supported formats are nv12.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200645 const uint8_t* y_ptr = payload;
646 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000647 libyuv::NV12ToI420(
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200648 y_ptr, stride,
649 uv_ptr, stride,
650 frame_buffer->MutableData(webrtc::kYPlane),
651 frame_buffer->stride(webrtc::kYPlane),
652 frame_buffer->MutableData(webrtc::kUPlane),
653 frame_buffer->stride(webrtc::kUPlane),
654 frame_buffer->MutableData(webrtc::kVPlane),
655 frame_buffer->stride(webrtc::kVPlane),
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000656 width, height);
657 }
658 }
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200659 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000660
661 // Get frame timestamps from a queue.
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000662 if (timestamps_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200663 decoded_frame.set_timestamp(timestamps_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000664 timestamps_.erase(timestamps_.begin());
665 }
666 if (ntp_times_ms_.size() > 0) {
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200667 decoded_frame.set_ntp_time_ms(ntp_times_ms_.front());
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000668 ntp_times_ms_.erase(ntp_times_ms_.begin());
669 }
670 int64_t frame_decoding_time_ms = 0;
671 if (frame_rtc_times_ms_.size() > 0) {
672 frame_decoding_time_ms = GetCurrentTimeMs() - frame_rtc_times_ms_.front();
673 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
674 }
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000675 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. TS: %ld."
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000676 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
glaznev@webrtc.orga4623d22015-02-25 00:02:50 +0000677 color_format, output_timestamps_ms, frame_decoding_time_ms);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000678
679 // Return output buffer back to codec.
680 bool success = jni->CallBooleanMethod(
681 *j_media_codec_video_decoder_,
682 j_release_output_buffer_method_,
Magnus Jedvert207370f2015-09-16 12:32:21 +0200683 output_buffer_index);
Alex Glaznev782671f2015-06-12 16:40:44 -0700684 if (CheckException(jni) || !success) {
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000685 ALOGE("releaseOutputBuffer error");
686 return false;
687 }
688
689 // Calculate and print decoding statistics - every 3 seconds.
690 frames_decoded_++;
691 current_frames_++;
692 current_decoding_time_ms_ += frame_decoding_time_ms;
693 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
694 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
695 current_frames_ > 0) {
696 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
697 current_bytes_ * 8 / statistic_time_ms,
698 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
699 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
700 start_time_ms_ = GetCurrentTimeMs();
701 current_frames_ = 0;
702 current_bytes_ = 0;
703 current_decoding_time_ms_ = 0;
704 }
705
706 // Callback - output decoded frame.
Magnus Jedvertbbda54e2015-09-30 16:06:37 +0200707 const int32_t callback_status = callback_->Decoded(decoded_frame);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000708 if (callback_status > 0) {
709 ALOGE("callback error");
710 }
711
712 return true;
713}
714
715int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
716 DecodedImageCallback* callback) {
717 callback_ = callback;
718 return WEBRTC_VIDEO_CODEC_OK;
719}
720
721int32_t MediaCodecVideoDecoder::Reset() {
722 ALOGD("DecoderReset");
723 if (!inited_) {
724 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
725 }
726 return InitDecode(&codec_, 1);
727}
728
729void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
730 JNIEnv* jni = AttachCurrentThreadIfNeeded();
731 ScopedLocalRefFrame local_ref_frame(jni);
732 if (!inited_) {
733 return;
734 }
735 // We only ever send one message to |this| directly (not through a Bind()'d
736 // functor), so expect no ID/data.
henrikg91d6ede2015-09-17 00:24:34 -0700737 RTC_CHECK(!msg->message_id) << "Unexpected message!";
738 RTC_CHECK(!msg->pdata) << "Unexpected message!";
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000739 CheckOnCodecThread();
740
741 if (!DeliverPendingOutputs(jni, 0)) {
Alex Glaznev782671f2015-06-12 16:40:44 -0700742 ALOGE("OnMessage: DeliverPendingOutputs error");
743 ProcessHWErrorOnCodecThread();
744 return;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000745 }
746 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
747}
748
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700749MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() :
750 render_egl_context_(NULL) {
751 ALOGD("MediaCodecVideoDecoderFactory ctor");
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000752 JNIEnv* jni = AttachCurrentThreadIfNeeded();
753 ScopedLocalRefFrame local_ref_frame(jni);
754 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000755 supported_codec_types_.clear();
756
757 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000758 j_decoder_class,
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000759 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700760 if (CheckException(jni)) {
761 is_vp8_hw_supported = false;
762 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000763 if (is_vp8_hw_supported) {
764 ALOGD("VP8 HW Decoder supported.");
765 supported_codec_types_.push_back(kVideoCodecVP8);
766 }
767
768 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
769 j_decoder_class,
770 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
Alex Glaznev782671f2015-06-12 16:40:44 -0700771 if (CheckException(jni)) {
772 is_h264_hw_supported = false;
773 }
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000774 if (is_h264_hw_supported) {
775 ALOGD("H264 HW Decoder supported.");
776 supported_codec_types_.push_back(kVideoCodecH264);
777 }
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000778}
779
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700780MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
781 ALOGD("MediaCodecVideoDecoderFactory dtor");
782 if (render_egl_context_) {
783 JNIEnv* jni = AttachCurrentThreadIfNeeded();
784 jni->DeleteGlobalRef(render_egl_context_);
785 render_egl_context_ = NULL;
786 }
787}
788
789void MediaCodecVideoDecoderFactory::SetEGLContext(
790 JNIEnv* jni, jobject render_egl_context) {
791 ALOGD("MediaCodecVideoDecoderFactory::SetEGLContext");
792 if (render_egl_context_) {
793 jni->DeleteGlobalRef(render_egl_context_);
794 render_egl_context_ = NULL;
795 }
796 if (!IsNull(jni, render_egl_context)) {
797 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
798 if (CheckException(jni)) {
799 ALOGE("error calling NewGlobalRef for EGL Context.");
800 render_egl_context_ = NULL;
801 } else {
802 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
803 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
804 ALOGE("Wrong EGL Context.");
805 jni->DeleteGlobalRef(render_egl_context_);
806 render_egl_context_ = NULL;
807 }
808 }
809 }
810 if (render_egl_context_ == NULL) {
811 ALOGW("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
812 }
813}
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000814
815webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000816 VideoCodecType type) {
817 if (supported_codec_types_.empty()) {
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700818 ALOGE("No HW video decoder for type %d.", (int)type);
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000819 return NULL;
820 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700821 for (VideoCodecType codec_type : supported_codec_types_) {
822 if (codec_type == type) {
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000823 ALOGD("Create HW video decoder for type %d.", (int)type);
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700824 return new MediaCodecVideoDecoder(
825 AttachCurrentThreadIfNeeded(), type, render_egl_context_);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000826 }
827 }
Alex Glaznev4d2f4d12015-09-01 15:04:13 -0700828 ALOGE("Can not find HW video decoder for type %d.", (int)type);
glaznev@webrtc.orgb28474c2015-02-23 17:44:27 +0000829 return NULL;
glaznev@webrtc.org18c92472015-02-18 18:42:55 +0000830}
831
832void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
833 webrtc::VideoDecoder* decoder) {
834 delete decoder;
835}
836
837} // namespace webrtc_jni
838