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

Side by Side Diff: media/muxers/webm_muxer.cc

Issue 2633623002: MediaRecorder: handle libwebm::Segment::AddFrame() errors and wire up to Blink (Closed)
Patch Set: I can haz moar testing? Created 3 years, 11 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
« no previous file with comments | « media/muxers/webm_muxer.h ('k') | media/muxers/webm_muxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "media/muxers/webm_muxer.h" 5 #include "media/muxers/webm_muxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 WebmMuxer::WebmMuxer(VideoCodec codec, 99 WebmMuxer::WebmMuxer(VideoCodec codec,
100 bool has_video, 100 bool has_video,
101 bool has_audio, 101 bool has_audio,
102 const WriteDataCB& write_data_callback) 102 const WriteDataCB& write_data_callback)
103 : video_codec_(codec), 103 : video_codec_(codec),
104 video_track_index_(0), 104 video_track_index_(0),
105 audio_track_index_(0), 105 audio_track_index_(0),
106 has_video_(has_video), 106 has_video_(has_video),
107 has_audio_(has_audio), 107 has_audio_(has_audio),
108 write_data_callback_(write_data_callback), 108 write_data_callback_(write_data_callback),
109 position_(0) { 109 position_(0),
110 force_one_libwebm_error_(false) {
110 DCHECK(has_video_ || has_audio_); 111 DCHECK(has_video_ || has_audio_);
111 DCHECK(!write_data_callback_.is_null()); 112 DCHECK(!write_data_callback_.is_null());
112 DCHECK(codec == kCodecVP8 || codec == kCodecVP9 || codec == kCodecH264) 113 DCHECK(codec == kCodecVP8 || codec == kCodecVP9 || codec == kCodecH264)
113 << " Unsupported codec: " << GetCodecName(codec); 114 << " Unsupported codec: " << GetCodecName(codec);
114 115
115 segment_.Init(this); 116 segment_.Init(this);
116 segment_.set_mode(mkvmuxer::Segment::kLive); 117 segment_.set_mode(mkvmuxer::Segment::kLive);
117 segment_.OutputCues(false); 118 segment_.OutputCues(false);
118 119
119 mkvmuxer::SegmentInfo* const info = segment_.GetSegmentInfo(); 120 mkvmuxer::SegmentInfo* const info = segment_.GetSegmentInfo();
120 info->set_writing_app("Chrome"); 121 info->set_writing_app("Chrome");
121 info->set_muxing_app("Chrome"); 122 info->set_muxing_app("Chrome");
122 123
123 // Creation is done on a different thread than main activities. 124 // Creation is done on a different thread than main activities.
124 thread_checker_.DetachFromThread(); 125 thread_checker_.DetachFromThread();
125 } 126 }
126 127
127 WebmMuxer::~WebmMuxer() { 128 WebmMuxer::~WebmMuxer() {
128 // No need to segment_.Finalize() since is not Seekable(), i.e. a live 129 // No need to segment_.Finalize() since is not Seekable(), i.e. a live
129 // stream, but is a good practice. 130 // stream, but is a good practice.
130 DCHECK(thread_checker_.CalledOnValidThread()); 131 DCHECK(thread_checker_.CalledOnValidThread());
131 segment_.Finalize(); 132 segment_.Finalize();
132 } 133 }
133 134
134 void WebmMuxer::OnEncodedVideo(const VideoParameters& params, 135 bool WebmMuxer::OnEncodedVideo(const VideoParameters& params,
135 std::unique_ptr<std::string> encoded_data, 136 std::unique_ptr<std::string> encoded_data,
136 base::TimeTicks timestamp, 137 base::TimeTicks timestamp,
137 bool is_key_frame) { 138 bool is_key_frame) {
138 DVLOG(1) << __func__ << " - " << encoded_data->size() << "B"; 139 DVLOG(1) << __func__ << " - " << encoded_data->size() << "B";
139 DCHECK(thread_checker_.CalledOnValidThread()); 140 DCHECK(thread_checker_.CalledOnValidThread());
140 141
141 if (!video_track_index_) { 142 if (!video_track_index_) {
142 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. 143 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case.
143 // http://www.matroska.org/technical/specs/index.html#Tracks 144 // http://www.matroska.org/technical/specs/index.html#Tracks
144 AddVideoTrack(params.visible_rect_size, GetFrameRate(params)); 145 AddVideoTrack(params.visible_rect_size, GetFrameRate(params));
145 if (first_frame_timestamp_video_.is_null()) 146 if (first_frame_timestamp_video_.is_null())
146 first_frame_timestamp_video_ = timestamp; 147 first_frame_timestamp_video_ = timestamp;
147 } 148 }
148 149
149 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 150 // TODO(ajose): Support multiple tracks: http://crbug.com/528523
150 if (has_audio_ && !audio_track_index_) { 151 if (has_audio_ && !audio_track_index_) {
151 DVLOG(1) << __func__ << ": delaying until audio track ready."; 152 DVLOG(1) << __func__ << ": delaying until audio track ready.";
152 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. 153 if (is_key_frame) // Upon Key frame reception, empty the encoded queue.
153 encoded_frames_queue_.clear(); 154 encoded_frames_queue_.clear();
154 155
155 encoded_frames_queue_.push_back(base::MakeUnique<EncodedVideoFrame>( 156 encoded_frames_queue_.push_back(base::MakeUnique<EncodedVideoFrame>(
156 std::move(encoded_data), timestamp, is_key_frame)); 157 std::move(encoded_data), timestamp, is_key_frame));
157 return; 158 return true;
158 } 159 }
159 160
160 // Dump all saved encoded video frames if any. 161 // Any saved encoded video frames must have been dumped in OnEncodedAudio();
161 while (!encoded_frames_queue_.empty()) { 162 DCHECK(encoded_frames_queue_.empty());
162 AddFrame(
163 std::move(encoded_frames_queue_.front()->data), video_track_index_,
164 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_,
165 encoded_frames_queue_.front()->is_keyframe);
166 encoded_frames_queue_.pop_front();
167 }
168 163
169 AddFrame(std::move(encoded_data), video_track_index_, 164 return AddFrame(std::move(encoded_data), video_track_index_,
170 timestamp - first_frame_timestamp_video_, is_key_frame); 165 timestamp - first_frame_timestamp_video_, is_key_frame);
171 } 166 }
172 167
173 void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, 168 bool WebmMuxer::OnEncodedAudio(const media::AudioParameters& params,
174 std::unique_ptr<std::string> encoded_data, 169 std::unique_ptr<std::string> encoded_data,
175 base::TimeTicks timestamp) { 170 base::TimeTicks timestamp) {
176 DVLOG(2) << __func__ << " - " << encoded_data->size() << "B"; 171 DVLOG(2) << __func__ << " - " << encoded_data->size() << "B";
177 DCHECK(thread_checker_.CalledOnValidThread()); 172 DCHECK(thread_checker_.CalledOnValidThread());
178 173
179 if (!audio_track_index_) { 174 if (!audio_track_index_) {
180 AddAudioTrack(params); 175 AddAudioTrack(params);
181 if (first_frame_timestamp_audio_.is_null()) 176 if (first_frame_timestamp_audio_.is_null())
182 first_frame_timestamp_audio_ = timestamp; 177 first_frame_timestamp_audio_ = timestamp;
183 } 178 }
184 179
185 // TODO(ajose): Don't drop audio data: http://crbug.com/547948 180 // TODO(ajose): Don't drop audio data: http://crbug.com/547948
186 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 181 // TODO(ajose): Support multiple tracks: http://crbug.com/528523
187 if (has_video_ && !video_track_index_) { 182 if (has_video_ && !video_track_index_) {
188 DVLOG(1) << __func__ << ": delaying until video track ready."; 183 DVLOG(1) << __func__ << ": delaying until video track ready.";
189 return; 184 return true;
190 } 185 }
191 186
192 // Dump all saved encoded video frames if any. 187 // Dump all saved encoded video frames if any.
193 while (!encoded_frames_queue_.empty()) { 188 while (!encoded_frames_queue_.empty()) {
194 AddFrame( 189 const bool res = AddFrame(
195 std::move(encoded_frames_queue_.front()->data), video_track_index_, 190 base::MakeUnique<std::string>(*encoded_frames_queue_.front()->data),
191 video_track_index_,
196 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, 192 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_,
197 encoded_frames_queue_.front()->is_keyframe); 193 encoded_frames_queue_.front()->is_keyframe);
194 if (!res)
195 return false;
198 encoded_frames_queue_.pop_front(); 196 encoded_frames_queue_.pop_front();
199 } 197 }
200 198
201 AddFrame(std::move(encoded_data), audio_track_index_, 199 return AddFrame(std::move(encoded_data), audio_track_index_,
202 timestamp - first_frame_timestamp_audio_, 200 timestamp - first_frame_timestamp_audio_,
203 true /* is_key_frame -- always true for audio */); 201 true /* is_key_frame -- always true for audio */);
204 } 202 }
205 203
206 void WebmMuxer::Pause() { 204 void WebmMuxer::Pause() {
207 DVLOG(1) << __func__; 205 DVLOG(1) << __func__;
208 DCHECK(thread_checker_.CalledOnValidThread()); 206 DCHECK(thread_checker_.CalledOnValidThread());
209 if (!elapsed_time_in_pause_) 207 if (!elapsed_time_in_pause_)
210 elapsed_time_in_pause_.reset(new base::ElapsedTimer()); 208 elapsed_time_in_pause_.reset(new base::ElapsedTimer());
211 } 209 }
212 210
213 void WebmMuxer::Resume() { 211 void WebmMuxer::Resume() {
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 return false; 300 return false;
303 } 301 }
304 302
305 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id, 303 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id,
306 mkvmuxer::int64 position) { 304 mkvmuxer::int64 position) {
307 // This method gets pinged before items are sent to |write_data_callback_|. 305 // This method gets pinged before items are sent to |write_data_callback_|.
308 DCHECK_GE(position, position_.ValueOrDefault(0)) 306 DCHECK_GE(position, position_.ValueOrDefault(0))
309 << "Can't go back in a live WebM stream."; 307 << "Can't go back in a live WebM stream.";
310 } 308 }
311 309
312 void WebmMuxer::AddFrame(std::unique_ptr<std::string> encoded_data, 310 bool WebmMuxer::AddFrame(std::unique_ptr<std::string> encoded_data,
313 uint8_t track_index, 311 uint8_t track_index,
314 base::TimeDelta timestamp, 312 base::TimeDelta timestamp,
315 bool is_key_frame) { 313 bool is_key_frame) {
316 DCHECK(thread_checker_.CalledOnValidThread()); 314 DCHECK(thread_checker_.CalledOnValidThread());
317 DCHECK(!has_video_ || video_track_index_); 315 DCHECK(!has_video_ || video_track_index_);
318 DCHECK(!has_audio_ || audio_track_index_); 316 DCHECK(!has_audio_ || audio_track_index_);
319 317
320 most_recent_timestamp_ = 318 most_recent_timestamp_ =
321 std::max(most_recent_timestamp_, timestamp - total_time_in_pause_); 319 std::max(most_recent_timestamp_, timestamp - total_time_in_pause_);
322 320
323 segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()), 321 if (force_one_libwebm_error_) {
324 encoded_data->size(), track_index, 322 DVLOG(1) << "Forcing a libwebm error";
325 most_recent_timestamp_.InMicroseconds() * 323 force_one_libwebm_error_ = false;
326 base::Time::kNanosecondsPerMicrosecond, 324 return false;
327 is_key_frame); 325 }
326
327 DCHECK(encoded_data->data());
328 return segment_.AddFrame(
329 reinterpret_cast<const uint8_t*>(encoded_data->data()),
330 encoded_data->size(), track_index,
331 most_recent_timestamp_.InMicroseconds() *
332 base::Time::kNanosecondsPerMicrosecond,
333 is_key_frame);
328 } 334 }
329 335
330 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame( 336 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame(
331 std::unique_ptr<std::string> data, 337 std::unique_ptr<std::string> data,
332 base::TimeTicks timestamp, 338 base::TimeTicks timestamp,
333 bool is_keyframe) 339 bool is_keyframe)
334 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} 340 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {}
335 341
336 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} 342 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {}
337 343
338 } // namespace media 344 } // namespace media
OLDNEW
« no previous file with comments | « media/muxers/webm_muxer.h ('k') | media/muxers/webm_muxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698