• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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