1 // Copyright 2015 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 MEDIA_MUXERS_WEBM_MUXER_H_ 6 #define MEDIA_MUXERS_WEBM_MUXER_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 12 #include "base/callback.h" 13 #include "base/containers/circular_deque.h" 14 #include "base/macros.h" 15 #include "base/numerics/safe_math.h" 16 #include "base/sequence_checker.h" 17 #include "base/strings/string_piece.h" 18 #include "base/time/time.h" 19 #include "base/timer/elapsed_timer.h" 20 #include "media/base/audio_codecs.h" 21 #include "media/base/media_export.h" 22 #include "media/base/video_codecs.h" 23 #include "media/base/video_color_space.h" 24 #include "third_party/libwebm/source/mkvmuxer.hpp" 25 #include "ui/gfx/geometry/size.h" 26 27 namespace gfx { 28 class Size; 29 } // namespace gfx 30 31 namespace media { 32 33 class VideoFrame; 34 class AudioParameters; 35 36 // Adapter class to manage a WebM container [1], a simplified version of a 37 // Matroska container [2], composed of an EBML header, and a single Segment 38 // including at least a Track Section and a number of SimpleBlocks each 39 // containing a single encoded video or audio frame. WebM container has no 40 // Trailer. 41 // Clients will push encoded VPx or AV1 video frames and Opus or PCM audio 42 // frames one by one via OnEncoded{Video|Audio}(). libwebm will eventually ping 43 // the WriteDataCB passed on contructor with the wrapped encoded data. 44 // WebmMuxer is designed for use on a single thread. 45 // [1] http://www.webmproject.org/docs/container/ 46 // [2] http://www.matroska.org/technical/specs/index.html 47 class MEDIA_EXPORT WebmMuxer : public mkvmuxer::IMkvWriter { 48 public: 49 // Callback to be called when WebmMuxer is ready to write a chunk of data, 50 // either any file header or a SingleBlock. 51 using WriteDataCB = base::RepeatingCallback<void(base::StringPiece)>; 52 53 // Container for the parameters that muxer uses that is extracted from 54 // media::VideoFrame. 55 struct MEDIA_EXPORT VideoParameters { 56 VideoParameters(scoped_refptr<media::VideoFrame> frame); 57 VideoParameters(gfx::Size visible_rect_size, 58 double frame_rate, 59 VideoCodec codec, 60 base::Optional<gfx::ColorSpace> color_space); 61 VideoParameters(const VideoParameters&); 62 ~VideoParameters(); 63 gfx::Size visible_rect_size; 64 double frame_rate; 65 VideoCodec codec; 66 base::Optional<gfx::ColorSpace> color_space; 67 }; 68 69 // |audio_codec| should coincide with whatever is sent in OnEncodedAudio(), 70 WebmMuxer(AudioCodec audio_codec, 71 bool has_video_, 72 bool has_audio_, 73 const WriteDataCB& write_data_callback); 74 ~WebmMuxer() override; 75 76 // Functions to add video and audio frames with |encoded_data.data()| 77 // to WebM Segment. Either one returns true on success. 78 // |encoded_alpha| represents the encode output of alpha channel when 79 // available, can be nullptr otherwise. 80 bool OnEncodedVideo(const VideoParameters& params, 81 std::string encoded_data, 82 std::string encoded_alpha, 83 base::TimeTicks timestamp, 84 bool is_key_frame); 85 bool OnEncodedAudio(const media::AudioParameters& params, 86 std::string encoded_data, 87 base::TimeTicks timestamp); 88 89 void Pause(); 90 void Resume(); 91 92 // Drains and writes out all buffered frames and finalizes the segment. 93 // Returns true on success, false otherwise. 94 bool Flush(); 95 ForceOneLibWebmErrorForTesting()96 void ForceOneLibWebmErrorForTesting() { force_one_libwebm_error_ = true; } 97 98 private: 99 friend class WebmMuxerTest; 100 101 // Methods for creating and adding video and audio tracks, called upon 102 // receiving the first frame of a given Track. 103 // AddVideoTrack adds |frame_size| and |frame_rate| to the Segment 104 // info, although individual frames passed to OnEncodedVideo() can have any 105 // frame size. 106 void AddVideoTrack(const gfx::Size& frame_size, 107 double frame_rate, 108 const base::Optional<gfx::ColorSpace>& color_space); 109 void AddAudioTrack(const media::AudioParameters& params); 110 111 // IMkvWriter interface. 112 mkvmuxer::int32 Write(const void* buf, mkvmuxer::uint32 len) override; 113 mkvmuxer::int64 Position() const override; 114 mkvmuxer::int32 Position(mkvmuxer::int64 position) override; 115 bool Seekable() const override; 116 void ElementStartNotify(mkvmuxer::uint64 element_id, 117 mkvmuxer::int64 position) override; 118 119 // Adds all currently buffered frames to the mkvmuxer in timestamp order, 120 // until the queues are depleted. 121 void FlushQueues(); 122 // Flushes out frames to the mkvmuxer while ensuring monotonically increasing 123 // timestamps as per the WebM specification, 124 // https://www.webmproject.org/docs/container/. Returns true on success and 125 // false on mkvmuxer failure. 126 // 127 // Note that frames may still be around in the queues after this call. The 128 // method stops flushing when timestamp monotonicity can't be guaranteed 129 // anymore. 130 bool PartiallyFlushQueues(); 131 // Flushes out the next frame in timestamp order from the queues. Returns true 132 // on success and false on mkvmuxer failure. 133 // 134 // Note: it's assumed that at least one video or audio frame is queued. 135 bool FlushNextFrame(); 136 // Calculates a monotonically increasing timestamp from an input |timestamp| 137 // and a pointer to a previously stored |last_timestamp| by taking the maximum 138 // of |timestamp| and *|last_timestamp|. Updates *|last_timestamp| if 139 // |timestamp| is greater. 140 base::TimeTicks UpdateLastTimestampMonotonically( 141 base::TimeTicks timestamp, 142 base::TimeTicks* last_timestamp); 143 144 // Audio codec configured on construction. Video codec is taken from first 145 // received frame. 146 const AudioCodec audio_codec_; 147 VideoCodec video_codec_; 148 149 // Caller-side identifiers to interact with |segment_|, initialised upon 150 // first frame arrival to Add{Video, Audio}Track(). 151 uint8_t video_track_index_; 152 uint8_t audio_track_index_; 153 154 // Origin of times for frame timestamps. 155 base::TimeTicks first_frame_timestamp_video_; 156 base::TimeTicks last_frame_timestamp_video_; 157 base::TimeTicks first_frame_timestamp_audio_; 158 base::TimeTicks last_frame_timestamp_audio_; 159 160 // Variables to measure and accumulate, respectively, the time in pause state. 161 std::unique_ptr<base::ElapsedTimer> elapsed_time_in_pause_; 162 base::TimeDelta total_time_in_pause_; 163 164 // TODO(ajose): Change these when support is added for multiple tracks. 165 // http://crbug.com/528523 166 const bool has_video_; 167 const bool has_audio_; 168 169 // Callback to dump written data as being called by libwebm. 170 const WriteDataCB write_data_callback_; 171 172 // Rolling counter of the position in bytes of the written goo. 173 base::CheckedNumeric<mkvmuxer::int64> position_; 174 175 // The MkvMuxer active element. 176 mkvmuxer::Segment segment_; 177 // Flag to force the next call to a |segment_| method to return false. 178 bool force_one_libwebm_error_; 179 180 struct EncodedFrame { 181 std::string data; 182 std::string alpha_data; 183 base::TimeDelta 184 relative_timestamp; // relative to first_frame_timestamp_xxx_ 185 bool is_keyframe; 186 }; 187 188 // The following two queues hold frames to ensure that monotonically 189 // increasing timestamps are stored in the resulting webm file without 190 // modifying the timestamps. 191 base::circular_deque<EncodedFrame> audio_frames_; 192 // If muxing audio and video, this queue holds frames until the first audio 193 // frame appears. 194 base::circular_deque<EncodedFrame> video_frames_; 195 196 SEQUENCE_CHECKER(sequence_checker_); 197 198 DISALLOW_COPY_AND_ASSIGN(WebmMuxer); 199 }; 200 201 } // namespace media 202 203 #endif // MEDIA_MUXERS_WEBM_MUXER_H_ 204