Add SwapFrame() to VideoSendStreamInput.
Optionally prevents doing a frame copy when putting frames into a
VideoSendStream. PutFrame() is still there, which copies the frame.
Also removes time_since_capture_ms as a parameter, since
I420VideoFrame::render_time_ms() denotes when the frame was captured.
BUG=2657
R=mflodman@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/5119004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5265 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/common_video/common_video.gyp b/common_video/common_video.gyp
index f4d9ceb..97cb941 100644
--- a/common_video/common_video.gyp
+++ b/common_video/common_video.gyp
@@ -49,84 +49,4 @@
],
},
], # targets
- 'conditions': [
- ['include_tests==1', {
- 'targets': [
- {
- 'target_name': 'frame_generator',
- 'type': 'static_library',
- 'sources': [
- 'test/frame_generator.h',
- 'test/frame_generator.cc',
- ],
- 'dependencies': [
- 'common_video',
- ],
- },
- {
- 'target_name': 'common_video_unittests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- 'common_video',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
- '<(webrtc_root)/test/test.gyp:test_support_main',
- ],
- 'sources': [
- 'i420_video_frame_unittest.cc',
- 'libyuv/libyuv_unittest.cc',
- 'libyuv/scaler_unittest.cc',
- 'plane_unittest.cc',
- 'texture_video_frame_unittest.cc'
- ],
- # Disable warnings to enable Win64 build, issue 1323.
- 'msvs_disabled_warnings': [
- 4267, # size_t to int truncation.
- ],
- 'conditions': [
- # TODO(henrike): remove build_with_chromium==1 when the bots are
- # using Chromium's buildbots.
- ['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
- 'dependencies': [
- '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code',
- ],
- }],
- ],
- },
- ], # targets
- 'conditions': [
- # TODO(henrike): remove build_with_chromium==1 when the bots are using
- # Chromium's buildbots.
- ['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
- 'targets': [
- {
- 'target_name': 'common_video_unittests_apk_target',
- 'type': 'none',
- 'dependencies': [
- '<(apk_tests_path):common_video_unittests_apk',
- ],
- },
- ],
- }],
- ['test_isolation_mode != "noop"', {
- 'targets': [
- {
- 'target_name': 'common_video_unittests_run',
- 'type': 'none',
- 'dependencies': [
- 'common_video_unittests',
- ],
- 'includes': [
- '../build/isolate.gypi',
- 'common_video_unittests.isolate',
- ],
- 'sources': [
- 'common_video_unittests.isolate',
- ],
- },
- ],
- }],
- ],
- }], # include_tests
- ],
}
diff --git a/common_video/common_video_unittests.gyp b/common_video/common_video_unittests.gyp
new file mode 100644
index 0000000..9523361
--- /dev/null
+++ b/common_video/common_video_unittests.gyp
@@ -0,0 +1,76 @@
+# Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+{
+ 'includes': ['../build/common.gypi'],
+ 'targets': [
+ {
+ 'target_name': 'common_video_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ '<(webrtc_root)/common_video/common_video.gyp:common_video',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
+ '<(webrtc_root)/test/test.gyp:test_support_main',
+ ],
+ 'sources': [
+ 'i420_video_frame_unittest.cc',
+ 'libyuv/libyuv_unittest.cc',
+ 'libyuv/scaler_unittest.cc',
+ 'plane_unittest.cc',
+ 'texture_video_frame_unittest.cc'
+ ],
+ # Disable warnings to enable Win64 build, issue 1323.
+ 'msvs_disabled_warnings': [
+ 4267, # size_t to int truncation.
+ ],
+ 'conditions': [
+ # TODO(henrike): remove build_with_chromium==1 when the bots are
+ # using Chromium's buildbots.
+ ['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
+ 'dependencies': [
+ '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
+ },
+ ], # targets
+ 'conditions': [
+ # TODO(henrike): remove build_with_chromium==1 when the bots are using
+ # Chromium's buildbots.
+ ['build_with_chromium==1 and OS=="android" and gtest_target_type=="shared_library"', {
+ 'targets': [
+ {
+ 'target_name': 'common_video_unittests_apk_target',
+ 'type': 'none',
+ 'dependencies': [
+ '<(apk_tests_path):common_video_unittests_apk',
+ ],
+ },
+ ],
+ }],
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'common_video_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'common_video_unittests',
+ ],
+ 'includes': [
+ '../build/isolate.gypi',
+ 'common_video_unittests.isolate',
+ ],
+ 'sources': [
+ 'common_video_unittests.isolate',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/modules/modules.gyp b/modules/modules.gyp
index 53e7b31..e33816c 100644
--- a/modules/modules.gyp
+++ b/modules/modules.gyp
@@ -98,7 +98,7 @@
'<(webrtc_root)/modules/video_coding/codecs/vp8/vp8.gyp:webrtc_vp8',
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
'<(webrtc_root)/test/test.gyp:test_support_main',
- '<(webrtc_root)/common_video/common_video.gyp:frame_generator',
+ '<(webrtc_root)/test/test.gyp:frame_generator',
],
'sources': [
'audio_coding/main/acm2/acm_receiver_unittest.cc',
diff --git a/modules/video_coding/main/source/video_sender_unittest.cc b/modules/video_coding/main/source/video_sender_unittest.cc
index bdf2947..513a99e 100644
--- a/modules/video_coding/main/source/video_sender_unittest.cc
+++ b/modules/video_coding/main/source/video_sender_unittest.cc
@@ -12,7 +12,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/common.h"
-#include "webrtc/common_video/test/frame_generator.h"
#include "webrtc/modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h"
#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
@@ -22,6 +21,7 @@
#include "webrtc/modules/video_coding/main/test/test_util.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/test/frame_generator.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/test/testsupport/gtest_disable.h"
@@ -70,7 +70,7 @@
class EmptyFrameGenerator : public FrameGenerator {
public:
- virtual I420VideoFrame& NextFrame() OVERRIDE { return frame_; }
+ I420VideoFrame* NextFrame() OVERRIDE { frame_.ResetSize(); return &frame_; }
private:
I420VideoFrame frame_;
@@ -180,7 +180,7 @@
void AddFrame() {
assert(generator_.get());
- sender_->AddVideoFrame(generator_->NextFrame(), NULL, NULL);
+ sender_->AddVideoFrame(*generator_->NextFrame(), NULL, NULL);
}
SimulatedClock clock_;
diff --git a/common_video/test/frame_generator.cc b/test/frame_generator.cc
similarity index 74%
rename from common_video/test/frame_generator.cc
rename to test/frame_generator.cc
index 062bd17..4dd76ae 100644
--- a/common_video/test/frame_generator.cc
+++ b/test/frame_generator.cc
@@ -7,7 +7,7 @@
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
-#include "webrtc/common_video/test/frame_generator.h"
+#include "webrtc/test/frame_generator.h"
#include <math.h>
#include <stdio.h>
@@ -21,29 +21,32 @@
class ChromaGenerator : public FrameGenerator {
public:
- ChromaGenerator(size_t width, size_t height) : angle_(0.0) {
+ ChromaGenerator(size_t width, size_t height)
+ : angle_(0.0), width_(width), height_(height) {
assert(width > 0);
assert(height > 0);
- frame_.CreateEmptyFrame(static_cast<int>(width),
- static_cast<int>(height),
- static_cast<int>(width),
- static_cast<int>((width + 1) / 2),
- static_cast<int>((width + 1) / 2));
- memset(frame_.buffer(kYPlane), 0x80, frame_.allocated_size(kYPlane));
}
- virtual I420VideoFrame& NextFrame() OVERRIDE {
+ virtual I420VideoFrame* NextFrame() OVERRIDE {
+ frame_.CreateEmptyFrame(static_cast<int>(width_),
+ static_cast<int>(height_),
+ static_cast<int>(width_),
+ static_cast<int>((width_ + 1) / 2),
+ static_cast<int>((width_ + 1) / 2));
angle_ += 30.0;
uint8_t u = fabs(sin(angle_)) * 0xFF;
uint8_t v = fabs(cos(angle_)) * 0xFF;
+ memset(frame_.buffer(kYPlane), 0x80, frame_.allocated_size(kYPlane));
memset(frame_.buffer(kUPlane), u, frame_.allocated_size(kUPlane));
memset(frame_.buffer(kVPlane), v, frame_.allocated_size(kVPlane));
- return frame_;
+ return &frame_;
}
private:
double angle_;
+ size_t width_;
+ size_t height_;
I420VideoFrame frame_;
};
@@ -57,11 +60,6 @@
frame_size_ = CalcBufferSize(
kI420, static_cast<int>(width_), static_cast<int>(height_));
frame_buffer_ = new uint8_t[frame_size_];
- frame_.CreateEmptyFrame(static_cast<int>(width),
- static_cast<int>(height),
- static_cast<int>(width),
- static_cast<int>((width + 1) / 2),
- static_cast<int>((width + 1) / 2));
}
virtual ~YuvFileGenerator() {
@@ -69,13 +67,19 @@
delete[] frame_buffer_;
}
- virtual I420VideoFrame& NextFrame() OVERRIDE {
+ virtual I420VideoFrame* NextFrame() OVERRIDE {
size_t count = fread(frame_buffer_, 1, frame_size_, file_);
if (count < frame_size_) {
rewind(file_);
return NextFrame();
}
+ frame_.CreateEmptyFrame(static_cast<int>(width_),
+ static_cast<int>(height_),
+ static_cast<int>(width_),
+ static_cast<int>((width_ + 1) / 2),
+ static_cast<int>((width_ + 1) / 2));
+
ConvertToI420(kI420,
frame_buffer_,
0,
@@ -85,7 +89,7 @@
0,
kRotateNone,
&frame_);
- return frame_;
+ return &frame_;
}
private:
diff --git a/common_video/test/frame_generator.h b/test/frame_generator.h
similarity index 95%
rename from common_video/test/frame_generator.h
rename to test/frame_generator.h
index 8233700..fe10612 100644
--- a/common_video/test/frame_generator.h
+++ b/test/frame_generator.h
@@ -22,7 +22,7 @@
virtual ~FrameGenerator() {}
// Returns video frame that remains valid until next call.
- virtual I420VideoFrame& NextFrame() = 0;
+ virtual I420VideoFrame* NextFrame() = 0;
static FrameGenerator* Create(size_t width, size_t height);
static FrameGenerator* CreateFromYuvFile(const char* file,
diff --git a/test/frame_generator_capturer.cc b/test/frame_generator_capturer.cc
index e04961d..6570c6f 100644
--- a/test/frame_generator_capturer.cc
+++ b/test/frame_generator_capturer.cc
@@ -10,7 +10,7 @@
#include "webrtc/test/frame_generator_capturer.h"
-#include "webrtc/common_video/test/frame_generator.h"
+#include "webrtc/test/frame_generator.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
@@ -111,11 +111,9 @@
{
CriticalSectionScoped cs(lock_.get());
if (sending_) {
- int64_t time_before = clock_->CurrentNtpInMilliseconds();
- I420VideoFrame& frame = frame_generator_->NextFrame();
- frame.set_render_time_ms(time_before);
- int64_t time_after = clock_->CurrentNtpInMilliseconds();
- input_->PutFrame(frame, static_cast<uint32_t>(time_after - time_before));
+ I420VideoFrame* frame = frame_generator_->NextFrame();
+ frame->set_render_time_ms(clock_->CurrentNtpInMilliseconds());
+ input_->SwapFrame(frame);
}
}
tick_->Wait(WEBRTC_EVENT_INFINITE);
diff --git a/test/test.gyp b/test/test.gyp
index 09851f5..0051bce 100644
--- a/test/test.gyp
+++ b/test/test.gyp
@@ -42,6 +42,17 @@
],
},
{
+ 'target_name': 'frame_generator',
+ 'type': 'static_library',
+ 'sources': [
+ 'frame_generator.cc',
+ 'frame_generator.h',
+ ],
+ 'dependencies': [
+ '<(webrtc_root)/common_video/common_video.gyp:common_video',
+ ],
+ },
+ {
'target_name': 'test_support',
'type': 'static_library',
'dependencies': [
diff --git a/test/vcm_capturer.cc b/test/vcm_capturer.cc
index cbf7b1f..a5820bf 100644
--- a/test/vcm_capturer.cc
+++ b/test/vcm_capturer.cc
@@ -17,7 +17,7 @@
namespace test {
VcmCapturer::VcmCapturer(webrtc::VideoSendStreamInput* input)
- : VideoCapturer(input), started_(false), vcm_(NULL), last_timestamp_(0) {}
+ : VideoCapturer(input), started_(false), vcm_(NULL) {}
bool VcmCapturer::Init(size_t width, size_t height, size_t target_fps) {
VideoCaptureModule::DeviceInfo* device_info =
@@ -88,14 +88,8 @@
void VcmCapturer::OnIncomingCapturedFrame(const int32_t id,
I420VideoFrame& frame) {
- if (last_timestamp_ == 0 || frame.timestamp() < last_timestamp_) {
- last_timestamp_ = frame.timestamp();
- }
-
- if (started_) {
- input_->PutFrame(frame, frame.timestamp() - last_timestamp_);
- }
- last_timestamp_ = frame.timestamp();
+ if (started_)
+ input_->SwapFrame(&frame);
}
void VcmCapturer::OnCaptureDelayChanged(const int32_t id, const int32_t delay) {
diff --git a/test/vcm_capturer.h b/test/vcm_capturer.h
index 40befe8..dde3edc 100644
--- a/test/vcm_capturer.h
+++ b/test/vcm_capturer.h
@@ -40,8 +40,6 @@
bool started_;
VideoCaptureModule* vcm_;
VideoCaptureCapability capability_;
-
- uint32_t last_timestamp_;
};
} // test
} // webrtc
diff --git a/test/webrtc_test_common.gyp b/test/webrtc_test_common.gyp
index c7f6df5..eae66a0 100644
--- a/test/webrtc_test_common.gyp
+++ b/test/webrtc_test_common.gyp
@@ -119,8 +119,8 @@
'<(DEPTH)/third_party/gflags/gflags.gyp:gflags',
'<(webrtc_root)/modules/modules.gyp:video_capture_module',
'<(webrtc_root)/modules/modules.gyp:media_file',
+ '<(webrtc_root)/test/test.gyp:frame_generator',
'<(webrtc_root)/test/test.gyp:test_support',
- '<(webrtc_root)/common_video/common_video.gyp:frame_generator',
],
},
],
diff --git a/video/call_tests.cc b/video/call_tests.cc
index 6c247e6..5e4d682 100644
--- a/video/call_tests.cc
+++ b/video/call_tests.cc
@@ -17,7 +17,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/call.h"
-#include "webrtc/common_video/test/frame_generator.h"
#include "webrtc/frame_callback.h"
#include "webrtc/modules/remote_bitrate_estimator/include/rtp_to_ntp.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
@@ -25,20 +24,21 @@
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/test/direct_transport.h"
+#include "webrtc/test/fake_audio_device.h"
+#include "webrtc/test/fake_decoder.h"
+#include "webrtc/test/fake_encoder.h"
+#include "webrtc/test/frame_generator.h"
+#include "webrtc/test/frame_generator_capturer.h"
+#include "webrtc/test/rtp_rtcp_observer.h"
+#include "webrtc/test/testsupport/fileutils.h"
+#include "webrtc/test/testsupport/perf_test.h"
#include "webrtc/video/transport_adapter.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_codec.h"
#include "webrtc/voice_engine/include/voe_network.h"
#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
#include "webrtc/voice_engine/include/voe_video_sync.h"
-#include "webrtc/test/direct_transport.h"
-#include "webrtc/test/fake_audio_device.h"
-#include "webrtc/test/fake_decoder.h"
-#include "webrtc/test/fake_encoder.h"
-#include "webrtc/test/frame_generator_capturer.h"
-#include "webrtc/test/rtp_rtcp_observer.h"
-#include "webrtc/test/testsupport/fileutils.h"
-#include "webrtc/test/testsupport/perf_test.h"
namespace webrtc {
@@ -336,7 +336,7 @@
scoped_ptr<test::FrameGenerator> frame_generator(test::FrameGenerator::Create(
send_config_.codec.width, send_config_.codec.height));
- send_stream_->Input()->PutFrame(frame_generator->NextFrame(), 0);
+ send_stream_->Input()->SwapFrame(frame_generator->NextFrame());
EXPECT_EQ(kEventSignaled, renderer.Wait())
<< "Timed out while waiting for the frame to render.";
@@ -499,7 +499,7 @@
// check that the callbacks are done after processing video.
scoped_ptr<test::FrameGenerator> frame_generator(
test::FrameGenerator::Create(kWidth / 2, kHeight / 2));
- send_stream_->Input()->PutFrame(frame_generator->NextFrame(), 0);
+ send_stream_->Input()->SwapFrame(frame_generator->NextFrame());
EXPECT_EQ(kEventSignaled, pre_encode_callback.Wait())
<< "Timed out while waiting for pre-encode callback.";
@@ -1147,7 +1147,7 @@
scoped_ptr<test::FrameGenerator> frame_generator(test::FrameGenerator::Create(
send_config_.codec.width, send_config_.codec.height));
- send_stream_->Input()->PutFrame(frame_generator->NextFrame(), 0);
+ send_stream_->Input()->SwapFrame(frame_generator->NextFrame());
EXPECT_EQ(kEventSignaled, post_encode_observer.Wait())
<< "Timed out while waiting for send-side encoded-frame callback.";
diff --git a/video/full_stack.cc b/video/full_stack.cc
index f4e07e0..1181bfe 100644
--- a/video/full_stack.cc
+++ b/video/full_stack.cc
@@ -123,8 +123,11 @@
return receiver_->DeliverPacket(packet, length);
}
- virtual void PutFrame(const I420VideoFrame& video_frame,
- uint32_t delta_capture_ms) OVERRIDE {
+ virtual void PutFrame(const I420VideoFrame& video_frame) OVERRIDE {
+ ADD_FAILURE() << "PutFrame() should not have been called in this test.";
+ }
+
+ virtual void SwapFrame(I420VideoFrame* video_frame) OVERRIDE {
I420VideoFrame* copy = NULL;
{
CriticalSectionScoped cs(crit_.get());
@@ -136,7 +139,7 @@
if (copy == NULL)
copy = new I420VideoFrame();
- copy->CopyFrame(video_frame);
+ copy->CopyFrame(*video_frame);
copy->set_timestamp(copy->render_time_ms() * 90);
{
@@ -147,7 +150,7 @@
frames_.push_back(copy);
}
- input_->PutFrame(video_frame, delta_capture_ms);
+ input_->SwapFrame(video_frame);
}
virtual bool SendRtp(const uint8_t* packet, size_t length) OVERRIDE {
diff --git a/video/video_send_stream.cc b/video/video_send_stream.cc
index d90c733..2b83a48 100644
--- a/video/video_send_stream.cc
+++ b/video/video_send_stream.cc
@@ -211,31 +211,24 @@
rtp_rtcp_->Release();
}
-void VideoSendStream::PutFrame(const I420VideoFrame& frame,
- uint32_t time_since_capture_ms) {
- // TODO(pbos): frame_copy should happen after the VideoProcessingModule has
- // resized the frame.
- I420VideoFrame frame_copy;
- frame_copy.CopyFrame(frame);
+void VideoSendStream::PutFrame(const I420VideoFrame& frame) {
+ input_frame_.CopyFrame(frame);
+ SwapFrame(&input_frame_);
+}
- ViEVideoFrameI420 vf;
+void VideoSendStream::SwapFrame(I420VideoFrame* frame) {
+ // TODO(pbos): Warn if frame is "too far" into the future, or too old. This
+ // would help detect if frame's being used without NTP.
+ // TO REVIEWER: Is there any good check for this? Should it be
+ // skipped?
+ if (frame != &input_frame_)
+ input_frame_.SwapFrame(frame);
- // TODO(pbos): This represents a memcpy step and is only required because
- // external_capture_ only takes ViEVideoFrameI420s.
- vf.y_plane = frame_copy.buffer(kYPlane);
- vf.u_plane = frame_copy.buffer(kUPlane);
- vf.v_plane = frame_copy.buffer(kVPlane);
- vf.y_pitch = frame.stride(kYPlane);
- vf.u_pitch = frame.stride(kUPlane);
- vf.v_pitch = frame.stride(kVPlane);
- vf.width = frame.width();
- vf.height = frame.height();
+ // TODO(pbos): Local rendering should not be done on the capture thread.
+ if (config_.local_renderer != NULL)
+ config_.local_renderer->RenderFrame(input_frame_, 0);
- external_capture_->IncomingFrameI420(vf, frame.render_time_ms());
-
- if (config_.local_renderer != NULL) {
- config_.local_renderer->RenderFrame(frame, 0);
- }
+ external_capture_->SwapFrame(&input_frame_);
}
VideoSendStreamInput* VideoSendStream::Input() { return this; }
diff --git a/video/video_send_stream.h b/video/video_send_stream.h
index 0881d91..addb045 100644
--- a/video/video_send_stream.h
+++ b/video/video_send_stream.h
@@ -46,8 +46,9 @@
virtual ~VideoSendStream();
- virtual void PutFrame(const I420VideoFrame& frame,
- uint32_t time_since_capture_ms) OVERRIDE;
+ virtual void PutFrame(const I420VideoFrame& frame) OVERRIDE;
+
+ virtual void SwapFrame(I420VideoFrame* frame) OVERRIDE;
virtual VideoSendStreamInput* Input() OVERRIDE;
@@ -62,6 +63,7 @@
bool DeliverRtcp(const uint8_t* packet, size_t length);
private:
+ I420VideoFrame input_frame_;
TransportAdapter transport_adapter_;
EncodedFrameCallbackAdapter encoded_frame_proxy_;
scoped_ptr<CriticalSectionWrapper> codec_lock_;
diff --git a/video/video_send_stream_tests.cc b/video/video_send_stream_tests.cc
index d45a9c3..ae33e81 100644
--- a/video/video_send_stream_tests.cc
+++ b/video/video_send_stream_tests.cc
@@ -368,6 +368,30 @@
StatisticianMap stats_map_;
};
+TEST_F(VideoSendStreamTest, SwapsI420VideoFrames) {
+ static const size_t kWidth = 320;
+ static const size_t kHeight = 240;
+
+ test::NullTransport transport;
+ Call::Config call_config(&transport);
+ scoped_ptr<Call> call(Call::Create(call_config));
+
+ VideoSendStream::Config send_config = GetSendTestConfig(call.get(), 1);
+ VideoSendStream* video_send_stream = call->CreateVideoSendStream(send_config);
+ video_send_stream->StartSending();
+
+ I420VideoFrame frame;
+ frame.CreateEmptyFrame(
+ kWidth, kHeight, kWidth, (kWidth + 1) / 2, (kWidth + 1) / 2);
+ uint8_t* old_y_buffer = frame.buffer(kYPlane);
+
+ video_send_stream->Input()->SwapFrame(&frame);
+
+ EXPECT_NE(frame.buffer(kYPlane), old_y_buffer);
+
+ call->DestroyVideoSendStream(video_send_stream);
+}
+
TEST_F(VideoSendStreamTest, SupportsFec) {
static const int kRedPayloadType = 118;
static const int kUlpfecPayloadType = 119;
diff --git a/video_engine/include/vie_capture.h b/video_engine/include/vie_capture.h
index 2174d5d..cee3626 100644
--- a/video_engine/include/vie_capture.h
+++ b/video_engine/include/vie_capture.h
@@ -19,6 +19,7 @@
#define WEBRTC_VIDEO_ENGINE_INCLUDE_VIE_CAPTURE_H_
#include "webrtc/common_types.h"
+#include "webrtc/common_video/interface/i420_video_frame.h"
namespace webrtc {
@@ -117,6 +118,8 @@
virtual int IncomingFrameI420(
const ViEVideoFrameI420& video_frame,
unsigned long long capture_time = 0) = 0;
+
+ virtual void SwapFrame(I420VideoFrame* frame) {}
};
// This class declares an abstract interface for a user defined observer. It is
diff --git a/video_engine/vie_capturer.cc b/video_engine/vie_capturer.cc
index 9a2e3fc..aec5b39 100644
--- a/video_engine/vie_capturer.cc
+++ b/video_engine/vie_capturer.cc
@@ -363,6 +363,11 @@
capture_time);
}
+void ViECapturer::SwapFrame(I420VideoFrame* frame) {
+ external_capture_module_->IncomingI420VideoFrame(frame,
+ frame->render_time_ms());
+}
+
void ViECapturer::OnIncomingCapturedFrame(const int32_t capture_id,
I420VideoFrame& video_frame) {
WEBRTC_TRACE(kTraceStream, kTraceVideo, ViEId(engine_id_, capture_id_),
diff --git a/video_engine/vie_capturer.h b/video_engine/vie_capturer.h
index 9da187a..1fa2b53 100644
--- a/video_engine/vie_capturer.h
+++ b/video_engine/vie_capturer.h
@@ -76,6 +76,8 @@
virtual int IncomingFrameI420(const ViEVideoFrameI420& video_frame,
unsigned long long capture_time = 0); // NOLINT
+ virtual void SwapFrame(I420VideoFrame* frame) OVERRIDE;
+
// Start/Stop.
int32_t Start(
const CaptureCapability& capture_capability = CaptureCapability());
diff --git a/video_send_stream.h b/video_send_stream.h
index 2358042..9d4695d 100644
--- a/video_send_stream.h
+++ b/video_send_stream.h
@@ -26,10 +26,11 @@
// Class to deliver captured frame to the video send stream.
class VideoSendStreamInput {
public:
- // TODO(mflodman) Replace time_since_capture_ms when I420VideoFrame uses NTP
- // time.
- virtual void PutFrame(const I420VideoFrame& video_frame,
- uint32_t time_since_capture_ms) = 0;
+ // These methods do not lock internally and must be called sequentially.
+ // If your application switches input sources synchronization must be done
+ // externally to make sure that any old frames are not delivered concurrently.
+ virtual void PutFrame(const I420VideoFrame& video_frame) = 0;
+ virtual void SwapFrame(I420VideoFrame* video_frame) = 0;
protected:
virtual ~VideoSendStreamInput() {}
diff --git a/webrtc.gyp b/webrtc.gyp
index 7da4433..ed101b6 100644
--- a/webrtc.gyp
+++ b/webrtc.gyp
@@ -39,6 +39,7 @@
'conditions': [
['include_tests==1', {
'dependencies': [
+ 'common_video/common_video_unittests.gyp:*',
'system_wrappers/source/system_wrappers_tests.gyp:*',
'test/metrics.gyp:*',
'test/test.gyp:*',