| 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 "media/muxers/webm_muxer.h" | 5 #include "media/muxers/webm_muxer.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "media/audio/audio_parameters.h" | 8 #include "media/audio/audio_parameters.h" |
| 9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
| 10 #include "media/base/video_frame.h" | 10 #include "media/base/video_frame.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 base::TimeTicks timestamp, | 110 base::TimeTicks timestamp, |
| 111 bool is_key_frame) { | 111 bool is_key_frame) { |
| 112 DVLOG(1) << __FUNCTION__ << " - " << encoded_data->size() << "B"; | 112 DVLOG(1) << __FUNCTION__ << " - " << encoded_data->size() << "B"; |
| 113 DCHECK(thread_checker_.CalledOnValidThread()); | 113 DCHECK(thread_checker_.CalledOnValidThread()); |
| 114 | 114 |
| 115 if (!video_track_index_) { | 115 if (!video_track_index_) { |
| 116 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. | 116 // |track_index_|, cannot be zero (!), initialize WebmMuxer in that case. |
| 117 // http://www.matroska.org/technical/specs/index.html#Tracks | 117 // http://www.matroska.org/technical/specs/index.html#Tracks |
| 118 AddVideoTrack(video_frame->visible_rect().size(), | 118 AddVideoTrack(video_frame->visible_rect().size(), |
| 119 GetFrameRate(video_frame)); | 119 GetFrameRate(video_frame)); |
| 120 if (first_frame_timestamp_.is_null()) | 120 if (first_frame_timestamp_video_.is_null()) |
| 121 first_frame_timestamp_ = timestamp; | 121 first_frame_timestamp_video_ = timestamp; |
| 122 } | 122 } |
| 123 | 123 |
| 124 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 | 124 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 |
| 125 if (has_audio_ && !audio_track_index_) { | 125 if (has_audio_ && !audio_track_index_) { |
| 126 DVLOG(1) << __FUNCTION__ << ": delaying until audio track ready."; | 126 DVLOG(1) << __FUNCTION__ << ": delaying until audio track ready."; |
| 127 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. | 127 if (is_key_frame) // Upon Key frame reception, empty the encoded queue. |
| 128 encoded_frames_queue_.clear(); | 128 encoded_frames_queue_.clear(); |
| 129 | 129 |
| 130 encoded_frames_queue_.push_back(make_scoped_ptr(new EncodedVideoFrame( | 130 encoded_frames_queue_.push_back(make_scoped_ptr(new EncodedVideoFrame( |
| 131 std::move(encoded_data), timestamp, is_key_frame))); | 131 std::move(encoded_data), timestamp, is_key_frame))); |
| 132 return; | 132 return; |
| 133 } | 133 } |
| 134 | 134 |
| 135 // Dump all saved encoded video frames if any. | 135 // Dump all saved encoded video frames if any. |
| 136 while (!encoded_frames_queue_.empty()) { | 136 while (!encoded_frames_queue_.empty()) { |
| 137 AddFrame(std::move(encoded_frames_queue_.front()->data), video_track_index_, | 137 AddFrame( |
| 138 encoded_frames_queue_.front()->timestamp, | 138 std::move(encoded_frames_queue_.front()->data), video_track_index_, |
| 139 encoded_frames_queue_.front()->is_keyframe); | 139 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, |
| 140 encoded_frames_queue_.front()->is_keyframe); |
| 140 encoded_frames_queue_.pop_front(); | 141 encoded_frames_queue_.pop_front(); |
| 141 } | 142 } |
| 142 | 143 |
| 143 AddFrame(std::move(encoded_data), video_track_index_, timestamp, | 144 AddFrame(std::move(encoded_data), video_track_index_, |
| 144 is_key_frame); | 145 timestamp - first_frame_timestamp_video_, is_key_frame); |
| 145 } | 146 } |
| 146 | 147 |
| 147 void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, | 148 void WebmMuxer::OnEncodedAudio(const media::AudioParameters& params, |
| 148 scoped_ptr<std::string> encoded_data, | 149 scoped_ptr<std::string> encoded_data, |
| 149 base::TimeTicks timestamp) { | 150 base::TimeTicks timestamp) { |
| 150 DVLOG(2) << __FUNCTION__ << " - " << encoded_data->size() << "B"; | 151 DVLOG(2) << __FUNCTION__ << " - " << encoded_data->size() << "B"; |
| 151 DCHECK(thread_checker_.CalledOnValidThread()); | 152 DCHECK(thread_checker_.CalledOnValidThread()); |
| 152 | 153 |
| 153 if (!audio_track_index_) { | 154 if (!audio_track_index_) { |
| 154 AddAudioTrack(params); | 155 AddAudioTrack(params); |
| 155 if (first_frame_timestamp_.is_null()) | 156 if (first_frame_timestamp_audio_.is_null()) |
| 156 first_frame_timestamp_ = timestamp; | 157 first_frame_timestamp_audio_ = timestamp; |
| 157 } | 158 } |
| 158 | 159 |
| 159 // TODO(ajose): Don't drop audio data: http://crbug.com/547948 | 160 // TODO(ajose): Don't drop audio data: http://crbug.com/547948 |
| 160 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 | 161 // TODO(ajose): Support multiple tracks: http://crbug.com/528523 |
| 161 if (has_video_ && !video_track_index_) { | 162 if (has_video_ && !video_track_index_) { |
| 162 DVLOG(1) << __FUNCTION__ << ": delaying until video track ready."; | 163 DVLOG(1) << __FUNCTION__ << ": delaying until video track ready."; |
| 163 return; | 164 return; |
| 164 } | 165 } |
| 165 | 166 |
| 166 // Dump all saved encoded video frames if any. | 167 // Dump all saved encoded video frames if any. |
| 167 while (!encoded_frames_queue_.empty()) { | 168 while (!encoded_frames_queue_.empty()) { |
| 168 AddFrame(std::move(encoded_frames_queue_.front()->data), video_track_index_, | 169 AddFrame( |
| 169 encoded_frames_queue_.front()->timestamp, | 170 std::move(encoded_frames_queue_.front()->data), video_track_index_, |
| 170 encoded_frames_queue_.front()->is_keyframe); | 171 encoded_frames_queue_.front()->timestamp - first_frame_timestamp_video_, |
| 172 encoded_frames_queue_.front()->is_keyframe); |
| 171 encoded_frames_queue_.pop_front(); | 173 encoded_frames_queue_.pop_front(); |
| 172 } | 174 } |
| 173 | 175 |
| 174 AddFrame(std::move(encoded_data), audio_track_index_, timestamp, | 176 AddFrame(std::move(encoded_data), audio_track_index_, |
| 177 timestamp - first_frame_timestamp_audio_, |
| 175 true /* is_key_frame -- always true for audio */); | 178 true /* is_key_frame -- always true for audio */); |
| 176 } | 179 } |
| 177 | 180 |
| 178 void WebmMuxer::Pause() { | 181 void WebmMuxer::Pause() { |
| 179 DVLOG(1) << __FUNCTION__; | 182 DVLOG(1) << __FUNCTION__; |
| 180 DCHECK(thread_checker_.CalledOnValidThread()); | 183 DCHECK(thread_checker_.CalledOnValidThread()); |
| 181 if (!elapsed_time_in_pause_) | 184 if (!elapsed_time_in_pause_) |
| 182 elapsed_time_in_pause_.reset(new base::ElapsedTimer()); | 185 elapsed_time_in_pause_.reset(new base::ElapsedTimer()); |
| 183 } | 186 } |
| 184 | 187 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 | 276 |
| 274 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id, | 277 void WebmMuxer::ElementStartNotify(mkvmuxer::uint64 element_id, |
| 275 mkvmuxer::int64 position) { | 278 mkvmuxer::int64 position) { |
| 276 // This method gets pinged before items are sent to |write_data_callback_|. | 279 // This method gets pinged before items are sent to |write_data_callback_|. |
| 277 DCHECK_GE(position, position_.ValueOrDefault(0)) | 280 DCHECK_GE(position, position_.ValueOrDefault(0)) |
| 278 << "Can't go back in a live WebM stream."; | 281 << "Can't go back in a live WebM stream."; |
| 279 } | 282 } |
| 280 | 283 |
| 281 void WebmMuxer::AddFrame(scoped_ptr<std::string> encoded_data, | 284 void WebmMuxer::AddFrame(scoped_ptr<std::string> encoded_data, |
| 282 uint8_t track_index, | 285 uint8_t track_index, |
| 283 base::TimeTicks timestamp, | 286 base::TimeDelta timestamp, |
| 284 bool is_key_frame) { | 287 bool is_key_frame) { |
| 285 DCHECK(thread_checker_.CalledOnValidThread()); | 288 DCHECK(thread_checker_.CalledOnValidThread()); |
| 286 DCHECK(!has_video_ || video_track_index_); | 289 DCHECK(!has_video_ || video_track_index_); |
| 287 DCHECK(!has_audio_ || audio_track_index_); | 290 DCHECK(!has_audio_ || audio_track_index_); |
| 288 | 291 |
| 289 most_recent_timestamp_ = | 292 most_recent_timestamp_ = |
| 290 std::max(most_recent_timestamp_, | 293 std::max(most_recent_timestamp_, timestamp - total_time_in_pause_); |
| 291 timestamp - total_time_in_pause_ - first_frame_timestamp_); | |
| 292 | 294 |
| 293 segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()), | 295 segment_.AddFrame(reinterpret_cast<const uint8_t*>(encoded_data->data()), |
| 294 encoded_data->size(), track_index, | 296 encoded_data->size(), track_index, |
| 295 most_recent_timestamp_.InMicroseconds() * | 297 most_recent_timestamp_.InMicroseconds() * |
| 296 base::Time::kNanosecondsPerMicrosecond, | 298 base::Time::kNanosecondsPerMicrosecond, |
| 297 is_key_frame); | 299 is_key_frame); |
| 298 } | 300 } |
| 299 | 301 |
| 300 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame(scoped_ptr<std::string> data, | 302 WebmMuxer::EncodedVideoFrame::EncodedVideoFrame(scoped_ptr<std::string> data, |
| 301 base::TimeTicks timestamp, | 303 base::TimeTicks timestamp, |
| 302 bool is_keyframe) | 304 bool is_keyframe) |
| 303 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} | 305 : data(std::move(data)), timestamp(timestamp), is_keyframe(is_keyframe) {} |
| 304 | 306 |
| 305 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} | 307 WebmMuxer::EncodedVideoFrame::~EncodedVideoFrame() {} |
| 306 | 308 |
| 307 } // namespace media | 309 } // namespace media |
| OLD | NEW |