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
SetAdditionalDecoderParameters(AVCodecContext * decoder_context)88 void SimulatedCapturer::SetAdditionalDecoderParameters(
89 AVCodecContext* decoder_context) {}
90
ProcessDecodedFrame(const AVFrame & frame)91 absl::optional<Clock::duration> SimulatedCapturer::ProcessDecodedFrame(
92 const AVFrame& frame) {
93 return Clock::duration::zero();
94 }
95
OnError(const char * function_name,int av_errnum)96 void SimulatedCapturer::OnError(const char* function_name, int av_errnum) {
97 // Make a human-readable string from the libavcodec error.
98 std::ostringstream error;
99 error << "For " << av_get_media_type_string(media_type_) << ", "
100 << function_name << " returned error: " << av_err2str(av_errnum);
101
102 // Deliver the error notification in a separate task since this method might
103 // have been called from the constructor.
104 next_task_.Schedule(
105 [this, error_string = error.str()] {
106 observer_->OnError(this, error_string);
107 // Capturer is now halted.
108 },
109 Alarm::kImmediately);
110 }
111
112 // static
ToApproximateClockDuration(int64_t ticks,const AVRational & time_base)113 Clock::duration SimulatedCapturer::ToApproximateClockDuration(
114 int64_t ticks,
115 const AVRational& time_base) {
116 return Clock::duration(av_rescale_q(
117 ticks, time_base,
118 AVRational{Clock::duration::period::num, Clock::duration::period::den}));
119 }
120
StartDecodingNextFrame()121 void SimulatedCapturer::StartDecodingNextFrame() {
122 const int read_frame_result =
123 av_read_frame(format_context_.get(), packet_.get());
124 if (read_frame_result < 0) {
125 if (read_frame_result == AVERROR_EOF) {
126 // Insert a "flush request" into the decoder's pipeline, which will
127 // signal an EOF in ConsumeNextDecodedFrame() later.
128 avcodec_send_packet(decoder_context_.get(), nullptr);
129 next_task_.Schedule([this] { ConsumeNextDecodedFrame(); },
130 Alarm::kImmediately);
131 } else {
132 // All other error codes are fatal.
133 OnError("av_read_frame", read_frame_result);
134 // Capturer is now halted.
135 }
136 return;
137 }
138
139 if (packet_->stream_index != stream_index_) {
140 av_packet_unref(packet_.get());
141 next_task_.Schedule([this] { StartDecodingNextFrame(); },
142 Alarm::kImmediately);
143 return;
144 }
145
146 const int send_packet_result =
147 avcodec_send_packet(decoder_context_.get(), packet_.get());
148 av_packet_unref(packet_.get());
149 if (send_packet_result < 0) {
150 // Note: AVERROR(EAGAIN) is also treated as fatal here because
151 // avcodec_receive_frame() will be called repeatedly until its result code
152 // indicates avcodec_send_packet() must be called again.
153 OnError("avcodec_send_packet", send_packet_result);
154 return; // Capturer is now halted.
155 }
156
157 next_task_.Schedule([this] { ConsumeNextDecodedFrame(); },
158 Alarm::kImmediately);
159 }
160
ConsumeNextDecodedFrame()161 void SimulatedCapturer::ConsumeNextDecodedFrame() {
162 const int receive_frame_result =
163 avcodec_receive_frame(decoder_context_.get(), decoded_frame_.get());
164 if (receive_frame_result < 0) {
165 switch (receive_frame_result) {
166 case AVERROR(EAGAIN):
167 // This result code, according to libavcodec documentation, means more
168 // data should be fed into the decoder (e.g., interframe dependencies).
169 next_task_.Schedule([this] { StartDecodingNextFrame(); },
170 Alarm::kImmediately);
171 return;
172 case AVERROR_EOF:
173 observer_->OnEndOfFile(this);
174 return; // Capturer is now halted.
175 default:
176 OnError("avcodec_receive_frame", receive_frame_result);
177 return; // Capturer is now halted.
178 }
179 }
180
181 const Clock::duration frame_timestamp = ToApproximateClockDuration(
182 decoded_frame_->best_effort_timestamp,
183 format_context_->streams[stream_index_]->time_base);
184 if (last_frame_timestamp_) {
185 const Clock::duration delta = frame_timestamp - *last_frame_timestamp_;
186 if (delta <= Clock::duration::zero()) {
187 OSP_LOG_WARN << "Dropping " << av_get_media_type_string(media_type_)
188 << " frame with illegal timestamp (delta from last frame: "
189 << delta << "). Bad media file!";
190 av_frame_unref(decoded_frame_.get());
191 next_task_.Schedule([this] { ConsumeNextDecodedFrame(); },
192 Alarm::kImmediately);
193 return;
194 } else if (delta >= kPauseWarningThreshold) {
195 OSP_LOG_INFO << "For " << av_get_media_type_string(media_type_)
196 << ", encountered a media pause (" << delta
197 << ") in the file.";
198 }
199 }
200 last_frame_timestamp_ = frame_timestamp;
201
202 Clock::time_point capture_time = start_time_ + frame_timestamp;
203 const auto delay_adjustment_or_null = ProcessDecodedFrame(*decoded_frame_);
204 if (!delay_adjustment_or_null) {
205 av_frame_unref(decoded_frame_.get());
206 return; // Stop. Fatal error occurred.
207 }
208 capture_time += *delay_adjustment_or_null;
209
210 next_task_.Schedule(
211 [this, capture_time] {
212 DeliverDataToClient(*decoded_frame_, capture_time);
213 av_frame_unref(decoded_frame_.get());
214 ConsumeNextDecodedFrame();
215 },
216 capture_time);
217 }
218
219 SimulatedAudioCapturer::Client::~Client() = default;
220
SimulatedAudioCapturer(Environment * environment,const char * path,int num_channels,int sample_rate,Clock::time_point start_time,Client * client)221 SimulatedAudioCapturer::SimulatedAudioCapturer(Environment* environment,
222 const char* path,
223 int num_channels,
224 int sample_rate,
225 Clock::time_point start_time,
226 Client* client)
227 : SimulatedCapturer(environment,
228 path,
229 AVMEDIA_TYPE_AUDIO,
230 start_time,
231 client),
232 num_channels_(num_channels),
233 sample_rate_(sample_rate),
234 client_(client),
235 resampler_(MakeUniqueSwrContext()) {
236 OSP_DCHECK_GT(num_channels_, 0);
237 OSP_DCHECK_GT(sample_rate_, 0);
238 }
239
~SimulatedAudioCapturer()240 SimulatedAudioCapturer::~SimulatedAudioCapturer() {
241 if (swr_is_initialized(resampler_.get())) {
242 swr_close(resampler_.get());
243 }
244 }
245
EnsureResamplerIsInitializedFor(const AVFrame & frame)246 bool SimulatedAudioCapturer::EnsureResamplerIsInitializedFor(
247 const AVFrame& frame) {
248 if (swr_is_initialized(resampler_.get())) {
249 if (input_sample_format_ == static_cast<AVSampleFormat>(frame.format) &&
250 input_sample_rate_ == frame.sample_rate &&
251 input_channel_layout_ == frame.channel_layout) {
252 return true;
253 }
254
255 // Note: Usually, the resampler should be flushed before being destroyed.
256 // However, because of the way SimulatedAudioCapturer uses the API, only one
257 // audio sample should be dropped in the worst case. Log what's being
258 // dropped, just in case libswresample is behaving differently than
259 // expected.
260 const std::chrono::microseconds amount(
261 swr_get_delay(resampler_.get(), std::micro::den));
262 OSP_LOG_INFO << "Discarding " << amount
263 << " of audio from the resampler before re-init.";
264 }
265
266 input_sample_format_ = AV_SAMPLE_FMT_NONE;
267
268 // Create a fake output frame to hold the output audio parameters, because the
269 // resampler API is weird that way.
270 const auto fake_output_frame = MakeUniqueAVFrame();
271 fake_output_frame->channel_layout =
272 av_get_default_channel_layout(num_channels_);
273 fake_output_frame->format = AV_SAMPLE_FMT_FLT;
274 fake_output_frame->sample_rate = sample_rate_;
275 const int config_result =
276 swr_config_frame(resampler_.get(), fake_output_frame.get(), &frame);
277 if (config_result < 0) {
278 OnError("swr_config_frame", config_result);
279 return false; // Capturer is now halted.
280 }
281
282 const int init_result = swr_init(resampler_.get());
283 if (init_result < 0) {
284 OnError("swr_init", init_result);
285 return false; // Capturer is now halted.
286 }
287
288 input_sample_format_ = static_cast<AVSampleFormat>(frame.format);
289 input_sample_rate_ = frame.sample_rate;
290 input_channel_layout_ = frame.channel_layout;
291 return true;
292 }
293
ProcessDecodedFrame(const AVFrame & frame)294 absl::optional<Clock::duration> SimulatedAudioCapturer::ProcessDecodedFrame(
295 const AVFrame& frame) {
296 if (!EnsureResamplerIsInitializedFor(frame)) {
297 return absl::nullopt;
298 }
299
300 const int64_t num_leftover_input_samples =
301 swr_get_delay(resampler_.get(), input_sample_rate_);
302 OSP_DCHECK_GE(num_leftover_input_samples, 0);
303 const Clock::duration capture_time_adjustment = -ToApproximateClockDuration(
304 num_leftover_input_samples, AVRational{1, input_sample_rate_});
305
306 const int64_t num_output_samples_desired =
307 av_rescale_rnd(num_leftover_input_samples + frame.nb_samples,
308 sample_rate_, input_sample_rate_, AV_ROUND_ZERO);
309 OSP_DCHECK_GE(num_output_samples_desired, 0);
310 resampled_audio_.resize(num_channels_ * num_output_samples_desired);
311 uint8_t* output_argument[1] = {
312 reinterpret_cast<uint8_t*>(resampled_audio_.data())};
313 const int num_samples_converted_or_error = swr_convert(
314 resampler_.get(), output_argument, num_output_samples_desired,
315 const_cast<const uint8_t**>(frame.extended_data), frame.nb_samples);
316 if (num_samples_converted_or_error < 0) {
317 resampled_audio_.clear();
318 swr_close(resampler_.get());
319 OnError("swr_convert", num_samples_converted_or_error);
320 return absl::nullopt; // Capturer is now halted.
321 }
322 resampled_audio_.resize(num_channels_ * num_samples_converted_or_error);
323
324 return capture_time_adjustment;
325 }
326
DeliverDataToClient(const AVFrame & unused,Clock::time_point capture_time)327 void SimulatedAudioCapturer::DeliverDataToClient(
328 const AVFrame& unused,
329 Clock::time_point capture_time) {
330 if (resampled_audio_.empty()) {
331 return;
332 }
333 client_->OnAudioData(resampled_audio_.data(),
334 resampled_audio_.size() / num_channels_, capture_time);
335 resampled_audio_.clear();
336 }
337
338 SimulatedVideoCapturer::Client::~Client() = default;
339
SimulatedVideoCapturer(Environment * environment,const char * path,Clock::time_point start_time,Client * client)340 SimulatedVideoCapturer::SimulatedVideoCapturer(Environment* environment,
341 const char* path,
342 Clock::time_point start_time,
343 Client* client)
344 : SimulatedCapturer(environment,
345 path,
346 AVMEDIA_TYPE_VIDEO,
347 start_time,
348 client),
349 client_(client) {}
350
351 SimulatedVideoCapturer::~SimulatedVideoCapturer() = default;
352
SetAdditionalDecoderParameters(AVCodecContext * decoder_context)353 void SimulatedVideoCapturer::SetAdditionalDecoderParameters(
354 AVCodecContext* decoder_context) {
355 // Require the I420 planar format for video.
356 decoder_context->get_format = [](struct AVCodecContext* s,
357 const enum AVPixelFormat* formats) {
358 // Return AV_PIX_FMT_YUV420P if it's in the provided list of supported
359 // formats. Otherwise, return AV_PIX_FMT_NONE.
360 //
361 // |formats| is a NONE-terminated array.
362 for (; *formats != AV_PIX_FMT_NONE; ++formats) {
363 if (*formats == AV_PIX_FMT_YUV420P) {
364 break;
365 }
366 }
367 return *formats;
368 };
369 }
370
DeliverDataToClient(const AVFrame & frame,Clock::time_point capture_time)371 void SimulatedVideoCapturer::DeliverDataToClient(
372 const AVFrame& frame,
373 Clock::time_point capture_time) {
374 client_->OnVideoFrame(frame, capture_time);
375 }
376
377 } // namespace cast
378 } // namespace openscreen
379