Chromium Code Reviews| Index: content/renderer/media/gpu/rtc_video_encoder.cc |
| diff --git a/content/renderer/media/gpu/rtc_video_encoder.cc b/content/renderer/media/gpu/rtc_video_encoder.cc |
| index 5cf10a7bb77c5b5300a3064795ea4b73fe2d1a8f..608f83133f9a871a98883eb34b0ba545dd2c0677 100644 |
| --- a/content/renderer/media/gpu/rtc_video_encoder.cc |
| +++ b/content/renderer/media/gpu/rtc_video_encoder.cc |
| @@ -6,6 +6,7 @@ |
| #include <string.h> |
| +#include <deque> |
| #include <memory> |
| #include <vector> |
| @@ -20,6 +21,7 @@ |
| #include "base/synchronization/lock.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| +#include "base/time/time.h" |
| #include "media/base/bind_to_current_loop.h" |
| #include "media/base/bitstream_buffer.h" |
| #include "media/base/video_frame.h" |
| @@ -34,6 +36,17 @@ namespace content { |
| namespace { |
| +struct RTCTimestamps { |
| + RTCTimestamps(const base::TimeDelta& media_timestamp, int32_t rtp_timestamp) |
| + : media_timestamp_in_microseconds(media_timestamp.InMicroseconds()), |
| + rtp_timestamp(rtp_timestamp) {} |
| + const int64_t media_timestamp_in_microseconds; |
|
liberato (no reviews please)
2017/03/27 19:31:49
why not use base::TimeDelta for this? seems like
emircan
2017/03/27 20:20:32
Done.
|
| + const int32_t rtp_timestamp; |
| + |
| + private: |
| + DISALLOW_IMPLICIT_CONSTRUCTORS(RTCTimestamps); |
| +}; |
| + |
| // Translate from webrtc::VideoCodecType and webrtc::VideoCodec to |
| // media::VideoCodecProfile. |
| media::VideoCodecProfile WebRTCVideoCodecToVideoCodecProfile( |
| @@ -212,6 +225,14 @@ class RTCVideoEncoder::Impl |
| // The underlying VEA to perform encoding on. |
| std::unique_ptr<media::VideoEncodeAccelerator> video_encoder_; |
| + // Used to match the encoded frame timestamp with WebRTC's given RTP |
| + // timestamp. |
| + std::deque<RTCTimestamps> pending_timestamps_; |
| + |
| + // Indicates that timestamp match failed and we should no longer attempt |
| + // matching. |
| + bool failed_timestamp_match_; |
| + |
| // Next input frame. Since there is at most one next frame, a single-element |
| // queue is sufficient. |
| const webrtc::VideoFrame* input_next_frame_; |
| @@ -264,9 +285,10 @@ class RTCVideoEncoder::Impl |
| RTCVideoEncoder::Impl::Impl(media::GpuVideoAcceleratorFactories* gpu_factories, |
| webrtc::VideoCodecType video_codec_type) |
| : gpu_factories_(gpu_factories), |
| - async_waiter_(NULL), |
| - async_retval_(NULL), |
| - input_next_frame_(NULL), |
| + async_waiter_(nullptr), |
| + async_retval_(nullptr), |
| + failed_timestamp_match_(false), |
| + input_next_frame_(nullptr), |
| input_next_frame_keyframe_(false), |
| output_buffers_free_count_(0), |
| last_capture_time_ms_(-1), |
| @@ -455,9 +477,9 @@ void RTCVideoEncoder::Impl::RequireBitstreamBuffers( |
| } |
| void RTCVideoEncoder::Impl::BitstreamBufferReady(int32_t bitstream_buffer_id, |
| - size_t payload_size, |
| - bool key_frame, |
| - base::TimeDelta timestamp) { |
| + size_t payload_size, |
| + bool key_frame, |
| + base::TimeDelta timestamp) { |
| DVLOG(3) << "Impl::BitstreamBufferReady(): bitstream_buffer_id=" |
| << bitstream_buffer_id << ", payload_size=" << payload_size |
| << ", key_frame=" << key_frame |
| @@ -487,21 +509,37 @@ void RTCVideoEncoder::Impl::BitstreamBufferReady(int32_t bitstream_buffer_id, |
| capture_time_ms = std::max(capture_time_ms, last_capture_time_ms_ + 1); |
| last_capture_time_ms_ = capture_time_ms; |
| - // Fallback to the current time if encoder does not provide timestamp. |
| - const int64_t encoder_time_us = |
| - timestamp.is_zero() ? capture_time_us : timestamp.InMicroseconds(); |
| - |
| - // Derive the RTP timestamp (in 90KHz ticks). It can wrap around, get the |
| - // lower 32 bits. |
| - const uint32_t rtp_timestamp = static_cast<uint32_t>( |
| - encoder_time_us * 90 / base::Time::kMicrosecondsPerMillisecond); |
| + // Find RTP timestamp by going through |pending_timestamps_|. Derive it from |
| + // capture time otherwise. |
| + base::Optional<uint32_t> rtp_timestamp; |
| + if (!timestamp.is_zero() && !failed_timestamp_match_) { |
| + // Pop timestamps until we have a match. |
| + while (!pending_timestamps_.empty()) { |
| + const auto& front_timestamps = pending_timestamps_.front(); |
| + if (front_timestamps.media_timestamp_in_microseconds == |
| + timestamp.InMicroseconds()) { |
| + rtp_timestamp = front_timestamps.rtp_timestamp; |
| + pending_timestamps_.pop_front(); |
| + break; |
| + } |
| + pending_timestamps_.pop_front(); |
| + } |
| + DCHECK(rtp_timestamp.has_value()); |
| + } |
| + if (!rtp_timestamp.has_value()) { |
| + failed_timestamp_match_ = true; |
| + pending_timestamps_.clear(); |
| + // RTP timestamp can wrap around. Get the lower 32 bits. |
| + rtp_timestamp = static_cast<uint32_t>( |
| + capture_time_us * 90 / base::Time::kMicrosecondsPerMillisecond); |
| + } |
| webrtc::EncodedImage image( |
| reinterpret_cast<uint8_t*>(output_buffer->memory()), payload_size, |
| output_buffer->mapped_size()); |
| image._encodedWidth = input_visible_size_.width(); |
| image._encodedHeight = input_visible_size_.height(); |
| - image._timeStamp = rtp_timestamp; |
| + image._timeStamp = rtp_timestamp.value(); |
| image.capture_time_ms_ = capture_time_ms; |
| image._frameType = |
| (key_frame ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta); |
| @@ -621,6 +659,15 @@ void RTCVideoEncoder::Impl::EncodeOneFrame() { |
| } |
| frame->AddDestructionObserver(media::BindToCurrentLoop( |
| base::Bind(&RTCVideoEncoder::Impl::EncodeFrameFinished, this, index))); |
| + if (!failed_timestamp_match_) { |
| + DCHECK(std::find_if(pending_timestamps_.begin(), pending_timestamps_.end(), |
| + [&frame](const RTCTimestamps& entry) { |
| + return entry.media_timestamp_in_microseconds == |
| + frame->timestamp().InMicroseconds(); |
| + }) == pending_timestamps_.end()); |
| + pending_timestamps_.emplace_back(frame->timestamp(), |
| + next_frame->timestamp()); |
| + } |
| video_encoder_->Encode(frame, next_frame_keyframe); |
| input_buffers_free_.pop_back(); |
| SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); |