| OLD | NEW | 
|     1 /* |     1 /* | 
|     2  *  Copyright 2015 The WebRTC project authors. All Rights Reserved. |     2  *  Copyright 2015 The WebRTC project authors. All Rights Reserved. | 
|     3  * |     3  * | 
|     4  *  Use of this source code is governed by a BSD-style license |     4  *  Use of this source code is governed by a BSD-style license | 
|     5  *  that can be found in the LICENSE file in the root of the source |     5  *  that can be found in the LICENSE file in the root of the source | 
|     6  *  tree. An additional intellectual property rights grant can be found |     6  *  tree. An additional intellectual property rights grant can be found | 
|     7  *  in the file PATENTS.  All contributing project authors may |     7  *  in the file PATENTS.  All contributing project authors may | 
|     8  *  be found in the AUTHORS file in the root of the source tree. |     8  *  be found in the AUTHORS file in the root of the source tree. | 
|     9  */ |     9  */ | 
|    10  |    10  | 
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   122  |   122  | 
|   123   void OnDroppedFrame() override; |   123   void OnDroppedFrame() override; | 
|   124  |   124  | 
|   125   bool SupportsNativeHandle() const override { return egl_context_ != nullptr; } |   125   bool SupportsNativeHandle() const override { return egl_context_ != nullptr; } | 
|   126   const char* ImplementationName() const override; |   126   const char* ImplementationName() const override; | 
|   127  |   127  | 
|   128  private: |   128  private: | 
|   129   // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and |   129   // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and | 
|   130   // InitEncodeOnCodecThread() in an attempt to restore the codec to an |   130   // InitEncodeOnCodecThread() in an attempt to restore the codec to an | 
|   131   // operable state.  Necessary after all manner of OMX-layer errors. |   131   // operable state.  Necessary after all manner of OMX-layer errors. | 
 |   132   // Returns true if the codec was reset successfully. | 
|   132   bool ResetCodecOnCodecThread(); |   133   bool ResetCodecOnCodecThread(); | 
|   133  |   134  | 
 |   135   // Fallback to a software encoder if one is supported else try to reset the | 
 |   136   // encoder. Called with |reset_if_fallback_unavailable| equal to false from | 
 |   137   // init/release encoder so that we don't go into infinite recursion. | 
 |   138   // Returns true if the codec was reset successfully. | 
 |   139   bool ProcessHWErrorOnCodecThread(bool reset_if_fallback_unavailable); | 
 |   140  | 
 |   141   // Calls ProcessHWErrorOnCodecThread(true). Returns | 
 |   142   // WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE if sw_fallback_required_ was set or | 
 |   143   // WEBRTC_VIDEO_CODEC_ERROR otherwise. | 
 |   144   int32_t ProcessHWErrorOnEncodeOnCodecThread(); | 
 |   145  | 
|   134   // Implementation of webrtc::VideoEncoder methods above, all running on the |   146   // Implementation of webrtc::VideoEncoder methods above, all running on the | 
|   135   // codec thread exclusively. |   147   // codec thread exclusively. | 
|   136   // |   148   // | 
|   137   // If width==0 then this is assumed to be a re-initialization and the |   149   // If width==0 then this is assumed to be a re-initialization and the | 
|   138   // previously-current values are reused instead of the passed parameters |   150   // previously-current values are reused instead of the passed parameters | 
|   139   // (makes it easier to reason about thread-safety). |   151   // (makes it easier to reason about thread-safety). | 
|   140   int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps, |   152   int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps, | 
|   141       bool use_surface); |   153       bool use_surface); | 
|   142   // Reconfigure to match |frame| in width, height. Also reconfigures the |   154   // Reconfigure to match |frame| in width, height. Also reconfigures the | 
|   143   // encoder if |frame| is a texture/byte buffer and the encoder is initialized |   155   // encoder if |frame| is a texture/byte buffer and the encoder is initialized | 
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   275   // EGL context - owned by factory, should not be allocated/destroyed |   287   // EGL context - owned by factory, should not be allocated/destroyed | 
|   276   // by MediaCodecVideoEncoder. |   288   // by MediaCodecVideoEncoder. | 
|   277   jobject egl_context_; |   289   jobject egl_context_; | 
|   278  |   290  | 
|   279   // Temporary fix for VP8. |   291   // Temporary fix for VP8. | 
|   280   // Sends a key frame if frames are largely spaced apart (possibly |   292   // Sends a key frame if frames are largely spaced apart (possibly | 
|   281   // corresponding to a large image change). |   293   // corresponding to a large image change). | 
|   282   int64_t last_frame_received_ms_; |   294   int64_t last_frame_received_ms_; | 
|   283   int frames_received_since_last_key_; |   295   int frames_received_since_last_key_; | 
|   284   webrtc::VideoCodecMode codec_mode_; |   296   webrtc::VideoCodecMode codec_mode_; | 
 |   297  | 
 |   298   bool sw_fallback_required_; | 
|   285 }; |   299 }; | 
|   286  |   300  | 
|   287 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { |   301 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { | 
|   288   // Call Release() to ensure no more callbacks to us after we are deleted. |   302   // Call Release() to ensure no more callbacks to us after we are deleted. | 
|   289   Release(); |   303   Release(); | 
|   290 } |   304 } | 
|   291  |   305  | 
|   292 MediaCodecVideoEncoder::MediaCodecVideoEncoder( |   306 MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni, | 
|   293     JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : |   307                                                VideoCodecType codecType, | 
|   294     codecType_(codecType), |   308                                                jobject egl_context) | 
|   295     callback_(NULL), |   309     : codecType_(codecType), | 
|   296     codec_thread_(new Thread()), |   310       callback_(NULL), | 
|   297     j_media_codec_video_encoder_class_( |   311       codec_thread_(new Thread()), | 
|   298         jni, |   312       j_media_codec_video_encoder_class_( | 
|   299         FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), |   313           jni, | 
|   300     j_media_codec_video_encoder_( |   314           FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")), | 
|   301         jni, |   315       j_media_codec_video_encoder_( | 
|   302         jni->NewObject(*j_media_codec_video_encoder_class_, |   316           jni, | 
|   303                        GetMethodID(jni, |   317           jni->NewObject(*j_media_codec_video_encoder_class_, | 
|   304                                    *j_media_codec_video_encoder_class_, |   318                          GetMethodID(jni, | 
|   305                                    "<init>", |   319                                      *j_media_codec_video_encoder_class_, | 
|   306                                    "()V"))), |   320                                      "<init>", | 
|   307     inited_(false), |   321                                      "()V"))), | 
|   308     use_surface_(false), |   322       inited_(false), | 
|   309     picture_id_(0), |   323       use_surface_(false), | 
|   310     egl_context_(egl_context) { |   324       picture_id_(0), | 
 |   325       egl_context_(egl_context), | 
 |   326       sw_fallback_required_(false) { | 
|   311   ScopedLocalRefFrame local_ref_frame(jni); |   327   ScopedLocalRefFrame local_ref_frame(jni); | 
|   312   // It would be nice to avoid spinning up a new thread per MediaCodec, and |   328   // It would be nice to avoid spinning up a new thread per MediaCodec, and | 
|   313   // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug |   329   // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug | 
|   314   // 2732 means that deadlocks abound.  This class synchronously trampolines |   330   // 2732 means that deadlocks abound.  This class synchronously trampolines | 
|   315   // to |codec_thread_|, so if anything else can be coming to _us_ from |   331   // to |codec_thread_|, so if anything else can be coming to _us_ from | 
|   316   // |codec_thread_|, or from any thread holding the |_sendCritSect| described |   332   // |codec_thread_|, or from any thread holding the |_sendCritSect| described | 
|   317   // in the bug, we have a problem.  For now work around that with a dedicated |   333   // in the bug, we have a problem.  For now work around that with a dedicated | 
|   318   // thread. |   334   // thread. | 
|   319   codec_thread_->SetName("MediaCodecVideoEncoder", NULL); |   335   codec_thread_->SetName("MediaCodecVideoEncoder", NULL); | 
|   320   RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; |   336   RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder"; | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   354   j_color_format_field_ = |   370   j_color_format_field_ = | 
|   355       GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I"); |   371       GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I"); | 
|   356   j_info_index_field_ = |   372   j_info_index_field_ = | 
|   357       GetFieldID(jni, j_output_buffer_info_class, "index", "I"); |   373       GetFieldID(jni, j_output_buffer_info_class, "index", "I"); | 
|   358   j_info_buffer_field_ = GetFieldID( |   374   j_info_buffer_field_ = GetFieldID( | 
|   359       jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;"); |   375       jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;"); | 
|   360   j_info_is_key_frame_field_ = |   376   j_info_is_key_frame_field_ = | 
|   361       GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z"); |   377       GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z"); | 
|   362   j_info_presentation_timestamp_us_field_ = GetFieldID( |   378   j_info_presentation_timestamp_us_field_ = GetFieldID( | 
|   363       jni, j_output_buffer_info_class, "presentationTimestampUs", "J"); |   379       jni, j_output_buffer_info_class, "presentationTimestampUs", "J"); | 
|   364   CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed"; |   380   if (CheckException(jni)) { | 
 |   381     ALOGW << "MediaCodecVideoEncoder ctor failed."; | 
 |   382     ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |   383   } | 
|   365   srand(time(NULL)); |   384   srand(time(NULL)); | 
|   366   AllowBlockingCalls(); |   385   AllowBlockingCalls(); | 
|   367 } |   386 } | 
|   368  |   387  | 
|   369 int32_t MediaCodecVideoEncoder::InitEncode( |   388 int32_t MediaCodecVideoEncoder::InitEncode( | 
|   370     const webrtc::VideoCodec* codec_settings, |   389     const webrtc::VideoCodec* codec_settings, | 
|   371     int32_t /* number_of_cores */, |   390     int32_t /* number_of_cores */, | 
|   372     size_t /* max_payload_size */) { |   391     size_t /* max_payload_size */) { | 
|   373   if (codec_settings == NULL) { |   392   if (codec_settings == NULL) { | 
|   374     ALOGE << "NULL VideoCodec instance"; |   393     ALOGE << "NULL VideoCodec instance"; | 
|   375     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |   394     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 
|   376   } |   395   } | 
|   377   // Factory should guard against other codecs being used with us. |   396   // Factory should guard against other codecs being used with us. | 
|   378   RTC_CHECK(codec_settings->codecType == codecType_) |   397   RTC_CHECK(codec_settings->codecType == codecType_) | 
|   379       << "Unsupported codec " << codec_settings->codecType << " for " |   398       << "Unsupported codec " << codec_settings->codecType << " for " | 
|   380       << codecType_; |   399       << codecType_; | 
|   381  |   400   if (sw_fallback_required_) { | 
 |   401     return WEBRTC_VIDEO_CODEC_OK; | 
 |   402   } | 
|   382   codec_mode_ = codec_settings->mode; |   403   codec_mode_ = codec_settings->mode; | 
|   383   int init_width = codec_settings->width; |   404   int init_width = codec_settings->width; | 
|   384   int init_height = codec_settings->height; |   405   int init_height = codec_settings->height; | 
|   385   // Scaling is disabled for VP9, but optionally enabled for VP8. |   406   // Scaling is disabled for VP9, but optionally enabled for VP8. | 
|   386   // TODO(pbos): Extract automaticResizeOn out of VP8 settings. |   407   // TODO(pbos): Extract automaticResizeOn out of VP8 settings. | 
|   387   scale_ = false; |   408   scale_ = false; | 
|   388   if (codecType_ == kVideoCodecVP8) { |   409   if (codecType_ == kVideoCodecVP8) { | 
|   389     scale_ = codec_settings->codecSpecific.VP8.automaticResizeOn; |   410     scale_ = codec_settings->codecSpecific.VP8.automaticResizeOn; | 
|   390   } else if (codecType_ != kVideoCodecVP9) { |   411   } else if (codecType_ != kVideoCodecVP9) { | 
|   391     scale_ = true; |   412     scale_ = true; | 
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   487   } |   508   } | 
|   488  |   509  | 
|   489   // Call log statistics here so it's called even if no frames are being |   510   // Call log statistics here so it's called even if no frames are being | 
|   490   // delivered. |   511   // delivered. | 
|   491   LogStatistics(false); |   512   LogStatistics(false); | 
|   492 } |   513 } | 
|   493  |   514  | 
|   494 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { |   515 bool MediaCodecVideoEncoder::ResetCodecOnCodecThread() { | 
|   495   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   516   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   496   ALOGE << "ResetOnCodecThread"; |   517   ALOGE << "ResetOnCodecThread"; | 
|   497   if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK || |   518   if (ReleaseOnCodecThread() != WEBRTC_VIDEO_CODEC_OK) { | 
|   498       InitEncodeOnCodecThread(width_, height_, 0, 0, false) != |   519     ALOGE << "Releasing codec failed during reset."; | 
|   499           WEBRTC_VIDEO_CODEC_OK) { |   520     return false; | 
|   500     // TODO(fischman): wouldn't it be nice if there was a way to gracefully |   521   } | 
|   501     // degrade to a SW encoder at this point?  There isn't one AFAICT :( |   522   if (InitEncodeOnCodecThread(width_, height_, 0, 0, false) != | 
|   502     // https://code.google.com/p/webrtc/issues/detail?id=2920 |   523       WEBRTC_VIDEO_CODEC_OK) { | 
 |   524     ALOGE << "Initializing encoder failed during reset."; | 
|   503     return false; |   525     return false; | 
|   504   } |   526   } | 
|   505   return true; |   527   return true; | 
|   506 } |   528 } | 
|   507  |   529  | 
 |   530 bool MediaCodecVideoEncoder::ProcessHWErrorOnCodecThread( | 
 |   531     bool reset_if_fallback_unavailable) { | 
 |   532   ALOGE << "ProcessHWErrorOnCodecThread"; | 
 |   533   if (VideoEncoder::IsSupportedSoftware( | 
 |   534           VideoEncoder::CodecToEncoderType(codecType_))) { | 
 |   535     ALOGE << "Fallback to SW encoder."; | 
 |   536     sw_fallback_required_ = true; | 
 |   537     return false; | 
 |   538   } else if (reset_if_fallback_unavailable) { | 
 |   539     ALOGE << "Reset encoder."; | 
 |   540     return ResetCodecOnCodecThread(); | 
 |   541   } | 
 |   542   return false; | 
 |   543 } | 
 |   544  | 
 |   545 int32_t MediaCodecVideoEncoder::ProcessHWErrorOnEncodeOnCodecThread() { | 
 |   546   ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |   547   return sw_fallback_required_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE | 
 |   548                                : WEBRTC_VIDEO_CODEC_ERROR; | 
 |   549 } | 
 |   550  | 
|   508 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( |   551 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread( | 
|   509     int width, int height, int kbps, int fps, bool use_surface) { |   552     int width, int height, int kbps, int fps, bool use_surface) { | 
|   510   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   553   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
 |   554   if (sw_fallback_required_) { | 
 |   555     return WEBRTC_VIDEO_CODEC_OK; | 
 |   556   } | 
|   511   RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; |   557   RTC_CHECK(!use_surface || egl_context_ != nullptr) << "EGL context not set."; | 
|   512   JNIEnv* jni = AttachCurrentThreadIfNeeded(); |   558   JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 
|   513   ScopedLocalRefFrame local_ref_frame(jni); |   559   ScopedLocalRefFrame local_ref_frame(jni); | 
|   514  |   560  | 
|   515   ALOGD << "InitEncodeOnCodecThread Type: " <<  (int)codecType_ << ", " << |   561   ALOGD << "InitEncodeOnCodecThread Type: " <<  (int)codecType_ << ", " << | 
|   516       width << " x " << height << ". Bitrate: " << kbps << |   562       width << " x " << height << ". Bitrate: " << kbps << | 
|   517       " kbps. Fps: " << fps; |   563       " kbps. Fps: " << fps; | 
|   518   if (kbps == 0) { |   564   if (kbps == 0) { | 
|   519     kbps = last_set_bitrate_kbps_; |   565     kbps = last_set_bitrate_kbps_; | 
|   520   } |   566   } | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   553  |   599  | 
|   554   // We enforce no extra stride/padding in the format creation step. |   600   // We enforce no extra stride/padding in the format creation step. | 
|   555   jobject j_video_codec_enum = JavaEnumFromIndexAndClassName( |   601   jobject j_video_codec_enum = JavaEnumFromIndexAndClassName( | 
|   556       jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); |   602       jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); | 
|   557   const bool encode_status = jni->CallBooleanMethod( |   603   const bool encode_status = jni->CallBooleanMethod( | 
|   558       *j_media_codec_video_encoder_, j_init_encode_method_, |   604       *j_media_codec_video_encoder_, j_init_encode_method_, | 
|   559       j_video_codec_enum, width, height, kbps, fps, |   605       j_video_codec_enum, width, height, kbps, fps, | 
|   560       (use_surface ? egl_context_ : nullptr)); |   606       (use_surface ? egl_context_ : nullptr)); | 
|   561   if (!encode_status) { |   607   if (!encode_status) { | 
|   562     ALOGE << "Failed to configure encoder."; |   608     ALOGE << "Failed to configure encoder."; | 
 |   609     ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
|   563     return WEBRTC_VIDEO_CODEC_ERROR; |   610     return WEBRTC_VIDEO_CODEC_ERROR; | 
|   564   } |   611   } | 
|   565   CHECK_EXCEPTION(jni); |   612   if (CheckException(jni)) { | 
 |   613     ALOGE << "Exception in init encode."; | 
 |   614     ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
 |   615     return WEBRTC_VIDEO_CODEC_ERROR; | 
 |   616   } | 
|   566  |   617  | 
|   567   if (!use_surface) { |   618   if (!use_surface) { | 
|   568     jobjectArray input_buffers = reinterpret_cast<jobjectArray>( |   619     jobjectArray input_buffers = reinterpret_cast<jobjectArray>( | 
|   569         jni->CallObjectMethod(*j_media_codec_video_encoder_, |   620         jni->CallObjectMethod(*j_media_codec_video_encoder_, | 
|   570             j_get_input_buffers_method_)); |   621             j_get_input_buffers_method_)); | 
|   571     CHECK_EXCEPTION(jni); |   622     if (CheckException(jni)) { | 
|   572     if (IsNull(jni, input_buffers)) { |   623       ALOGE << "Exception in get input buffers."; | 
 |   624       ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
|   573       return WEBRTC_VIDEO_CODEC_ERROR; |   625       return WEBRTC_VIDEO_CODEC_ERROR; | 
|   574     } |   626     } | 
|   575  |   627  | 
 |   628     if (IsNull(jni, input_buffers)) { | 
 |   629       ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
 |   630       return WEBRTC_VIDEO_CODEC_ERROR; | 
 |   631     } | 
 |   632  | 
|   576     switch (GetIntField(jni, *j_media_codec_video_encoder_, |   633     switch (GetIntField(jni, *j_media_codec_video_encoder_, | 
|   577         j_color_format_field_)) { |   634         j_color_format_field_)) { | 
|   578       case COLOR_FormatYUV420Planar: |   635       case COLOR_FormatYUV420Planar: | 
|   579         encoder_fourcc_ = libyuv::FOURCC_YU12; |   636         encoder_fourcc_ = libyuv::FOURCC_YU12; | 
|   580         break; |   637         break; | 
|   581       case COLOR_FormatYUV420SemiPlanar: |   638       case COLOR_FormatYUV420SemiPlanar: | 
|   582       case COLOR_QCOM_FormatYUV420SemiPlanar: |   639       case COLOR_QCOM_FormatYUV420SemiPlanar: | 
|   583       case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: |   640       case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m: | 
|   584         encoder_fourcc_ = libyuv::FOURCC_NV12; |   641         encoder_fourcc_ = libyuv::FOURCC_NV12; | 
|   585         break; |   642         break; | 
|   586       default: |   643       default: | 
|   587         LOG(LS_ERROR) << "Wrong color format."; |   644         LOG(LS_ERROR) << "Wrong color format."; | 
 |   645         ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
|   588         return WEBRTC_VIDEO_CODEC_ERROR; |   646         return WEBRTC_VIDEO_CODEC_ERROR; | 
|   589     } |   647     } | 
|   590     size_t num_input_buffers = jni->GetArrayLength(input_buffers); |   648     size_t num_input_buffers = jni->GetArrayLength(input_buffers); | 
|   591     RTC_CHECK(input_buffers_.empty()) |   649     RTC_CHECK(input_buffers_.empty()) | 
|   592         << "Unexpected double InitEncode without Release"; |   650         << "Unexpected double InitEncode without Release"; | 
|   593     input_buffers_.resize(num_input_buffers); |   651     input_buffers_.resize(num_input_buffers); | 
|   594     for (size_t i = 0; i < num_input_buffers; ++i) { |   652     for (size_t i = 0; i < num_input_buffers; ++i) { | 
|   595       input_buffers_[i] = |   653       input_buffers_[i] = | 
|   596           jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); |   654           jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | 
|   597       int64_t yuv_buffer_capacity = |   655       int64_t yuv_buffer_capacity = | 
|   598           jni->GetDirectBufferCapacity(input_buffers_[i]); |   656           jni->GetDirectBufferCapacity(input_buffers_[i]); | 
|   599       CHECK_EXCEPTION(jni); |   657       if (CheckException(jni)) { | 
 |   658         ALOGE << "Exception in get direct buffer capacity."; | 
 |   659         ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
 |   660         return WEBRTC_VIDEO_CODEC_ERROR; | 
 |   661       } | 
|   600       RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; |   662       RTC_CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity"; | 
|   601     } |   663     } | 
|   602   } |   664   } | 
|   603  |   665  | 
|   604   inited_ = true; |   666   inited_ = true; | 
|   605   return WEBRTC_VIDEO_CODEC_OK; |   667   return WEBRTC_VIDEO_CODEC_OK; | 
|   606 } |   668 } | 
|   607  |   669  | 
|   608 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( |   670 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread( | 
|   609     const webrtc::VideoFrame& frame, |   671     const webrtc::VideoFrame& frame, | 
|   610     const std::vector<webrtc::FrameType>* frame_types, |   672     const std::vector<webrtc::FrameType>* frame_types, | 
|   611     const int64_t frame_input_time_ms) { |   673     const int64_t frame_input_time_ms) { | 
|   612   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   674   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
 |   675   if (sw_fallback_required_) | 
 |   676     return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 
|   613   JNIEnv* jni = AttachCurrentThreadIfNeeded(); |   677   JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 
|   614   ScopedLocalRefFrame local_ref_frame(jni); |   678   ScopedLocalRefFrame local_ref_frame(jni); | 
|   615  |   679  | 
|   616   if (!inited_) { |   680   if (!inited_) { | 
|   617     return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |   681     return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 
|   618   } |   682   } | 
|   619  |   683  | 
|   620   bool send_key_frame = false; |   684   bool send_key_frame = false; | 
|   621   if (codec_mode_ == webrtc::kRealtimeVideo) { |   685   if (codec_mode_ == webrtc::kRealtimeVideo) { | 
|   622     ++frames_received_since_last_key_; |   686     ++frames_received_since_last_key_; | 
|   623     int64_t now_ms = rtc::TimeMillis(); |   687     int64_t now_ms = rtc::TimeMillis(); | 
|   624     if (last_frame_received_ms_ != -1 && |   688     if (last_frame_received_ms_ != -1 && | 
|   625         (now_ms - last_frame_received_ms_) > kFrameDiffThresholdMs) { |   689         (now_ms - last_frame_received_ms_) > kFrameDiffThresholdMs) { | 
|   626       // Add limit to prevent triggering a key for every frame for very low |   690       // Add limit to prevent triggering a key for every frame for very low | 
|   627       // framerates (e.g. if frame diff > kFrameDiffThresholdMs). |   691       // framerates (e.g. if frame diff > kFrameDiffThresholdMs). | 
|   628       if (frames_received_since_last_key_ > kMinKeyFrameInterval) { |   692       if (frames_received_since_last_key_ > kMinKeyFrameInterval) { | 
|   629         ALOGD << "Send key, frame diff: " << (now_ms - last_frame_received_ms_); |   693         ALOGD << "Send key, frame diff: " << (now_ms - last_frame_received_ms_); | 
|   630         send_key_frame = true; |   694         send_key_frame = true; | 
|   631       } |   695       } | 
|   632       frames_received_since_last_key_ = 0; |   696       frames_received_since_last_key_ = 0; | 
|   633     } |   697     } | 
|   634     last_frame_received_ms_ = now_ms; |   698     last_frame_received_ms_ = now_ms; | 
|   635   } |   699   } | 
|   636  |   700  | 
|   637   frames_received_++; |   701   frames_received_++; | 
|   638   if (!DeliverPendingOutputs(jni)) { |   702   if (!DeliverPendingOutputs(jni)) { | 
|   639     if (!ResetCodecOnCodecThread()) |   703     if (!ProcessHWErrorOnCodecThread( | 
|   640       return WEBRTC_VIDEO_CODEC_ERROR; |   704             true /* reset_if_fallback_unavailable */)) { | 
 |   705       return sw_fallback_required_ ? WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE | 
 |   706                                    : WEBRTC_VIDEO_CODEC_ERROR; | 
 |   707     } | 
|   641   } |   708   } | 
|   642   if (frames_encoded_ < kMaxEncodedLogFrames) { |   709   if (frames_encoded_ < kMaxEncodedLogFrames) { | 
|   643     ALOGD << "Encoder frame in # " << (frames_received_ - 1) |   710     ALOGD << "Encoder frame in # " << (frames_received_ - 1) | 
|   644           << ". TS: " << (int)(current_timestamp_us_ / 1000) |   711           << ". TS: " << (int)(current_timestamp_us_ / 1000) | 
|   645           << ". Q: " << input_frame_infos_.size() << ". Fps: " << last_set_fps_ |   712           << ". Q: " << input_frame_infos_.size() << ". Fps: " << last_set_fps_ | 
|   646           << ". Kbps: " << last_set_bitrate_kbps_; |   713           << ". Kbps: " << last_set_bitrate_kbps_; | 
|   647   } |   714   } | 
|   648  |   715  | 
|   649   if (drop_next_input_frame_) { |   716   if (drop_next_input_frame_) { | 
|   650     ALOGW << "Encoder drop frame - failed callback."; |   717     ALOGW << "Encoder drop frame - failed callback."; | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
|   662   if (input_frame_infos_.size() > MAX_ENCODER_Q_SIZE) { |   729   if (input_frame_infos_.size() > MAX_ENCODER_Q_SIZE) { | 
|   663     ALOGD << "Already " << input_frame_infos_.size() |   730     ALOGD << "Already " << input_frame_infos_.size() | 
|   664           << " frames in the queue, dropping" |   731           << " frames in the queue, dropping" | 
|   665           << ". TS: " << (int)(current_timestamp_us_ / 1000) |   732           << ". TS: " << (int)(current_timestamp_us_ / 1000) | 
|   666           << ". Fps: " << last_set_fps_ |   733           << ". Fps: " << last_set_fps_ | 
|   667           << ". Consecutive drops: " << consecutive_full_queue_frame_drops_; |   734           << ". Consecutive drops: " << consecutive_full_queue_frame_drops_; | 
|   668     current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |   735     current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 
|   669     consecutive_full_queue_frame_drops_++; |   736     consecutive_full_queue_frame_drops_++; | 
|   670     if (consecutive_full_queue_frame_drops_ >= |   737     if (consecutive_full_queue_frame_drops_ >= | 
|   671         ENCODER_STALL_FRAMEDROP_THRESHOLD) { |   738         ENCODER_STALL_FRAMEDROP_THRESHOLD) { | 
|   672       ALOGE << "Encoder got stuck. Reset."; |   739       ALOGE << "Encoder got stuck."; | 
|   673       ResetCodecOnCodecThread(); |   740       return ProcessHWErrorOnEncodeOnCodecThread(); | 
|   674       return WEBRTC_VIDEO_CODEC_ERROR; |  | 
|   675     } |   741     } | 
|   676     frames_dropped_media_encoder_++; |   742     frames_dropped_media_encoder_++; | 
|   677     OnDroppedFrameOnCodecThread(); |   743     OnDroppedFrameOnCodecThread(); | 
|   678     return WEBRTC_VIDEO_CODEC_OK; |   744     return WEBRTC_VIDEO_CODEC_OK; | 
|   679   } |   745   } | 
|   680   consecutive_full_queue_frame_drops_ = 0; |   746   consecutive_full_queue_frame_drops_ = 0; | 
|   681  |   747  | 
|   682   rtc::scoped_refptr<webrtc::VideoFrameBuffer> input_buffer( |   748   rtc::scoped_refptr<webrtc::VideoFrameBuffer> input_buffer( | 
|   683       frame.video_frame_buffer()); |   749       frame.video_frame_buffer()); | 
|   684   if (scale_) { |   750   if (scale_) { | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
|   708     ALOGE << "Failed to reconfigure encoder."; |   774     ALOGE << "Failed to reconfigure encoder."; | 
|   709     return WEBRTC_VIDEO_CODEC_ERROR; |   775     return WEBRTC_VIDEO_CODEC_ERROR; | 
|   710   } |   776   } | 
|   711  |   777  | 
|   712   const bool key_frame = |   778   const bool key_frame = | 
|   713       frame_types->front() != webrtc::kVideoFrameDelta || send_key_frame; |   779       frame_types->front() != webrtc::kVideoFrameDelta || send_key_frame; | 
|   714   bool encode_status = true; |   780   bool encode_status = true; | 
|   715   if (!input_frame.video_frame_buffer()->native_handle()) { |   781   if (!input_frame.video_frame_buffer()->native_handle()) { | 
|   716     int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, |   782     int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, | 
|   717         j_dequeue_input_buffer_method_); |   783         j_dequeue_input_buffer_method_); | 
|   718     CHECK_EXCEPTION(jni); |   784     if (CheckException(jni)) { | 
 |   785       ALOGE << "Exception in dequeu input buffer."; | 
 |   786       return ProcessHWErrorOnEncodeOnCodecThread(); | 
 |   787     } | 
|   719     if (j_input_buffer_index == -1) { |   788     if (j_input_buffer_index == -1) { | 
|   720       // Video codec falls behind - no input buffer available. |   789       // Video codec falls behind - no input buffer available. | 
|   721       ALOGW << "Encoder drop frame - no input buffers available"; |   790       ALOGW << "Encoder drop frame - no input buffers available"; | 
|   722       if (frames_received_ > 1) { |   791       if (frames_received_ > 1) { | 
|   723         current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |   792         current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 
|   724         frames_dropped_media_encoder_++; |   793         frames_dropped_media_encoder_++; | 
|   725         OnDroppedFrameOnCodecThread(); |   794         OnDroppedFrameOnCodecThread(); | 
|   726       } else { |   795       } else { | 
|   727         // Input buffers are not ready after codec initialization, HW is still |   796         // Input buffers are not ready after codec initialization, HW is still | 
|   728         // allocating thme - this is expected and should not result in drop |   797         // allocating thme - this is expected and should not result in drop | 
|   729         // frame report. |   798         // frame report. | 
|   730         frames_received_ = 0; |   799         frames_received_ = 0; | 
|   731       } |   800       } | 
|   732       return WEBRTC_VIDEO_CODEC_OK;  // TODO(fischman): see webrtc bug 2887. |   801       return WEBRTC_VIDEO_CODEC_OK;  // TODO(fischman): see webrtc bug 2887. | 
|   733     } else if (j_input_buffer_index == -2) { |   802     } else if (j_input_buffer_index == -2) { | 
|   734       ResetCodecOnCodecThread(); |   803       return ProcessHWErrorOnEncodeOnCodecThread(); | 
|   735       return WEBRTC_VIDEO_CODEC_ERROR; |  | 
|   736     } |   804     } | 
|   737     encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, |   805     encode_status = EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, | 
|   738         j_input_buffer_index); |   806         j_input_buffer_index); | 
|   739   } else { |   807   } else { | 
|   740     encode_status = EncodeTextureOnCodecThread(jni, key_frame, input_frame); |   808     encode_status = EncodeTextureOnCodecThread(jni, key_frame, input_frame); | 
|   741   } |   809   } | 
|   742  |   810  | 
|   743   if (!encode_status) { |   811   if (!encode_status) { | 
|   744     ALOGE << "Failed encode frame with timestamp: " << input_frame.timestamp(); |   812     ALOGE << "Failed encode frame with timestamp: " << input_frame.timestamp(); | 
|   745     ResetCodecOnCodecThread(); |   813     return ProcessHWErrorOnEncodeOnCodecThread(); | 
|   746     return WEBRTC_VIDEO_CODEC_ERROR; |  | 
|   747   } |   814   } | 
|   748  |   815  | 
|   749   // Save input image timestamps for later output. |   816   // Save input image timestamps for later output. | 
|   750   input_frame_infos_.emplace_back( |   817   input_frame_infos_.emplace_back( | 
|   751       frame_input_time_ms, input_frame.timestamp(), |   818       frame_input_time_ms, input_frame.timestamp(), | 
|   752       input_frame.render_time_ms(), input_frame.rotation()); |   819       input_frame.render_time_ms(), input_frame.rotation()); | 
|   753  |   820  | 
|   754   last_input_timestamp_ms_ = |   821   last_input_timestamp_ms_ = | 
|   755       current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; |   822       current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; | 
|   756  |   823  | 
|   757   current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |   824   current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 
|   758  |   825  | 
|   759   codec_thread_->Clear(this); |   826   codec_thread_->Clear(this); | 
|   760   codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this); |   827   codec_thread_->PostDelayed(RTC_FROM_HERE, kMediaCodecPollMs, this); | 
|   761  |   828  | 
|   762   if (!DeliverPendingOutputs(jni)) { |   829   if (!DeliverPendingOutputs(jni)) { | 
|   763     ALOGE << "Failed deliver pending outputs."; |   830     return ProcessHWErrorOnEncodeOnCodecThread(); | 
|   764     ResetCodecOnCodecThread(); |  | 
|   765     return WEBRTC_VIDEO_CODEC_ERROR; |  | 
|   766   } |   831   } | 
|   767   return WEBRTC_VIDEO_CODEC_OK; |   832   return WEBRTC_VIDEO_CODEC_OK; | 
|   768 } |   833 } | 
|   769  |   834  | 
|   770 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( |   835 bool MediaCodecVideoEncoder::MaybeReconfigureEncoderOnCodecThread( | 
|   771     const webrtc::VideoFrame& frame) { |   836     const webrtc::VideoFrame& frame) { | 
|   772   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   837   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   773  |   838  | 
|   774   const bool is_texture_frame = |   839   const bool is_texture_frame = | 
|   775       frame.video_frame_buffer()->native_handle() != nullptr; |   840       frame.video_frame_buffer()->native_handle() != nullptr; | 
| (...skipping 27 matching lines...) Expand all  Loading... | 
|   803 } |   868 } | 
|   804  |   869  | 
|   805 bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, |   870 bool MediaCodecVideoEncoder::EncodeByteBufferOnCodecThread(JNIEnv* jni, | 
|   806     bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index) { |   871     bool key_frame, const webrtc::VideoFrame& frame, int input_buffer_index) { | 
|   807   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   872   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   808   RTC_CHECK(!use_surface_); |   873   RTC_CHECK(!use_surface_); | 
|   809  |   874  | 
|   810   jobject j_input_buffer = input_buffers_[input_buffer_index]; |   875   jobject j_input_buffer = input_buffers_[input_buffer_index]; | 
|   811   uint8_t* yuv_buffer = |   876   uint8_t* yuv_buffer = | 
|   812       reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); |   877       reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); | 
|   813   CHECK_EXCEPTION(jni); |   878   if (CheckException(jni)) { | 
 |   879     ALOGE << "Exception in get direct buffer address."; | 
 |   880     ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |   881     return false; | 
 |   882   } | 
|   814   RTC_CHECK(yuv_buffer) << "Indirect buffer??"; |   883   RTC_CHECK(yuv_buffer) << "Indirect buffer??"; | 
|   815   RTC_CHECK(!libyuv::ConvertFromI420( |   884   RTC_CHECK(!libyuv::ConvertFromI420( | 
|   816       frame.video_frame_buffer()->DataY(), |   885       frame.video_frame_buffer()->DataY(), | 
|   817       frame.video_frame_buffer()->StrideY(), |   886       frame.video_frame_buffer()->StrideY(), | 
|   818       frame.video_frame_buffer()->DataU(), |   887       frame.video_frame_buffer()->DataU(), | 
|   819       frame.video_frame_buffer()->StrideU(), |   888       frame.video_frame_buffer()->StrideU(), | 
|   820       frame.video_frame_buffer()->DataV(), |   889       frame.video_frame_buffer()->DataV(), | 
|   821       frame.video_frame_buffer()->StrideV(), |   890       frame.video_frame_buffer()->StrideV(), | 
|   822       yuv_buffer, width_, width_, height_, encoder_fourcc_)) |   891       yuv_buffer, width_, width_, height_, encoder_fourcc_)) | 
|   823       << "ConvertFromI420 failed"; |   892       << "ConvertFromI420 failed"; | 
|   824  |   893  | 
|   825   bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, |   894   bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | 
|   826                                               j_encode_buffer_method_, |   895                                               j_encode_buffer_method_, | 
|   827                                               key_frame, |   896                                               key_frame, | 
|   828                                               input_buffer_index, |   897                                               input_buffer_index, | 
|   829                                               yuv_size_, |   898                                               yuv_size_, | 
|   830                                               current_timestamp_us_); |   899                                               current_timestamp_us_); | 
|   831   CHECK_EXCEPTION(jni); |   900   if (CheckException(jni)) { | 
 |   901     ALOGE << "Exception in encode buffer."; | 
 |   902     ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |   903     return false; | 
 |   904   } | 
|   832   return encode_status; |   905   return encode_status; | 
|   833 } |   906 } | 
|   834  |   907  | 
|   835 bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, |   908 bool MediaCodecVideoEncoder::EncodeTextureOnCodecThread(JNIEnv* jni, | 
|   836     bool key_frame, const webrtc::VideoFrame& frame) { |   909     bool key_frame, const webrtc::VideoFrame& frame) { | 
|   837   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   910   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   838   RTC_CHECK(use_surface_); |   911   RTC_CHECK(use_surface_); | 
|   839   NativeHandleImpl* handle = static_cast<NativeHandleImpl*>( |   912   NativeHandleImpl* handle = static_cast<NativeHandleImpl*>( | 
|   840       frame.video_frame_buffer()->native_handle()); |   913       frame.video_frame_buffer()->native_handle()); | 
|   841   jfloatArray sampling_matrix = handle->sampling_matrix.ToJava(jni); |   914   jfloatArray sampling_matrix = handle->sampling_matrix.ToJava(jni); | 
|   842   bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, |   915   bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | 
|   843                                               j_encode_texture_method_, |   916                                               j_encode_texture_method_, | 
|   844                                               key_frame, |   917                                               key_frame, | 
|   845                                               handle->oes_texture_id, |   918                                               handle->oes_texture_id, | 
|   846                                               sampling_matrix, |   919                                               sampling_matrix, | 
|   847                                               current_timestamp_us_); |   920                                               current_timestamp_us_); | 
|   848   CHECK_EXCEPTION(jni); |   921   if (CheckException(jni)) { | 
 |   922     ALOGE << "Exception in encode texture."; | 
 |   923     ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |   924     return false; | 
 |   925   } | 
|   849   return encode_status; |   926   return encode_status; | 
|   850 } |   927 } | 
|   851  |   928  | 
|   852 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( |   929 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread( | 
|   853     webrtc::EncodedImageCallback* callback) { |   930     webrtc::EncodedImageCallback* callback) { | 
|   854   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   931   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   855   JNIEnv* jni = AttachCurrentThreadIfNeeded(); |   932   JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 
|   856   ScopedLocalRefFrame local_ref_frame(jni); |   933   ScopedLocalRefFrame local_ref_frame(jni); | 
|   857   callback_ = callback; |   934   callback_ = callback; | 
|   858   return WEBRTC_VIDEO_CODEC_OK; |   935   return WEBRTC_VIDEO_CODEC_OK; | 
|   859 } |   936 } | 
|   860  |   937  | 
|   861 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { |   938 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() { | 
|   862   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   939   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   863   if (!inited_) { |   940   if (!inited_) { | 
|   864     return WEBRTC_VIDEO_CODEC_OK; |   941     return WEBRTC_VIDEO_CODEC_OK; | 
|   865   } |   942   } | 
|   866   JNIEnv* jni = AttachCurrentThreadIfNeeded(); |   943   JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 
|   867   ALOGD << "EncoderReleaseOnCodecThread: Frames received: " << |   944   ALOGD << "EncoderReleaseOnCodecThread: Frames received: " << | 
|   868       frames_received_ << ". Encoded: " << frames_encoded_ << |   945       frames_received_ << ". Encoded: " << frames_encoded_ << | 
|   869       ". Dropped: " << frames_dropped_media_encoder_; |   946       ". Dropped: " << frames_dropped_media_encoder_; | 
|   870   ScopedLocalRefFrame local_ref_frame(jni); |   947   ScopedLocalRefFrame local_ref_frame(jni); | 
|   871   for (size_t i = 0; i < input_buffers_.size(); ++i) |   948   for (size_t i = 0; i < input_buffers_.size(); ++i) | 
|   872     jni->DeleteGlobalRef(input_buffers_[i]); |   949     jni->DeleteGlobalRef(input_buffers_[i]); | 
|   873   input_buffers_.clear(); |   950   input_buffers_.clear(); | 
|   874   jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_); |   951   jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_); | 
|   875   CHECK_EXCEPTION(jni); |   952   if (CheckException(jni)) { | 
 |   953     ALOGE << "Exception in release."; | 
 |   954     ProcessHWErrorOnCodecThread(false /* reset_if_fallback_unavailable */); | 
 |   955     return WEBRTC_VIDEO_CODEC_ERROR; | 
 |   956   } | 
|   876   rtc::MessageQueueManager::Clear(this); |   957   rtc::MessageQueueManager::Clear(this); | 
|   877   inited_ = false; |   958   inited_ = false; | 
|   878   use_surface_ = false; |   959   use_surface_ = false; | 
|   879   ALOGD << "EncoderReleaseOnCodecThread done."; |   960   ALOGD << "EncoderReleaseOnCodecThread done."; | 
|   880   return WEBRTC_VIDEO_CODEC_OK; |   961   return WEBRTC_VIDEO_CODEC_OK; | 
|   881 } |   962 } | 
|   882  |   963  | 
|   883 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, |   964 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate, | 
|   884                                                       uint32_t frame_rate) { |   965                                                       uint32_t frame_rate) { | 
|   885   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |   966   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
 |   967   if (sw_fallback_required_) | 
 |   968     return WEBRTC_VIDEO_CODEC_OK; | 
|   886   frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ? |   969   frame_rate = (frame_rate < MAX_ALLOWED_VIDEO_FPS) ? | 
|   887       frame_rate : MAX_ALLOWED_VIDEO_FPS; |   970       frame_rate : MAX_ALLOWED_VIDEO_FPS; | 
|   888   if (last_set_bitrate_kbps_ == new_bit_rate && |   971   if (last_set_bitrate_kbps_ == new_bit_rate && | 
|   889       last_set_fps_ == frame_rate) { |   972       last_set_fps_ == frame_rate) { | 
|   890     return WEBRTC_VIDEO_CODEC_OK; |   973     return WEBRTC_VIDEO_CODEC_OK; | 
|   891   } |   974   } | 
|   892   if (scale_) { |   975   if (scale_) { | 
|   893     quality_scaler_.ReportFramerate(frame_rate); |   976     quality_scaler_.ReportFramerate(frame_rate); | 
|   894   } |   977   } | 
|   895   JNIEnv* jni = AttachCurrentThreadIfNeeded(); |   978   JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 
|   896   ScopedLocalRefFrame local_ref_frame(jni); |   979   ScopedLocalRefFrame local_ref_frame(jni); | 
|   897   if (new_bit_rate > 0) { |   980   if (new_bit_rate > 0) { | 
|   898     last_set_bitrate_kbps_ = new_bit_rate; |   981     last_set_bitrate_kbps_ = new_bit_rate; | 
|   899   } |   982   } | 
|   900   if (frame_rate > 0) { |   983   if (frame_rate > 0) { | 
|   901     last_set_fps_ = frame_rate; |   984     last_set_fps_ = frame_rate; | 
|   902   } |   985   } | 
|   903   bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_, |   986   bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | 
|   904                                        j_set_rates_method_, |   987                                        j_set_rates_method_, | 
|   905                                        last_set_bitrate_kbps_, |   988                                        last_set_bitrate_kbps_, | 
|   906                                        last_set_fps_); |   989                                        last_set_fps_); | 
|   907   CHECK_EXCEPTION(jni); |   990   if (CheckException(jni) || !ret) { | 
|   908   if (!ret) { |   991     ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
|   909     ResetCodecOnCodecThread(); |   992     return sw_fallback_required_ ? WEBRTC_VIDEO_CODEC_OK | 
|   910     return WEBRTC_VIDEO_CODEC_ERROR; |   993                                  : WEBRTC_VIDEO_CODEC_ERROR; | 
|   911   } |   994   } | 
|   912   return WEBRTC_VIDEO_CODEC_OK; |   995   return WEBRTC_VIDEO_CODEC_OK; | 
|   913 } |   996 } | 
|   914  |   997  | 
|   915 int MediaCodecVideoEncoder::GetOutputBufferInfoIndex( |   998 int MediaCodecVideoEncoder::GetOutputBufferInfoIndex( | 
|   916     JNIEnv* jni, |   999     JNIEnv* jni, | 
|   917     jobject j_output_buffer_info) { |  1000     jobject j_output_buffer_info) { | 
|   918   return GetIntField(jni, j_output_buffer_info, j_info_index_field_); |  1001   return GetIntField(jni, j_output_buffer_info, j_info_index_field_); | 
|   919 } |  1002 } | 
|   920  |  1003  | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|   936   return GetLongField( |  1019   return GetLongField( | 
|   937       jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_); |  1020       jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_); | 
|   938 } |  1021 } | 
|   939  |  1022  | 
|   940 bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) { |  1023 bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) { | 
|   941   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |  1024   RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 
|   942  |  1025  | 
|   943   while (true) { |  1026   while (true) { | 
|   944     jobject j_output_buffer_info = jni->CallObjectMethod( |  1027     jobject j_output_buffer_info = jni->CallObjectMethod( | 
|   945         *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_); |  1028         *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_); | 
|   946     CHECK_EXCEPTION(jni); |  1029     if (CheckException(jni)) { | 
 |  1030       ALOGE << "Exception in set dequeue output buffer."; | 
 |  1031       ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |  1032       return WEBRTC_VIDEO_CODEC_ERROR; | 
 |  1033     } | 
|   947     if (IsNull(jni, j_output_buffer_info)) { |  1034     if (IsNull(jni, j_output_buffer_info)) { | 
|   948       break; |  1035       break; | 
|   949     } |  1036     } | 
|   950  |  1037  | 
|   951     int output_buffer_index = |  1038     int output_buffer_index = | 
|   952         GetOutputBufferInfoIndex(jni, j_output_buffer_info); |  1039         GetOutputBufferInfoIndex(jni, j_output_buffer_info); | 
|   953     if (output_buffer_index == -1) { |  1040     if (output_buffer_index == -1) { | 
|   954       ResetCodecOnCodecThread(); |  1041       ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
|   955       return false; |  1042       return false; | 
|   956     } |  1043     } | 
|   957  |  1044  | 
|   958     // Get key and config frame flags. |  1045     // Get key and config frame flags. | 
|   959     jobject j_output_buffer = |  1046     jobject j_output_buffer = | 
|   960         GetOutputBufferInfoBuffer(jni, j_output_buffer_info); |  1047         GetOutputBufferInfoBuffer(jni, j_output_buffer_info); | 
|   961     bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info); |  1048     bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info); | 
|   962  |  1049  | 
|   963     // Get frame timestamps from a queue - for non config frames only. |  1050     // Get frame timestamps from a queue - for non config frames only. | 
|   964     int64_t encoding_start_time_ms = 0; |  1051     int64_t encoding_start_time_ms = 0; | 
|   965     int64_t frame_encoding_time_ms = 0; |  1052     int64_t frame_encoding_time_ms = 0; | 
|   966     last_output_timestamp_ms_ = |  1053     last_output_timestamp_ms_ = | 
|   967         GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) / |  1054         GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) / | 
|   968         rtc::kNumMicrosecsPerMillisec; |  1055         rtc::kNumMicrosecsPerMillisec; | 
|   969     if (!input_frame_infos_.empty()) { |  1056     if (!input_frame_infos_.empty()) { | 
|   970       const InputFrameInfo& frame_info = input_frame_infos_.front(); |  1057       const InputFrameInfo& frame_info = input_frame_infos_.front(); | 
|   971       output_timestamp_ = frame_info.frame_timestamp; |  1058       output_timestamp_ = frame_info.frame_timestamp; | 
|   972       output_render_time_ms_ = frame_info.frame_render_time_ms; |  1059       output_render_time_ms_ = frame_info.frame_render_time_ms; | 
|   973       output_rotation_ = frame_info.rotation; |  1060       output_rotation_ = frame_info.rotation; | 
|   974       encoding_start_time_ms = frame_info.encode_start_time; |  1061       encoding_start_time_ms = frame_info.encode_start_time; | 
|   975       input_frame_infos_.pop_front(); |  1062       input_frame_infos_.pop_front(); | 
|   976     } |  1063     } | 
|   977  |  1064  | 
|   978     // Extract payload. |  1065     // Extract payload. | 
|   979     size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer); |  1066     size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer); | 
|   980     uint8_t* payload = reinterpret_cast<uint8_t*>( |  1067     uint8_t* payload = reinterpret_cast<uint8_t*>( | 
|   981         jni->GetDirectBufferAddress(j_output_buffer)); |  1068         jni->GetDirectBufferAddress(j_output_buffer)); | 
|   982     CHECK_EXCEPTION(jni); |  1069     if (CheckException(jni)) { | 
 |  1070       ALOGE << "Exception in get direct buffer address."; | 
 |  1071       ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
 |  1072       return WEBRTC_VIDEO_CODEC_ERROR; | 
 |  1073     } | 
|   983  |  1074  | 
|   984     // Callback - return encoded frame. |  1075     // Callback - return encoded frame. | 
|   985     int32_t callback_status = 0; |  1076     int32_t callback_status = 0; | 
|   986     if (callback_) { |  1077     if (callback_) { | 
|   987       std::unique_ptr<webrtc::EncodedImage> image( |  1078       std::unique_ptr<webrtc::EncodedImage> image( | 
|   988           new webrtc::EncodedImage(payload, payload_size, payload_size)); |  1079           new webrtc::EncodedImage(payload, payload_size, payload_size)); | 
|   989       image->_encodedWidth = width_; |  1080       image->_encodedWidth = width_; | 
|   990       image->_encodedHeight = height_; |  1081       image->_encodedHeight = height_; | 
|   991       image->_timeStamp = output_timestamp_; |  1082       image->_timeStamp = output_timestamp_; | 
|   992       image->capture_time_ms_ = output_render_time_ms_; |  1083       image->capture_time_ms_ = output_render_time_ms_; | 
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1072           } |  1163           } | 
|  1073           scPosition += naluPosition; |  1164           scPosition += naluPosition; | 
|  1074           scPositions[scPositionsLength++] = scPosition; |  1165           scPositions[scPositionsLength++] = scPosition; | 
|  1075           scPosition += H264_SC_LENGTH; |  1166           scPosition += H264_SC_LENGTH; | 
|  1076         } |  1167         } | 
|  1077         if (scPositionsLength == 0) { |  1168         if (scPositionsLength == 0) { | 
|  1078           ALOGE << "Start code is not found!"; |  1169           ALOGE << "Start code is not found!"; | 
|  1079           ALOGE << "Data:" <<  image->_buffer[0] << " " << image->_buffer[1] |  1170           ALOGE << "Data:" <<  image->_buffer[0] << " " << image->_buffer[1] | 
|  1080               << " " << image->_buffer[2] << " " << image->_buffer[3] |  1171               << " " << image->_buffer[2] << " " << image->_buffer[3] | 
|  1081               << " " << image->_buffer[4] << " " << image->_buffer[5]; |  1172               << " " << image->_buffer[4] << " " << image->_buffer[5]; | 
|  1082           ResetCodecOnCodecThread(); |  1173           ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
|  1083           return false; |  1174           return false; | 
|  1084         } |  1175         } | 
|  1085         scPositions[scPositionsLength] = payload_size; |  1176         scPositions[scPositionsLength] = payload_size; | 
|  1086         header.VerifyAndAllocateFragmentationHeader(scPositionsLength); |  1177         header.VerifyAndAllocateFragmentationHeader(scPositionsLength); | 
|  1087         for (size_t i = 0; i < scPositionsLength; i++) { |  1178         for (size_t i = 0; i < scPositionsLength; i++) { | 
|  1088           header.fragmentationOffset[i] = scPositions[i] + H264_SC_LENGTH; |  1179           header.fragmentationOffset[i] = scPositions[i] + H264_SC_LENGTH; | 
|  1089           header.fragmentationLength[i] = |  1180           header.fragmentationLength[i] = | 
|  1090               scPositions[i + 1] - header.fragmentationOffset[i]; |  1181               scPositions[i + 1] - header.fragmentationOffset[i]; | 
|  1091           header.fragmentationPlType[i] = 0; |  1182           header.fragmentationPlType[i] = 0; | 
|  1092           header.fragmentationTimeDiff[i] = 0; |  1183           header.fragmentationTimeDiff[i] = 0; | 
|  1093         } |  1184         } | 
|  1094       } |  1185       } | 
|  1095  |  1186  | 
|  1096       callback_status = callback_->Encoded(*image, &info, &header); |  1187       callback_status = callback_->Encoded(*image, &info, &header); | 
|  1097     } |  1188     } | 
|  1098  |  1189  | 
|  1099     // Return output buffer back to the encoder. |  1190     // Return output buffer back to the encoder. | 
|  1100     bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_, |  1191     bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_, | 
|  1101                                           j_release_output_buffer_method_, |  1192                                           j_release_output_buffer_method_, | 
|  1102                                           output_buffer_index); |  1193                                           output_buffer_index); | 
|  1103     CHECK_EXCEPTION(jni); |  1194     if (CheckException(jni) || !success) { | 
|  1104     if (!success) { |  1195       ProcessHWErrorOnCodecThread(true /* reset_if_fallback_unavailable */); | 
|  1105       ResetCodecOnCodecThread(); |  | 
|  1106       return false; |  1196       return false; | 
|  1107     } |  1197     } | 
|  1108  |  1198  | 
|  1109     // Print per frame statistics. |  1199     // Print per frame statistics. | 
|  1110     if (encoding_start_time_ms > 0) { |  1200     if (encoding_start_time_ms > 0) { | 
|  1111       frame_encoding_time_ms = rtc::TimeMillis() - encoding_start_time_ms; |  1201       frame_encoding_time_ms = rtc::TimeMillis() - encoding_start_time_ms; | 
|  1112     } |  1202     } | 
|  1113     if (frames_encoded_ < kMaxEncodedLogFrames) { |  1203     if (frames_encoded_ < kMaxEncodedLogFrames) { | 
|  1114       int current_latency = |  1204       int current_latency = | 
|  1115           (int)(last_input_timestamp_ms_ - last_output_timestamp_ms_); |  1205           (int)(last_input_timestamp_ms_ - last_output_timestamp_ms_); | 
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1297   return supported_codecs_; |  1387   return supported_codecs_; | 
|  1298 } |  1388 } | 
|  1299  |  1389  | 
|  1300 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( |  1390 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( | 
|  1301     webrtc::VideoEncoder* encoder) { |  1391     webrtc::VideoEncoder* encoder) { | 
|  1302   ALOGD << "Destroy video encoder."; |  1392   ALOGD << "Destroy video encoder."; | 
|  1303   delete encoder; |  1393   delete encoder; | 
|  1304 } |  1394 } | 
|  1305  |  1395  | 
|  1306 }  // namespace webrtc_jni |  1396 }  // namespace webrtc_jni | 
| OLD | NEW |