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