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

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: 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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 return media::kUnknownVideoCodec; 51 return media::kUnknownVideoCodec;
52 } 52 }
53 53
54 } // anonymous namespace 54 } // anonymous namespace
55 55
56 MediaRecorderHandler::MediaRecorderHandler() 56 MediaRecorderHandler::MediaRecorderHandler()
57 : video_bits_per_second_(0), 57 : video_bits_per_second_(0),
58 audio_bits_per_second_(0), 58 audio_bits_per_second_(0),
59 codec_id_(VideoTrackRecorder::CodecId::VP8), 59 codec_id_(VideoTrackRecorder::CodecId::VP8),
60 recording_(false), 60 recording_(false),
61 media_stream_num_tracks_(0),
61 client_(nullptr), 62 client_(nullptr),
62 weak_factory_(this) {} 63 weak_factory_(this) {}
63 64
64 MediaRecorderHandler::~MediaRecorderHandler() { 65 MediaRecorderHandler::~MediaRecorderHandler() {
65 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 66 DCHECK(main_render_thread_checker_.CalledOnValidThread());
66 // Send a |last_in_slice| to our |client_|. 67 // Send a |last_in_slice| to our |client_|.
67 if (client_) 68 if (client_)
68 client_->writeData( 69 client_->writeData(
69 nullptr, 0u, true, 70 nullptr, 0u, true,
70 (TimeTicks::Now() - TimeTicks::UnixEpoch()).InMillisecondsF()); 71 (TimeTicks::Now() - TimeTicks::UnixEpoch()).InMillisecondsF());
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 else if (codecs_str.find("avc1") != std::string::npos) 140 else if (codecs_str.find("avc1") != std::string::npos)
140 codec_id_ = VideoTrackRecorder::CodecId::H264; 141 codec_id_ = VideoTrackRecorder::CodecId::H264;
141 #endif 142 #endif
142 else 143 else
143 codec_id_ = VideoTrackRecorder::GetPreferredCodecId(); 144 codec_id_ = VideoTrackRecorder::GetPreferredCodecId();
144 145
145 DVLOG_IF(1, codecs_str.empty()) << "Falling back to preferred codec id " 146 DVLOG_IF(1, codecs_str.empty()) << "Falling back to preferred codec id "
146 << static_cast<int>(codec_id_); 147 << static_cast<int>(codec_id_);
147 148
148 media_stream_ = media_stream; 149 media_stream_ = media_stream;
150 media_stream_num_tracks_ = 0; // Will be updated in start();
emircan 2017/02/17 00:19:07 Should we set it to 0 in Stop() as well?
mcasas 2017/02/17 01:46:14 Not really because after stop(), we'd need to ha
149 DCHECK(client); 151 DCHECK(client);
150 client_ = client; 152 client_ = client;
151 153
152 audio_bits_per_second_ = audio_bits_per_second; 154 audio_bits_per_second_ = audio_bits_per_second;
153 video_bits_per_second_ = video_bits_per_second; 155 video_bits_per_second_ = video_bits_per_second;
154 return true; 156 return true;
155 } 157 }
156 158
157 bool MediaRecorderHandler::start(int timeslice) { 159 bool MediaRecorderHandler::start(int timeslice) {
158 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 160 DCHECK(main_render_thread_checker_.CalledOnValidThread());
159 DCHECK(!recording_); 161 DCHECK(!recording_);
160 DCHECK(!media_stream_.isNull()); 162 DCHECK(!media_stream_.isNull());
161 DCHECK(timeslice_.is_zero()); 163 DCHECK(timeslice_.is_zero());
162 DCHECK(!webm_muxer_); 164 DCHECK(!webm_muxer_);
163 165
164 timeslice_ = TimeDelta::FromMilliseconds(timeslice); 166 timeslice_ = TimeDelta::FromMilliseconds(timeslice);
165 slice_origin_timestamp_ = TimeTicks::Now(); 167 slice_origin_timestamp_ = TimeTicks::Now();
166 168
167 blink::WebVector<blink::WebMediaStreamTrack> video_tracks, audio_tracks; 169 blink::WebVector<blink::WebMediaStreamTrack> video_tracks, audio_tracks;
168 media_stream_.videoTracks(video_tracks); 170 media_stream_.videoTracks(video_tracks);
169 media_stream_.audioTracks(audio_tracks); 171 media_stream_.audioTracks(audio_tracks);
172 media_stream_num_tracks_ = video_tracks.size() + audio_tracks.size();
170 173
171 if (video_tracks.isEmpty() && audio_tracks.isEmpty()) { 174 if (video_tracks.isEmpty() && audio_tracks.isEmpty()) {
172 LOG(WARNING) << __func__ << ": no media tracks."; 175 LOG(WARNING) << __func__ << ": no media tracks.";
173 return false; 176 return false;
174 } 177 }
175 178
176 const bool use_video_tracks = 179 const bool use_video_tracks =
177 !video_tracks.isEmpty() && video_tracks[0].isEnabled() && 180 !video_tracks.isEmpty() && video_tracks[0].isEnabled() &&
178 video_tracks[0].source().getReadyState() != 181 video_tracks[0].source().getReadyState() !=
179 blink::WebMediaStreamSource::ReadyStateEnded; 182 blink::WebMediaStreamSource::ReadyStateEnded;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 } 233 }
231 234
232 recording_ = true; 235 recording_ = true;
233 return true; 236 return true;
234 } 237 }
235 238
236 void MediaRecorderHandler::stop() { 239 void MediaRecorderHandler::stop() {
237 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 240 DCHECK(main_render_thread_checker_.CalledOnValidThread());
238 // Don't check |recording_| since we can go directly from pause() to stop(). 241 // Don't check |recording_| since we can go directly from pause() to stop().
239 242
243 weak_factory_.InvalidateWeakPtrs();
240 recording_ = false; 244 recording_ = false;
241 timeslice_ = TimeDelta::FromMilliseconds(0); 245 timeslice_ = TimeDelta::FromMilliseconds(0);
242 video_recorders_.clear(); 246 video_recorders_.clear();
243 audio_recorders_.clear(); 247 audio_recorders_.clear();
244 webm_muxer_.reset(); 248 webm_muxer_.reset();
245 } 249 }
246 250
247 void MediaRecorderHandler::pause() { 251 void MediaRecorderHandler::pause() {
248 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 252 DCHECK(main_render_thread_checker_.CalledOnValidThread());
249 DCHECK(recording_); 253 DCHECK(recording_);
(...skipping 15 matching lines...) Expand all
265 audio_recorder->Resume(); 269 audio_recorder->Resume();
266 webm_muxer_->Resume(); 270 webm_muxer_->Resume();
267 } 271 }
268 272
269 void MediaRecorderHandler::OnEncodedVideo( 273 void MediaRecorderHandler::OnEncodedVideo(
270 const media::WebmMuxer::VideoParameters& params, 274 const media::WebmMuxer::VideoParameters& params,
271 std::unique_ptr<std::string> encoded_data, 275 std::unique_ptr<std::string> encoded_data,
272 TimeTicks timestamp, 276 TimeTicks timestamp,
273 bool is_key_frame) { 277 bool is_key_frame) {
274 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 278 DCHECK(main_render_thread_checker_.CalledOnValidThread());
279
280 if (CheckAndUpdateAmountOfTracks()) {
281 client_->onError("Amount of tracks in MediaStream has changed.");
282 return;
283 }
275 if (!webm_muxer_) 284 if (!webm_muxer_)
276 return; 285 return;
277 if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), timestamp, 286 if (!webm_muxer_->OnEncodedVideo(params, std::move(encoded_data), timestamp,
278 is_key_frame)) { 287 is_key_frame)) {
279 DLOG(ERROR) << "Error muxing video data"; 288 DLOG(ERROR) << "Error muxing video data";
280 client_->onError("Error muxing video data"); 289 client_->onError("Error muxing video data");
281 } 290 }
282 } 291 }
283 292
284 void MediaRecorderHandler::OnEncodedAudio( 293 void MediaRecorderHandler::OnEncodedAudio(
285 const media::AudioParameters& params, 294 const media::AudioParameters& params,
286 std::unique_ptr<std::string> encoded_data, 295 std::unique_ptr<std::string> encoded_data,
287 base::TimeTicks timestamp) { 296 base::TimeTicks timestamp) {
288 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 297 DCHECK(main_render_thread_checker_.CalledOnValidThread());
298
299 if (CheckAndUpdateAmountOfTracks()) {
300 client_->onError("Amount of tracks in MediaStream has changed.");
301 return;
302 }
289 if (!webm_muxer_) 303 if (!webm_muxer_)
290 return; 304 return;
291 if (!webm_muxer_->OnEncodedAudio(params, std::move(encoded_data), 305 if (!webm_muxer_->OnEncodedAudio(params, std::move(encoded_data),
292 timestamp)) { 306 timestamp)) {
293 DLOG(ERROR) << "Error muxing audio data"; 307 DLOG(ERROR) << "Error muxing audio data";
294 client_->onError("Error muxing audio data"); 308 client_->onError("Error muxing audio data");
295 } 309 }
296 } 310 }
297 311
298 void MediaRecorderHandler::WriteData(base::StringPiece data) { 312 void MediaRecorderHandler::WriteData(base::StringPiece data) {
299 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 313 DCHECK(main_render_thread_checker_.CalledOnValidThread());
300 const TimeTicks now = TimeTicks::Now(); 314 const TimeTicks now = TimeTicks::Now();
301 // Non-buffered mode does not need to check timestamps. 315 // Non-buffered mode does not need to check timestamps.
302 if (timeslice_.is_zero()) { 316 if (timeslice_.is_zero()) {
303 client_->writeData(data.data(), data.length(), true /* lastInSlice */, 317 client_->writeData(data.data(), data.length(), true /* lastInSlice */,
304 (now - TimeTicks::UnixEpoch()).InMillisecondsF()); 318 (now - TimeTicks::UnixEpoch()).InMillisecondsF());
305 return; 319 return;
306 } 320 }
307 321
308 const bool last_in_slice = now > slice_origin_timestamp_ + timeslice_; 322 const bool last_in_slice = now > slice_origin_timestamp_ + timeslice_;
309 DVLOG_IF(1, last_in_slice) << "Slice finished @ " << now; 323 DVLOG_IF(1, last_in_slice) << "Slice finished @ " << now;
310 if (last_in_slice) 324 if (last_in_slice)
311 slice_origin_timestamp_ = now; 325 slice_origin_timestamp_ = now;
312 client_->writeData(data.data(), data.length(), last_in_slice, 326 client_->writeData(data.data(), data.length(), last_in_slice,
313 (now - TimeTicks::UnixEpoch()).InMillisecondsF()); 327 (now - TimeTicks::UnixEpoch()).InMillisecondsF());
314 } 328 }
315 329
330 bool MediaRecorderHandler::CheckAndUpdateAmountOfTracks() {
331 DCHECK(main_render_thread_checker_.CalledOnValidThread());
332
333 blink::WebVector<blink::WebMediaStreamTrack> video_tracks, audio_tracks;
334 media_stream_.videoTracks(video_tracks);
335 media_stream_.audioTracks(audio_tracks);
336 const size_t current_num_tracks = video_tracks.size() + audio_tracks.size();
337 if (media_stream_num_tracks_ == current_num_tracks)
emircan 2017/02/17 00:19:07 What about the case where one is added another is
mcasas 2017/02/17 01:46:14 Hmm good point, modified.
338 return false;
339
340 media_stream_num_tracks_ = current_num_tracks;
emircan 2017/02/17 00:19:07 Is it necessary to update |media_stream_num_tracks
mcasas 2017/02/17 01:46:14 I still need the update because at the end of the
341 return true;
342 }
343
316 void MediaRecorderHandler::OnVideoFrameForTesting( 344 void MediaRecorderHandler::OnVideoFrameForTesting(
317 const scoped_refptr<media::VideoFrame>& frame, 345 const scoped_refptr<media::VideoFrame>& frame,
318 const TimeTicks& timestamp) { 346 const TimeTicks& timestamp) {
319 for (const auto& recorder : video_recorders_) 347 for (const auto& recorder : video_recorders_)
320 recorder->OnVideoFrameForTesting(frame, timestamp); 348 recorder->OnVideoFrameForTesting(frame, timestamp);
321 } 349 }
322 350
323 void MediaRecorderHandler::OnAudioBusForTesting( 351 void MediaRecorderHandler::OnAudioBusForTesting(
324 const media::AudioBus& audio_bus, 352 const media::AudioBus& audio_bus,
325 const base::TimeTicks& timestamp) { 353 const base::TimeTicks& timestamp) {
326 for (const auto& recorder : audio_recorders_) 354 for (const auto& recorder : audio_recorders_)
327 recorder->OnData(audio_bus, timestamp); 355 recorder->OnData(audio_bus, timestamp);
328 } 356 }
329 357
330 void MediaRecorderHandler::SetAudioFormatForTesting( 358 void MediaRecorderHandler::SetAudioFormatForTesting(
331 const media::AudioParameters& params) { 359 const media::AudioParameters& params) {
332 for (const auto& recorder : audio_recorders_) 360 for (const auto& recorder : audio_recorders_)
333 recorder->OnSetFormat(params); 361 recorder->OnSetFormat(params);
334 } 362 }
335 363
336 } // namespace content 364 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698