blob: 23a83141b3853a9ef3c47a002aff9e3d9224359f [file] [log] [blame]
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +02001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/sdk/android/src/jni/videodecoderwrapper.h"
12
13#include "webrtc/api/video/video_frame.h"
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020014#include "webrtc/modules/video_coding/include/video_codec_interface.h"
sakal4dee3442017-08-17 02:18:04 -070015#include "webrtc/modules/video_coding/utility/vp8_header_parser.h"
16#include "webrtc/modules/video_coding/utility/vp9_uncompressed_header_parser.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020017#include "webrtc/rtc_base/logging.h"
sakale172d892017-08-31 02:37:28 -070018#include "webrtc/rtc_base/timeutils.h"
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020019#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
20
magjeda3d4f682017-08-28 16:24:06 -070021namespace webrtc {
22namespace jni {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020023
24VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder)
25 : android_video_buffer_factory_(jni),
26 decoder_(jni, decoder),
27 encoded_image_class_(jni, FindClass(jni, "org/webrtc/EncodedImage")),
28 frame_type_class_(jni,
29 FindClass(jni, "org/webrtc/EncodedImage$FrameType")),
30 settings_class_(jni, FindClass(jni, "org/webrtc/VideoDecoder$Settings")),
31 video_frame_class_(jni, FindClass(jni, "org/webrtc/VideoFrame")),
32 video_codec_status_class_(jni,
33 FindClass(jni, "org/webrtc/VideoCodecStatus")),
34 integer_class_(jni, jni->FindClass("java/lang/Integer")) {
35 encoded_image_constructor_ =
36 jni->GetMethodID(*encoded_image_class_, "<init>",
37 "(Ljava/nio/ByteBuffer;IIJLorg/webrtc/"
38 "EncodedImage$FrameType;IZLjava/lang/Integer;)V");
39 settings_constructor_ =
40 jni->GetMethodID(*settings_class_, "<init>", "(III)V");
41
42 empty_frame_field_ = jni->GetStaticFieldID(
43 *frame_type_class_, "EmptyFrame", "Lorg/webrtc/EncodedImage$FrameType;");
44 video_frame_key_field_ =
45 jni->GetStaticFieldID(*frame_type_class_, "VideoFrameKey",
46 "Lorg/webrtc/EncodedImage$FrameType;");
47 video_frame_delta_field_ =
48 jni->GetStaticFieldID(*frame_type_class_, "VideoFrameDelta",
49 "Lorg/webrtc/EncodedImage$FrameType;");
50
51 video_frame_get_timestamp_ns_method_ =
52 jni->GetMethodID(*video_frame_class_, "getTimestampNs", "()J");
53
54 jclass decoder_class = jni->GetObjectClass(decoder);
55 init_decode_method_ =
56 jni->GetMethodID(decoder_class, "initDecode",
57 "(Lorg/webrtc/VideoDecoder$Settings;Lorg/webrtc/"
58 "VideoDecoder$Callback;)Lorg/webrtc/VideoCodecStatus;");
59 release_method_ = jni->GetMethodID(decoder_class, "release",
60 "()Lorg/webrtc/VideoCodecStatus;");
61 decode_method_ = jni->GetMethodID(decoder_class, "decode",
62 "(Lorg/webrtc/EncodedImage;Lorg/webrtc/"
63 "VideoDecoder$DecodeInfo;)Lorg/webrtc/"
64 "VideoCodecStatus;");
65 get_prefers_late_decoding_method_ =
66 jni->GetMethodID(decoder_class, "getPrefersLateDecoding", "()Z");
67 get_implementation_name_method_ = jni->GetMethodID(
68 decoder_class, "getImplementationName", "()Ljava/lang/String;");
69
70 get_number_method_ =
71 jni->GetMethodID(*video_codec_status_class_, "getNumber", "()I");
72
73 integer_constructor_ = jni->GetMethodID(*integer_class_, "<init>", "(I)V");
74 int_value_method_ = jni->GetMethodID(*integer_class_, "intValue", "()I");
75
76 initialized_ = false;
sakal4dee3442017-08-17 02:18:04 -070077 // QP parsing starts enabled and we disable it if the decoder provides frames.
78 qp_parsing_enabled_ = true;
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020079}
80
magjeda3d4f682017-08-28 16:24:06 -070081int32_t VideoDecoderWrapper::InitDecode(const VideoCodec* codec_settings,
82 int32_t number_of_cores) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020083 JNIEnv* jni = AttachCurrentThreadIfNeeded();
84 ScopedLocalRefFrame local_ref_frame(jni);
85
86 codec_settings_ = *codec_settings;
87 number_of_cores_ = number_of_cores;
88 return InitDecodeInternal(jni);
89}
90
91int32_t VideoDecoderWrapper::InitDecodeInternal(JNIEnv* jni) {
92 jobject settings =
93 jni->NewObject(*settings_class_, settings_constructor_, number_of_cores_,
94 codec_settings_.width, codec_settings_.height);
95
96 jclass callback_class =
97 FindClass(jni, "org/webrtc/VideoDecoderWrapperCallback");
98 jmethodID callback_constructor =
99 jni->GetMethodID(callback_class, "<init>", "(J)V");
100 jobject callback = jni->NewObject(callback_class, callback_constructor,
101 jlongFromPointer(this));
102
103 jobject ret =
104 jni->CallObjectMethod(*decoder_, init_decode_method_, settings, callback);
105 if (jni->CallIntMethod(ret, get_number_method_) == WEBRTC_VIDEO_CODEC_OK) {
106 initialized_ = true;
107 }
sakal4dee3442017-08-17 02:18:04 -0700108
109 // The decoder was reinitialized so re-enable the QP parsing in case it stops
110 // providing QP values.
111 qp_parsing_enabled_ = true;
112
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200113 return HandleReturnCode(jni, ret);
114}
115
116int32_t VideoDecoderWrapper::Decode(
magjeda3d4f682017-08-28 16:24:06 -0700117 const EncodedImage& input_image,
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200118 bool missing_frames,
magjeda3d4f682017-08-28 16:24:06 -0700119 const RTPFragmentationHeader* fragmentation,
120 const CodecSpecificInfo* codec_specific_info,
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200121 int64_t render_time_ms) {
122 if (!initialized_) {
123 // Most likely initializing the codec failed.
124 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
125 }
126
127 JNIEnv* jni = AttachCurrentThreadIfNeeded();
128 ScopedLocalRefFrame local_ref_frame(jni);
129
130 FrameExtraInfo frame_extra_info;
sakale172d892017-08-31 02:37:28 -0700131 frame_extra_info.capture_time_ns =
132 input_image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec;
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200133 frame_extra_info.timestamp_rtp = input_image._timeStamp;
sakal4dee3442017-08-17 02:18:04 -0700134 frame_extra_info.qp =
135 qp_parsing_enabled_ ? ParseQP(input_image) : rtc::Optional<uint8_t>();
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200136 frame_extra_infos_.push_back(frame_extra_info);
137
138 jobject jinput_image =
139 ConvertEncodedImageToJavaEncodedImage(jni, input_image);
140 jobject ret =
141 jni->CallObjectMethod(*decoder_, decode_method_, jinput_image, nullptr);
142 return HandleReturnCode(jni, ret);
143}
144
145int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback(
magjeda3d4f682017-08-28 16:24:06 -0700146 DecodedImageCallback* callback) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200147 callback_ = callback;
148 return WEBRTC_VIDEO_CODEC_OK;
149}
150
151int32_t VideoDecoderWrapper::Release() {
152 JNIEnv* jni = AttachCurrentThreadIfNeeded();
153 ScopedLocalRefFrame local_ref_frame(jni);
154 jobject ret = jni->CallObjectMethod(*decoder_, release_method_);
155 frame_extra_infos_.clear();
156 initialized_ = false;
157 return HandleReturnCode(jni, ret);
158}
159
160bool VideoDecoderWrapper::PrefersLateDecoding() const {
161 JNIEnv* jni = AttachCurrentThreadIfNeeded();
162 return jni->CallBooleanMethod(*decoder_, get_prefers_late_decoding_method_);
163}
164
165const char* VideoDecoderWrapper::ImplementationName() const {
166 JNIEnv* jni = AttachCurrentThreadIfNeeded();
167 ScopedLocalRefFrame local_ref_frame(jni);
168 jstring jname = reinterpret_cast<jstring>(
169 jni->CallObjectMethod(*decoder_, get_implementation_name_method_));
170 return JavaToStdString(jni, jname).c_str();
171}
172
173void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* jni,
174 jobject jframe,
175 jobject jdecode_time_ms,
176 jobject jqp) {
177 const jlong capture_time_ns =
178 jni->CallLongMethod(jframe, video_frame_get_timestamp_ns_method_);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200179 FrameExtraInfo frame_extra_info;
180 do {
181 if (frame_extra_infos_.empty()) {
182 LOG(LS_WARNING) << "Java decoder produced an unexpected frame.";
183 return;
184 }
185
186 frame_extra_info = frame_extra_infos_.front();
187 frame_extra_infos_.pop_front();
188 // If the decoder might drop frames so iterate through the queue until we
189 // find a matching timestamp.
sakale172d892017-08-31 02:37:28 -0700190 } while (frame_extra_info.capture_time_ns != capture_time_ns);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200191
magjeda3d4f682017-08-28 16:24:06 -0700192 VideoFrame frame = android_video_buffer_factory_.CreateFrame(
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200193 jni, jframe, frame_extra_info.timestamp_rtp);
194
195 rtc::Optional<int32_t> decoding_time_ms;
196 if (jdecode_time_ms != nullptr) {
197 decoding_time_ms = rtc::Optional<int32_t>(
198 jni->CallIntMethod(jdecode_time_ms, int_value_method_));
199 }
200
201 rtc::Optional<uint8_t> qp;
202 if (jqp != nullptr) {
203 qp = rtc::Optional<uint8_t>(jni->CallIntMethod(jqp, int_value_method_));
sakal4dee3442017-08-17 02:18:04 -0700204 // The decoder provides QP values itself, no need to parse the bitstream.
205 qp_parsing_enabled_ = false;
206 } else {
207 qp = frame_extra_info.qp;
208 // The decoder doesn't provide QP values, ensure bitstream parsing is
209 // enabled.
210 qp_parsing_enabled_ = true;
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200211 }
212
sakal4dee3442017-08-17 02:18:04 -0700213 callback_->Decoded(frame, decoding_time_ms, qp);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200214}
215
216jobject VideoDecoderWrapper::ConvertEncodedImageToJavaEncodedImage(
217 JNIEnv* jni,
magjeda3d4f682017-08-28 16:24:06 -0700218 const EncodedImage& image) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200219 jobject buffer = jni->NewDirectByteBuffer(image._buffer, image._length);
220 jfieldID frame_type_field;
221 switch (image._frameType) {
magjeda3d4f682017-08-28 16:24:06 -0700222 case kEmptyFrame:
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200223 frame_type_field = empty_frame_field_;
224 break;
magjeda3d4f682017-08-28 16:24:06 -0700225 case kVideoFrameKey:
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200226 frame_type_field = video_frame_key_field_;
227 break;
magjeda3d4f682017-08-28 16:24:06 -0700228 case kVideoFrameDelta:
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200229 frame_type_field = video_frame_delta_field_;
230 break;
231 default:
232 RTC_NOTREACHED();
233 return nullptr;
234 }
235 jobject frame_type =
236 jni->GetStaticObjectField(*frame_type_class_, frame_type_field);
237 jobject qp = nullptr;
238 if (image.qp_ != -1) {
239 qp = jni->NewObject(*integer_class_, integer_constructor_, image.qp_);
240 }
sakale172d892017-08-31 02:37:28 -0700241 return jni->NewObject(
242 *encoded_image_class_, encoded_image_constructor_, buffer,
243 static_cast<jint>(image._encodedWidth),
244 static_cast<jint>(image._encodedHeight),
245 static_cast<jlong>(image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec),
246 frame_type, static_cast<jint>(image.rotation_), image._completeFrame, qp);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200247}
248
249int32_t VideoDecoderWrapper::HandleReturnCode(JNIEnv* jni, jobject code) {
250 int32_t value = jni->CallIntMethod(code, get_number_method_);
251 if (value < 0) { // Any errors are represented by negative values.
252 // Reset the codec.
253 if (Release() == WEBRTC_VIDEO_CODEC_OK) {
254 InitDecodeInternal(jni);
255 }
256
257 LOG(LS_WARNING) << "Falling back to software decoder.";
258 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
259 } else {
260 return value;
261 }
262}
263
sakal4dee3442017-08-17 02:18:04 -0700264rtc::Optional<uint8_t> VideoDecoderWrapper::ParseQP(
magjeda3d4f682017-08-28 16:24:06 -0700265 const EncodedImage& input_image) {
sakal4dee3442017-08-17 02:18:04 -0700266 if (input_image.qp_ != -1) {
267 return rtc::Optional<uint8_t>(input_image.qp_);
268 }
269
270 rtc::Optional<uint8_t> qp;
271 switch (codec_settings_.codecType) {
magjeda3d4f682017-08-28 16:24:06 -0700272 case kVideoCodecVP8: {
sakal4dee3442017-08-17 02:18:04 -0700273 int qp_int;
magjeda3d4f682017-08-28 16:24:06 -0700274 if (vp8::GetQp(input_image._buffer, input_image._length, &qp_int)) {
sakal4dee3442017-08-17 02:18:04 -0700275 qp = rtc::Optional<uint8_t>(qp_int);
276 }
277 break;
278 }
magjeda3d4f682017-08-28 16:24:06 -0700279 case kVideoCodecVP9: {
sakal4dee3442017-08-17 02:18:04 -0700280 int qp_int;
magjeda3d4f682017-08-28 16:24:06 -0700281 if (vp9::GetQp(input_image._buffer, input_image._length, &qp_int)) {
sakal4dee3442017-08-17 02:18:04 -0700282 qp = rtc::Optional<uint8_t>(qp_int);
283 }
284 break;
285 }
magjeda3d4f682017-08-28 16:24:06 -0700286 case kVideoCodecH264: {
sakal4dee3442017-08-17 02:18:04 -0700287 h264_bitstream_parser_.ParseBitstream(input_image._buffer,
288 input_image._length);
289 int qp_int;
290 if (h264_bitstream_parser_.GetLastSliceQp(&qp_int)) {
291 qp = rtc::Optional<uint8_t>(qp_int);
292 }
293 break;
294 }
295 default:
296 break; // Default is to not provide QP.
297 }
298 return qp;
299}
300
magjed09f3f6e2017-08-26 03:25:43 -0700301JNI_FUNCTION_DECLARATION(void,
302 VideoDecoderWrapperCallback_nativeOnDecodedFrame,
303 JNIEnv* jni,
304 jclass,
305 jlong jnative_decoder,
306 jobject jframe,
307 jobject jdecode_time_ms,
308 jobject jqp) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200309 VideoDecoderWrapper* native_decoder =
310 reinterpret_cast<VideoDecoderWrapper*>(jnative_decoder);
311 native_decoder->OnDecodedFrame(jni, jframe, jdecode_time_ms, jqp);
312}
313
magjeda3d4f682017-08-28 16:24:06 -0700314} // namespace jni
315} // namespace webrtc