1 // Copyright 2019 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_RECEIVER_SDL_PLAYER_BASE_H_ 6 #define CAST_STANDALONE_RECEIVER_SDL_PLAYER_BASE_H_ 7 8 #include <stdint.h> 9 10 #include <functional> 11 #include <map> 12 #include <string> 13 14 #include "cast/standalone_receiver/decoder.h" 15 #include "cast/standalone_receiver/sdl_glue.h" 16 #include "cast/streaming/message_fields.h" 17 #include "cast/streaming/receiver.h" 18 #include "platform/api/task_runner.h" 19 #include "platform/api/time.h" 20 #include "platform/base/error.h" 21 22 namespace openscreen { 23 namespace cast { 24 25 // Common base class that consumes frames from a Receiver, decodes them, and 26 // plays them out via the appropriate SDL subsystem. Subclasses implement the 27 // specifics, based on the type of media (audio or video). 28 class SDLPlayerBase : public Receiver::Consumer, public Decoder::Client { 29 public: 30 ~SDLPlayerBase() override; 31 32 // Returns OK unless a fatal error has occurred. error_status()33 const Error& error_status() const { return error_status_; } 34 35 protected: 36 // Current player state, which is used to determine what to render/present, 37 // and how frequently. 38 enum PlayerState { 39 kWaitingForFirstFrame, // Render silent "blue splash" screen at idle FPS. 40 kScheduledToPresent, // Present new content at an exact time point. 41 kPresented, // Continue presenting same content at idle FPS. 42 kError, // Render silent "red splash" screen at idle FPS. 43 }; 44 45 // A decoded frame and its target presentation time. 46 struct PresentableFrame { 47 Clock::time_point presentation_time; 48 AVFrameUniquePtr decoded_frame; 49 50 PresentableFrame(); 51 ~PresentableFrame(); 52 PresentableFrame(PresentableFrame&& other) noexcept; 53 PresentableFrame& operator=(PresentableFrame&& other) noexcept; 54 }; 55 56 // |error_callback| is run only if a fatal error occurs, at which point the 57 // player has halted and set |error_status()|. |media_type| should be "audio" 58 // or "video" (only used when logging). 59 SDLPlayerBase(ClockNowFunctionPtr now_function, 60 TaskRunner* task_runner, 61 Receiver* receiver, 62 const std::string& codec_name, 63 std::function<void()> error_callback, 64 const char* media_type); 65 state()66 PlayerState state() const { return state_; } 67 68 // Called back from either |decoder_| or a player subclass to handle a fatal 69 // error event. 70 void OnFatalError(std::string message) final; 71 72 // Renders the |frame| and returns its [possibly adjusted] presentation time. 73 virtual ErrorOr<Clock::time_point> RenderNextFrame( 74 const PresentableFrame& frame) = 0; 75 76 // Called to render when the player has no new content, and returns true if a 77 // Present() is necessary. |frame| may be null, if it is not available. This 78 // method can be called before the first frame, after any frame, or after a 79 // fatal error has occurred. 80 virtual bool RenderWhileIdle(const PresentableFrame* frame) = 0; 81 82 // Presents the rendering from the last call to RenderNextFrame() or 83 // RenderWhileIdle(). 84 virtual void Present() = 0; 85 86 private: 87 struct PendingFrame : public PresentableFrame { 88 Clock::time_point start_time; 89 90 PendingFrame(); 91 ~PendingFrame(); 92 PendingFrame(PendingFrame&& other) noexcept; 93 PendingFrame& operator=(PendingFrame&& other) noexcept; 94 }; 95 96 // Receiver::Consumer implementation. 97 void OnFramesReady(int next_frame_buffer_size) final; 98 99 // Determine the presentation time of the frame. Ideally, this will occur 100 // based on the time progression of the media, given by the RTP timestamps. 101 // However, if this falls too far out-of-sync with the system reference clock, 102 // re-synchronize, possibly causing user-visible "jank." 103 Clock::time_point ResyncAndDeterminePresentationTime( 104 const EncodedFrame& frame); 105 106 // AVCodecDecoder::Client implementation. These are called-back from 107 // |decoder_| to provide results. 108 void OnFrameDecoded(FrameId frame_id, const AVFrame& frame) final; 109 void OnDecodeError(FrameId frame_id, std::string message) final; 110 111 // Calls RenderNextFrame() on the next available decoded frame, and schedules 112 // its presentation. If no decoded frame is available, RenderWhileIdle() is 113 // called instead. 114 void RenderAndSchedulePresentation(); 115 116 // Schedules an explicit check to see if more frames are ready for 117 // consumption. Normally, the Receiver will notify this Consumer when more 118 // frames are ready. However, there are cases where prior notifications were 119 // ignored because there were too many frames in the player's pipeline. Thus, 120 // whenever frames are removed from the pipeline, this method should be 121 // called. 122 void ResumeDecoding(); 123 124 // Called whenever a frame has been decoded, presentation of a prior frame has 125 // completed, and/or the player has encountered a state change that might 126 // require rendering/presenting a different output. 127 void ResumeRendering(); 128 129 const ClockNowFunctionPtr now_; 130 Receiver* const receiver_; 131 std::function<void()> error_callback_; // Run once by OnFatalError(). 132 const char* const media_type_; // For logging only. 133 134 // Set to the error code that placed the player in a fatal error state. 135 Error error_status_; 136 137 // Current player state, which is used to determine what to render/present, 138 // and how frequently. 139 PlayerState state_ = kWaitingForFirstFrame; 140 141 // Queue of frames currently being decoded and decoded frames awaiting 142 // rendering. 143 144 std::map<FrameId, PendingFrame> frames_to_render_; 145 146 // Buffer for holding EncodedFrame::data. 147 Decoder::Buffer buffer_; 148 149 // Associates a RTP timestamp with a local clock time point. This is updated 150 // whenever the media (RTP) timestamps drift too much away from the rate at 151 // which the local clock ticks. This is important for A/V synchronization. 152 RtpTimeTicks last_sync_rtp_timestamp_{}; 153 Clock::time_point last_sync_reference_time_{}; 154 155 Decoder decoder_; 156 157 // The decoded frame to be rendered/presented. 158 PendingFrame current_frame_; 159 160 // A cumulative moving average of recent single-frame processing times 161 // (consume + decode + render). This is passed to the Cast Receiver so that it 162 // can determine when to drop late frames. 163 Clock::duration recent_processing_time_{}; 164 165 // Alarms that execute the various stages of the player pipeline at certain 166 // times. 167 Alarm decode_alarm_; 168 Alarm render_alarm_; 169 Alarm presentation_alarm_; 170 171 // Maximum number of frames in the decode/render pipeline. This limit is about 172 // making sure the player uses resources efficiently: It is better for frames 173 // to remain in the Receiver's queue until this player is ready to process 174 // them. 175 static constexpr int kMaxFramesInPipeline = 8; 176 }; 177 178 } // namespace cast 179 } // namespace openscreen 180 181 #endif // CAST_STANDALONE_RECEIVER_SDL_PLAYER_BASE_H_ 182