Chromium Code Reviews| 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_enabled_ = true; | |
|
kthelgason
2017/08/16 13:57:58
It's quite unclear what this depends on, can we tr
sakal
2017/08/16 14:47:07
I added comments.
| |
| 73 } | 76 } |
| 74 | 77 |
| 75 int32_t VideoDecoderWrapper::InitDecode( | 78 int32_t VideoDecoderWrapper::InitDecode( |
| 76 const webrtc::VideoCodec* codec_settings, | 79 const webrtc::VideoCodec* codec_settings, |
| 77 int32_t number_of_cores) { | 80 int32_t number_of_cores) { |
| 78 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 81 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
| 79 ScopedLocalRefFrame local_ref_frame(jni); | 82 ScopedLocalRefFrame local_ref_frame(jni); |
| 80 | 83 |
| 81 codec_settings_ = *codec_settings; | 84 codec_settings_ = *codec_settings; |
| 82 number_of_cores_ = number_of_cores; | 85 number_of_cores_ = number_of_cores; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 93 jmethodID callback_constructor = | 96 jmethodID callback_constructor = |
| 94 jni->GetMethodID(callback_class, "<init>", "(J)V"); | 97 jni->GetMethodID(callback_class, "<init>", "(J)V"); |
| 95 jobject callback = jni->NewObject(callback_class, callback_constructor, | 98 jobject callback = jni->NewObject(callback_class, callback_constructor, |
| 96 jlongFromPointer(this)); | 99 jlongFromPointer(this)); |
| 97 | 100 |
| 98 jobject ret = | 101 jobject ret = |
| 99 jni->CallObjectMethod(*decoder_, init_decode_method_, settings, callback); | 102 jni->CallObjectMethod(*decoder_, init_decode_method_, settings, callback); |
| 100 if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) { | 103 if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) { |
| 101 initialized_ = true; | 104 initialized_ = true; |
| 102 } | 105 } |
| 106 | |
| 107 qp_parsing_enabled_ = true; | |
| 108 | |
| 103 return HandleReturnCode(jni, ret); | 109 return HandleReturnCode(jni, ret); |
| 104 } | 110 } |
| 105 | 111 |
| 106 int32_t VideoDecoderWrapper::Decode( | 112 int32_t VideoDecoderWrapper::Decode( |
| 107 const webrtc::EncodedImage& input_image, | 113 const webrtc::EncodedImage& input_image, |
| 108 bool missing_frames, | 114 bool missing_frames, |
| 109 const webrtc::RTPFragmentationHeader* fragmentation, | 115 const webrtc::RTPFragmentationHeader* fragmentation, |
| 110 const webrtc::CodecSpecificInfo* codec_specific_info, | 116 const webrtc::CodecSpecificInfo* codec_specific_info, |
| 111 int64_t render_time_ms) { | 117 int64_t render_time_ms) { |
| 112 if (!initialized_) { | 118 if (!initialized_) { |
| 113 // Most likely initializing the codec failed. | 119 // Most likely initializing the codec failed. |
| 114 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 120 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
| 115 } | 121 } |
| 116 | 122 |
| 117 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 123 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
| 118 ScopedLocalRefFrame local_ref_frame(jni); | 124 ScopedLocalRefFrame local_ref_frame(jni); |
| 119 | 125 |
| 120 FrameExtraInfo frame_extra_info; | 126 FrameExtraInfo frame_extra_info; |
| 121 frame_extra_info.capture_time_ms = input_image.capture_time_ms_; | 127 frame_extra_info.capture_time_ms = input_image.capture_time_ms_; |
| 122 frame_extra_info.timestamp_rtp = input_image._timeStamp; | 128 frame_extra_info.timestamp_rtp = input_image._timeStamp; |
| 129 frame_extra_info.qp = | |
| 130 qp_parsing_enabled_ ? ParseQP(input_image) : rtc::Optional<uint8_t>(); | |
| 123 frame_extra_infos_.push_back(frame_extra_info); | 131 frame_extra_infos_.push_back(frame_extra_info); |
| 124 | 132 |
| 125 jobject jinput_image = | 133 jobject jinput_image = |
| 126 ConvertEncodedImageToJavaEncodedImage(jni, input_image); | 134 ConvertEncodedImageToJavaEncodedImage(jni, input_image); |
| 127 jobject ret = | 135 jobject ret = |
| 128 jni->CallObjectMethod(*decoder_, decode_method_, jinput_image, nullptr); | 136 jni->CallObjectMethod(*decoder_, decode_method_, jinput_image, nullptr); |
| 129 return HandleReturnCode(jni, ret); | 137 return HandleReturnCode(jni, ret); |
| 130 } | 138 } |
| 131 | 139 |
| 132 int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback( | 140 int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback( |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 182 | 190 |
| 183 rtc::Optional<int32_t> decoding_time_ms; | 191 rtc::Optional<int32_t> decoding_time_ms; |
| 184 if (jdecode_time_ms != nullptr) { | 192 if (jdecode_time_ms != nullptr) { |
| 185 decoding_time_ms = rtc::Optional<int32_t>( | 193 decoding_time_ms = rtc::Optional<int32_t>( |
| 186 jni->CallIntMethod(jdecode_time_ms, int_value_method_)); | 194 jni->CallIntMethod(jdecode_time_ms, int_value_method_)); |
| 187 } | 195 } |
| 188 | 196 |
| 189 rtc::Optional<uint8_t> qp; | 197 rtc::Optional<uint8_t> qp; |
| 190 if (jqp != nullptr) { | 198 if (jqp != nullptr) { |
| 191 qp = rtc::Optional<uint8_t>(jni->CallIntMethod(jqp, int_value_method_)); | 199 qp = rtc::Optional<uint8_t>(jni->CallIntMethod(jqp, int_value_method_)); |
| 200 qp_parsing_enabled_ = false; | |
| 201 } else { | |
| 202 qp = frame_extra_info.qp; | |
| 203 qp_parsing_enabled_ = true; | |
| 192 } | 204 } |
| 193 | 205 |
| 194 callback_->Decoded(frame, decoding_time_ms, rtc::Optional<uint8_t>()); | 206 callback_->Decoded(frame, decoding_time_ms, qp); |
| 195 } | 207 } |
| 196 | 208 |
| 197 jobject VideoDecoderWrapper::ConvertEncodedImageToJavaEncodedImage( | 209 jobject VideoDecoderWrapper::ConvertEncodedImageToJavaEncodedImage( |
| 198 JNIEnv* jni, | 210 JNIEnv* jni, |
| 199 const webrtc::EncodedImage& image) { | 211 const webrtc::EncodedImage& image) { |
| 200 jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length); | 212 jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length); |
| 201 jfieldID frame_type_field; | 213 jfieldID frame_type_field; |
| 202 switch (image._frameType) { | 214 switch (image._frameType) { |
| 203 case webrtc::kEmptyFrame: | 215 case webrtc::kEmptyFrame: |
| 204 frame_type_field = empty_frame_field_; | 216 frame_type_field = empty_frame_field_; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 235 InitDecodeInternal(jni); | 247 InitDecodeInternal(jni); |
| 236 } | 248 } |
| 237 | 249 |
| 238 LOG(LS_WARNING) << "Falling back to software decoder."; | 250 LOG(LS_WARNING) << "Falling back to software decoder."; |
| 239 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 251 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
| 240 } else { | 252 } else { |
| 241 return value; | 253 return value; |
| 242 } | 254 } |
| 243 } | 255 } |
| 244 | 256 |
| 257 rtc::Optional<uint8_t> VideoDecoderWrapper::ParseQP( | |
| 258 const webrtc::EncodedImage& input_image) { | |
| 259 if (input_image.qp_ != -1) { | |
| 260 return rtc::Optional<uint8_t>(input_image.qp_); | |
| 261 } | |
| 262 | |
| 263 rtc::Optional<uint8_t> qp; | |
| 264 switch (codec_settings_.codecType) { | |
| 265 case webrtc::kVideoCodecVP8: { | |
| 266 int qp_int; | |
| 267 if (webrtc::vp8::GetQp(input_image._buffer, input_image._length, | |
| 268 &qp_int)) { | |
| 269 qp = rtc::Optional<uint8_t>(qp_int); | |
| 270 } | |
| 271 break; | |
| 272 } | |
| 273 case webrtc::kVideoCodecVP9: { | |
| 274 int qp_int; | |
| 275 if (webrtc::vp9::GetQp(input_image._buffer, input_image._length, | |
| 276 &qp_int)) { | |
| 277 qp = rtc::Optional<uint8_t>(qp_int); | |
| 278 } | |
| 279 break; | |
| 280 } | |
| 281 case webrtc::kVideoCodecH264: { | |
| 282 h264_bitstream_parser_.ParseBitstream(input_image._buffer, | |
| 283 input_image._length); | |
| 284 int qp_int; | |
| 285 if (h264_bitstream_parser_.GetLastSliceQp(&qp_int)) { | |
| 286 qp = rtc::Optional<uint8_t>(qp_int); | |
| 287 } | |
| 288 break; | |
| 289 } | |
| 290 default: | |
| 291 break; // Default is to not provide QP. | |
| 292 } | |
| 293 return qp; | |
| 294 } | |
| 295 | |
| 245 JOW(void, VideoDecoderWrapperCallback_nativeOnDecodedFrame) | 296 JOW(void, VideoDecoderWrapperCallback_nativeOnDecodedFrame) |
| 246 (JNIEnv* jni, | 297 (JNIEnv* jni, |
| 247 jclass, | 298 jclass, |
| 248 jlong jnative_decoder, | 299 jlong jnative_decoder, |
| 249 jobject jframe, | 300 jobject jframe, |
| 250 jobject jdecode_time_ms, | 301 jobject jdecode_time_ms, |
| 251 jobject jqp) { | 302 jobject jqp) { |
| 252 VideoDecoderWrapper* native_decoder = | 303 VideoDecoderWrapper* native_decoder = |
| 253 reinterpret_cast<VideoDecoderWrapper*>(jnative_decoder); | 304 reinterpret_cast<VideoDecoderWrapper*>(jnative_decoder); |
| 254 native_decoder->OnDecodedFrame(jni, jframe, jdecode_time_ms, jqp); | 305 native_decoder->OnDecodedFrame(jni, jframe, jdecode_time_ms, jqp); |
| 255 } | 306 } |
| 256 | 307 |
| 257 } // namespace webrtc_jni | 308 } // namespace webrtc_jni |
| OLD | NEW |