blob: 6b29c0eefe7e5b217fd57ab7b9422f4dbfa0ecdc [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "sdk/android/src/jni/videodecoderwrapper.h"
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "api/video/video_frame.h"
14#include "modules/video_coding/include/video_codec_interface.h"
15#include "modules/video_coding/utility/vp8_header_parser.h"
16#include "modules/video_coding/utility/vp9_uncompressed_header_parser.h"
17#include "rtc_base/logging.h"
Magnus Jedvert4eb01882017-11-20 22:33:40 +010018#include "sdk/android/generated_video_jni/jni/VideoDecoderWrapper_jni.h"
19#include "sdk/android/generated_video_jni/jni/VideoDecoder_jni.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "sdk/android/src/jni/classreferenceholder.h"
Magnus Jedvert4eb01882017-11-20 22:33:40 +010021#include "sdk/android/src/jni/encodedimage.h"
22#include "sdk/android/src/jni/videocodecstatus.h"
23#include "sdk/android/src/jni/videoframe.h"
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020024
magjeda3d4f682017-08-28 16:24:06 -070025namespace webrtc {
26namespace jni {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020027
Magnus Jedvertcdda0d92017-11-18 14:02:59 +010028namespace {
Sami Kalliomäkice86e292017-11-22 13:20:11 +010029// RTP timestamps are 90 kHz.
30const int64_t kNumRtpTicksPerMillisec = 90000 / rtc::kNumMillisecsPerSec;
31
Magnus Jedvertcdda0d92017-11-18 14:02:59 +010032template <typename Dst, typename Src>
33inline rtc::Optional<Dst> cast_optional(const rtc::Optional<Src>& value) {
34 return value ? rtc::Optional<Dst>(rtc::dchecked_cast<Dst, Src>(*value))
35 : rtc::nullopt;
36}
37} // namespace
38
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020039VideoDecoderWrapper::VideoDecoderWrapper(JNIEnv* jni, jobject decoder)
Magnus Jedvert4eb01882017-11-20 22:33:40 +010040 : decoder_(jni, decoder) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020041 initialized_ = false;
sakal4dee3442017-08-17 02:18:04 -070042 // QP parsing starts enabled and we disable it if the decoder provides frames.
43 qp_parsing_enabled_ = true;
Sami Kalliomäkicee3e532017-10-13 15:20:32 +020044
Magnus Jedvert4eb01882017-11-20 22:33:40 +010045 implementation_name_ = JavaToStdString(
46 jni, Java_VideoDecoder_getImplementationName(jni, decoder));
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020047}
48
magjeda3d4f682017-08-28 16:24:06 -070049int32_t VideoDecoderWrapper::InitDecode(const VideoCodec* codec_settings,
50 int32_t number_of_cores) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020051 JNIEnv* jni = AttachCurrentThreadIfNeeded();
52 ScopedLocalRefFrame local_ref_frame(jni);
53
54 codec_settings_ = *codec_settings;
55 number_of_cores_ = number_of_cores;
56 return InitDecodeInternal(jni);
57}
58
59int32_t VideoDecoderWrapper::InitDecodeInternal(JNIEnv* jni) {
Magnus Jedvert1f2a3e72017-11-23 16:56:44 +010060 jobject settings = Java_Settings_Constructor(
Magnus Jedvert4eb01882017-11-20 22:33:40 +010061 jni, number_of_cores_, codec_settings_.width, codec_settings_.height);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020062
Magnus Jedvert4eb01882017-11-20 22:33:40 +010063 jobject callback = Java_VideoDecoderWrapper_createDecoderCallback(
64 jni, jlongFromPointer(this));
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020065
66 jobject ret =
Magnus Jedvert4eb01882017-11-20 22:33:40 +010067 Java_VideoDecoder_initDecode(jni, *decoder_, settings, callback);
68 if (JavaToNativeVideoCodecStatus(jni, ret) == WEBRTC_VIDEO_CODEC_OK) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020069 initialized_ = true;
70 }
sakal4dee3442017-08-17 02:18:04 -070071
72 // The decoder was reinitialized so re-enable the QP parsing in case it stops
73 // providing QP values.
74 qp_parsing_enabled_ = true;
75
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020076 return HandleReturnCode(jni, ret);
77}
78
79int32_t VideoDecoderWrapper::Decode(
Sami Kalliomäkice86e292017-11-22 13:20:11 +010080 const EncodedImage& image_param,
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020081 bool missing_frames,
magjeda3d4f682017-08-28 16:24:06 -070082 const RTPFragmentationHeader* fragmentation,
83 const CodecSpecificInfo* codec_specific_info,
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020084 int64_t render_time_ms) {
85 if (!initialized_) {
86 // Most likely initializing the codec failed.
87 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
88 }
89
90 JNIEnv* jni = AttachCurrentThreadIfNeeded();
91 ScopedLocalRefFrame local_ref_frame(jni);
92
Sami Kalliomäkice86e292017-11-22 13:20:11 +010093 // Make a mutable copy so we can modify the timestamp.
94 EncodedImage input_image(image_param);
95 // We use RTP timestamp for capture time because capture_time_ms_ is always 0.
96 input_image.capture_time_ms_ =
97 input_image._timeStamp / kNumRtpTicksPerMillisec;
98
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +020099 FrameExtraInfo frame_extra_info;
Sami Kalliomäkice86e292017-11-22 13:20:11 +0100100 frame_extra_info.timestamp_ns =
sakale172d892017-08-31 02:37:28 -0700101 input_image.capture_time_ms_ * rtc::kNumNanosecsPerMillisec;
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200102 frame_extra_info.timestamp_rtp = input_image._timeStamp;
Sami Kalliomäkice86e292017-11-22 13:20:11 +0100103 frame_extra_info.timestamp_ntp = input_image.ntp_time_ms_;
sakal4dee3442017-08-17 02:18:04 -0700104 frame_extra_info.qp =
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100105 qp_parsing_enabled_ ? ParseQP(input_image) : rtc::nullopt;
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200106 frame_extra_infos_.push_back(frame_extra_info);
107
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100108 jobject jinput_image = NativeToJavaEncodedImage(jni, input_image);
109 jobject ret = Java_VideoDecoder_decode(jni, *decoder_, jinput_image, nullptr);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200110 return HandleReturnCode(jni, ret);
111}
112
113int32_t VideoDecoderWrapper::RegisterDecodeCompleteCallback(
magjeda3d4f682017-08-28 16:24:06 -0700114 DecodedImageCallback* callback) {
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200115 callback_ = callback;
116 return WEBRTC_VIDEO_CODEC_OK;
117}
118
119int32_t VideoDecoderWrapper::Release() {
120 JNIEnv* jni = AttachCurrentThreadIfNeeded();
121 ScopedLocalRefFrame local_ref_frame(jni);
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100122 jobject ret = Java_VideoDecoder_release(jni, *decoder_);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200123 frame_extra_infos_.clear();
124 initialized_ = false;
125 return HandleReturnCode(jni, ret);
126}
127
128bool VideoDecoderWrapper::PrefersLateDecoding() const {
129 JNIEnv* jni = AttachCurrentThreadIfNeeded();
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100130 return Java_VideoDecoder_getPrefersLateDecoding(jni, *decoder_);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200131}
132
133const char* VideoDecoderWrapper::ImplementationName() const {
Sami Kalliomäkicee3e532017-10-13 15:20:32 +0200134 return implementation_name_.c_str();
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200135}
136
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100137void VideoDecoderWrapper::OnDecodedFrame(JNIEnv* env,
138 jobject j_caller,
139 jobject j_frame,
140 jobject j_decode_time_ms,
141 jobject j_qp) {
Sami Kalliomäkice86e292017-11-22 13:20:11 +0100142 const uint64_t timestamp_ns = GetJavaVideoFrameTimestampNs(env, j_frame);
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100143
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200144 FrameExtraInfo frame_extra_info;
145 do {
146 if (frame_extra_infos_.empty()) {
Sami Kalliomäkice86e292017-11-22 13:20:11 +0100147 RTC_LOG(LS_WARNING) << "Java decoder produced an unexpected frame: "
148 << timestamp_ns;
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200149 return;
150 }
151
152 frame_extra_info = frame_extra_infos_.front();
153 frame_extra_infos_.pop_front();
154 // If the decoder might drop frames so iterate through the queue until we
155 // find a matching timestamp.
Sami Kalliomäkice86e292017-11-22 13:20:11 +0100156 } while (frame_extra_info.timestamp_ns != timestamp_ns);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200157
Magnus Jedvertc2ac3c62017-11-14 17:08:59 +0100158 VideoFrame frame =
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100159 JavaToNativeFrame(env, j_frame, frame_extra_info.timestamp_rtp);
Sami Kalliomäkice86e292017-11-22 13:20:11 +0100160 frame.set_ntp_time_ms(frame_extra_info.timestamp_ntp);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200161
Magnus Jedvertcdda0d92017-11-18 14:02:59 +0100162 rtc::Optional<int32_t> decoding_time_ms =
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100163 JavaIntegerToOptionalInt(env, j_decode_time_ms);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200164
Magnus Jedvertcdda0d92017-11-18 14:02:59 +0100165 rtc::Optional<uint8_t> decoder_qp =
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100166 cast_optional<uint8_t, int32_t>(JavaIntegerToOptionalInt(env, j_qp));
Magnus Jedvertcdda0d92017-11-18 14:02:59 +0100167 // If the decoder provides QP values itself, no need to parse the bitstream.
168 // Enable QP parsing if decoder does not provide QP values itself.
169 qp_parsing_enabled_ = !decoder_qp.has_value();
170 callback_->Decoded(frame, decoding_time_ms,
171 decoder_qp ? decoder_qp : frame_extra_info.qp);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200172}
173
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200174int32_t VideoDecoderWrapper::HandleReturnCode(JNIEnv* jni, jobject code) {
Magnus Jedvert4eb01882017-11-20 22:33:40 +0100175 int32_t value = JavaToNativeVideoCodecStatus(jni, code);
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200176 if (value < 0) { // Any errors are represented by negative values.
177 // Reset the codec.
178 if (Release() == WEBRTC_VIDEO_CODEC_OK) {
179 InitDecodeInternal(jni);
180 }
181
Mirko Bonadei675513b2017-11-09 11:09:25 +0100182 RTC_LOG(LS_WARNING) << "Falling back to software decoder.";
Sami Kalliomäki93ad1f72017-06-27 10:03:49 +0200183 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
184 } else {
185 return value;
186 }
187}
188
sakal4dee3442017-08-17 02:18:04 -0700189rtc::Optional<uint8_t> VideoDecoderWrapper::ParseQP(
magjeda3d4f682017-08-28 16:24:06 -0700190 const EncodedImage& input_image) {
sakal4dee3442017-08-17 02:18:04 -0700191 if (input_image.qp_ != -1) {
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100192 return input_image.qp_;
sakal4dee3442017-08-17 02:18:04 -0700193 }
194
195 rtc::Optional<uint8_t> qp;
196 switch (codec_settings_.codecType) {
magjeda3d4f682017-08-28 16:24:06 -0700197 case kVideoCodecVP8: {
sakal4dee3442017-08-17 02:18:04 -0700198 int qp_int;
magjeda3d4f682017-08-28 16:24:06 -0700199 if (vp8::GetQp(input_image._buffer, input_image._length, &qp_int)) {
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100200 qp = qp_int;
sakal4dee3442017-08-17 02:18:04 -0700201 }
202 break;
203 }
magjeda3d4f682017-08-28 16:24:06 -0700204 case kVideoCodecVP9: {
sakal4dee3442017-08-17 02:18:04 -0700205 int qp_int;
magjeda3d4f682017-08-28 16:24:06 -0700206 if (vp9::GetQp(input_image._buffer, input_image._length, &qp_int)) {
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100207 qp = qp_int;
sakal4dee3442017-08-17 02:18:04 -0700208 }
209 break;
210 }
magjeda3d4f682017-08-28 16:24:06 -0700211 case kVideoCodecH264: {
sakal4dee3442017-08-17 02:18:04 -0700212 h264_bitstream_parser_.ParseBitstream(input_image._buffer,
213 input_image._length);
214 int qp_int;
215 if (h264_bitstream_parser_.GetLastSliceQp(&qp_int)) {
Oskar Sundbom9ced7e52017-11-16 10:52:24 +0100216 qp = qp_int;
sakal4dee3442017-08-17 02:18:04 -0700217 }
218 break;
219 }
220 default:
221 break; // Default is to not provide QP.
222 }
223 return qp;
224}
225
magjeda3d4f682017-08-28 16:24:06 -0700226} // namespace jni
227} // namespace webrtc