Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(532)

Side by Side Diff: content/renderer/media/recorder/media_recorder_handler.cc

Issue 2697703003: MediaRecorder: make sure ondataavailable+onstop events are fired before onerror (Closed)
Patch Set: fix some naming confusion Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698