Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/cast/video_receiver/video_receiver.h" | 5 #include "media/cast/video_receiver/video_receiver.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | |
| 8 #include "base/bind.h" | 9 #include "base/bind.h" |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 10 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "crypto/symmetric_key.h" | |
| 11 #include "media/cast/cast_defines.h" | 13 #include "media/cast/cast_defines.h" |
| 12 #include "media/cast/framer/framer.h" | 14 #include "media/cast/framer/framer.h" |
| 13 #include "media/cast/video_receiver/video_decoder.h" | 15 #include "media/cast/video_receiver/video_decoder.h" |
| 14 | 16 |
| 15 namespace media { | 17 namespace media { |
| 16 namespace cast { | 18 namespace cast { |
| 17 | 19 |
| 18 const int64 kMinSchedulingDelayMs = 1; | 20 const int64 kMinSchedulingDelayMs = 1; |
| 19 | 21 |
| 20 static const int64 kMinTimeBetweenOffsetUpdatesMs = 2000; | 22 static const int64 kMinTimeBetweenOffsetUpdatesMs = 2000; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 incoming_payload_feedback_(new LocalRtpVideoFeedback(this)), | 120 incoming_payload_feedback_(new LocalRtpVideoFeedback(this)), |
| 119 rtp_receiver_(cast_environment_->Clock(), NULL, &video_config, | 121 rtp_receiver_(cast_environment_->Clock(), NULL, &video_config, |
| 120 incoming_payload_callback_.get()), | 122 incoming_payload_callback_.get()), |
| 121 rtp_video_receiver_statistics_( | 123 rtp_video_receiver_statistics_( |
| 122 new LocalRtpReceiverStatistics(&rtp_receiver_)), | 124 new LocalRtpReceiverStatistics(&rtp_receiver_)), |
| 123 weak_factory_(this) { | 125 weak_factory_(this) { |
| 124 int max_unacked_frames = video_config.rtp_max_delay_ms * | 126 int max_unacked_frames = video_config.rtp_max_delay_ms * |
| 125 video_config.max_frame_rate / 1000; | 127 video_config.max_frame_rate / 1000; |
| 126 DCHECK(max_unacked_frames) << "Invalid argument"; | 128 DCHECK(max_unacked_frames) << "Invalid argument"; |
| 127 | 129 |
| 130 if (video_config.aes_iv_mask.size() == kAesBlockSize * 2 && | |
| 131 video_config.aes_key.size() == kAesBlockSize * 2) { | |
| 132 iv_mask_ = ConvertFromBase16String(video_config.aes_iv_mask); | |
| 133 crypto::SymmetricKey* key = crypto::SymmetricKey::Import( | |
| 134 crypto::SymmetricKey::AES, | |
| 135 ConvertFromBase16String(video_config.aes_key)); | |
|
Alpha Left Google
2013/11/07 01:10:11
Again don't do the conversion in this low level st
pwestin
2013/11/07 17:16:04
Done.
| |
| 136 encryptor_.reset(new crypto::Encryptor()); | |
| 137 encryptor_->Init(key, crypto::Encryptor::CTR, std::string()); | |
| 138 } else if (video_config.aes_iv_mask.size() != 0 || | |
| 139 video_config.aes_iv_mask.size() != 0) { | |
| 140 DCHECK(false) << "Invalid crypto configuration"; | |
| 141 } | |
| 142 | |
| 128 framer_.reset(new Framer(cast_environment->Clock(), | 143 framer_.reset(new Framer(cast_environment->Clock(), |
| 129 incoming_payload_feedback_.get(), | 144 incoming_payload_feedback_.get(), |
| 130 video_config.incoming_ssrc, | 145 video_config.incoming_ssrc, |
| 131 video_config.decoder_faster_than_max_frame_rate, | 146 video_config.decoder_faster_than_max_frame_rate, |
| 132 max_unacked_frames)); | 147 max_unacked_frames)); |
| 133 if (!video_config.use_external_decoder) { | 148 if (!video_config.use_external_decoder) { |
| 134 video_decoder_.reset(new VideoDecoder(video_config)); | 149 video_decoder_.reset(new VideoDecoder(video_config)); |
| 135 } | 150 } |
| 136 | 151 |
| 137 rtcp_.reset( | 152 rtcp_.reset( |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 base::Bind(frame_decoded_callback, | 208 base::Bind(frame_decoded_callback, |
| 194 base::Passed(&video_frame), render_time)); | 209 base::Passed(&video_frame), render_time)); |
| 195 } else { | 210 } else { |
| 196 // This will happen if we decide to decode but not show a frame. | 211 // This will happen if we decide to decode but not show a frame. |
| 197 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, | 212 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| 198 base::Bind(&VideoReceiver::GetRawVideoFrame, | 213 base::Bind(&VideoReceiver::GetRawVideoFrame, |
| 199 weak_factory_.GetWeakPtr(), frame_decoded_callback)); | 214 weak_factory_.GetWeakPtr(), frame_decoded_callback)); |
| 200 } | 215 } |
| 201 } | 216 } |
| 202 | 217 |
| 218 bool VideoReceiver::DecryptVideoFrame( | |
| 219 const EncodedVideoFrame* encrypted_frame, | |
| 220 EncodedVideoFrame* video_frame) { | |
| 221 DCHECK(encryptor_) << "Invalid state"; | |
| 222 | |
| 223 // TODO(pwestin): the frame id must be a 32 bit number. | |
| 224 encryptor_->SetCounter(GetAesNounce(encrypted_frame->frame_id, iv_mask_)); | |
| 225 | |
| 226 video_frame->codec = encrypted_frame->codec; | |
| 227 video_frame->key_frame = encrypted_frame->key_frame; | |
| 228 video_frame->frame_id = encrypted_frame->frame_id; | |
| 229 video_frame->last_referenced_frame_id = | |
| 230 encrypted_frame->last_referenced_frame_id; | |
| 231 | |
| 232 return encryptor_->Decrypt(encrypted_frame->data, &video_frame->data); | |
| 233 } | |
| 234 | |
| 203 // Called from the main cast thread. | 235 // Called from the main cast thread. |
| 204 void VideoReceiver::GetEncodedVideoFrame( | 236 void VideoReceiver::GetEncodedVideoFrame( |
| 205 const VideoFrameEncodedCallback& callback) { | 237 const VideoFrameEncodedCallback& callback) { |
| 206 scoped_ptr<EncodedVideoFrame> encoded_frame(new EncodedVideoFrame()); | 238 scoped_ptr<EncodedVideoFrame> encoded_frame(new EncodedVideoFrame()); |
| 207 uint32 rtp_timestamp = 0; | 239 uint32 rtp_timestamp = 0; |
| 208 bool next_frame = false; | 240 bool next_frame = false; |
| 209 | 241 |
| 210 if (!framer_->GetEncodedVideoFrame(encoded_frame.get(), &rtp_timestamp, | 242 if (!framer_->GetEncodedVideoFrame(encoded_frame.get(), &rtp_timestamp, |
| 211 &next_frame)) { | 243 &next_frame)) { |
| 212 // We have no video frames. Wait for new packet(s). | 244 // We have no video frames. Wait for new packet(s). |
| 213 queued_encoded_callbacks_.push_back(callback); | 245 queued_encoded_callbacks_.push_back(callback); |
| 214 return; | 246 return; |
| 215 } | 247 } |
| 248 | |
| 249 if (encryptor_) { | |
| 250 EncodedVideoFrame* decrypted_video_frame = new EncodedVideoFrame(); | |
|
Alpha Left Google
2013/11/07 01:10:11
This should be a scoped_ptr<T>.
pwestin
2013/11/07 17:16:04
Done.
| |
| 251 | |
| 252 if (DecryptVideoFrame(encoded_frame.get(), decrypted_video_frame)) { | |
| 253 encoded_frame.reset(decrypted_video_frame); | |
| 254 } else { | |
| 255 DCHECK(false) << "Decryption error"; | |
| 256 return; | |
| 257 } | |
| 258 } | |
| 259 | |
| 216 base::TimeTicks render_time; | 260 base::TimeTicks render_time; |
| 217 if (PullEncodedVideoFrame(rtp_timestamp, next_frame, &encoded_frame, | 261 if (PullEncodedVideoFrame(rtp_timestamp, next_frame, &encoded_frame, |
| 218 &render_time)) { | 262 &render_time)) { |
| 219 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, | 263 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| 220 base::Bind(callback, base::Passed(&encoded_frame), render_time)); | 264 base::Bind(callback, base::Passed(&encoded_frame), render_time)); |
| 221 } else { | 265 } else { |
| 222 // We have a video frame; however we are missing packets and we have time | 266 // We have a video frame; however we are missing packets and we have time |
| 223 // to wait for new packet(s). | 267 // to wait for new packet(s). |
| 224 queued_encoded_callbacks_.push_back(callback); | 268 queued_encoded_callbacks_.push_back(callback); |
| 225 } | 269 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 // We have no video frames. Wait for new packet(s). | 330 // We have no video frames. Wait for new packet(s). |
| 287 // Since the application can post multiple VideoFrameEncodedCallback and | 331 // Since the application can post multiple VideoFrameEncodedCallback and |
| 288 // we only check the next frame to play out we might have multiple timeout | 332 // we only check the next frame to play out we might have multiple timeout |
| 289 // events firing after each other; however this should be a rare event. | 333 // events firing after each other; however this should be a rare event. |
| 290 VLOG(1) << "Failed to retrieved a complete frame at this point in time"; | 334 VLOG(1) << "Failed to retrieved a complete frame at this point in time"; |
| 291 return; | 335 return; |
| 292 } | 336 } |
| 293 VLOG(1) << "PlayoutTimeout retrieved frame " | 337 VLOG(1) << "PlayoutTimeout retrieved frame " |
| 294 << static_cast<int>(encoded_frame->frame_id); | 338 << static_cast<int>(encoded_frame->frame_id); |
| 295 | 339 |
| 340 if (encryptor_) { | |
| 341 EncodedVideoFrame* decrypted_video_frame = new EncodedVideoFrame(); | |
|
Alpha Left Google
2013/11/07 01:10:11
Same here, use scoped_ptr<T>.
pwestin
2013/11/07 17:16:04
Done.
| |
| 342 | |
| 343 if (DecryptVideoFrame(encoded_frame.get(), decrypted_video_frame)) { | |
| 344 encoded_frame.reset(decrypted_video_frame); | |
| 345 } else { | |
| 346 DCHECK(false) << "Decryption error"; | |
| 347 delete decrypted_video_frame; | |
| 348 return; | |
| 349 } | |
| 350 } | |
| 351 | |
| 296 base::TimeTicks render_time; | 352 base::TimeTicks render_time; |
| 297 if (PullEncodedVideoFrame(rtp_timestamp, next_frame, &encoded_frame, | 353 if (PullEncodedVideoFrame(rtp_timestamp, next_frame, &encoded_frame, |
| 298 &render_time)) { | 354 &render_time)) { |
| 299 if (!queued_encoded_callbacks_.empty()) { | 355 if (!queued_encoded_callbacks_.empty()) { |
| 300 VideoFrameEncodedCallback callback = queued_encoded_callbacks_.front(); | 356 VideoFrameEncodedCallback callback = queued_encoded_callbacks_.front(); |
| 301 queued_encoded_callbacks_.pop_front(); | 357 queued_encoded_callbacks_.pop_front(); |
| 302 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, | 358 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| 303 base::Bind(callback, base::Passed(&encoded_frame), render_time)); | 359 base::Bind(callback, base::Passed(&encoded_frame), render_time)); |
| 304 } | 360 } |
| 305 } else { | 361 } else { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 419 weak_factory_.GetWeakPtr()), time_to_next); | 475 weak_factory_.GetWeakPtr()), time_to_next); |
| 420 } | 476 } |
| 421 | 477 |
| 422 void VideoReceiver::SendNextRtcpReport() { | 478 void VideoReceiver::SendNextRtcpReport() { |
| 423 rtcp_->SendRtcpReport(incoming_ssrc_); | 479 rtcp_->SendRtcpReport(incoming_ssrc_); |
| 424 ScheduleNextRtcpReport(); | 480 ScheduleNextRtcpReport(); |
| 425 } | 481 } |
| 426 | 482 |
| 427 } // namespace cast | 483 } // namespace cast |
| 428 } // namespace media | 484 } // namespace media |
| OLD | NEW |