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

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

Powered by Google App Engine
This is Rietveld 408576698