• 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 
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