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