| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2017 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 |
| 11 #include "webrtc/sdk/android/src/jni/videodecoderwrapper.h" | 11 #include "webrtc/sdk/android/src/jni/videodecoderwrapper.h" |
| 12 | 12 |
| 13 #include "webrtc/api/video/video_frame.h" | 13 #include "webrtc/api/video/video_frame.h" |
| 14 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 14 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 15 #include "webrtc/modules/video_coding/utility/vp8_header_parser.h" |
| 16 #include "webrtc/modules/video_coding/utility/vp9_uncompressed_header_parser.h" |
| 15 #include "webrtc/rtc_base/logging.h" | 17 #include "webrtc/rtc_base/logging.h" |
| 16 #include "webrtc/sdk/android/src/jni/classreferenceholder.h" | 18 #include "webrtc/sdk/android/src/jni/classreferenceholder.h" |
| 17 | 19 |
| 18 namespace webrtc_jni { | 20 namespace webrtc_jni { |
| 19 | 21 |
| 20 VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder) | 22 VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder) |
| 21 : android_video_buffer_factory_(jni), | 23 : android_video_buffer_factory_(jni), |
| 22 decoder_(jni, decoder), | 24 decoder_(jni, decoder), |
| 23 encoded_image_class_(jni, FindClass(jni, "org/webrtc/EncodedImage")), | 25 encoded_image_class_(jni, FindClass(jni, "org/webrtc/EncodedImage")), |
| 24 frame_type_class_(jni, | 26 frame_type_class_(jni, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 get_implementation_name_method_ = jni->GetMethodID( | 65 get_implementation_name_method_ = jni->GetMethodID( |
| 64 decoder_class, "getImplementationName", "()Ljava/lang/String;"); | 66 decoder_class, "getImplementationName", "()Ljava/lang/String;"); |
| 65 | 67 |
| 66 get_number_method_ = | 68 get_number_method_ = |
| 67 jni->GetMethodID(*video_codec_status_class_, "getNumber", "()I"); | 69 jni->GetMethodID(*video_codec_status_class_, "getNumber", "()I"); |
| 68 | 70 |
| 69 integer_constructor_ = jni->GetMethodID(*integer_class_, "<init>", "(I)V"); | 71 integer_constructor_ = jni->GetMethodID(*integer_class_, "<init>", "(I)V"); |
| 70 int_value_method_ = jni->GetMethodID(*integer_class_, "intValue", "()I"); | 72 int_value_method_ = jni->GetMethodID(*integer_class_, "intValue", "()I"); |
| 71 | 73 |
| 72 initialized_ = false; | 74 initialized_ = false; |
| 75 // QP parsing starts enabled and we disable it if the decoder provides frames. |
| 76 qp_parsing_enabled_ = true; |
| 73 } | 77 } |
| 74 | 78 |
| 75 int32_t VideoDecoderWrapper::InitDecode( | 79 int32_t VideoDecoderWrapper::InitDecode( |
| 76 const webrtc::VideoCodec* codec_settings, | 80 const webrtc::VideoCodec* codec_settings, |
| 77 int32_t number_of_cores) { | 81 int32_t number_of_cores) { |
| 78 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 82 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
| 79 ScopedLocalRefFrame local_ref_frame(jni); | 83 ScopedLocalRefFrame local_ref_frame(jni); |
| 80 | 84 |
| 81 codec_settings_ = *codec_settings; | 85 codec_settings_ = *codec_settings; |
| 82 number_of_cores_ = number_of_cores; | 86 number_of_cores_ = number_of_cores; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 93 jmethodID callback_constructor = | 97 jmethodID callback_constructor = |
| 94 jni->GetMethodID(callback_class, "<init>", "(J)V"); | 98 jni->GetMethodID(callback_class, "<init>", "(J)V"); |
| 95 jobject callback = jni->NewObject(callback_class, callback_constructor, | 99 jobject callback = jni->NewObject(callback_class, callback_constructor, |
| 96 jlongFromPointer(this)); | 100 jlongFromPointer(this)); |
| 97 | 101 |
| 98 jobject ret = | 102 jobject ret = |
| 99 jni->CallObjectMethod(*decoder_, init_decode_method_, settings, callback); | 103 jni->CallObjectMethod(*decoder_, init_decode_method_, settings, callback); |
| 100 if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) { | 104 if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) { |
| 101 initialized_ = true; | 105 initialized_ = true; |
| 102 } | 106 } |
| 107 |
| 108 // The decoder was reinitialized so re-enable the QP parsing in case it stops |
| 109 // providing QP values. |
| 110 qp_parsing_enabled_ = true; |
| 111 |
| 103 return HandleReturnCode(jni, ret); | 112 return HandleReturnCode(jni, ret); |
| 104 } | 113 } |
| 105 | 114 |
| 106 int32_t VideoDecoderWrapper::Decode( | 115 int32_t VideoDecoderWrapper::Decode( |
| 107 const webrtc::EncodedImage& input_image, | 116 const webrtc::EncodedImage& input_image, |
| 108 bool missing_frames, | 117 bool missing_frames, |
| 109 const webrtc::RTPFragmentationHeader* fragmentation, | 118 const webrtc::RTPFragmentationHeader* fragmentation, |
| 110 const webrtc::CodecSpecificInfo* codec_specific_info, | 119 const webrtc::CodecSpecificInfo* codec_specific_info, |
| 111 int64_t render_time_ms) { | 120 int64_t render_time_ms) { |
| 112 if (!initialized_) { | 121 if (!initialized_) { |
| 113 // Most likely initializing the codec failed. | 122 // Most likely initializing the codec failed. |
| 114 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 123 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
| 115 } | 124 } |
| 116 | 125 |
| 117 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 126 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
| 118 ScopedLocalRefFrame local_ref_frame(jni); | 127 ScopedLocalRefFrame local_ref_frame(jni); |
| 119 | 128 |
| 120 FrameExtraInfo frame_extra_info; | 129 FrameExtraInfo frame_extra_info; |
| 121 frame_extra_info.capture_time_ms = input_image.capture_time_ms_; | 130 frame_extra_info.capture_time_ms = input_image.capture_time_ms_; |
| 122 frame_extra_info.timestamp_rtp = input_image._timeStamp; | 131 frame_extra_info.timestamp_rtp = input_image._timeStamp; |
| 132 frame_extra_info.qp = |
| 133 qp_parsing_enabled_ ? ParseQP(input_image) : rtc::Optional<uint8_t>(); |
| 123 frame_extra_infos_.push_back(frame_extra_info); | 134 frame_extra_infos_.push_back(frame_extra_info); |
| 124 | 135 |
| 125 jobject jinput_image = | 136 jobject jinput_image = |
| 126 ConvertEncodedImageToJavaEncodedImage(jni, input_image); | 137 ConvertEncodedImageToJavaEncodedImage(jni, input_image); |
| 127 jobject ret = | 138 jobject ret = |
| 128 jni->CallObjectMethod(*decoder_, decode_method_, jinput_image, nullptr); | 139 jni->CallObjectMethod(*decoder_, decode_method_, jinput_image, nullptr); |
| 129 return HandleReturnCode(jni, ret); | 140 return HandleReturnCode(jni, ret); |
| 130 } | 141 } |
| 131 | 142 |
| 132 int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback( | 143 int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback( |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 | 193 |
| 183 rtc::Optional<int32_t> decoding_time_ms; | 194 rtc::Optional<int32_t> decoding_time_ms; |
| 184 if (jdecode_time_ms != nullptr) { | 195 if (jdecode_time_ms != nullptr) { |
| 185 decoding_time_ms = rtc::Optional<int32_t>( | 196 decoding_time_ms = rtc::Optional<int32_t>( |
| 186 jni->CallIntMethod(jdecode_time_ms, int_value_method_)); | 197 jni->CallIntMethod(jdecode_time_ms, int_value_method_)); |
| 187 } | 198 } |
| 188 | 199 |
| 189 rtc::Optional<uint8_t> qp; | 200 rtc::Optional<uint8_t> qp; |
| 190 if (jqp != nullptr) { | 201 if (jqp != nullptr) { |
| 191 qp = rtc::Optional<uint8_t>(jni->CallIntMethod(jqp, int_value_method_)); | 202 qp = rtc::Optional<uint8_t>(jni->CallIntMethod(jqp, int_value_method_)); |
| 203 // The decoder provides QP values itself, no need to parse the bitstream. |
| 204 qp_parsing_enabled_ = false; |
| 205 } else { |
| 206 qp = frame_extra_info.qp; |
| 207 // The decoder doesn't provide QP values, ensure bitstream parsing is |
| 208 // enabled. |
| 209 qp_parsing_enabled_ = true; |
| 192 } | 210 } |
| 193 | 211 |
| 194 callback_->Decoded(frame, decoding_time_ms, rtc::Optional<uint8_t>()); | 212 callback_->Decoded(frame, decoding_time_ms, qp); |
| 195 } | 213 } |
| 196 | 214 |
| 197 jobject VideoDecoderWrapper::ConvertEncodedImageToJavaEncodedImage( | 215 jobject VideoDecoderWrapper::ConvertEncodedImageToJavaEncodedImage( |
| 198 JNIEnv* jni, | 216 JNIEnv* jni, |
| 199 const webrtc::EncodedImage& image) { | 217 const webrtc::EncodedImage& image) { |
| 200 jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length); | 218 jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length); |
| 201 jfieldID frame_type_field; | 219 jfieldID frame_type_field; |
| 202 switch (image._frameType) { | 220 switch (image._frameType) { |
| 203 case webrtc::kEmptyFrame: | 221 case webrtc::kEmptyFrame: |
| 204 frame_type_field = empty_frame_field_; | 222 frame_type_field = empty_frame_field_; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 235 InitDecodeInternal(jni); | 253 InitDecodeInternal(jni); |
| 236 } | 254 } |
| 237 | 255 |
| 238 LOG(LS_WARNING) << "Falling back to software decoder."; | 256 LOG(LS_WARNING) << "Falling back to software decoder."; |
| 239 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 257 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
| 240 } else { | 258 } else { |
| 241 return value; | 259 return value; |
| 242 } | 260 } |
| 243 } | 261 } |
| 244 | 262 |
| 263 rtc::Optional<uint8_t> VideoDecoderWrapper::ParseQP( |
| 264 const webrtc::EncodedImage& input_image) { |
| 265 if (input_image.qp_ != -1) { |
| 266 return rtc::Optional<uint8_t>(input_image.qp_); |
| 267 } |
| 268 |
| 269 rtc::Optional<uint8_t> qp; |
| 270 switch (codec_settings_.codecType) { |
| 271 case webrtc::kVideoCodecVP8: { |
| 272 int qp_int; |
| 273 if (webrtc::vp8::GetQp(input_image._buffer, input_image._length, |
| 274 &qp_int)) { |
| 275 qp = rtc::Optional<uint8_t>(qp_int); |
| 276 } |
| 277 break; |
| 278 } |
| 279 case webrtc::kVideoCodecVP9: { |
| 280 int qp_int; |
| 281 if (webrtc::vp9::GetQp(input_image._buffer, input_image._length, |
| 282 &qp_int)) { |
| 283 qp = rtc::Optional<uint8_t>(qp_int); |
| 284 } |
| 285 break; |
| 286 } |
| 287 case webrtc::kVideoCodecH264: { |
| 288 h264_bitstream_parser_.ParseBitstream(input_image._buffer, |
| 289 input_image._length); |
| 290 int qp_int; |
| 291 if (h264_bitstream_parser_.GetLastSliceQp(&qp_int)) { |
| 292 qp = rtc::Optional<uint8_t>(qp_int); |
| 293 } |
| 294 break; |
| 295 } |
| 296 default: |
| 297 break; // Default is to not provide QP. |
| 298 } |
| 299 return qp; |
| 300 } |
| 301 |
| 245 JOW(void, VideoDecoderWrapperCallback_nativeOnDecodedFrame) | 302 JOW(void, VideoDecoderWrapperCallback_nativeOnDecodedFrame) |
| 246 (JNIEnv* jni, | 303 (JNIEnv* jni, |
| 247 jclass, | 304 jclass, |
| 248 jlong jnative_decoder, | 305 jlong jnative_decoder, |
| 249 jobject jframe, | 306 jobject jframe, |
| 250 jobject jdecode_time_ms, | 307 jobject jdecode_time_ms, |
| 251 jobject jqp) { | 308 jobject jqp) { |
| 252 VideoDecoderWrapper* native_decoder = | 309 VideoDecoderWrapper* native_decoder = |
| 253 reinterpret_cast<VideoDecoderWrapper*>(jnative_decoder); | 310 reinterpret_cast<VideoDecoderWrapper*>(jnative_decoder); |
| 254 native_decoder->OnDecodedFrame(jni, jframe, jdecode_time_ms, jqp); | 311 native_decoder->OnDecodedFrame(jni, jframe, jdecode_time_ms, jqp); |
| 255 } | 312 } |
| 256 | 313 |
| 257 } // namespace webrtc_jni | 314 } // namespace webrtc_jni |
| OLD | NEW |