xref: /aosp_15_r20/external/openscreen/cast/standalone_sender/simulated_capturer.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
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