Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Side by Side Diff: talk/app/webrtc/java/jni/androidmediadecoder_jni.cc

Issue 1610243002: Move talk/app/webrtc to webrtc/api (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Removed processing of api.gyp for Chromium builds Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
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 <algorithm>
30 #include <vector>
31
32 #include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
33 // NOTICE: androidmediadecoder_jni.h must be included before
34 // androidmediacodeccommon.h to avoid build errors.
35 #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h"
36 #include "talk/app/webrtc/java/jni/classreferenceholder.h"
37 #include "talk/app/webrtc/java/jni/native_handle_impl.h"
38 #include "talk/app/webrtc/java/jni/surfacetexturehelper_jni.h"
39 #include "third_party/libyuv/include/libyuv/convert.h"
40 #include "third_party/libyuv/include/libyuv/convert_from.h"
41 #include "third_party/libyuv/include/libyuv/video_common.h"
42 #include "webrtc/base/bind.h"
43 #include "webrtc/base/checks.h"
44 #include "webrtc/base/logging.h"
45 #include "webrtc/base/scoped_ref_ptr.h"
46 #include "webrtc/base/thread.h"
47 #include "webrtc/base/timeutils.h"
48 #include "webrtc/common_video/include/i420_buffer_pool.h"
49 #include "webrtc/modules/video_coding/include/video_codec_interface.h"
50 #include "webrtc/system_wrappers/include/logcat_trace_context.h"
51 #include "webrtc/system_wrappers/include/tick_util.h"
52
53 using rtc::Bind;
54 using rtc::Thread;
55 using rtc::ThreadManager;
56 using rtc::scoped_ptr;
57
58 using webrtc::CodecSpecificInfo;
59 using webrtc::DecodedImageCallback;
60 using webrtc::EncodedImage;
61 using webrtc::VideoFrame;
62 using webrtc::RTPFragmentationHeader;
63 using webrtc::TickTime;
64 using webrtc::VideoCodec;
65 using webrtc::VideoCodecType;
66 using webrtc::kVideoCodecH264;
67 using webrtc::kVideoCodecVP8;
68 using webrtc::kVideoCodecVP9;
69
70 namespace webrtc_jni {
71
72 // Logging macros.
73 #define TAG_DECODER "MediaCodecVideoDecoder"
74 #ifdef TRACK_BUFFER_TIMING
75 #define ALOGV(...)
76 __android_log_print(ANDROID_LOG_VERBOSE, TAG_DECODER, __VA_ARGS__)
77 #else
78 #define ALOGV(...)
79 #endif
80 #define ALOGD LOG_TAG(rtc::LS_INFO, TAG_DECODER)
81 #define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_DECODER)
82 #define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_DECODER)
83
84 enum { kMaxWarningLogFrames = 2 };
85
86 class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
87 public rtc::MessageHandler {
88 public:
89 explicit MediaCodecVideoDecoder(
90 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context);
91 virtual ~MediaCodecVideoDecoder();
92
93 int32_t InitDecode(const VideoCodec* codecSettings, int32_t numberOfCores)
94 override;
95
96 int32_t Decode(
97 const EncodedImage& inputImage, bool missingFrames,
98 const RTPFragmentationHeader* fragmentation,
99 const CodecSpecificInfo* codecSpecificInfo = NULL,
100 int64_t renderTimeMs = -1) override;
101
102 int32_t RegisterDecodeCompleteCallback(DecodedImageCallback* callback)
103 override;
104
105 int32_t Release() override;
106
107 bool PrefersLateDecoding() const override { return true; }
108
109 // rtc::MessageHandler implementation.
110 void OnMessage(rtc::Message* msg) override;
111
112 const char* ImplementationName() const override;
113
114 private:
115 // CHECK-fail if not running on |codec_thread_|.
116 void CheckOnCodecThread();
117
118 int32_t InitDecodeOnCodecThread();
119 int32_t ReleaseOnCodecThread();
120 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
121 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
122 // true on success.
123 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
124 int32_t ProcessHWErrorOnCodecThread();
125 void EnableFrameLogOnWarning();
126
127 // Type of video codec.
128 VideoCodecType codecType_;
129
130 // Render EGL context - owned by factory, should not be allocated/destroyed
131 // by VideoDecoder.
132 jobject render_egl_context_;
133
134 bool key_frame_required_;
135 bool inited_;
136 bool sw_fallback_required_;
137 bool use_surface_;
138 VideoCodec codec_;
139 webrtc::I420BufferPool decoded_frame_pool_;
140 rtc::scoped_refptr<SurfaceTextureHelper> surface_texture_helper_;
141 DecodedImageCallback* callback_;
142 int frames_received_; // Number of frames received by decoder.
143 int frames_decoded_; // Number of frames decoded by decoder.
144 // Number of decoded frames for which log information is displayed.
145 int frames_decoded_logged_;
146 int64_t start_time_ms_; // Start time for statistics.
147 int current_frames_; // Number of frames in the current statistics interval.
148 int current_bytes_; // Encoded bytes in the current statistics interval.
149 int current_decoding_time_ms_; // Overall decoding time in the current second
150 int current_delay_time_ms_; // Overall delay time in the current second.
151 uint32_t max_pending_frames_; // Maximum number of pending input frames.
152
153 // State that is constant for the lifetime of this object once the ctor
154 // returns.
155 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
156 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
157 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
158 jmethodID j_init_decode_method_;
159 jmethodID j_release_method_;
160 jmethodID j_dequeue_input_buffer_method_;
161 jmethodID j_queue_input_buffer_method_;
162 jmethodID j_dequeue_byte_buffer_method_;
163 jmethodID j_dequeue_texture_buffer_method_;
164 jmethodID j_return_decoded_byte_buffer_method_;
165 // MediaCodecVideoDecoder fields.
166 jfieldID j_input_buffers_field_;
167 jfieldID j_output_buffers_field_;
168 jfieldID j_color_format_field_;
169 jfieldID j_width_field_;
170 jfieldID j_height_field_;
171 jfieldID j_stride_field_;
172 jfieldID j_slice_height_field_;
173 // MediaCodecVideoDecoder.DecodedTextureBuffer fields.
174 jfieldID j_texture_id_field_;
175 jfieldID j_transform_matrix_field_;
176 jfieldID j_texture_presentation_timestamp_ms_field_;
177 jfieldID j_texture_timestamp_ms_field_;
178 jfieldID j_texture_ntp_timestamp_ms_field_;
179 jfieldID j_texture_decode_time_ms_field_;
180 jfieldID j_texture_frame_delay_ms_field_;
181 // MediaCodecVideoDecoder.DecodedOutputBuffer fields.
182 jfieldID j_info_index_field_;
183 jfieldID j_info_offset_field_;
184 jfieldID j_info_size_field_;
185 jfieldID j_presentation_timestamp_ms_field_;
186 jfieldID j_timestamp_ms_field_;
187 jfieldID j_ntp_timestamp_ms_field_;
188 jfieldID j_byte_buffer_decode_time_ms_field_;
189
190 // Global references; must be deleted in Release().
191 std::vector<jobject> input_buffers_;
192 };
193
194 MediaCodecVideoDecoder::MediaCodecVideoDecoder(
195 JNIEnv* jni, VideoCodecType codecType, jobject render_egl_context) :
196 codecType_(codecType),
197 render_egl_context_(render_egl_context),
198 key_frame_required_(true),
199 inited_(false),
200 sw_fallback_required_(false),
201 codec_thread_(new Thread()),
202 j_media_codec_video_decoder_class_(
203 jni,
204 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
205 j_media_codec_video_decoder_(
206 jni,
207 jni->NewObject(*j_media_codec_video_decoder_class_,
208 GetMethodID(jni,
209 *j_media_codec_video_decoder_class_,
210 "<init>",
211 "()V"))) {
212 ScopedLocalRefFrame local_ref_frame(jni);
213 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
214 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
215
216 j_init_decode_method_ = GetMethodID(
217 jni, *j_media_codec_video_decoder_class_, "initDecode",
218 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;"
219 "IILorg/webrtc/SurfaceTextureHelper;)Z");
220 j_release_method_ =
221 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
222 j_dequeue_input_buffer_method_ = GetMethodID(
223 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
224 j_queue_input_buffer_method_ = GetMethodID(
225 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z");
226 j_dequeue_byte_buffer_method_ = GetMethodID(
227 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
228 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;");
229 j_dequeue_texture_buffer_method_ = GetMethodID(
230 jni, *j_media_codec_video_decoder_class_, "dequeueTextureBuffer",
231 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer;");
232 j_return_decoded_byte_buffer_method_ =
233 GetMethodID(jni, *j_media_codec_video_decoder_class_,
234 "returnDecodedOutputBuffer", "(I)V");
235
236 j_input_buffers_field_ = GetFieldID(
237 jni, *j_media_codec_video_decoder_class_,
238 "inputBuffers", "[Ljava/nio/ByteBuffer;");
239 j_output_buffers_field_ = GetFieldID(
240 jni, *j_media_codec_video_decoder_class_,
241 "outputBuffers", "[Ljava/nio/ByteBuffer;");
242 j_color_format_field_ = GetFieldID(
243 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
244 j_width_field_ = GetFieldID(
245 jni, *j_media_codec_video_decoder_class_, "width", "I");
246 j_height_field_ = GetFieldID(
247 jni, *j_media_codec_video_decoder_class_, "height", "I");
248 j_stride_field_ = GetFieldID(
249 jni, *j_media_codec_video_decoder_class_, "stride", "I");
250 j_slice_height_field_ = GetFieldID(
251 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
252
253 jclass j_decoded_texture_buffer_class = FindClass(jni,
254 "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
255 j_texture_id_field_ = GetFieldID(
256 jni, j_decoded_texture_buffer_class, "textureID", "I");
257 j_transform_matrix_field_ = GetFieldID(
258 jni, j_decoded_texture_buffer_class, "transformMatrix", "[F");
259 j_texture_presentation_timestamp_ms_field_ = GetFieldID(
260 jni, j_decoded_texture_buffer_class, "presentationTimeStampMs", "J");
261 j_texture_timestamp_ms_field_ = GetFieldID(
262 jni, j_decoded_texture_buffer_class, "timeStampMs", "J");
263 j_texture_ntp_timestamp_ms_field_ = GetFieldID(
264 jni, j_decoded_texture_buffer_class, "ntpTimeStampMs", "J");
265 j_texture_decode_time_ms_field_ = GetFieldID(
266 jni, j_decoded_texture_buffer_class, "decodeTimeMs", "J");
267 j_texture_frame_delay_ms_field_ = GetFieldID(
268 jni, j_decoded_texture_buffer_class, "frameDelayMs", "J");
269
270 jclass j_decoded_output_buffer_class = FindClass(jni,
271 "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
272 j_info_index_field_ = GetFieldID(
273 jni, j_decoded_output_buffer_class, "index", "I");
274 j_info_offset_field_ = GetFieldID(
275 jni, j_decoded_output_buffer_class, "offset", "I");
276 j_info_size_field_ = GetFieldID(
277 jni, j_decoded_output_buffer_class, "size", "I");
278 j_presentation_timestamp_ms_field_ = GetFieldID(
279 jni, j_decoded_output_buffer_class, "presentationTimeStampMs", "J");
280 j_timestamp_ms_field_ = GetFieldID(
281 jni, j_decoded_output_buffer_class, "timeStampMs", "J");
282 j_ntp_timestamp_ms_field_ = GetFieldID(
283 jni, j_decoded_output_buffer_class, "ntpTimeStampMs", "J");
284 j_byte_buffer_decode_time_ms_field_ = GetFieldID(
285 jni, j_decoded_output_buffer_class, "decodeTimeMs", "J");
286
287 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
288 use_surface_ = (render_egl_context_ != NULL);
289 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_;
290 memset(&codec_, 0, sizeof(codec_));
291 AllowBlockingCalls();
292 }
293
294 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
295 // Call Release() to ensure no more callbacks to us after we are deleted.
296 Release();
297 }
298
299 int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
300 int32_t numberOfCores) {
301 ALOGD << "InitDecode.";
302 if (inst == NULL) {
303 ALOGE << "NULL VideoCodec instance";
304 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
305 }
306 // Factory should guard against other codecs being used with us.
307 RTC_CHECK(inst->codecType == codecType_)
308 << "Unsupported codec " << inst->codecType << " for " << codecType_;
309
310 if (sw_fallback_required_) {
311 ALOGE << "InitDecode() - fallback to SW decoder";
312 return WEBRTC_VIDEO_CODEC_OK;
313 }
314 // Save VideoCodec instance for later.
315 if (&codec_ != inst) {
316 codec_ = *inst;
317 }
318 // If maxFramerate is not set then assume 30 fps.
319 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30;
320
321 // Call Java init.
322 return codec_thread_->Invoke<int32_t>(
323 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
324 }
325
326 int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
327 CheckOnCodecThread();
328 JNIEnv* jni = AttachCurrentThreadIfNeeded();
329 ScopedLocalRefFrame local_ref_frame(jni);
330 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". "
331 << codec_.width << " x " << codec_.height << ". Fps: " <<
332 (int)codec_.maxFramerate;
333
334 // Release previous codec first if it was allocated before.
335 int ret_val = ReleaseOnCodecThread();
336 if (ret_val < 0) {
337 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec";
338 sw_fallback_required_ = true;
339 return WEBRTC_VIDEO_CODEC_ERROR;
340 }
341
342 // Always start with a complete key frame.
343 key_frame_required_ = true;
344 frames_received_ = 0;
345 frames_decoded_ = 0;
346 frames_decoded_logged_ = kMaxDecodedLogFrames;
347
348 jobject java_surface_texture_helper_ = nullptr;
349 if (use_surface_) {
350 java_surface_texture_helper_ = jni->CallStaticObjectMethod(
351 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
352 GetStaticMethodID(jni,
353 FindClass(jni, "org/webrtc/SurfaceTextureHelper"),
354 "create",
355 "(Lorg/webrtc/EglBase$Context;)"
356 "Lorg/webrtc/SurfaceTextureHelper;"),
357 render_egl_context_);
358 RTC_CHECK(java_surface_texture_helper_ != nullptr);
359 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>(
360 jni, java_surface_texture_helper_);
361 }
362
363 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName(
364 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_);
365 bool success = jni->CallBooleanMethod(
366 *j_media_codec_video_decoder_,
367 j_init_decode_method_,
368 j_video_codec_enum,
369 codec_.width,
370 codec_.height,
371 java_surface_texture_helper_);
372 if (CheckException(jni) || !success) {
373 ALOGE << "Codec initialization error - fallback to SW codec.";
374 sw_fallback_required_ = true;
375 return WEBRTC_VIDEO_CODEC_ERROR;
376 }
377 inited_ = true;
378
379 switch (codecType_) {
380 case kVideoCodecVP8:
381 max_pending_frames_ = kMaxPendingFramesVp8;
382 break;
383 case kVideoCodecVP9:
384 max_pending_frames_ = kMaxPendingFramesVp9;
385 break;
386 case kVideoCodecH264:
387 max_pending_frames_ = kMaxPendingFramesH264;
388 break;
389 default:
390 max_pending_frames_ = 0;
391 }
392 start_time_ms_ = GetCurrentTimeMs();
393 current_frames_ = 0;
394 current_bytes_ = 0;
395 current_decoding_time_ms_ = 0;
396 current_delay_time_ms_ = 0;
397
398 jobjectArray input_buffers = (jobjectArray)GetObjectField(
399 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
400 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
401 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_;
402 input_buffers_.resize(num_input_buffers);
403 for (size_t i = 0; i < num_input_buffers; ++i) {
404 input_buffers_[i] =
405 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
406 if (CheckException(jni)) {
407 ALOGE << "NewGlobalRef error - fallback to SW codec.";
408 sw_fallback_required_ = true;
409 return WEBRTC_VIDEO_CODEC_ERROR;
410 }
411 }
412
413 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
414
415 return WEBRTC_VIDEO_CODEC_OK;
416 }
417
418 int32_t MediaCodecVideoDecoder::Release() {
419 ALOGD << "DecoderRelease request";
420 return codec_thread_->Invoke<int32_t>(
421 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
422 }
423
424 int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
425 if (!inited_) {
426 return WEBRTC_VIDEO_CODEC_OK;
427 }
428 CheckOnCodecThread();
429 JNIEnv* jni = AttachCurrentThreadIfNeeded();
430 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " <<
431 frames_received_ << ". Frames decoded: " << frames_decoded_;
432 ScopedLocalRefFrame local_ref_frame(jni);
433 for (size_t i = 0; i < input_buffers_.size(); i++) {
434 jni->DeleteGlobalRef(input_buffers_[i]);
435 }
436 input_buffers_.clear();
437 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
438 surface_texture_helper_ = nullptr;
439 inited_ = false;
440 rtc::MessageQueueManager::Clear(this);
441 if (CheckException(jni)) {
442 ALOGE << "Decoder release exception";
443 return WEBRTC_VIDEO_CODEC_ERROR;
444 }
445 ALOGD << "DecoderReleaseOnCodecThread done";
446 return WEBRTC_VIDEO_CODEC_OK;
447 }
448
449 void MediaCodecVideoDecoder::CheckOnCodecThread() {
450 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
451 << "Running on wrong thread!";
452 }
453
454 void MediaCodecVideoDecoder::EnableFrameLogOnWarning() {
455 // Log next 2 output frames.
456 frames_decoded_logged_ = std::max(
457 frames_decoded_logged_, frames_decoded_ + kMaxWarningLogFrames);
458 }
459
460 int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() {
461 CheckOnCodecThread();
462 int ret_val = ReleaseOnCodecThread();
463 if (ret_val < 0) {
464 ALOGE << "ProcessHWError: Release failure";
465 }
466 if (codecType_ == kVideoCodecH264) {
467 // For now there is no SW H.264 which can be used as fallback codec.
468 // So try to restart hw codec for now.
469 ret_val = InitDecodeOnCodecThread();
470 ALOGE << "Reset H.264 codec done. Status: " << ret_val;
471 if (ret_val == WEBRTC_VIDEO_CODEC_OK) {
472 // H.264 codec was succesfully reset - return regular error code.
473 return WEBRTC_VIDEO_CODEC_ERROR;
474 } else {
475 // Fail to restart H.264 codec - return error code which should stop the
476 // call.
477 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
478 }
479 } else {
480 sw_fallback_required_ = true;
481 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE";
482 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
483 }
484 }
485
486 int32_t MediaCodecVideoDecoder::Decode(
487 const EncodedImage& inputImage,
488 bool missingFrames,
489 const RTPFragmentationHeader* fragmentation,
490 const CodecSpecificInfo* codecSpecificInfo,
491 int64_t renderTimeMs) {
492 if (sw_fallback_required_) {
493 ALOGE << "Decode() - fallback to SW codec";
494 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
495 }
496 if (callback_ == NULL) {
497 ALOGE << "Decode() - callback_ is NULL";
498 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
499 }
500 if (inputImage._buffer == NULL && inputImage._length > 0) {
501 ALOGE << "Decode() - inputImage is incorrect";
502 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
503 }
504 if (!inited_) {
505 ALOGE << "Decode() - decoder is not initialized";
506 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
507 }
508
509 // Check if encoded frame dimension has changed.
510 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
511 (inputImage._encodedWidth != codec_.width ||
512 inputImage._encodedHeight != codec_.height)) {
513 codec_.width = inputImage._encodedWidth;
514 codec_.height = inputImage._encodedHeight;
515 int32_t ret = InitDecode(&codec_, 1);
516 if (ret < 0) {
517 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec";
518 sw_fallback_required_ = true;
519 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
520 }
521 }
522
523 // Always start with a complete key frame.
524 if (key_frame_required_) {
525 if (inputImage._frameType != webrtc::kVideoFrameKey) {
526 ALOGE << "Decode() - key frame is required";
527 return WEBRTC_VIDEO_CODEC_ERROR;
528 }
529 if (!inputImage._completeFrame) {
530 ALOGE << "Decode() - complete frame is required";
531 return WEBRTC_VIDEO_CODEC_ERROR;
532 }
533 key_frame_required_ = false;
534 }
535 if (inputImage._length == 0) {
536 return WEBRTC_VIDEO_CODEC_ERROR;
537 }
538
539 return codec_thread_->Invoke<int32_t>(Bind(
540 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
541 }
542
543 int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
544 const EncodedImage& inputImage) {
545 CheckOnCodecThread();
546 JNIEnv* jni = AttachCurrentThreadIfNeeded();
547 ScopedLocalRefFrame local_ref_frame(jni);
548
549 // Try to drain the decoder and wait until output is not too
550 // much behind the input.
551 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
552 ALOGW << "Decoder is too far behind. Try to drain. Received: " <<
553 frames_received_ << ". Decoded: " << frames_decoded_;
554 EnableFrameLogOnWarning();
555 }
556 const int64 drain_start = GetCurrentTimeMs();
557 while ((frames_received_ > frames_decoded_ + max_pending_frames_) &&
558 (GetCurrentTimeMs() - drain_start) < kMediaCodecTimeoutMs) {
559 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
560 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
561 frames_received_ << ". Frames decoded: " << frames_decoded_;
562 return ProcessHWErrorOnCodecThread();
563 }
564 }
565 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
566 ALOGE << "Output buffer dequeue timeout. Frames received: " <<
567 frames_received_ << ". Frames decoded: " << frames_decoded_;
568 return ProcessHWErrorOnCodecThread();
569 }
570
571 // Get input buffer.
572 int j_input_buffer_index = jni->CallIntMethod(
573 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
574 if (CheckException(jni) || j_input_buffer_index < 0) {
575 ALOGE << "dequeueInputBuffer error: " << j_input_buffer_index <<
576 ". Retry DeliverPendingOutputs.";
577 EnableFrameLogOnWarning();
578 // Try to drain the decoder.
579 if (!DeliverPendingOutputs(jni, kMediaCodecPollMs)) {
580 ALOGE << "DeliverPendingOutputs error. Frames received: " <<
581 frames_received_ << ". Frames decoded: " << frames_decoded_;
582 return ProcessHWErrorOnCodecThread();
583 }
584 // Try dequeue input buffer one last time.
585 j_input_buffer_index = jni->CallIntMethod(
586 *j_media_codec_video_decoder_, j_dequeue_input_buffer_method_);
587 if (CheckException(jni) || j_input_buffer_index < 0) {
588 ALOGE << "dequeueInputBuffer critical error: " << j_input_buffer_index;
589 return ProcessHWErrorOnCodecThread();
590 }
591 }
592
593 // Copy encoded data to Java ByteBuffer.
594 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
595 uint8_t* buffer =
596 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer));
597 RTC_CHECK(buffer) << "Indirect buffer??";
598 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
599 if (CheckException(jni) || buffer_capacity < inputImage._length) {
600 ALOGE << "Input frame size "<< inputImage._length <<
601 " is bigger than buffer size " << buffer_capacity;
602 return ProcessHWErrorOnCodecThread();
603 }
604 jlong presentation_timestamp_us = static_cast<jlong>(
605 static_cast<int64_t>(frames_received_) * 1000000 / codec_.maxFramerate);
606 memcpy(buffer, inputImage._buffer, inputImage._length);
607
608 if (frames_decoded_ < frames_decoded_logged_) {
609 ALOGD << "Decoder frame in # " << frames_received_ <<
610 ". Type: " << inputImage._frameType <<
611 ". Buffer # " << j_input_buffer_index <<
612 ". TS: " << presentation_timestamp_us / 1000 <<
613 ". Size: " << inputImage._length;
614 }
615
616 // Save input image timestamps for later output.
617 frames_received_++;
618 current_bytes_ += inputImage._length;
619
620 // Feed input to decoder.
621 bool success = jni->CallBooleanMethod(
622 *j_media_codec_video_decoder_,
623 j_queue_input_buffer_method_,
624 j_input_buffer_index,
625 inputImage._length,
626 presentation_timestamp_us,
627 static_cast<int64_t> (inputImage._timeStamp),
628 inputImage.ntp_time_ms_);
629 if (CheckException(jni) || !success) {
630 ALOGE << "queueInputBuffer error";
631 return ProcessHWErrorOnCodecThread();
632 }
633
634 // Try to drain the decoder
635 if (!DeliverPendingOutputs(jni, 0)) {
636 ALOGE << "DeliverPendingOutputs error";
637 return ProcessHWErrorOnCodecThread();
638 }
639
640 return WEBRTC_VIDEO_CODEC_OK;
641 }
642
643 bool MediaCodecVideoDecoder::DeliverPendingOutputs(
644 JNIEnv* jni, int dequeue_timeout_ms) {
645 if (frames_received_ <= frames_decoded_) {
646 // No need to query for output buffers - decoder is drained.
647 return true;
648 }
649 // Get decoder output.
650 jobject j_decoder_output_buffer =
651 jni->CallObjectMethod(*j_media_codec_video_decoder_,
652 use_surface_ ? j_dequeue_texture_buffer_method_
653 : j_dequeue_byte_buffer_method_,
654 dequeue_timeout_ms);
655
656 if (CheckException(jni)) {
657 ALOGE << "dequeueOutputBuffer() error";
658 return false;
659 }
660 if (IsNull(jni, j_decoder_output_buffer)) {
661 // No decoded frame ready.
662 return true;
663 }
664
665 // Get decoded video frame properties.
666 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
667 j_color_format_field_);
668 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
669 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
670 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
671 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
672 j_slice_height_field_);
673
674 rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer;
675 int64_t presentation_timestamps_ms = 0;
676 int64_t output_timestamps_ms = 0;
677 int64_t output_ntp_timestamps_ms = 0;
678 int decode_time_ms = 0;
679 int64_t frame_delayed_ms = 0;
680 if (use_surface_) {
681 // Extract data from Java DecodedTextureBuffer.
682 presentation_timestamps_ms = GetLongField(
683 jni, j_decoder_output_buffer,
684 j_texture_presentation_timestamp_ms_field_);
685 output_timestamps_ms = GetLongField(
686 jni, j_decoder_output_buffer, j_texture_timestamp_ms_field_);
687 output_ntp_timestamps_ms = GetLongField(
688 jni, j_decoder_output_buffer, j_texture_ntp_timestamp_ms_field_);
689 decode_time_ms = GetLongField(
690 jni, j_decoder_output_buffer, j_texture_decode_time_ms_field_);
691
692 const int texture_id =
693 GetIntField(jni, j_decoder_output_buffer, j_texture_id_field_);
694 if (texture_id != 0) { // |texture_id| == 0 represents a dropped frame.
695 const jfloatArray j_transform_matrix =
696 reinterpret_cast<jfloatArray>(GetObjectField(
697 jni, j_decoder_output_buffer, j_transform_matrix_field_));
698 frame_delayed_ms = GetLongField(
699 jni, j_decoder_output_buffer, j_texture_frame_delay_ms_field_);
700
701 // Create webrtc::VideoFrameBuffer with native texture handle.
702 frame_buffer = surface_texture_helper_->CreateTextureFrame(
703 width, height, NativeHandleImpl(jni, texture_id, j_transform_matrix));
704 } else {
705 EnableFrameLogOnWarning();
706 }
707 } else {
708 // Extract data from Java ByteBuffer and create output yuv420 frame -
709 // for non surface decoding only.
710 const int output_buffer_index = GetIntField(
711 jni, j_decoder_output_buffer, j_info_index_field_);
712 const int output_buffer_offset = GetIntField(
713 jni, j_decoder_output_buffer, j_info_offset_field_);
714 const int output_buffer_size = GetIntField(
715 jni, j_decoder_output_buffer, j_info_size_field_);
716 presentation_timestamps_ms = GetLongField(
717 jni, j_decoder_output_buffer, j_presentation_timestamp_ms_field_);
718 output_timestamps_ms = GetLongField(
719 jni, j_decoder_output_buffer, j_timestamp_ms_field_);
720 output_ntp_timestamps_ms = GetLongField(
721 jni, j_decoder_output_buffer, j_ntp_timestamp_ms_field_);
722
723 decode_time_ms = GetLongField(jni, j_decoder_output_buffer,
724 j_byte_buffer_decode_time_ms_field_);
725
726 if (output_buffer_size < width * height * 3 / 2) {
727 ALOGE << "Insufficient output buffer size: " << output_buffer_size;
728 return false;
729 }
730 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
731 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
732 jobject output_buffer =
733 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
734 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
735 output_buffer));
736 if (CheckException(jni)) {
737 return false;
738 }
739 payload += output_buffer_offset;
740
741 // Create yuv420 frame.
742 frame_buffer = decoded_frame_pool_.CreateBuffer(width, height);
743 if (color_format == COLOR_FormatYUV420Planar) {
744 RTC_CHECK_EQ(0, stride % 2);
745 RTC_CHECK_EQ(0, slice_height % 2);
746 const int uv_stride = stride / 2;
747 const int u_slice_height = slice_height / 2;
748 const uint8_t* y_ptr = payload;
749 const uint8_t* u_ptr = y_ptr + stride * slice_height;
750 const uint8_t* v_ptr = u_ptr + uv_stride * u_slice_height;
751 libyuv::I420Copy(y_ptr, stride,
752 u_ptr, uv_stride,
753 v_ptr, uv_stride,
754 frame_buffer->MutableData(webrtc::kYPlane),
755 frame_buffer->stride(webrtc::kYPlane),
756 frame_buffer->MutableData(webrtc::kUPlane),
757 frame_buffer->stride(webrtc::kUPlane),
758 frame_buffer->MutableData(webrtc::kVPlane),
759 frame_buffer->stride(webrtc::kVPlane),
760 width, height);
761 } else {
762 // All other supported formats are nv12.
763 const uint8_t* y_ptr = payload;
764 const uint8_t* uv_ptr = y_ptr + stride * slice_height;
765 libyuv::NV12ToI420(
766 y_ptr, stride,
767 uv_ptr, stride,
768 frame_buffer->MutableData(webrtc::kYPlane),
769 frame_buffer->stride(webrtc::kYPlane),
770 frame_buffer->MutableData(webrtc::kUPlane),
771 frame_buffer->stride(webrtc::kUPlane),
772 frame_buffer->MutableData(webrtc::kVPlane),
773 frame_buffer->stride(webrtc::kVPlane),
774 width, height);
775 }
776 // Return output byte buffer back to codec.
777 jni->CallVoidMethod(
778 *j_media_codec_video_decoder_,
779 j_return_decoded_byte_buffer_method_,
780 output_buffer_index);
781 if (CheckException(jni)) {
782 ALOGE << "returnDecodedOutputBuffer error";
783 return false;
784 }
785 }
786 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0);
787 decoded_frame.set_timestamp(output_timestamps_ms);
788 decoded_frame.set_ntp_time_ms(output_ntp_timestamps_ms);
789
790 if (frames_decoded_ < frames_decoded_logged_) {
791 ALOGD << "Decoder frame out # " << frames_decoded_ <<
792 ". " << width << " x " << height <<
793 ". " << stride << " x " << slice_height <<
794 ". Color: " << color_format <<
795 ". TS: " << presentation_timestamps_ms <<
796 ". DecTime: " << (int)decode_time_ms <<
797 ". DelayTime: " << (int)frame_delayed_ms;
798 }
799
800 // Calculate and print decoding statistics - every 3 seconds.
801 frames_decoded_++;
802 current_frames_++;
803 current_decoding_time_ms_ += decode_time_ms;
804 current_delay_time_ms_ += frame_delayed_ms;
805 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
806 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
807 current_frames_ > 0) {
808 int current_bitrate = current_bytes_ * 8 / statistic_time_ms;
809 int current_fps =
810 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms;
811 ALOGD << "Frames decoded: " << frames_decoded_ <<
812 ". Received: " << frames_received_ <<
813 ". Bitrate: " << current_bitrate << " kbps" <<
814 ". Fps: " << current_fps <<
815 ". DecTime: " << (current_decoding_time_ms_ / current_frames_) <<
816 ". DelayTime: " << (current_delay_time_ms_ / current_frames_) <<
817 " for last " << statistic_time_ms << " ms.";
818 start_time_ms_ = GetCurrentTimeMs();
819 current_frames_ = 0;
820 current_bytes_ = 0;
821 current_decoding_time_ms_ = 0;
822 current_delay_time_ms_ = 0;
823 }
824
825 // |.IsZeroSize())| returns true when a frame has been dropped.
826 if (!decoded_frame.IsZeroSize()) {
827 // Callback - output decoded frame.
828 const int32_t callback_status =
829 callback_->Decoded(decoded_frame, decode_time_ms);
830 if (callback_status > 0) {
831 ALOGE << "callback error";
832 }
833 }
834 return true;
835 }
836
837 int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
838 DecodedImageCallback* callback) {
839 callback_ = callback;
840 return WEBRTC_VIDEO_CODEC_OK;
841 }
842
843 void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
844 JNIEnv* jni = AttachCurrentThreadIfNeeded();
845 ScopedLocalRefFrame local_ref_frame(jni);
846 if (!inited_) {
847 return;
848 }
849 // We only ever send one message to |this| directly (not through a Bind()'d
850 // functor), so expect no ID/data.
851 RTC_CHECK(!msg->message_id) << "Unexpected message!";
852 RTC_CHECK(!msg->pdata) << "Unexpected message!";
853 CheckOnCodecThread();
854
855 if (!DeliverPendingOutputs(jni, 0)) {
856 ALOGE << "OnMessage: DeliverPendingOutputs error";
857 ProcessHWErrorOnCodecThread();
858 return;
859 }
860 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
861 }
862
863 MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
864 ALOGD << "MediaCodecVideoDecoderFactory ctor";
865 JNIEnv* jni = AttachCurrentThreadIfNeeded();
866 ScopedLocalRefFrame local_ref_frame(jni);
867 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
868 supported_codec_types_.clear();
869
870 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod(
871 j_decoder_class,
872 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z"));
873 if (CheckException(jni)) {
874 is_vp8_hw_supported = false;
875 }
876 if (is_vp8_hw_supported) {
877 ALOGD << "VP8 HW Decoder supported.";
878 supported_codec_types_.push_back(kVideoCodecVP8);
879 }
880
881 bool is_vp9_hw_supported = jni->CallStaticBooleanMethod(
882 j_decoder_class,
883 GetStaticMethodID(jni, j_decoder_class, "isVp9HwSupported", "()Z"));
884 if (CheckException(jni)) {
885 is_vp9_hw_supported = false;
886 }
887 if (is_vp9_hw_supported) {
888 ALOGD << "VP9 HW Decoder supported.";
889 supported_codec_types_.push_back(kVideoCodecVP9);
890 }
891
892 bool is_h264_hw_supported = jni->CallStaticBooleanMethod(
893 j_decoder_class,
894 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z"));
895 if (CheckException(jni)) {
896 is_h264_hw_supported = false;
897 }
898 if (is_h264_hw_supported) {
899 ALOGD << "H264 HW Decoder supported.";
900 supported_codec_types_.push_back(kVideoCodecH264);
901 }
902 }
903
904 MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {
905 ALOGD << "MediaCodecVideoDecoderFactory dtor";
906 }
907
908 void MediaCodecVideoDecoderFactory::SetEGLContext(
909 JNIEnv* jni, jobject render_egl_context) {
910 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext";
911 if (!egl_.CreateEglBase(jni, render_egl_context)) {
912 ALOGW << "Invalid EGL context - HW surface decoding is disabled.";
913 }
914 }
915
916 webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
917 VideoCodecType type) {
918 if (supported_codec_types_.empty()) {
919 ALOGW << "No HW video decoder for type " << (int)type;
920 return nullptr;
921 }
922 for (VideoCodecType codec_type : supported_codec_types_) {
923 if (codec_type == type) {
924 ALOGD << "Create HW video decoder for type " << (int)type;
925 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded(), type,
926 egl_.egl_base_context());
927 }
928 }
929 ALOGW << "Can not find HW video decoder for type " << (int)type;
930 return nullptr;
931 }
932
933 void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
934 webrtc::VideoDecoder* decoder) {
935 ALOGD << "Destroy video decoder.";
936 delete decoder;
937 }
938
939 const char* MediaCodecVideoDecoder::ImplementationName() const {
940 return "MediaCodec";
941 }
942
943 } // namespace webrtc_jni
944
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/jni/androidmediadecoder_jni.h ('k') | talk/app/webrtc/java/jni/androidmediaencoder_jni.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698