blob: 3e67e5c47cbe7f15bcac028ee98fe8d2c80ea76c [file] [log] [blame]
philipel2fee4d62018-03-21 16:52:13 +01001/*
2 * Copyright (c) 2018 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 "video/video_stream_decoder_impl.h"
12
Karl Wiberg918f50c2018-07-05 11:40:33 +020013#include "absl/memory/memory.h"
philipel97187112018-03-23 10:43:21 +010014#include "rtc_base/logging.h"
philipel844876d2018-04-05 11:02:54 +020015#include "rtc_base/numerics/mod_ops.h"
philipel2fee4d62018-03-21 16:52:13 +010016
17namespace webrtc {
philipel97187112018-03-23 10:43:21 +010018
philipel2fee4d62018-03-21 16:52:13 +010019VideoStreamDecoderImpl::VideoStreamDecoderImpl(
20 VideoStreamDecoder::Callbacks* callbacks,
21 VideoDecoderFactory* decoder_factory,
22 std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings)
23 : callbacks_(callbacks),
24 decoder_factory_(decoder_factory),
philipel97187112018-03-23 10:43:21 +010025 decoder_settings_(std::move(decoder_settings)),
26 bookkeeping_queue_("video_stream_decoder_bookkeeping_queue"),
philipel844876d2018-04-05 11:02:54 +020027 decode_thread_(&DecodeLoop,
28 this,
29 "video_stream_decoder_decode_thread",
30 rtc::kHighestPriority),
philipel97187112018-03-23 10:43:21 +010031 jitter_estimator_(Clock::GetRealTimeClock()),
32 timing_(Clock::GetRealTimeClock()),
33 frame_buffer_(Clock::GetRealTimeClock(),
34 &jitter_estimator_,
35 &timing_,
philipel844876d2018-04-05 11:02:54 +020036 nullptr),
philipel6847f9b2018-04-20 15:05:37 +020037 next_frame_timestamps_index_(0) {
38 frame_timestamps_.fill({-1, -1, -1});
philipel844876d2018-04-05 11:02:54 +020039 decode_thread_.Start();
40}
philipel2fee4d62018-03-21 16:52:13 +010041
philipel97187112018-03-23 10:43:21 +010042VideoStreamDecoderImpl::~VideoStreamDecoderImpl() {
43 frame_buffer_.Stop();
philipel844876d2018-04-05 11:02:54 +020044 decode_thread_.Stop();
philipel97187112018-03-23 10:43:21 +010045}
philipel2fee4d62018-03-21 16:52:13 +010046
47void VideoStreamDecoderImpl::OnFrame(
philipel97187112018-03-23 10:43:21 +010048 std::unique_ptr<video_coding::EncodedFrame> frame) {
49 if (!bookkeeping_queue_.IsCurrent()) {
50 struct OnFrameTask : rtc::QueuedTask {
51 OnFrameTask(std::unique_ptr<video_coding::EncodedFrame> frame,
52 VideoStreamDecoderImpl* video_stream_decoder)
53 : frame_(std::move(frame)),
54 video_stream_decoder_(video_stream_decoder) {}
55
Niels Möllerbe682d42018-03-27 08:31:45 +020056 bool Run() override {
philipel97187112018-03-23 10:43:21 +010057 video_stream_decoder_->OnFrame(std::move(frame_));
58 return true;
59 }
60
61 std::unique_ptr<video_coding::EncodedFrame> frame_;
62 VideoStreamDecoderImpl* video_stream_decoder_;
63 };
64
65 bookkeeping_queue_.PostTask(
Karl Wiberg918f50c2018-07-05 11:40:33 +020066 absl::make_unique<OnFrameTask>(std::move(frame), this));
philipel97187112018-03-23 10:43:21 +010067 return;
68 }
69
70 RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
71
72 uint64_t continuous_pid = frame_buffer_.InsertFrame(std::move(frame));
73 video_coding::VideoLayerFrameId continuous_id(continuous_pid, 0);
74 if (last_continuous_id_ < continuous_id) {
75 last_continuous_id_ = continuous_id;
76 callbacks_->OnContinuousUntil(last_continuous_id_);
77 }
78}
79
philipel79aab3f2018-03-26 14:31:23 +020080VideoDecoder* VideoStreamDecoderImpl::GetDecoder(int payload_type) {
81 if (current_payload_type_ == payload_type) {
82 RTC_DCHECK(decoder_);
83 return decoder_.get();
84 }
85
86 current_payload_type_.reset();
87 decoder_.reset();
88
89 auto decoder_settings_it = decoder_settings_.find(payload_type);
90 if (decoder_settings_it == decoder_settings_.end()) {
91 RTC_LOG(LS_WARNING) << "Payload type " << payload_type
92 << " not registered.";
93 return nullptr;
94 }
95
96 const SdpVideoFormat& video_format = decoder_settings_it->second.first;
97 std::unique_ptr<VideoDecoder> decoder =
98 decoder_factory_->CreateVideoDecoder(video_format);
99 if (!decoder) {
100 RTC_LOG(LS_WARNING) << "Failed to create decoder for payload type "
101 << payload_type << ".";
102 return nullptr;
103 }
104
105 int num_cores = decoder_settings_it->second.second;
106 int32_t init_result = decoder->InitDecode(nullptr, num_cores);
107 if (init_result != WEBRTC_VIDEO_CODEC_OK) {
108 RTC_LOG(LS_WARNING) << "Failed to initialize decoder for payload type "
109 << payload_type << ".";
110 return nullptr;
111 }
112
113 int32_t register_result = decoder->RegisterDecodeCompleteCallback(this);
114 if (register_result != WEBRTC_VIDEO_CODEC_OK) {
115 RTC_LOG(LS_WARNING) << "Failed to register decode callback.";
116 return nullptr;
117 }
118
119 current_payload_type_.emplace(payload_type);
120 decoder_ = std::move(decoder);
121 return decoder_.get();
122}
123
philipel844876d2018-04-05 11:02:54 +0200124// static
125void VideoStreamDecoderImpl::DecodeLoop(void* ptr) {
126 // TODO(philipel): Remove this and use rtc::Event::kForever when it's
127 // supported by the |frame_buffer_|.
128 static constexpr int kForever = 100000000;
129
130 int max_wait_time_ms = kForever;
131 bool keyframe_required = true;
132 auto* vs_decoder = static_cast<VideoStreamDecoderImpl*>(ptr);
133 while (true) {
134 DecodeResult decode_result =
135 vs_decoder->DecodeNextFrame(max_wait_time_ms, keyframe_required);
136
137 switch (decode_result) {
138 case kOk: {
139 max_wait_time_ms = kForever;
140 keyframe_required = false;
141 break;
142 }
143 case kDecodeFailure: {
144 max_wait_time_ms = 0;
145 keyframe_required = true;
146 break;
147 }
148 case kNoFrame: {
149 max_wait_time_ms = kForever;
150 // If we end up here it means that we got a decoding error and there is
151 // no keyframe available in the |frame_buffer_|.
152 vs_decoder->bookkeeping_queue_.PostTask([vs_decoder]() {
153 RTC_DCHECK_RUN_ON(&vs_decoder->bookkeeping_queue_);
154 vs_decoder->callbacks_->OnNonDecodableState();
155 });
156 break;
157 }
158 case kNoDecoder: {
159 max_wait_time_ms = kForever;
160 break;
161 }
162 case kShutdown: {
163 return;
164 }
165 }
166 }
167}
168
169VideoStreamDecoderImpl::DecodeResult VideoStreamDecoderImpl::DecodeNextFrame(
170 int max_wait_time_ms,
171 bool keyframe_required) {
172 std::unique_ptr<video_coding::EncodedFrame> frame;
173 video_coding::FrameBuffer::ReturnReason res =
174 frame_buffer_.NextFrame(max_wait_time_ms, &frame, keyframe_required);
175
176 if (res == video_coding::FrameBuffer::ReturnReason::kStopped)
177 return kShutdown;
178
179 if (frame) {
180 VideoDecoder* decoder = GetDecoder(frame->PayloadType());
181 if (!decoder) {
182 RTC_LOG(LS_WARNING) << "Failed to get decoder, dropping frame ("
183 << frame->id.picture_id << ":"
184 << frame->id.spatial_layer << ").";
185 return kNoDecoder;
186 }
187
188 int64_t decode_start_time_ms = rtc::TimeMillis();
Niels Möller23775882018-08-16 10:24:12 +0200189 int64_t timestamp = frame->Timestamp();
philipel6847f9b2018-04-20 15:05:37 +0200190 int64_t render_time_us = frame->RenderTimeMs() * 1000;
philipel844876d2018-04-05 11:02:54 +0200191 bookkeeping_queue_.PostTask(
philipel6847f9b2018-04-20 15:05:37 +0200192 [this, decode_start_time_ms, timestamp, render_time_us]() {
philipel844876d2018-04-05 11:02:54 +0200193 RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
194 // Saving decode start time this way wont work if we decode spatial
195 // layers sequentially.
philipel6847f9b2018-04-20 15:05:37 +0200196 FrameTimestamps* frame_timestamps =
197 &frame_timestamps_[next_frame_timestamps_index_];
198 frame_timestamps->timestamp = timestamp;
199 frame_timestamps->decode_start_time_ms = decode_start_time_ms;
200 frame_timestamps->render_time_us = render_time_us;
201
202 next_frame_timestamps_index_ =
203 Add<kFrameTimestampsMemory>(next_frame_timestamps_index_, 1);
philipel844876d2018-04-05 11:02:54 +0200204 });
205
Yves Gerey665174f2018-06-19 15:03:05 +0200206 int32_t decode_result = decoder->Decode(frame->EncodedImage(),
207 false, // missing_frame
208 nullptr, // codec specific info
209 frame->RenderTimeMs());
philipel844876d2018-04-05 11:02:54 +0200210
211 return decode_result == WEBRTC_VIDEO_CODEC_OK ? kOk : kDecodeFailure;
212 }
213
214 return kNoFrame;
215}
216
philipel6847f9b2018-04-20 15:05:37 +0200217VideoStreamDecoderImpl::FrameTimestamps*
218VideoStreamDecoderImpl::GetFrameTimestamps(int64_t timestamp) {
219 RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
220
221 int start_time_index = next_frame_timestamps_index_;
222 for (int i = 0; i < kFrameTimestampsMemory; ++i) {
223 start_time_index = Subtract<kFrameTimestampsMemory>(start_time_index, 1);
224
225 if (frame_timestamps_[start_time_index].timestamp == timestamp)
226 return &frame_timestamps_[start_time_index];
227 }
228
229 return nullptr;
230}
231
232// VideoDecoder::DecodedImageCallback
233int32_t VideoStreamDecoderImpl::Decoded(VideoFrame& decoded_image) {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200234 Decoded(decoded_image, absl::nullopt, absl::nullopt);
philipel6847f9b2018-04-20 15:05:37 +0200235 return WEBRTC_VIDEO_CODEC_OK;
236}
237
238// VideoDecoder::DecodedImageCallback
239int32_t VideoStreamDecoderImpl::Decoded(VideoFrame& decoded_image,
240 int64_t decode_time_ms) {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200241 Decoded(decoded_image, decode_time_ms, absl::nullopt);
philipel6847f9b2018-04-20 15:05:37 +0200242 return WEBRTC_VIDEO_CODEC_OK;
243}
244
245// VideoDecoder::DecodedImageCallback
246void VideoStreamDecoderImpl::Decoded(VideoFrame& decoded_image,
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200247 absl::optional<int32_t> decode_time_ms,
248 absl::optional<uint8_t> qp) {
philipel6847f9b2018-04-20 15:05:37 +0200249 int64_t decode_stop_time_ms = rtc::TimeMillis();
250
251 bookkeeping_queue_.PostTask([this, decode_stop_time_ms, decoded_image,
252 decode_time_ms, qp]() {
253 RTC_DCHECK_RUN_ON(&bookkeeping_queue_);
254
255 FrameTimestamps* frame_timestamps =
256 GetFrameTimestamps(decoded_image.timestamp());
257 if (!frame_timestamps) {
258 RTC_LOG(LS_ERROR) << "No frame information found for frame with timestamp"
259 << decoded_image.timestamp();
260 return;
261 }
262
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200263 absl::optional<int> casted_qp;
philipel6847f9b2018-04-20 15:05:37 +0200264 if (qp)
265 casted_qp.emplace(*qp);
266
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200267 absl::optional<int> casted_decode_time_ms(decode_time_ms.value_or(
philipel6847f9b2018-04-20 15:05:37 +0200268 decode_stop_time_ms - frame_timestamps->decode_start_time_ms));
269
270 timing_.StopDecodeTimer(0, *casted_decode_time_ms, decode_stop_time_ms,
271 frame_timestamps->render_time_us / 1000);
272
273 callbacks_->OnDecodedFrame(
274 VideoFrame(decoded_image.video_frame_buffer(), decoded_image.rotation(),
275 frame_timestamps->render_time_us),
276 casted_decode_time_ms, casted_qp);
277 });
278}
279
philipel2fee4d62018-03-21 16:52:13 +0100280} // namespace webrtc