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 "content/renderer/media/recorder/media_recorder_handler.h" | 5 #include "content/renderer/media/recorder/media_recorder_handler.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 bool MediaRecorderHandler::start(int timeslice) { | 157 bool MediaRecorderHandler::start(int timeslice) { |
158 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 158 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
159 DCHECK(!recording_); | 159 DCHECK(!recording_); |
160 DCHECK(!media_stream_.isNull()); | 160 DCHECK(!media_stream_.isNull()); |
161 DCHECK(timeslice_.is_zero()); | 161 DCHECK(timeslice_.is_zero()); |
162 DCHECK(!webm_muxer_); | 162 DCHECK(!webm_muxer_); |
163 | 163 |
164 timeslice_ = TimeDelta::FromMilliseconds(timeslice); | 164 timeslice_ = TimeDelta::FromMilliseconds(timeslice); |
165 slice_origin_timestamp_ = TimeTicks::Now(); | 165 slice_origin_timestamp_ = TimeTicks::Now(); |
166 | 166 |
167 blink::WebVector<blink::WebMediaStreamTrack> video_tracks, audio_tracks; | 167 media_stream_.videoTracks(video_tracks_); |
168 media_stream_.videoTracks(video_tracks); | 168 media_stream_.audioTracks(audio_tracks_); |
169 media_stream_.audioTracks(audio_tracks); | |
170 | 169 |
171 if (video_tracks.isEmpty() && audio_tracks.isEmpty()) { | 170 if (video_tracks_.isEmpty() && audio_tracks_.isEmpty()) { |
172 LOG(WARNING) << __func__ << ": no media tracks."; | 171 LOG(WARNING) << __func__ << ": no media tracks."; |
173 return false; | 172 return false; |
174 } | 173 } |
175 | 174 |
176 const bool use_video_tracks = | 175 const bool use_video_tracks = |
177 !video_tracks.isEmpty() && video_tracks[0].isEnabled() && | 176 !video_tracks_.isEmpty() && video_tracks_[0].isEnabled() && |
178 video_tracks[0].source().getReadyState() != | 177 video_tracks_[0].source().getReadyState() != |
179 blink::WebMediaStreamSource::ReadyStateEnded; | 178 blink::WebMediaStreamSource::ReadyStateEnded; |
180 const bool use_audio_tracks = | 179 const bool use_audio_tracks = |
181 !audio_tracks.isEmpty() && MediaStreamAudioTrack::From(audio_tracks[0]) && | 180 !audio_tracks_.isEmpty() && |
182 audio_tracks[0].isEnabled() && | 181 MediaStreamAudioTrack::From(audio_tracks_[0]) && |
183 audio_tracks[0].source().getReadyState() != | 182 audio_tracks_[0].isEnabled() && |
| 183 audio_tracks_[0].source().getReadyState() != |
184 blink::WebMediaStreamSource::ReadyStateEnded; | 184 blink::WebMediaStreamSource::ReadyStateEnded; |
185 | 185 |
186 if (!use_video_tracks && !use_audio_tracks) { | 186 if (!use_video_tracks && !use_audio_tracks) { |
187 LOG(WARNING) << __func__ << ": no tracks to be recorded."; | 187 LOG(WARNING) << __func__ << ": no tracks to be recorded."; |
188 return false; | 188 return false; |
189 } | 189 } |
190 | 190 |
191 webm_muxer_.reset(new media::WebmMuxer( | 191 webm_muxer_.reset(new media::WebmMuxer( |
192 CodecIdToMediaVideoCodec(codec_id_), use_video_tracks, use_audio_tracks, | 192 CodecIdToMediaVideoCodec(codec_id_), use_video_tracks, use_audio_tracks, |
193 base::Bind(&MediaRecorderHandler::WriteData, | 193 base::Bind(&MediaRecorderHandler::WriteData, |
194 weak_factory_.GetWeakPtr()))); | 194 weak_factory_.GetWeakPtr()))); |
195 | 195 |
196 if (use_video_tracks) { | 196 if (use_video_tracks) { |
197 // TODO(mcasas): The muxer API supports only one video track. Extend it to | 197 // TODO(mcasas): The muxer API supports only one video track. Extend it to |
198 // several video tracks, see http://crbug.com/528523. | 198 // several video tracks, see http://crbug.com/528523. |
199 LOG_IF(WARNING, video_tracks.size() > 1u) | 199 LOG_IF(WARNING, video_tracks_.size() > 1u) |
200 << "Recording multiple video tracks is not implemented. " | 200 << "Recording multiple video tracks is not implemented. " |
201 << "Only recording first video track."; | 201 << "Only recording first video track."; |
202 const blink::WebMediaStreamTrack& video_track = video_tracks[0]; | 202 const blink::WebMediaStreamTrack& video_track = video_tracks_[0]; |
203 if (video_track.isNull()) | 203 if (video_track.isNull()) |
204 return false; | 204 return false; |
205 | 205 |
206 const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb = | 206 const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb = |
207 media::BindToCurrentLoop(base::Bind( | 207 media::BindToCurrentLoop(base::Bind( |
208 &MediaRecorderHandler::OnEncodedVideo, weak_factory_.GetWeakPtr())); | 208 &MediaRecorderHandler::OnEncodedVideo, weak_factory_.GetWeakPtr())); |
209 | 209 |
210 video_recorders_.emplace_back(new VideoTrackRecorder( | 210 video_recorders_.emplace_back(new VideoTrackRecorder( |
211 codec_id_, video_track, on_encoded_video_cb, video_bits_per_second_)); | 211 codec_id_, video_track, on_encoded_video_cb, video_bits_per_second_)); |
212 } | 212 } |
213 | 213 |
214 if (use_audio_tracks) { | 214 if (use_audio_tracks) { |
215 // TODO(ajose): The muxer API supports only one audio track. Extend it to | 215 // TODO(ajose): The muxer API supports only one audio track. Extend it to |
216 // several tracks. | 216 // several tracks. |
217 LOG_IF(WARNING, audio_tracks.size() > 1u) | 217 LOG_IF(WARNING, audio_tracks_.size() > 1u) |
218 << "Recording multiple audio" | 218 << "Recording multiple audio" |
219 << " tracks is not implemented. Only recording first audio track."; | 219 << " tracks is not implemented. Only recording first audio track."; |
220 const blink::WebMediaStreamTrack& audio_track = audio_tracks[0]; | 220 const blink::WebMediaStreamTrack& audio_track = audio_tracks_[0]; |
221 if (audio_track.isNull()) | 221 if (audio_track.isNull()) |
222 return false; | 222 return false; |
223 | 223 |
224 const AudioTrackRecorder::OnEncodedAudioCB on_encoded_audio_cb = | 224 const AudioTrackRecorder::OnEncodedAudioCB on_encoded_audio_cb = |
225 media::BindToCurrentLoop(base::Bind( | 225 media::BindToCurrentLoop(base::Bind( |
226 &MediaRecorderHandler::OnEncodedAudio, weak_factory_.GetWeakPtr())); | 226 &MediaRecorderHandler::OnEncodedAudio, weak_factory_.GetWeakPtr())); |
227 | 227 |
228 audio_recorders_.emplace_back(new AudioTrackRecorder( | 228 audio_recorders_.emplace_back(new AudioTrackRecorder( |
229 audio_track, on_encoded_audio_cb, audio_bits_per_second_)); | 229 audio_track, on_encoded_audio_cb, audio_bits_per_second_)); |
230 } | 230 } |
231 | 231 |
232 recording_ = true; | 232 recording_ = true; |
233 return true; | 233 return true; |
234 } | 234 } |
235 | 235 |
236 void MediaRecorderHandler::stop() { | 236 void MediaRecorderHandler::stop() { |
237 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 237 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
238 // Don't check |recording_| since we can go directly from pause() to stop(). | 238 // Don't check |recording_| since we can go directly from pause() to stop(). |
239 | 239 |
| 240 weak_factory_.InvalidateWeakPtrs(); |
240 recording_ = false; | 241 recording_ = false; |
241 timeslice_ = TimeDelta::FromMilliseconds(0); | 242 timeslice_ = TimeDelta::FromMilliseconds(0); |
242 video_recorders_.clear(); | 243 video_recorders_.clear(); |
243 audio_recorders_.clear(); | 244 audio_recorders_.clear(); |
244 webm_muxer_.reset(); | 245 webm_muxer_.reset(); |
245 } | 246 } |
246 | 247 |
247 void MediaRecorderHandler::pause() { | 248 void MediaRecorderHandler::pause() { |
248 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 249 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
249 DCHECK(recording_); | 250 DCHECK(recording_); |
(...skipping 15 matching lines...) Expand all Loading... |
265 audio_recorder->Resume(); | 266 audio_recorder->Resume(); |
266 webm_muxer_->Resume(); | 267 webm_muxer_->Resume(); |
267 } | 268 } |
268 | 269 |
269 void MediaRecorderHandler::OnEncodedVideo( | 270 void MediaRecorderHandler::OnEncodedVideo( |
270 const media::WebmMuxer::VideoParameters& params, | 271 const media::WebmMuxer::VideoParameters& params, |
271 std::unique_ptr<std::string> encoded_data, | 272 std::unique_ptr<std::string> encoded_data, |
272 TimeTicks timestamp, | 273 TimeTicks timestamp, |
273 bool is_key_frame) { | 274 bool is_key_frame) { |
274 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 275 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 276 |
| 277 if (UpdateTracksAndCheckIfChanged()) { |
| 278 client_->onError("Amount of tracks in MediaStream has changed."); |
| 279 return; |
| 280 } |
275 if (!webm_muxer_) | 281 if (!webm_muxer_) |
276 return; | 282 return; |
277 if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), timestamp, | 283 if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), timestamp, |
278 is_key_frame)) { | 284 is_key_frame)) { |
279 DLOG(ERROR) << "Error muxing video data"; | 285 DLOG(ERROR) << "Error muxing video data"; |
280 client_->onError("Error muxing video data"); | 286 client_->onError("Error muxing video data"); |
281 } | 287 } |
282 } | 288 } |
283 | 289 |
284 void MediaRecorderHandler::OnEncodedAudio( | 290 void MediaRecorderHandler::OnEncodedAudio( |
285 const media::AudioParameters& params, | 291 const media::AudioParameters& params, |
286 std::unique_ptr<std::string> encoded_data, | 292 std::unique_ptr<std::string> encoded_data, |
287 base::TimeTicks timestamp) { | 293 base::TimeTicks timestamp) { |
288 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 294 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 295 |
| 296 if (UpdateTracksAndCheckIfChanged()) { |
| 297 client_->onError("Amount of tracks in MediaStream has changed."); |
| 298 return; |
| 299 } |
289 if (!webm_muxer_) | 300 if (!webm_muxer_) |
290 return; | 301 return; |
291 if (!webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), | 302 if (!webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), |
292 timestamp)) { | 303 timestamp)) { |
293 DLOG(ERROR) << "Error muxing audio data"; | 304 DLOG(ERROR) << "Error muxing audio data"; |
294 client_->onError("Error muxing audio data"); | 305 client_->onError("Error muxing audio data"); |
295 } | 306 } |
296 } | 307 } |
297 | 308 |
298 void MediaRecorderHandler::WriteData(base::StringPiece data) { | 309 void MediaRecorderHandler::WriteData(base::StringPiece data) { |
299 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 310 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
300 const TimeTicks now = TimeTicks::Now(); | 311 const TimeTicks now = TimeTicks::Now(); |
301 // Non-buffered mode does not need to check timestamps. | 312 // Non-buffered mode does not need to check timestamps. |
302 if (timeslice_.is_zero()) { | 313 if (timeslice_.is_zero()) { |
303 client_->writeData(data.data(), data.length(), true /* lastInSlice */, | 314 client_->writeData(data.data(), data.length(), true /* lastInSlice */, |
304 (now - TimeTicks::UnixEpoch()).InMillisecondsF()); | 315 (now - TimeTicks::UnixEpoch()).InMillisecondsF()); |
305 return; | 316 return; |
306 } | 317 } |
307 | 318 |
308 const bool last_in_slice = now > slice_origin_timestamp_ + timeslice_; | 319 const bool last_in_slice = now > slice_origin_timestamp_ + timeslice_; |
309 DVLOG_IF(1, last_in_slice) << "Slice finished @ " << now; | 320 DVLOG_IF(1, last_in_slice) << "Slice finished @ " << now; |
310 if (last_in_slice) | 321 if (last_in_slice) |
311 slice_origin_timestamp_ = now; | 322 slice_origin_timestamp_ = now; |
312 client_->writeData(data.data(), data.length(), last_in_slice, | 323 client_->writeData(data.data(), data.length(), last_in_slice, |
313 (now - TimeTicks::UnixEpoch()).InMillisecondsF()); | 324 (now - TimeTicks::UnixEpoch()).InMillisecondsF()); |
314 } | 325 } |
315 | 326 |
| 327 bool MediaRecorderHandler::UpdateTracksAndCheckIfChanged() { |
| 328 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 329 |
| 330 blink::WebVector<blink::WebMediaStreamTrack> video_tracks, audio_tracks; |
| 331 media_stream_.videoTracks(video_tracks); |
| 332 media_stream_.audioTracks(audio_tracks); |
| 333 |
| 334 bool video_tracks_changed = video_tracks_.size() != video_tracks.size(); |
| 335 bool audio_tracks_changed = audio_tracks_.size() != audio_tracks.size(); |
| 336 |
| 337 if (!video_tracks_changed) { |
| 338 for (size_t i = 0; i < video_tracks.size(); ++i) { |
| 339 if (video_tracks_[i].id() != video_tracks[i].id()) { |
| 340 video_tracks_changed = true; |
| 341 break; |
| 342 } |
| 343 } |
| 344 } |
| 345 if (!video_tracks_changed && !audio_tracks_changed) { |
| 346 for (size_t i = 0; i < audio_tracks.size(); ++i) { |
| 347 if (audio_tracks_[i].id() != audio_tracks[i].id()) { |
| 348 audio_tracks_changed = true; |
| 349 break; |
| 350 } |
| 351 } |
| 352 } |
| 353 |
| 354 if (video_tracks_changed) |
| 355 video_tracks_ = video_tracks; |
| 356 if (audio_tracks_changed) |
| 357 audio_tracks_ = audio_tracks; |
| 358 |
| 359 return video_tracks_changed || audio_tracks_changed; |
| 360 } |
| 361 |
316 void MediaRecorderHandler::OnVideoFrameForTesting( | 362 void MediaRecorderHandler::OnVideoFrameForTesting( |
317 const scoped_refptr<media::VideoFrame>& frame, | 363 const scoped_refptr<media::VideoFrame>& frame, |
318 const TimeTicks& timestamp) { | 364 const TimeTicks& timestamp) { |
319 for (const auto& recorder : video_recorders_) | 365 for (const auto& recorder : video_recorders_) |
320 recorder->OnVideoFrameForTesting(frame, timestamp); | 366 recorder->OnVideoFrameForTesting(frame, timestamp); |
321 } | 367 } |
322 | 368 |
323 void MediaRecorderHandler::OnAudioBusForTesting( | 369 void MediaRecorderHandler::OnAudioBusForTesting( |
324 const media::AudioBus& audio_bus, | 370 const media::AudioBus& audio_bus, |
325 const base::TimeTicks& timestamp) { | 371 const base::TimeTicks& timestamp) { |
326 for (const auto& recorder : audio_recorders_) | 372 for (const auto& recorder : audio_recorders_) |
327 recorder->OnData(audio_bus, timestamp); | 373 recorder->OnData(audio_bus, timestamp); |
328 } | 374 } |
329 | 375 |
330 void MediaRecorderHandler::SetAudioFormatForTesting( | 376 void MediaRecorderHandler::SetAudioFormatForTesting( |
331 const media::AudioParameters& params) { | 377 const media::AudioParameters& params) { |
332 for (const auto& recorder : audio_recorders_) | 378 for (const auto& recorder : audio_recorders_) |
333 recorder->OnSetFormat(params); | 379 recorder->OnSetFormat(params); |
334 } | 380 } |
335 | 381 |
336 } // namespace content | 382 } // namespace content |
OLD | NEW |