1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/standalone_sender/simulated_capturer.h"
6
7 #include <algorithm>
8 #include <chrono>
9 #include <ratio>
10 #include <sstream>
11 #include <thread>
12
13 #include "cast/streaming/environment.h"
14 #include "util/osp_logging.h"
15
16 namespace openscreen {
17 namespace cast {
18
19 using openscreen::operator<<; // To pretty-print chrono values.
20
21 namespace {
22 // Threshold at which a warning about media pausing should be logged.
23 constexpr std::chrono::seconds kPauseWarningThreshold{3};
24 } // namespace
25
26 SimulatedCapturer::Observer::~Observer() = default;
27
SimulatedCapturer(Environment * environment,const char * path,AVMediaType media_type,Clock::time_point start_time,Observer * observer)28 SimulatedCapturer::SimulatedCapturer(Environment* environment,
29 const char* path,
30 AVMediaType media_type,
31 Clock::time_point start_time,
32 Observer* observer)
33 : format_context_(MakeUniqueAVFormatContext(path)),
34 media_type_(media_type),
35 start_time_(start_time),
36 observer_(observer),
37 packet_(MakeUniqueAVPacket()),
38 decoded_frame_(MakeUniqueAVFrame()),
39 next_task_(environment->now_function(), environment->task_runner()) {
40 OSP_DCHECK(observer_);
41
42 if (!format_context_) {
43 OnError("MakeUniqueAVFormatContext", AVERROR_UNKNOWN);
44 return; // Capturer is halted (unable to start).
45 }
46
47 AVCodec* codec;
48 const int stream_result = av_find_best_stream(format_context_.get(),
49 media_type_, -1, -1, &codec, 0);
50 if (stream_result < 0) {
51 OnError("av_find_best_stream", stream_result);
52 return; // Capturer is halted (unable to start).
53 }
54
55 stream_index_ = stream_result;
56 decoder_context_ = MakeUniqueAVCodecContext(codec);
57 if (!decoder_context_) {
58 OnError("MakeUniqueAVCodecContext", AVERROR_BUG);
59 return; // Capturer is halted (unable to start).
60 }
61 // This should also be 16 or less, since the encoder implementations emit
62 // warnings about too many encode threads. FFMPEG's VP8 implementation
63 // actually silently freezes if this is 10 or more. Thus, 8 is used for the
64 // max here, just to be safe.
65 decoder_context_->thread_count =
66 std::min(std::max<int>(std::thread::hardware_concurrency(), 1), 8);
67 const int params_result = avcodec_parameters_to_context(
68 decoder_context_.get(),
69 format_context_->streams[stream_index_]->codecpar);
70 if (params_result < 0) {
71 OnError("avcodec_parameters_to_context", params_result);
72 return; // Capturer is halted (unable to start).
73 }
74 SetAdditionalDecoderParameters(decoder_context_.get());
75
76 const int open_result = avcodec_open2(decoder_context_.get(), codec, nullptr);
77 if (open_result < 0) {
78 OnError("avcodec_open2", open_result);
79 return; // Capturer is halted (unable to start).
80 }
81
82 next_task_.Schedule([this] { StartDecodingNextFrame(); },
83 Alarm::kImmediately);
84 }
85
86 SimulatedCapturer::~SimulatedCapturer() = default;
87
SetPlaybackRate(double rate)88 void SimulatedCapturer::SetPlaybackRate(double rate) {
89 playback_rate_is_non_zero_ = rate > 0;
90 if (playback_rate_is_non_zero_) {
91 // Restart playback now that playback rate is nonzero.
92 StartDecodingNextFrame();
93 }
94 }
95
SetAdditionalDecoderParameters(AVCodecContext * decoder_context)96 void SimulatedCapturer::SetAdditionalDecoderParameters(
97 AVCodecContext* decoder_context) {}
98
ProcessDecodedFrame(const AVFrame & frame)99 absl::optional<Clock::duration> SimulatedCapturer::ProcessDecodedFrame(
100 const AVFrame& frame) {
101 return Clock::duration::zero();
102 }
103
OnError(const char * function_name,int av_errnum)104 void SimulatedCapturer::OnError(const char* function_name, int av_errnum) {
105 // Make a human-readable string from the libavcodec error.
106 std::ostringstream error;
107 error << "For " << av_get_media_type_string(media_type_) << ", "
108 << function_name << " returned error: " << av_err2str(av_errnum);
109
110 // Deliver the error notification in a separate task since this method might
111 // have been called from the constructor.
112 next_task_.Schedule(
113 [this, error_string = error.str()] {
114 observer_->OnError(this, error_string);
115 // Capturer is now halted.
116 },
117 Alarm::kImmediately);
118 }
119
120 // static
ToApproximateClockDuration(int64_t ticks,const AVRational & time_base)121 Clock::duration SimulatedCapturer::ToApproximateClockDuration(
122 int64_t ticks,
123 const AVRational& time_base) {
124 return Clock::duration(av_rescale_q(
125 ticks, time_base,
126 AVRational{Clock::duration::period::num, Clock::duration::period::den}));
127 }
128
StartDecodingNextFrame()129 void SimulatedCapturer::StartDecodingNextFrame() {
130 if (!playback_rate_is_non_zero_) {
131 return;
132 }
133 const int read_frame_result =
134 av_read_frame(format_context_.get(), packet_.get());
135 if (read_frame_result < 0) {
136 if (read_frame_result == AVERROR_EOF) {
137 // Insert a "flush request" into the decoder's pipeline, which will
138 // signal an EOF in ConsumeNextDecodedFrame() later.
139 avcodec_send_packet(decoder_context_.get(), nullptr);
140 next_task_.Schedule([this] { ConsumeNextDecodedFrame(); },
141 Alarm::kImmediately);
142 } else {
143 // All other error codes are fatal.
144 OnError("av_read_frame", read_frame_result);
145 // Capturer is now halted.
146 }
147 return;
148 }
149
150 if (packet_->stream_index != stream_index_) {
151 av_packet_unref(packet_.get());
152 next_task_.Schedule([this] { StartDecodingNextFrame(); },
153 Alarm::kImmediately);
154 return;
155 }
156
157 const int send_packet_result =
158 avcodec_send_packet(decoder_context_.get(), packet_.get());
159 av_packet_unref(packet_.get());
160 if (send_packet_result < 0) {
161 // Note: AVERROR(EAGAIN) is also treated as fatal here because
162 // avcodec_receive_frame() will be called repeatedly until its result code
163 // indicates avcodec_send_packet() must be called again.
164 OnError("avcodec_send_packet", send_packet_result);
165 return; // Capturer is now halted.
166 }
167
168 next_task_.Schedule([this] { ConsumeNextDecodedFrame(); },
169 Alarm::kImmediately);
170 }
171
ConsumeNextDecodedFrame()172 void SimulatedCapturer::ConsumeNextDecodedFrame() {
173 const int receive_frame_result =
174 avcodec_receive_frame(decoder_context_.get(), decoded_frame_.get());
175 if (receive_frame_result < 0) {
176 switch (receive_frame_result) {
177 case AVERROR(EAGAIN):
178 // This result code, according to libavcodec documentation, means more
179 // data should be fed into the decoder (e.g., interframe dependencies).
180 next_task_.Schedule([this] { StartDecodingNextFrame(); },
181 Alarm::kImmediately);
182 return;
183 case AVERROR_EOF:
184 observer_->OnEndOfFile(this);
185 return; // Capturer is now halted.
186 default:
187 OnError("avcodec_receive_frame", receive_frame_result);
188 return; // Capturer is now halted.
189 }
190 }
191
192 const Clock::duration frame_timestamp = ToApproximateClockDuration(
193 decoded_frame_->best_effort_timestamp,
194 format_context_->streams[stream_index_]->time_base);
195 if (last_frame_timestamp_) {
196 const Clock::duration delta = frame_timestamp - *last_frame_timestamp_;
197 if (delta <= Clock::duration::zero()) {
198 OSP_LOG_WARN << "Dropping " << av_get_media_type_string(media_type_)
199 << " frame with illegal timestamp (delta from last frame: "
200 << delta << "). Bad media file!";
201 av_frame_unref(decoded_frame_.get());
202 next_task_.Schedule([this] { ConsumeNextDecodedFrame(); },
203 Alarm::kImmediately);
204 return;
205 } else if (delta >= kPauseWarningThreshold) {
206 OSP_LOG_INFO << "For " << av_get_media_type_string(media_type_)
207 << ", encountered a media pause (" << delta
208 << ") in the file.";
209 }
210 }
211 last_frame_timestamp_ = frame_timestamp;
212
213 Clock::time_point capture_time = start_time_ + frame_timestamp;
214 const auto delay_adjustment_or_null = ProcessDecodedFrame(*decoded_frame_);
215 if (!delay_adjustment_or_null) {
216 av_frame_unref(decoded_frame_.get());
217 return; // Stop. Fatal error occurred.
218 }
219 capture_time += *delay_adjustment_or_null;
220
221 next_task_.Schedule(
222 [this, capture_time] {
223 DeliverDataToClient(*decoded_frame_, capture_time);
224 av_frame_unref(decoded_frame_.get());
225 ConsumeNextDecodedFrame();
226 },
227 capture_time);
228 }
229
230 SimulatedAudioCapturer::Client::~Client() = default;
231
SimulatedAudioCapturer(Environment * environment,const char * path,int num_channels,int sample_rate,Clock::time_point start_time,Client * client)232 SimulatedAudioCapturer::SimulatedAudioCapturer(Environment* environment,
233 const char* path,
234 int num_channels,
235 int sample_rate,
236 Clock::time_point start_time,
237 Client* client)
238 : SimulatedCapturer(environment,
239 path,
240 AVMEDIA_TYPE_AUDIO,
241 start_time,
242 client),
243 num_channels_(num_channels),
244 sample_rate_(sample_rate),
245 client_(client),
246 resampler_(MakeUniqueSwrContext()) {
247 OSP_DCHECK_GT(num_channels_, 0);
248 OSP_DCHECK_GT(sample_rate_, 0);
249 }
250
~SimulatedAudioCapturer()251 SimulatedAudioCapturer::~SimulatedAudioCapturer() {
252 if (swr_is_initialized(resampler_.get())) {
253 swr_close(resampler_.get());
254 }
255 }
256
EnsureResamplerIsInitializedFor(const AVFrame & frame)257 bool SimulatedAudioCapturer::EnsureResamplerIsInitializedFor(
258 const AVFrame& frame) {
259 if (swr_is_initialized(resampler_.get())) {
260 if (input_sample_format_ == static_cast<AVSampleFormat>(frame.format) &&
261 input_sample_rate_ == frame.sample_rate &&
262 input_channel_layout_ == frame.channel_layout) {
263 return true;
264 }
265
266 // Note: Usually, the resampler should be flushed before being destroyed.
267 // However, because of the way SimulatedAudioCapturer uses the API, only one
268 // audio sample should be dropped in the worst case. Log what's being
269 // dropped, just in case libswresample is behaving differently than
270 // expected.
271 const std::chrono::microseconds amount(
272 swr_get_delay(resampler_.get(), std::micro::den));
273 OSP_LOG_INFO << "Discarding " << amount
274 << " of audio from the resampler before re-init.";
275 }
276
277 input_sample_format_ = AV_SAMPLE_FMT_NONE;
278
279 // Create a fake output frame to hold the output audio parameters, because the
280 // resampler API is weird that way.
281 const auto fake_output_frame = MakeUniqueAVFrame();
282 fake_output_frame->channel_layout =
283 av_get_default_channel_layout(num_channels_);
284 fake_output_frame->format = AV_SAMPLE_FMT_FLT;
285 fake_output_frame->sample_rate = sample_rate_;
286 const int config_result =
287 swr_config_frame(resampler_.get(), fake_output_frame.get(), &frame);
288 if (config_result < 0) {
289 OnError("swr_config_frame", config_result);
290 return false; // Capturer is now halted.
291 }
292
293 const int init_result = swr_init(resampler_.get());
294 if (init_result < 0) {
295 OnError("swr_init", init_result);
296 return false; // Capturer is now halted.
297 }
298
299 input_sample_format_ = static_cast<AVSampleFormat>(frame.format);
300 input_sample_rate_ = frame.sample_rate;
301 input_channel_layout_ = frame.channel_layout;
302 return true;
303 }
304
ProcessDecodedFrame(const AVFrame & frame)305 absl::optional<Clock::duration> SimulatedAudioCapturer::ProcessDecodedFrame(
306 const AVFrame& frame) {
307 if (!EnsureResamplerIsInitializedFor(frame)) {
308 return absl::nullopt;
309 }
310
311 const int64_t num_leftover_input_samples =
312 swr_get_delay(resampler_.get(), input_sample_rate_);
313 OSP_DCHECK_GE(num_leftover_input_samples, 0);
314 const Clock::duration capture_time_adjustment = -ToApproximateClockDuration(
315 num_leftover_input_samples, AVRational{1, input_sample_rate_});
316
317 const int64_t num_output_samples_desired =
318 av_rescale_rnd(num_leftover_input_samples + frame.nb_samples,
319 sample_rate_, input_sample_rate_, AV_ROUND_ZERO);
320 OSP_DCHECK_GE(num_output_samples_desired, 0);
321 resampled_audio_.resize(num_channels_ * num_output_samples_desired);
322 uint8_t* output_argument[1] = {
323 reinterpret_cast<uint8_t*>(resampled_audio_.data())};
324 const int num_samples_converted_or_error = swr_convert(
325 resampler_.get(), output_argument, num_output_samples_desired,
326 const_cast<const uint8_t**>(frame.extended_data), frame.nb_samples);
327 if (num_samples_converted_or_error < 0) {
328 resampled_audio_.clear();
329 swr_close(resampler_.get());
330 OnError("swr_convert", num_samples_converted_or_error);
331 return absl::nullopt; // Capturer is now halted.
332 }
333 resampled_audio_.resize(num_channels_ * num_samples_converted_or_error);
334
335 return capture_time_adjustment;
336 }
337
DeliverDataToClient(const AVFrame & unused,Clock::time_point capture_time)338 void SimulatedAudioCapturer::DeliverDataToClient(
339 const AVFrame& unused,
340 Clock::time_point capture_time) {
341 if (resampled_audio_.empty()) {
342 return;
343 }
344 client_->OnAudioData(resampled_audio_.data(),
345 resampled_audio_.size() / num_channels_, capture_time);
346 resampled_audio_.clear();
347 }
348
349 SimulatedVideoCapturer::Client::~Client() = default;
350
SimulatedVideoCapturer(Environment * environment,const char * path,Clock::time_point start_time,Client * client)351 SimulatedVideoCapturer::SimulatedVideoCapturer(Environment* environment,
352 const char* path,
353 Clock::time_point start_time,
354 Client* client)
355 : SimulatedCapturer(environment,
356 path,
357 AVMEDIA_TYPE_VIDEO,
358 start_time,
359 client),
360 client_(client) {}
361
362 SimulatedVideoCapturer::~SimulatedVideoCapturer() = default;
363
SetAdditionalDecoderParameters(AVCodecContext * decoder_context)364 void SimulatedVideoCapturer::SetAdditionalDecoderParameters(
365 AVCodecContext* decoder_context) {
366 // Require the I420 planar format for video.
367 decoder_context->get_format = [](struct AVCodecContext* s,
368 const enum AVPixelFormat* formats) {
369 // Return AV_PIX_FMT_YUV420P if it's in the provided list of supported
370 // formats. Otherwise, return AV_PIX_FMT_NONE.
371 //
372 // |formats| is a NONE-terminated array.
373 for (; *formats != AV_PIX_FMT_NONE; ++formats) {
374 if (*formats == AV_PIX_FMT_YUV420P) {
375 break;
376 }
377 }
378 return *formats;
379 };
380 }
381
DeliverDataToClient(const AVFrame & frame,Clock::time_point capture_time)382 void SimulatedVideoCapturer::DeliverDataToClient(
383 const AVFrame& frame,
384 Clock::time_point capture_time) {
385 client_->OnVideoFrame(frame, capture_time);
386 }
387
388 } // namespace cast
389 } // namespace openscreen
390