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