• 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 #ifndef CAST_STANDALONE_SENDER_SIMULATED_CAPTURER_H_
6 #define CAST_STANDALONE_SENDER_SIMULATED_CAPTURER_H_
7 
8 #include <stdint.h>
9 
10 #include <string>
11 #include <vector>
12 
13 #include "absl/types/optional.h"
14 #include "cast/standalone_sender/ffmpeg_glue.h"
15 #include "platform/api/time.h"
16 #include "util/alarm.h"
17 
18 namespace openscreen {
19 namespace cast {
20 
21 class Environment;
22 
23 // Simulates live media capture by demuxing, decoding, and emitting a stream of
24 // frames from a file at normal (1X) speed. This is a base class containing
25 // common functionality. Typical usage: Instantiate one SimulatedAudioCapturer
26 // and one FileVideoStreamCapturer.
27 class SimulatedCapturer {
28  public:
29   // Interface for receiving end-of-stream and fatal error notifications.
30   class Observer {
31    public:
32     // Called once the end of the file has been reached and the |capturer| has
33     // halted.
34     virtual void OnEndOfFile(SimulatedCapturer* capturer) = 0;
35 
36     // Called if a non-recoverable error occurs and the |capturer| has halted.
37     virtual void OnError(SimulatedCapturer* capturer, std::string message) = 0;
38 
39    protected:
40     virtual ~Observer();
41   };
42 
43   void SetPlaybackRate(double rate);
44 
45  protected:
46   SimulatedCapturer(Environment* environment,
47                     const char* path,
48                     AVMediaType media_type,
49                     Clock::time_point start_time,
50                     Observer* observer);
51 
52   virtual ~SimulatedCapturer();
53 
54   // Optionally overridden, to apply additional decoder context settings before
55   // avcodec_open2() is called.
56   virtual void SetAdditionalDecoderParameters(AVCodecContext* decoder_context);
57 
58   // Performs any additional processing on the decoded frame (e.g., audio
59   // resampling), and returns any adjustments to the frame's capture time (e.g.,
60   // to account for any buffering). If a fatal error occurs, absl::nullopt is
61   // returned. The default implementation does nothing.
62   //
63   // Mutating the |decoded_frame| is not allowed. If a subclass implementation
64   // wants to deliver different data (e.g., resampled audio), it must stash the
65   // data itself for the next DeliverDataToClient() call.
66   virtual absl::optional<Clock::duration> ProcessDecodedFrame(
67       const AVFrame& decoded_frame);
68 
69   // Delivers the decoded frame data to the client.
70   virtual void DeliverDataToClient(const AVFrame& decoded_frame,
71                                    Clock::time_point capture_time) = 0;
72 
73   // Called when any transient or fatal error occurs, generating an Error and
74   // scheduling a task to notify the Observer of it soon.
75   void OnError(const char* what, int av_errnum);
76 
77   // Converts the given FFMPEG tick count into an approximate Clock::duration.
78   static Clock::duration ToApproximateClockDuration(
79       int64_t ticks,
80       const AVRational& time_base);
81 
82  private:
83   // Reads the next frame from the file, sends it to the decoder, and schedules
84   // a future ConsumeNextDecodedFrame() call to continue processing.
85   void StartDecodingNextFrame();
86 
87   // Receives the next decoded frame and schedules media delivery to the client,
88   // and/or calls Observer::OnEndOfFile() if there are no more frames in the
89   // file.
90   void ConsumeNextDecodedFrame();
91 
92   const AVFormatContextUniquePtr format_context_;
93   const AVMediaType media_type_;  // Audio or Video.
94   const Clock::time_point start_time_;
95   Observer* const observer_;
96   const AVPacketUniquePtr packet_;        // Decoder input buffer.
97   const AVFrameUniquePtr decoded_frame_;  // Decoder output frame.
98   int stream_index_ = -1;                 // Selected stream from the file.
99   AVCodecContextUniquePtr decoder_context_;
100 
101   // The last frame's stream timestamp. This is used to detect bad stream
102   // timestamps in the file.
103   absl::optional<Clock::duration> last_frame_timestamp_;
104 
105   // Used to schedule the next task to execute and when it should execute. There
106   // is only ever one task scheduled/running at any time.
107   Alarm next_task_;
108 
109   // Used to determine playback rate. Currently, we only support "playing"
110   // at 1x speed, or "pausing" at 0x speed.
111   bool playback_rate_is_non_zero_ = true;
112 };
113 
114 // Emits the primary audio stream from a file.
115 class SimulatedAudioCapturer final : public SimulatedCapturer {
116  public:
117   class Client : public SimulatedCapturer::Observer {
118    public:
119     // Called to deliver more audio data as |interleaved_samples|, which
120     // contains |num_samples| tuples (i.e., multiply by the number of channels
121     // to determine the number of array elements). |capture_time| is used to
122     // synchronize the play-out of the first audio sample with respect to video
123     // frames.
124     virtual void OnAudioData(const float* interleaved_samples,
125                              int num_samples,
126                              Clock::time_point capture_time) = 0;
127 
128    protected:
129     ~Client() override;
130   };
131 
132   // Constructor: |num_channels| and |sample_rate| specify the required audio
133   // format. If necessary, audio from the file will be resampled to match the
134   // required format.
135   SimulatedAudioCapturer(Environment* environment,
136                          const char* path,
137                          int num_channels,
138                          int sample_rate,
139                          Clock::time_point start_time,
140                          Client* client);
141 
142   ~SimulatedAudioCapturer() final;
143 
144  private:
145   // Examines the audio format of the given |frame|, and ensures the resampler
146   // is initialized to take that as input.
147   bool EnsureResamplerIsInitializedFor(const AVFrame& frame);
148 
149   // Resamples the current |SimulatedCapturer::decoded_frame()| into the
150   // required output format/channels/rate. The result is stored in
151   // |resampled_audio_| for the next DeliverDataToClient() call.
152   absl::optional<Clock::duration> ProcessDecodedFrame(
153       const AVFrame& decoded_frame) final;
154 
155   // Called at the moment Client::OnAudioData() should be called to pass the
156   // |resampled_audio_|.
157   void DeliverDataToClient(const AVFrame& decoded_frame,
158                            Clock::time_point capture_time) final;
159 
160   const int num_channels_;  // Output number of channels.
161   const int sample_rate_;   // Output sample rate.
162   Client* const client_;
163 
164   const SwrContextUniquePtr resampler_;
165 
166   // Current resampler input audio parameters.
167   AVSampleFormat input_sample_format_ = AV_SAMPLE_FMT_NONE;
168   int input_sample_rate_;
169   uint64_t input_channel_layout_;  // Opaque value used by resampler library.
170 
171   std::vector<float> resampled_audio_;
172 };
173 
174 // Emits the primary video stream from a file.
175 class SimulatedVideoCapturer final : public SimulatedCapturer {
176  public:
177   class Client : public SimulatedCapturer::Observer {
178    public:
179     // Called to deliver the next video |frame|, which is always in I420 format.
180     // |capture_time| is used to synchronize the play-out of the video frame
181     // with respect to the audio track.
182     virtual void OnVideoFrame(const AVFrame& frame,
183                               Clock::time_point capture_time) = 0;
184 
185    protected:
186     ~Client() override;
187   };
188 
189   SimulatedVideoCapturer(Environment* environment,
190                          const char* path,
191                          Clock::time_point start_time,
192                          Client* client);
193 
194   ~SimulatedVideoCapturer() final;
195 
196  private:
197   Client* const client_;
198 
199   // Sets up the decoder to produce I420 format output.
200   void SetAdditionalDecoderParameters(AVCodecContext* decoder_context) final;
201 
202   // Called at the moment Client::OnVideoFrame() should be called to provide the
203   // next video frame.
204   void DeliverDataToClient(const AVFrame& decoded_frame,
205                            Clock::time_point capture_time) final;
206 };
207 
208 }  // namespace cast
209 }  // namespace openscreen
210 
211 #endif  // CAST_STANDALONE_SENDER_SIMULATED_CAPTURER_H_
212