OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/muxers/webm_muxer.h" | 5 #include "media/muxers/webm_muxer.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "media/base/audio_parameters.h" | 9 #include "media/base/audio_parameters.h" |
10 #include "media/base/limits.h" | 10 #include "media/base/limits.h" |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 // No need to segment_.Finalize() since is not Seekable(), i.e. a live | 119 // No need to segment_.Finalize() since is not Seekable(), i.e. a live |
120 // stream, but is a good practice. | 120 // stream, but is a good practice. |
121 DCHECK(thread_checker_.CalledOnValidThread()); | 121 DCHECK(thread_checker_.CalledOnValidThread()); |
122 segment_.Finalize(); | 122 segment_.Finalize(); |
123 } | 123 } |
124 | 124 |
125 void WebmMuxer::OnEncodedVideo(const scoped_refptr<VideoFrame>& video_frame, | 125 void WebmMuxer::OnEncodedVideo(const scoped_refptr<VideoFrame>& video_frame, |
126 std::unique_ptr<std::string> encoded_data, | 126 std::unique_ptr<std::string> encoded_data, |
127 base::TimeTicks timestamp, | 127 base::TimeTicks timestamp, |
128 bool is_key_frame) { | 128 bool is_key_frame) { |
129 DVLOG(1) << __FUNCTION__ << " - " << encoded_data->size() << "B"; | 129 DVLOG(1) << __func__ << " - " << encoded_data->size() << "B"; |
130 DCHECK(thread_checker_.CalledOnValidThread()); | 130 DCHECK(thread_checker_.CalledOnValidThread()); |
131 | 131 |
132 if (!video_track_index_) { | 132 if (!video_track_index_) { |
133 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. | 133 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. |
134 // http://www.matroska.org/technical/specs/index.html#Tracks | 134 // http://www.matroska.org/technical/specs/index.html#Tracks |
135 AddVideoTrack(video_frame->visible_rect().size(), | 135 AddVideoTrack(video_frame->visible_rect().size(), |
136 GetFrameRate(video_frame)); | 136 GetFrameRate(video_frame)); |
137 if (first_frame_timestamp_video_.is_null()) | 137 if (first_frame_timestamp_video_.is_null()) |
138 first_frame_timestamp_video_ = timestamp; | 138 first_frame_timestamp_video_ = timestamp; |
139 } | 139 } |
140 | 140 |
141 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 | 141 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 |
142 if (has_audio_ && !audio_track_index_) { | 142 if (has_audio_ && !audio_track_index_) { |
143 DVLOG(1) << __FUNCTION__ << ": delaying until audio track ready."; | 143 DVLOG(1) << __func__ << ": delaying until audio track ready."; |
144 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. | 144 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. |
145 encoded_frames_queue_.clear(); | 145 encoded_frames_queue_.clear(); |
146 | 146 |
147 encoded_frames_queue_.push_back(base::WrapUnique(new EncodedVideoFrame( | 147 encoded_frames_queue_.push_back(base::WrapUnique(new EncodedVideoFrame( |
148 std::move(encoded_data), timestamp, is_key_frame))); | 148 std::move(encoded_data), timestamp, is_key_frame))); |
149 return; | 149 return; |
150 } | 150 } |
151 | 151 |
152 // Dump all saved encoded video frames if any. | 152 // Dump all saved encoded video frames if any. |
153 while (!encoded_frames_queue_.empty()) { | 153 while (!encoded_frames_queue_.empty()) { |
154 AddFrame( | 154 AddFrame( |
155 std::move(encoded_frames_queue_.front()->data), video_track_index_, | 155 std::move(encoded_frames_queue_.front()->data), video_track_index_, |
156 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, | 156 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, |
157 encoded_frames_queue_.front()->is_keyframe); | 157 encoded_frames_queue_.front()->is_keyframe); |
158 encoded_frames_queue_.pop_front(); | 158 encoded_frames_queue_.pop_front(); |
159 } | 159 } |
160 | 160 |
161 AddFrame(std::move(encoded_data), video_track_index_, | 161 AddFrame(std::move(encoded_data), video_track_index_, |
162 timestamp - first_frame_timestamp_video_, is_key_frame); | 162 timestamp - first_frame_timestamp_video_, is_key_frame); |
163 } | 163 } |
164 | 164 |
165 void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, | 165 void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, |
166 std::unique_ptr<std::string> encoded_data, | 166 std::unique_ptr<std::string> encoded_data, |
167 base::TimeTicks timestamp) { | 167 base::TimeTicks timestamp) { |
168 DVLOG(2) << __FUNCTION__ << " - " << encoded_data->size() << "B"; | 168 DVLOG(2) << __func__ << " - " << encoded_data->size() << "B"; |
169 DCHECK(thread_checker_.CalledOnValidThread()); | 169 DCHECK(thread_checker_.CalledOnValidThread()); |
170 | 170 |
171 if (!audio_track_index_) { | 171 if (!audio_track_index_) { |
172 AddAudioTrack(params); | 172 AddAudioTrack(params); |
173 if (first_frame_timestamp_audio_.is_null()) | 173 if (first_frame_timestamp_audio_.is_null()) |
174 first_frame_timestamp_audio_ = timestamp; | 174 first_frame_timestamp_audio_ = timestamp; |
175 } | 175 } |
176 | 176 |
177 // TODO(ajose): Don't drop audio data: http://crbug.com/547948 | 177 // TODO(ajose): Don't drop audio data: http://crbug.com/547948 |
178 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 | 178 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 |
179 if (has_video_ && !video_track_index_) { | 179 if (has_video_ && !video_track_index_) { |
180 DVLOG(1) << __FUNCTION__ << ": delaying until video track ready."; | 180 DVLOG(1) << __func__ << ": delaying until video track ready."; |
181 return; | 181 return; |
182 } | 182 } |
183 | 183 |
184 // Dump all saved encoded video frames if any. | 184 // Dump all saved encoded video frames if any. |
185 while (!encoded_frames_queue_.empty()) { | 185 while (!encoded_frames_queue_.empty()) { |
186 AddFrame( | 186 AddFrame( |
187 std::move(encoded_frames_queue_.front()->data), video_track_index_, | 187 std::move(encoded_frames_queue_.front()->data), video_track_index_, |
188 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, | 188 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, |
189 encoded_frames_queue_.front()->is_keyframe); | 189 encoded_frames_queue_.front()->is_keyframe); |
190 encoded_frames_queue_.pop_front(); | 190 encoded_frames_queue_.pop_front(); |
191 } | 191 } |
192 | 192 |
193 AddFrame(std::move(encoded_data), audio_track_index_, | 193 AddFrame(std::move(encoded_data), audio_track_index_, |
194 timestamp - first_frame_timestamp_audio_, | 194 timestamp - first_frame_timestamp_audio_, |
195 true /* is_key_frame -- always true for audio */); | 195 true /* is_key_frame -- always true for audio */); |
196 } | 196 } |
197 | 197 |
198 void WebmMuxer::Pause() { | 198 void WebmMuxer::Pause() { |
199 DVLOG(1) << __FUNCTION__; | 199 DVLOG(1) << __func__; |
200 DCHECK(thread_checker_.CalledOnValidThread()); | 200 DCHECK(thread_checker_.CalledOnValidThread()); |
201 if (!elapsed_time_in_pause_) | 201 if (!elapsed_time_in_pause_) |
202 elapsed_time_in_pause_.reset(new base::ElapsedTimer()); | 202 elapsed_time_in_pause_.reset(new base::ElapsedTimer()); |
203 } | 203 } |
204 | 204 |
205 void WebmMuxer::Resume() { | 205 void WebmMuxer::Resume() { |
206 DVLOG(1) << __FUNCTION__; | 206 DVLOG(1) << __func__; |
207 DCHECK(thread_checker_.CalledOnValidThread()); | 207 DCHECK(thread_checker_.CalledOnValidThread()); |
208 if (elapsed_time_in_pause_) { | 208 if (elapsed_time_in_pause_) { |
209 total_time_in_pause_ += elapsed_time_in_pause_->Elapsed(); | 209 total_time_in_pause_ += elapsed_time_in_pause_->Elapsed(); |
210 elapsed_time_in_pause_.reset(); | 210 elapsed_time_in_pause_.reset(); |
211 } | 211 } |
212 } | 212 } |
213 | 213 |
214 void WebmMuxer::AddVideoTrack(const gfx::Size& frame_size, double frame_rate) { | 214 void WebmMuxer::AddVideoTrack(const gfx::Size& frame_size, double frame_rate) { |
215 DCHECK(thread_checker_.CalledOnValidThread()); | 215 DCHECK(thread_checker_.CalledOnValidThread()); |
216 DCHECK_EQ(0u, video_track_index_) | 216 DCHECK_EQ(0u, video_track_index_) |
(...skipping 18 matching lines...) Expand all Loading... |
235 DCHECK_EQ(0.0f, video_track->frame_rate()); | 235 DCHECK_EQ(0.0f, video_track->frame_rate()); |
236 | 236 |
237 video_track->set_default_duration(base::Time::kNanosecondsPerSecond / | 237 video_track->set_default_duration(base::Time::kNanosecondsPerSecond / |
238 frame_rate); | 238 frame_rate); |
239 // Segment's timestamps should be in milliseconds, DCHECK it. See | 239 // Segment's timestamps should be in milliseconds, DCHECK it. See |
240 // http://www.webmproject.org/docs/container/#muxer-guidelines | 240 // http://www.webmproject.org/docs/container/#muxer-guidelines |
241 DCHECK_EQ(1000000ull, segment_.GetSegmentInfo()->timecode_scale()); | 241 DCHECK_EQ(1000000ull, segment_.GetSegmentInfo()->timecode_scale()); |
242 } | 242 } |
243 | 243 |
244 void WebmMuxer::AddAudioTrack(const media::AudioParameters& params) { | 244 void WebmMuxer::AddAudioTrack(const media::AudioParameters& params) { |
245 DVLOG(1) << __FUNCTION__ << " " << params.AsHumanReadableString(); | 245 DVLOG(1) << __func__ << " " << params.AsHumanReadableString(); |
246 DCHECK(thread_checker_.CalledOnValidThread()); | 246 DCHECK(thread_checker_.CalledOnValidThread()); |
247 DCHECK_EQ(0u, audio_track_index_) | 247 DCHECK_EQ(0u, audio_track_index_) |
248 << "WebmMuxer audio can only be initialised once."; | 248 << "WebmMuxer audio can only be initialised once."; |
249 | 249 |
250 audio_track_index_ = | 250 audio_track_index_ = |
251 segment_.AddAudioTrack(params.sample_rate(), params.channels(), 0); | 251 segment_.AddAudioTrack(params.sample_rate(), params.channels(), 0); |
252 if (audio_track_index_ <= 0) { // See https://crbug.com/616391. | 252 if (audio_track_index_ <= 0) { // See https://crbug.com/616391. |
253 NOTREACHED() << "Error adding audio track"; | 253 NOTREACHED() << "Error adding audio track"; |
254 return; | 254 return; |
255 } | 255 } |
256 | 256 |
257 mkvmuxer::AudioTrack* const audio_track = | 257 mkvmuxer::AudioTrack* const audio_track = |
258 reinterpret_cast<mkvmuxer::AudioTrack*>( | 258 reinterpret_cast<mkvmuxer::AudioTrack*>( |
259 segment_.GetTrackByNumber(audio_track_index_)); | 259 segment_.GetTrackByNumber(audio_track_index_)); |
260 DCHECK(audio_track); | 260 DCHECK(audio_track); |
261 audio_track->set_codec_id(mkvmuxer::Tracks::kOpusCodecId); | 261 audio_track->set_codec_id(mkvmuxer::Tracks::kOpusCodecId); |
262 | 262 |
263 DCHECK_EQ(params.sample_rate(), audio_track->sample_rate()); | 263 DCHECK_EQ(params.sample_rate(), audio_track->sample_rate()); |
264 DCHECK_EQ(params.channels(), static_cast<int>(audio_track->channels())); | 264 DCHECK_EQ(params.channels(), static_cast<int>(audio_track->channels())); |
265 | 265 |
266 uint8_t opus_header[OPUS_EXTRADATA_SIZE]; | 266 uint8_t opus_header[OPUS_EXTRADATA_SIZE]; |
267 WriteOpusHeader(params, opus_header); | 267 WriteOpusHeader(params, opus_header); |
268 | 268 |
269 if (!audio_track->SetCodecPrivate(opus_header, OPUS_EXTRADATA_SIZE)) | 269 if (!audio_track->SetCodecPrivate(opus_header, OPUS_EXTRADATA_SIZE)) |
270 LOG(ERROR) << __FUNCTION__ << ": failed to set opus header."; | 270 LOG(ERROR) << __func__ << ": failed to set opus header."; |
271 | 271 |
272 // Segment's timestamps should be in milliseconds, DCHECK it. See | 272 // Segment's timestamps should be in milliseconds, DCHECK it. See |
273 // http://www.webmproject.org/docs/container/#muxer-guidelines | 273 // http://www.webmproject.org/docs/container/#muxer-guidelines |
274 DCHECK_EQ(1000000ull, segment_.GetSegmentInfo()->timecode_scale()); | 274 DCHECK_EQ(1000000ull, segment_.GetSegmentInfo()->timecode_scale()); |
275 } | 275 } |
276 | 276 |
277 mkvmuxer::int32 WebmMuxer::Write(const void* buf, mkvmuxer::uint32 len) { | 277 mkvmuxer::int32 WebmMuxer::Write(const void* buf, mkvmuxer::uint32 len) { |
278 DCHECK(thread_checker_.CalledOnValidThread()); | 278 DCHECK(thread_checker_.CalledOnValidThread()); |
279 DCHECK(buf); | 279 DCHECK(buf); |
280 write_data_callback_.Run( | 280 write_data_callback_.Run( |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 | 323 |
324 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame( | 324 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame( |
325 std::unique_ptr<std::string> data, | 325 std::unique_ptr<std::string> data, |
326 base::TimeTicks timestamp, | 326 base::TimeTicks timestamp, |
327 bool is_keyframe) | 327 bool is_keyframe) |
328 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} | 328 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} |
329 | 329 |
330 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} | 330 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} |
331 | 331 |
332 } // namespace media | 332 } // namespace media |
OLD | NEW |