New VideoEngine API implementation on top of old one, first steps.

BUG=1668
R=mflodman@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/1360004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4044 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pbos@webrtc.org 2013-05-16 12:08:03 +00:00
parent 2038214c77
commit 29d5839233
26 changed files with 2102 additions and 6 deletions

View File

@ -0,0 +1,186 @@
/*
* 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.
*/
#include "webrtc/video_engine/internal/video_call.h"
#include <cassert>
#include <cstring>
#include <map>
#include <vector>
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
#include "webrtc/video_engine/new_include/common.h"
#include "webrtc/video_engine/new_include/video_engine.h"
#include "webrtc/video_engine/internal/video_receive_stream.h"
#include "webrtc/video_engine/internal/video_send_stream.h"
namespace webrtc {
namespace internal {
VideoCall::VideoCall(webrtc::VideoEngine* video_engine,
newapi::Transport* send_transport)
: send_transport(send_transport), video_engine_(video_engine) {
assert(video_engine != NULL);
assert(send_transport != NULL);
rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine_);
assert(rtp_rtcp_ != NULL);
codec_ = ViECodec::GetInterface(video_engine_);
assert(codec_ != NULL);
}
VideoCall::~VideoCall() {
rtp_rtcp_->Release();
codec_->Release();
}
newapi::PacketReceiver* VideoCall::Receiver() { return this; }
std::vector<VideoCodec> VideoCall::GetVideoCodecs() {
std::vector<VideoCodec> codecs;
VideoCodec codec;
for (size_t i = 0; i < static_cast<size_t>(codec_->NumberOfCodecs()); ++i) {
if (codec_->GetCodec(i, codec) == 0) {
codecs.push_back(codec);
}
}
return codecs;
}
void VideoCall::GetDefaultSendConfig(
newapi::VideoSendStreamConfig* send_stream_config) {
*send_stream_config = newapi::VideoSendStreamConfig();
codec_->GetCodec(0, send_stream_config->codec);
}
newapi::VideoSendStream* VideoCall::CreateSendStream(
const newapi::VideoSendStreamConfig& send_stream_config) {
assert(send_stream_config.rtp.ssrcs.size() > 0);
assert(send_stream_config.codec.numberOfSimulcastStreams == 0 ||
send_stream_config.codec.numberOfSimulcastStreams ==
send_stream_config.rtp.ssrcs.size());
VideoSendStream* send_stream =
new VideoSendStream(send_transport, video_engine_, send_stream_config);
for (size_t i = 0; i < send_stream_config.rtp.ssrcs.size(); ++i) {
uint32_t ssrc = send_stream_config.rtp.ssrcs[i];
// SSRC must be previously unused!
assert(send_ssrcs_[ssrc] == NULL &&
receive_ssrcs_.find(ssrc) == receive_ssrcs_.end());
send_ssrcs_[ssrc] = send_stream;
}
return send_stream;
}
newapi::SendStreamState* VideoCall::DestroySendStream(
newapi::VideoSendStream* send_stream) {
if (send_stream == NULL) {
return NULL;
}
// TODO(pbos): Remove it properly! Free the SSRCs!
delete static_cast<VideoSendStream*>(send_stream);
// TODO(pbos): Return its previous state
return NULL;
}
void VideoCall::GetDefaultReceiveConfig(
newapi::VideoReceiveStreamConfig* receive_stream_config) {
// TODO(pbos): This is not the default config.
*receive_stream_config = newapi::VideoReceiveStreamConfig();
}
newapi::VideoReceiveStream* VideoCall::CreateReceiveStream(
const newapi::VideoReceiveStreamConfig& receive_stream_config) {
assert(receive_ssrcs_[receive_stream_config.rtp.ssrc] == NULL);
VideoReceiveStream* receive_stream = new VideoReceiveStream(
video_engine_, receive_stream_config, send_transport);
receive_ssrcs_[receive_stream_config.rtp.ssrc] = receive_stream;
return receive_stream;
}
void VideoCall::DestroyReceiveStream(
newapi::VideoReceiveStream* receive_stream) {
if (receive_stream == NULL) {
return;
}
// TODO(pbos): Remove its SSRCs!
delete static_cast<VideoReceiveStream*>(receive_stream);
}
uint32_t VideoCall::SendBitrateEstimate() {
// TODO(pbos): Return send-bitrate estimate
return 0;
}
uint32_t VideoCall::ReceiveBitrateEstimate() {
// TODO(pbos): Return receive-bitrate estimate
return 0;
}
bool VideoCall::DeliverRtcp(ModuleRTPUtility::RTPHeaderParser* rtp_parser,
const void* packet, size_t length) {
// TODO(pbos): Figure out what channel needs it actually.
// Do NOT broadcast! Also make sure it's a valid packet.
bool rtcp_delivered = false;
for (std::map<uint32_t, newapi::VideoReceiveStream*>::iterator it =
receive_ssrcs_.begin();
it != receive_ssrcs_.end(); ++it) {
if (static_cast<VideoReceiveStream*>(it->second)
->DeliverRtcp(packet, length)) {
rtcp_delivered = true;
}
}
return rtcp_delivered;
}
bool VideoCall::DeliverRtp(ModuleRTPUtility::RTPHeaderParser* rtp_parser,
const void* packet, size_t length) {
WebRtcRTPHeader rtp_header;
// TODO(pbos): ExtensionMap if there are extensions
if (!rtp_parser->Parse(rtp_header)) {
// TODO(pbos): Should this error be reported and trigger something?
return false;
}
uint32_t ssrc = rtp_header.header.ssrc;
if (receive_ssrcs_.find(ssrc) == receive_ssrcs_.end()) {
// TODO(pbos): Log some warning, SSRC without receiver.
return false;
}
VideoReceiveStream* receiver =
static_cast<VideoReceiveStream*>(receive_ssrcs_[ssrc]);
return receiver->DeliverRtp(packet, length);
}
bool VideoCall::DeliverPacket(const void* packet, size_t length) {
// TODO(pbos): Respect the constness of packet.
ModuleRTPUtility::RTPHeaderParser rtp_parser(
const_cast<uint8_t*>(static_cast<const uint8_t*>(packet)), length);
if (rtp_parser.RTCP()) {
return DeliverRtcp(&rtp_parser, packet, length);
}
return DeliverRtp(&rtp_parser, packet, length);
}
} // namespace internal
} // namespace webrtc

View File

@ -0,0 +1,85 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_VIDEO_CALL_IMPL_H_
#define WEBRTC_VIDEO_ENGINE_VIDEO_CALL_IMPL_H_
#include <map>
#include <vector>
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
#include "webrtc/video_engine/new_include/common.h"
#include "webrtc/video_engine/new_include/video_engine.h"
#include "webrtc/video_engine/internal/video_receive_stream.h"
#include "webrtc/video_engine/internal/video_send_stream.h"
namespace webrtc {
class VideoEngine;
class ViERTP_RTCP;
class ViECodec;
namespace internal {
// TODO(pbos): Split out the packet receiver, should be sharable between
// VideoEngine and VoiceEngine.
class VideoCall : public newapi::VideoCall, public newapi::PacketReceiver {
public:
VideoCall(webrtc::VideoEngine* video_engine,
newapi::Transport* send_transport);
virtual ~VideoCall();
virtual newapi::PacketReceiver* Receiver() OVERRIDE;
virtual std::vector<VideoCodec> GetVideoCodecs() OVERRIDE;
virtual void GetDefaultSendConfig(
newapi::VideoSendStreamConfig* send_stream_config) OVERRIDE;
virtual newapi::VideoSendStream* CreateSendStream(
const newapi::VideoSendStreamConfig& send_stream_config) OVERRIDE;
virtual newapi::SendStreamState* DestroySendStream(
newapi::VideoSendStream* send_stream) OVERRIDE;
virtual void GetDefaultReceiveConfig(
newapi::VideoReceiveStreamConfig* receive_stream_config) OVERRIDE;
virtual newapi::VideoReceiveStream* CreateReceiveStream(
const newapi::VideoReceiveStreamConfig& receive_stream_config) OVERRIDE;
virtual void DestroyReceiveStream(newapi::VideoReceiveStream* receive_stream)
OVERRIDE;
virtual uint32_t SendBitrateEstimate() OVERRIDE;
virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
virtual bool DeliverPacket(const void* packet, size_t length) OVERRIDE;
private:
bool DeliverRtp(ModuleRTPUtility::RTPHeaderParser* rtp_parser,
const void* packet, size_t length);
bool DeliverRtcp(ModuleRTPUtility::RTPHeaderParser* rtp_parser,
const void* packet, size_t length);
newapi::Transport* send_transport;
std::map<uint32_t, newapi::VideoReceiveStream*> receive_ssrcs_;
std::map<uint32_t, newapi::VideoSendStream*> send_ssrcs_;
webrtc::VideoEngine* video_engine_;
ViERTP_RTCP* rtp_rtcp_;
ViECodec* codec_;
DISALLOW_COPY_AND_ASSIGN(VideoCall);
};
} // namespace internal
} // namespace webrtc
#endif // WEBRTC_VIDEO_ENGINE_INTERNAL_VIDEO_CALL_H_

View File

@ -0,0 +1,59 @@
/*
* 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.
*/
#include "webrtc/video_engine/new_include/video_engine.h"
#include <cassert>
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/internal/video_call.h"
#include "webrtc/video_engine/vie_defines.h"
namespace webrtc {
namespace internal {
class VideoEngine : public newapi::VideoEngine {
public:
explicit VideoEngine(const newapi::VideoEngineConfig& engine_config)
: config_(engine_config) {
video_engine_ = webrtc::VideoEngine::Create();
assert(video_engine_ != NULL);
ViEBase* video_engine_base = ViEBase::GetInterface(video_engine_);
assert(video_engine_base != NULL);
if (video_engine_base->Init() != 0) {
abort();
}
video_engine_base->Release();
}
virtual ~VideoEngine() { webrtc::VideoEngine::Delete(video_engine_); }
virtual newapi::VideoCall* CreateCall(newapi::Transport* transport) OVERRIDE {
return new VideoCall(video_engine_, transport);
}
private:
newapi::VideoEngineConfig config_;
webrtc::VideoEngine* video_engine_;
DISALLOW_COPY_AND_ASSIGN(VideoEngine);
};
} // internal
namespace newapi {
VideoEngine* VideoEngine::Create(const VideoEngineConfig& engine_config) {
return new internal::VideoEngine(engine_config);
}
const char* Version() { return WEBRTC_SVNREVISION " (" BUILDINFO ")"; }
} // newapi
} // webrtc

View File

@ -0,0 +1,157 @@
/*
* 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.
*/
#include "webrtc/video_engine/internal/video_receive_stream.h"
#include <cassert>
#include <cstdlib>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_engine/include/vie_network.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
#include "webrtc/video_engine/new_include/video_receive_stream.h"
namespace webrtc {
namespace internal {
VideoReceiveStream::VideoReceiveStream(
webrtc::VideoEngine* video_engine,
const newapi::VideoReceiveStreamConfig& config,
newapi::Transport* transport)
: transport_(transport), config_(config) {
video_engine_base_ = ViEBase::GetInterface(video_engine);
// TODO(mflodman): Use the other CreateChannel method.
video_engine_base_->CreateChannel(channel_);
assert(channel_ != -1);
rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
assert(rtp_rtcp_ != NULL);
assert(config_.rtp.ssrc != 0);
network_ = ViENetwork::GetInterface(video_engine);
assert(network_ != NULL);
network_->RegisterSendTransport(channel_, *this);
codec_ = ViECodec::GetInterface(video_engine);
for (size_t i = 0; i < config_.codecs.size(); ++i) {
if (codec_->SetReceiveCodec(channel_, config_.codecs[i]) != 0) {
// TODO(pbos): Abort gracefully, this can be a runtime error.
// Factor out to an Init() method.
abort();
}
}
render_ = webrtc::ViERender::GetInterface(video_engine);
assert(render_ != NULL);
if (render_->AddRenderer(channel_, kVideoI420, this) != 0) {
abort();
}
clock_ = Clock::GetRealTimeClock();
}
VideoReceiveStream::~VideoReceiveStream() {
network_->DeregisterSendTransport(channel_);
video_engine_base_->Release();
codec_->Release();
network_->Release();
render_->Release();
rtp_rtcp_->Release();
}
void VideoReceiveStream::StartReceive() {
if (render_->StartRender(channel_)) {
abort();
}
if (video_engine_base_->StartReceive(channel_) != 0) {
abort();
}
}
void VideoReceiveStream::StopReceive() {
if (render_->StopRender(channel_)) {
abort();
}
if (video_engine_base_->StopReceive(channel_) != 0) {
abort();
}
}
void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) {
// TODO(pbos): Implement
}
void VideoReceiveStream::GetReceiveStatistics(
newapi::ReceiveStatistics* statistics) {
// TODO(pbos): Implement
}
bool VideoReceiveStream::DeliverRtcp(const void* packet, size_t length) {
return network_->ReceivedRTCPPacket(channel_, packet, length) == 0;
}
bool VideoReceiveStream::DeliverRtp(const void* packet, size_t length) {
return network_->ReceivedRTPPacket(channel_, packet, length) == 0;
}
int VideoReceiveStream::FrameSizeChange(unsigned int width, unsigned int height,
unsigned int /*number_of_streams*/) {
width_ = width;
height_ = height;
return 0;
}
int VideoReceiveStream::DeliverFrame(uint8_t* frame, int buffer_size,
uint32_t time_stamp, int64_t render_time) {
if (config_.renderer == NULL) {
return 0;
}
I420VideoFrame video_frame;
video_frame.CreateEmptyFrame(width_, height_, width_, height_, height_);
ConvertToI420(kI420, frame, 0, 0, width_, height_, buffer_size,
webrtc::kRotateNone, &video_frame);
if (config_.post_decode_callback != NULL) {
config_.post_decode_callback->FrameCallback(&video_frame);
}
if (config_.renderer != NULL) {
// TODO(pbos): Add timing to RenderFrame call
config_.renderer
->RenderFrame(video_frame, render_time - clock_->TimeInMilliseconds());
}
return 0;
}
int VideoReceiveStream::SendPacket(int /*channel*/, const void* packet,
int length) {
assert(length >= 0);
return transport_->SendRTP(packet, static_cast<size_t>(length)) ? 0 : -1;
}
int VideoReceiveStream::SendRTCPPacket(int /*channel*/, const void* packet,
int length) {
assert(length >= 0);
return transport_->SendRTCP(packet, static_cast<size_t>(length)) ? 0 : -1;
}
} // internal
} // webrtc

View File

@ -0,0 +1,83 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_VIDEO_RECEIVE_STREAM_IMPL_H_
#define WEBRTC_VIDEO_ENGINE_VIDEO_RECEIVE_STREAM_IMPL_H_
#include <vector>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "webrtc/video_engine/new_include/video_receive_stream.h"
namespace webrtc {
class VideoEngine;
class ViEBase;
class ViECodec;
class ViENetwork;
class ViERender;
class ViERTP_RTCP;
namespace internal {
class VideoReceiveStream : public newapi::VideoReceiveStream,
public webrtc::ExternalRenderer,
public webrtc::Transport {
public:
VideoReceiveStream(webrtc::VideoEngine* video_engine,
const newapi::VideoReceiveStreamConfig& config,
newapi::Transport* transport);
virtual ~VideoReceiveStream();
virtual void StartReceive() OVERRIDE;
virtual void StopReceive() OVERRIDE;
virtual void GetCurrentReceiveCodec(VideoCodec* receive_codec) OVERRIDE;
virtual void GetReceiveStatistics(newapi::ReceiveStatistics* statistics)
OVERRIDE;
virtual bool DeliverRtcp(const void* packet, size_t length);
virtual bool DeliverRtp(const void* packet, size_t length);
virtual int FrameSizeChange(unsigned int width, unsigned int height,
unsigned int /*number_of_streams*/) OVERRIDE;
virtual int DeliverFrame(uint8_t* frame, int buffer_size, uint32_t time_stamp,
int64_t render_time) OVERRIDE;
virtual int SendPacket(int /*channel*/, const void* packet, int length)
OVERRIDE;
virtual int SendRTCPPacket(int /*channel*/, const void* packet, int length)
OVERRIDE;
private:
newapi::Transport* transport_;
newapi::VideoReceiveStreamConfig config_;
Clock* clock_;
ViEBase* video_engine_base_;
ViECodec* codec_;
ViENetwork* network_;
ViERender* render_;
ViERTP_RTCP* rtp_rtcp_;
int channel_;
// TODO(pbos): Remove VideoReceiveStream can operate on I420 frames directly.
unsigned int height_;
unsigned int width_;
};
} // internal
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_INTERNAL_VIDEO_RECEIVE_STREAM_H_

View File

@ -0,0 +1,145 @@
/*
* 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.
*/
#include "webrtc/video_engine/internal/video_send_stream.h"
#include <vector>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_engine/include/vie_network.h"
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
namespace webrtc {
namespace internal {
VideoSendStream::VideoSendStream(
newapi::Transport* transport, webrtc::VideoEngine* video_engine,
const newapi::VideoSendStreamConfig& send_stream_config)
: transport_(transport), config_(send_stream_config) {
if (config_.codec.numberOfSimulcastStreams > 0) {
assert(config_.rtp.ssrcs.size() == config_.codec.numberOfSimulcastStreams);
} else {
assert(config_.rtp.ssrcs.size() == 1);
}
video_engine_base_ = ViEBase::GetInterface(video_engine);
video_engine_base_->CreateChannel(channel_);
assert(channel_ != -1);
rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
assert(rtp_rtcp_ != NULL);
assert(config_.rtp.ssrcs.size() == 1);
rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.ssrcs[0]);
capture_ = ViECapture::GetInterface(video_engine);
capture_->AllocateExternalCaptureDevice(capture_id_, external_capture_);
capture_->ConnectCaptureDevice(capture_id_, channel_);
network_ = ViENetwork::GetInterface(video_engine);
assert(network_ != NULL);
network_->RegisterSendTransport(channel_, *this);
codec_ = ViECodec::GetInterface(video_engine);
if (codec_->SetSendCodec(channel_, config_.codec) != 0) {
abort();
}
}
VideoSendStream::~VideoSendStream() {
network_->DeregisterSendTransport(channel_);
video_engine_base_->DeleteChannel(channel_);
capture_->DisconnectCaptureDevice(channel_);
capture_->ReleaseCaptureDevice(capture_id_);
video_engine_base_->Release();
capture_->Release();
codec_->Release();
network_->Release();
rtp_rtcp_->Release();
}
void VideoSendStream::PutFrame(const I420VideoFrame& frame,
int32_t delta_capture_time) {
I420VideoFrame frame_copy;
frame_copy.CopyFrame(frame);
if (config_.pre_encode_callback != NULL) {
config_.pre_encode_callback->FrameCallback(&frame_copy);
}
ViEVideoFrameI420 vf;
// 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();
external_capture_->IncomingFrameI420(vf, frame.timestamp());
if (config_.local_renderer != NULL) {
config_.local_renderer->RenderFrame(frame, 0);
}
}
newapi::VideoSendStreamInput* VideoSendStream::Input() { return this; }
void VideoSendStream::StartSend() {
if (video_engine_base_->StartSend(channel_) != 0) abort();
}
void VideoSendStream::StopSend() {
if (video_engine_base_->StopSend(channel_) != 0) abort();
}
void VideoSendStream::GetSendStatistics(
std::vector<newapi::SendStatistics>* statistics) {
// TODO(pbos): Implement
}
bool VideoSendStream::SetTargetBitrate(
int min_bitrate, int max_bitrate,
const std::vector<SimulcastStream>& streams) {
return false;
}
void VideoSendStream::GetSendCodec(VideoCodec* send_codec) {
*send_codec = config_.codec;
}
int VideoSendStream::SendPacket(int /*channel*/, const void* packet,
int length) {
// TODO(pbos): Lock these methods and the destructor so it can't be processing
// a packet when the destructor has been called.
assert(length >= 0);
return transport_->SendRTP(packet, static_cast<size_t>(length)) ? 0 : -1;
}
int VideoSendStream::SendRTCPPacket(int /*channel*/, const void* packet,
int length) {
assert(length >= 0);
return transport_->SendRTCP(packet, static_cast<size_t>(length)) ? 0 : -1;
}
} // namespace internal
} // namespace webrtc

View File

@ -0,0 +1,82 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_VIDEO_SEND_STREAM_IMPL_H_
#define WEBRTC_VIDEO_ENGINE_VIDEO_SEND_STREAM_IMPL_H_
#include <vector>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
#include "webrtc/video_engine/new_include/video_receive_stream.h"
namespace webrtc {
class VideoEngine;
class ViEBase;
class ViECapture;
class ViECodec;
class ViEExternalCapture;
class ViENetwork;
class ViERTP_RTCP;
namespace internal {
class VideoSendStream : public newapi::VideoSendStream,
public newapi::VideoSendStreamInput,
public webrtc::Transport {
public:
VideoSendStream(newapi::Transport* transport,
webrtc::VideoEngine* video_engine,
const newapi::VideoSendStreamConfig& send_stream_config);
virtual ~VideoSendStream();
virtual void PutFrame(const I420VideoFrame& frame, int32_t delta_capture_time)
OVERRIDE;
virtual newapi::VideoSendStreamInput* Input() OVERRIDE;
virtual void StartSend() OVERRIDE;
virtual void StopSend() OVERRIDE;
virtual void GetSendStatistics(
std::vector<newapi::SendStatistics>* statistics) OVERRIDE;
virtual bool SetTargetBitrate(int min_bitrate, int max_bitrate,
const std::vector<SimulcastStream>& streams)
OVERRIDE;
virtual void GetSendCodec(VideoCodec* send_codec) OVERRIDE;
virtual int SendPacket(int /*channel*/, const void* packet, int length)
OVERRIDE;
virtual int SendRTCPPacket(int /*channel*/, const void* packet, int length)
OVERRIDE;
private:
newapi::Transport* transport_;
newapi::VideoSendStreamConfig config_;
ViEBase* video_engine_base_;
ViECapture* capture_;
ViECodec* codec_;
ViEExternalCapture* external_capture_;
ViENetwork* network_;
ViERTP_RTCP* rtp_rtcp_;
int channel_;
int capture_id_;
};
} // namespace internal
} // namespace webrtc
#endif // WEBRTC_VIDEO_ENGINE_INTERNAL_VIDEO_SEND_STREAM_H_

View File

@ -19,7 +19,6 @@
#include "webrtc/video_engine/new_include/video_receive_stream.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
namespace webrtc {
namespace newapi {
@ -51,7 +50,7 @@ struct VideoEngineConfig {
// estimates etc.
class VideoCall {
public:
virtual void GetVideoCodecs(std::vector<VideoCodec>* codecs) = 0;
virtual std::vector<VideoCodec> GetVideoCodecs() = 0;
virtual void GetDefaultSendConfig(VideoSendStreamConfig* config) = 0;
@ -82,7 +81,6 @@ class VideoCall {
// differ from the actual receive bitrate.
virtual uint32_t ReceiveBitrateEstimate() = 0;
protected:
virtual ~VideoCall() {}
};
@ -91,11 +89,9 @@ class VideoCall {
class VideoEngine {
public:
static VideoEngine* Create(const VideoEngineConfig& engine_config);
virtual ~VideoEngine() {}
virtual VideoCall* CreateCall(Transport* send_transport) = 0;
protected:
virtual ~VideoEngine() {}
};
} // namespace newapi

View File

@ -0,0 +1,39 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_DIRECT_TRANSPORT_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_DIRECT_TRANSPORT_H_
#include "webrtc/video_engine/new_include/common.h"
namespace webrtc {
namespace test {
class DirectTransport : public newapi::Transport {
public:
explicit DirectTransport(newapi::PacketReceiver* receiver)
: receiver_(receiver) {}
void SetReceiver(newapi::PacketReceiver* receiver) { receiver_ = receiver; }
bool SendRTP(const void* data, size_t length) OVERRIDE {
return receiver_->DeliverPacket(data, length);
}
bool SendRTCP(const void* data, size_t length) OVERRIDE {
return SendRTP(data, length);
}
private:
newapi::PacketReceiver* receiver_;
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_DIRECT_TRANSPORT_H_

View File

@ -0,0 +1,51 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_GENERATE_SSRCS_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_GENERATE_SSRCS_H_
#include <map>
#include <vector>
#include "webrtc/video_engine/new_include/video_send_stream.h"
#include "webrtc/typedefs.h"
namespace webrtc {
namespace test {
void GenerateRandomSsrcs(newapi::VideoSendStreamConfig* config,
std::map<uint32_t, bool>* reserved_ssrcs) {
size_t num_ssrcs = config->codec.numberOfSimulcastStreams;
std::vector<uint32_t>* ssrcs = &config->rtp.ssrcs;
assert(ssrcs->size() == 0);
if (num_ssrcs == 0) {
num_ssrcs = 1;
}
while (ssrcs->size() < num_ssrcs) {
uint32_t rand_ssrc = static_cast<uint32_t>(rand() + 1); // NOLINT
// Make sure the ssrc is unique per-call
while (true) {
if (!(*reserved_ssrcs)[rand_ssrc]) {
(*reserved_ssrcs)[rand_ssrc] = true;
break;
}
++rand_ssrc;
}
ssrcs->push_back(rand_ssrc);
}
}
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_GENERATE_SSRCS_H_

View File

@ -0,0 +1,112 @@
/*
* 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.
*/
#include "webrtc/video_engine/test/common/gl/gl_renderer.h"
#include <cstring>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
namespace webrtc {
namespace test {
GlRenderer::GlRenderer()
: is_init_(false), buffer_(NULL), width_(0), height_(0) {}
void GlRenderer::Init() {
assert(!is_init_);
is_init_ = true;
glGenTextures(1, &texture_);
}
void GlRenderer::Destroy() {
if (!is_init_) {
return;
}
is_init_ = false;
delete[] buffer_;
buffer_ = NULL;
glDeleteTextures(1, &texture_);
}
void GlRenderer::ResizeViewport(size_t width, size_t height) {
// TODO(pbos): Aspect ratio, letterbox the video.
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glOrtho(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
}
void GlRenderer::ResizeVideo(size_t width, size_t height) {
assert(is_init_);
width_ = width;
height_ = height;
buffer_size_ = width * height * 4; // BGRA
delete[] buffer_;
buffer_ = new uint8_t[buffer_size_];
assert(buffer_ != NULL);
memset(buffer_, 0, buffer_size_);
glBindTexture(GL_TEXTURE_2D, texture_);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8, static_cast<GLvoid*>(buffer_));
}
void GlRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
int /*render_delay_ms*/) {
assert(is_init_);
if (static_cast<size_t>(frame.width()) != width_ ||
static_cast<size_t>(frame.height()) != height_) {
ResizeVideo(frame.width(), frame.height());
}
webrtc::ConvertFromI420(frame, kBGRA, 0, buffer_);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width_, height_, GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8, buffer_);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glBegin(GL_QUADS);
{
glTexCoord2f(0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
}
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
}
} // test
} // webrtc

View File

@ -0,0 +1,45 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_GL_GL_RENDERER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_GL_GL_RENDERER_H_
#include <GL/gl.h>
#include "webrtc/video_engine/test/common/video_renderer.h"
namespace webrtc {
namespace test {
class GlRenderer : public VideoRenderer {
public:
virtual void RenderFrame(const webrtc::I420VideoFrame& frame,
int time_to_render_ms) OVERRIDE;
protected:
GlRenderer();
void Init();
void Destroy();
void ResizeViewport(size_t width, size_t height);
private:
bool is_init_;
uint8_t* buffer_;
GLuint texture_;
size_t width_, height_, buffer_size_;
void ResizeVideo(size_t width, size_t height);
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_GL_GL_RENDERER_H_

View File

@ -0,0 +1,180 @@
/*
* 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.
*/
#include "webrtc/video_engine/test/common/linux/glx_renderer.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <cassert>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
namespace webrtc {
namespace test {
GlxRenderer::GlxRenderer(size_t width, size_t height)
: is_init_(false),
width_(width),
height_(height),
display_(NULL),
context_(NULL) {
assert(width > 0);
assert(height > 0);
}
bool GlxRenderer::Init(const char* window_title) {
if ((display_ = XOpenDisplay(NULL)) == NULL) {
Destroy();
return false;
}
int screen = DefaultScreen(display_);
XVisualInfo* vi;
int attr_list[] = { GLX_DOUBLEBUFFER, GLX_RGBA, GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4, GLX_DEPTH_SIZE, 16,
None, };
if ((vi = glXChooseVisual(display_, screen, attr_list)) == NULL) {
Destroy();
return false;
}
context_ = glXCreateContext(display_, vi, 0, true);
if (context_ == NULL) {
Destroy();
return false;
}
XSetWindowAttributes window_attributes;
window_attributes.colormap = XCreateColormap(
display_, RootWindow(display_, vi->screen), vi->visual, AllocNone);
window_attributes.border_pixel = 0;
window_attributes.event_mask = StructureNotifyMask | ExposureMask;
window_ = XCreateWindow(display_, RootWindow(display_, vi->screen), 0, 0,
width_, height_, 0, vi->depth, InputOutput,
vi->visual, CWBorderPixel | CWColormap | CWEventMask,
&window_attributes);
XFree(vi);
XSetStandardProperties(display_, window_, window_title, window_title, None,
NULL, 0, NULL);
Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", True);
if (wm_delete != None) {
XSetWMProtocols(display_, window_, &wm_delete, 1);
}
XMapRaised(display_, window_);
if (!glXMakeCurrent(display_, window_, context_)) {
Destroy();
return false;
}
GlRenderer::Init();
if (!glXMakeCurrent(display_, None, NULL)) {
Destroy();
return false;
}
Resize(width_, height_);
return true;
}
void GlxRenderer::Destroy() {
if (!is_init_) {
return;
}
is_init_ = false;
if (context_ != NULL) {
glXMakeCurrent(display_, window_, context_);
GlRenderer::Destroy();
glXMakeCurrent(display_, None, NULL);
glXDestroyContext(display_, context_);
context_ = NULL;
}
if (display_ != NULL) {
XCloseDisplay(display_);
display_ = NULL;
}
}
GlxRenderer* GlxRenderer::Create(const char* window_title, size_t width,
size_t height) {
GlxRenderer* glx_renderer = new GlxRenderer(width, height);
if (!glx_renderer->Init(window_title)) {
// TODO(pbos): Add GLX-failed warning here?
delete glx_renderer;
return NULL;
}
return glx_renderer;
}
GlxRenderer::~GlxRenderer() { Destroy(); }
void GlxRenderer::Resize(size_t width, size_t height) {
width_ = width;
height_ = height;
if (!glXMakeCurrent(display_, window_, context_)) {
abort();
}
GlRenderer::ResizeViewport(width_, height_);
if (!glXMakeCurrent(display_, None, NULL)) {
abort();
}
XSizeHints* size_hints = XAllocSizeHints();
if (size_hints == NULL) {
abort();
}
size_hints->flags = PAspect;
size_hints->min_aspect.x = size_hints->max_aspect.x = width_;
size_hints->min_aspect.y = size_hints->max_aspect.y = height_;
XSetWMNormalHints(display_, window_, size_hints);
XFree(size_hints);
}
void GlxRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
int /*render_delay_ms*/) {
if (static_cast<size_t>(frame.width()) != width_ ||
static_cast<size_t>(frame.height()) != height_) {
Resize(static_cast<size_t>(frame.width()),
static_cast<size_t>(frame.height()));
}
XEvent event;
if (!glXMakeCurrent(display_, window_, context_)) {
abort();
}
while (XPending(display_)) {
XNextEvent(display_, &event);
switch (event.type) {
case ConfigureNotify:
GlRenderer::ResizeViewport(event.xconfigure.width,
event.xconfigure.height);
break;
default:
break;
}
}
GlRenderer::RenderFrame(frame, 0);
glXSwapBuffers(display_, window_);
if (!glXMakeCurrent(display_, None, NULL)) {
abort();
}
}
} // test
} // webrtc

View File

@ -0,0 +1,47 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_GLX_RENDERER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_GLX_RENDERER_H_
#include <X11/Xlib.h>
#include <GL/glx.h>
#include "webrtc/video_engine/test/common/gl/gl_renderer.h"
namespace webrtc {
namespace test {
class GlxRenderer : public GlRenderer {
public:
static GlxRenderer* Create(const char* window_title, size_t width,
size_t height);
virtual ~GlxRenderer();
virtual void RenderFrame(const webrtc::I420VideoFrame& frame, int delta)
OVERRIDE;
private:
GlxRenderer(size_t width, size_t height);
bool Init(const char* window_title);
void Resize(size_t width, size_t height);
void Destroy();
bool is_init_;
size_t width_, height_;
Display* display_;
Window window_;
GLXContext context_;
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_GLX_RENDERER_H_

View File

@ -0,0 +1,210 @@
/*
* 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.
*/
#include "webrtc/video_engine/test/common/linux/xv_renderer.h"
#include <sys/shm.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xvlib.h>
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#define GUID_I420_PLANAR 0x30323449
namespace webrtc {
namespace test {
XvRenderer::XvRenderer(size_t width, size_t height)
: width(width),
height(height),
is_init(false),
display(NULL),
gc(NULL),
image(NULL) {
assert(width > 0);
assert(height > 0);
}
bool XvRenderer::Init(const char* window_title) {
assert(!is_init);
is_init = true;
if ((display = XOpenDisplay(NULL)) == NULL) {
Destroy();
return false;
}
int screen = DefaultScreen(display);
XVisualInfo vinfo;
if (!XMatchVisualInfo(display, screen, 24, TrueColor, &vinfo)) {
Destroy();
return false;
}
XSetWindowAttributes xswa;
xswa.colormap = XCreateColormap(display, DefaultRootWindow(display),
vinfo.visual, AllocNone);
xswa.event_mask = StructureNotifyMask | ExposureMask;
xswa.background_pixel = 0;
xswa.border_pixel = 0;
window = XCreateWindow(display, DefaultRootWindow(display), 0, 0, width,
height, 0, vinfo.depth, InputOutput, vinfo.visual,
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask,
&xswa);
XStoreName(display, window, window_title);
XSetIconName(display, window, window_title);
XSelectInput(display, window, StructureNotifyMask);
XMapRaised(display, window);
XEvent event;
do {
XNextEvent(display, &event);
} while (event.type != MapNotify || event.xmap.event != window);
if (!XShmQueryExtension(display)) {
Destroy();
return false;
}
xv_complete = XShmGetEventBase(display) + ShmCompletion;
XvAdaptorInfo* ai;
unsigned int p_num_adaptors;
if (XvQueryAdaptors(display, DefaultRootWindow(display), &p_num_adaptors,
&ai) !=
Success) {
Destroy();
return false;
}
if (p_num_adaptors <= 0) {
XvFreeAdaptorInfo(ai);
Destroy();
return false;
}
xv_port = ai[p_num_adaptors - 1].base_id;
XvFreeAdaptorInfo(ai);
if (xv_port == -1) {
Destroy();
return false;
}
gc = XCreateGC(display, window, 0, 0);
if (gc == NULL) {
Destroy();
return false;
}
Resize(width, height);
return true;
}
void XvRenderer::Destroy() {
if (image != NULL) {
XFree(image);
image = NULL;
}
if (gc != NULL) {
XFreeGC(display, gc);
gc = NULL;
}
if (display != NULL) {
XCloseDisplay(display);
display = NULL;
}
}
XvRenderer* XvRenderer::Create(const char* window_title, size_t width,
size_t height) {
XvRenderer* xv_renderer = new XvRenderer(width, height);
if (!xv_renderer->Init(window_title)) {
// TODO(pbos): Add Xv-failed warning here?
delete xv_renderer;
return NULL;
}
return xv_renderer;
}
XvRenderer::~XvRenderer() { Destroy(); }
void XvRenderer::Resize(size_t width, size_t height) {
this->width = width;
this->height = height;
if (image != NULL) {
XFree(image);
}
image = XvShmCreateImage(display, xv_port, GUID_I420_PLANAR, 0, width, height,
&shm_info);
assert(image != NULL);
shm_info.shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
shm_info.shmaddr = image->data =
reinterpret_cast<char*>(shmat(shm_info.shmid, 0, 0));
shm_info.readOnly = False;
if (!XShmAttach(display, &shm_info)) {
abort();
}
XSizeHints* size_hints = XAllocSizeHints();
if (size_hints == NULL) {
abort();
}
size_hints->flags = PAspect;
size_hints->min_aspect.x = size_hints->max_aspect.x = width;
size_hints->min_aspect.y = size_hints->max_aspect.y = height;
XSetWMNormalHints(display, window, size_hints);
XFree(size_hints);
XWindowChanges wc;
wc.width = width;
wc.height = height;
XConfigureWindow(display, window, CWWidth | CWHeight, &wc);
}
void XvRenderer::RenderFrame(const webrtc::I420VideoFrame& frame,
int /*render_delay_ms*/) {
int size = webrtc::ExtractBuffer(frame, image->data_size,
reinterpret_cast<uint8_t*>(image->data));
if (static_cast<size_t>(frame.width()) != width ||
static_cast<size_t>(frame.height()) != height) {
Resize(static_cast<size_t>(frame.width()),
static_cast<size_t>(frame.height()));
}
assert(size > 0);
Window root;
int temp;
unsigned int window_width, window_height, u_temp;
XGetGeometry(display, window, &root, &temp, &temp, &window_width,
&window_height, &u_temp, &u_temp);
XvShmPutImage(display, xv_port, window, gc, image, 0, 0, image->width,
image->height, 0, 0, window_width, window_height, True);
XFlush(display);
XEvent event;
while (XPending(display)) {
XNextEvent(display, &event);
}
}
} // test
} // webrtc

View File

@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_XV_RENDERER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_XV_RENDERER_H_
#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/Xvlib.h>
#include "webrtc/video_engine/new_include/common.h"
#include "webrtc/video_engine/test/common/video_renderer.h"
namespace webrtc {
namespace test {
class XvRenderer : public VideoRenderer {
public:
~XvRenderer();
virtual void RenderFrame(const webrtc::I420VideoFrame& frame, int delta)
OVERRIDE;
static XvRenderer* Create(const char *window_title, size_t width,
size_t height);
private:
XvRenderer(size_t width, size_t height);
bool Init(const char *window_title);
void Resize(size_t width, size_t height);
void Destroy();
size_t width, height;
bool is_init;
Display* display;
Window window;
GC gc;
XvImage* image;
XShmSegmentInfo shm_info;
int xv_port, xv_complete;
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_LINUX_XV_RENDERER_H_

View File

@ -0,0 +1,108 @@
/*
* 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.
*/
#include "webrtc/video_engine/test/common/vcm_capturer.h"
#include "webrtc/modules/video_capture/include/video_capture_factory.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
namespace webrtc {
namespace test {
VcmCapturer::VcmCapturer(webrtc::newapi::VideoSendStreamInput* input)
: VideoCapturer(input), started_(false), vcm(NULL), last_timestamp(0) {}
bool VcmCapturer::Init(size_t width, size_t height, size_t target_fps) {
VideoCaptureModule::DeviceInfo* device_info =
VideoCaptureFactory::CreateDeviceInfo(42); // Any ID (42) will do.
char device_name[256];
char unique_name[256];
if (device_info->GetDeviceName(0, device_name, sizeof(device_name),
unique_name, sizeof(unique_name)) !=
0) {
Destroy();
return false;
}
vcm = webrtc::VideoCaptureFactory::Create(0, unique_name);
vcm->RegisterCaptureDataCallback(*this);
device_info->GetCapability(vcm->CurrentDeviceName(), 0, capability_);
delete device_info;
capability_.width = static_cast<int32_t>(width);
capability_.height = static_cast<int32_t>(height);
capability_.maxFPS = static_cast<int32_t>(target_fps);
capability_.rawType = kVideoI420;
if (vcm->StartCapture(capability_) != 0) {
Destroy();
return false;
}
assert(vcm->CaptureStarted());
return true;
}
VcmCapturer* VcmCapturer::Create(newapi::VideoSendStreamInput* input,
size_t width, size_t height,
size_t target_fps) {
VcmCapturer* vcm_capturer = new VcmCapturer(input);
if (!vcm_capturer->Init(width, height, target_fps)) {
// TODO(pbos): Log a warning that this failed.
delete vcm_capturer;
return NULL;
}
return vcm_capturer;
}
void VcmCapturer::Start() { started_ = true; }
void VcmCapturer::Stop() { started_ = false; }
void VcmCapturer::Destroy() {
if (vcm == NULL) {
return;
}
vcm->StopCapture();
vcm->DeRegisterCaptureDataCallback();
vcm->Release();
// TODO(pbos): How do I destroy the VideoCaptureModule? This still leaves
// non-freed memory.
vcm = NULL;
}
VcmCapturer::~VcmCapturer() { Destroy(); }
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();
}
void VcmCapturer::OnIncomingCapturedEncodedFrame(const int32_t id,
VideoFrame& frame,
VideoCodecType codec_type) {}
void VcmCapturer::OnCaptureDelayChanged(const int32_t id, const int32_t delay) {
}
} // test
} // webrtc

View File

@ -0,0 +1,53 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_VCM_CAPTURER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_VCM_CAPTURER_H_
#include "webrtc/common_types.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/modules/video_capture/include/video_capture.h"
#include "webrtc/video_engine/test/common/video_capturer.h"
namespace webrtc {
namespace test {
class VcmCapturer : public VideoCapturer, public VideoCaptureDataCallback {
public:
static VcmCapturer* Create(newapi::VideoSendStreamInput* input, size_t width,
size_t height, size_t target_fps);
virtual ~VcmCapturer();
virtual void Start() OVERRIDE;
virtual void Stop() OVERRIDE;
virtual void OnIncomingCapturedFrame(const int32_t id, I420VideoFrame& frame)
OVERRIDE;
virtual void OnIncomingCapturedEncodedFrame(const int32_t id,
VideoFrame& frame,
VideoCodecType codec_type)
OVERRIDE;
virtual void OnCaptureDelayChanged(const int32_t id, const int32_t delay)
OVERRIDE;
private:
explicit VcmCapturer(newapi::VideoSendStreamInput* input);
bool Init(size_t width, size_t height, size_t target_fps);
void Destroy();
bool started_;
VideoCaptureModule* vcm;
VideoCaptureCapability capability_;
uint32_t last_timestamp;
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VCM_CAPTURER_H_

View File

@ -0,0 +1,47 @@
/*
* 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.
*/
#include "webrtc/video_engine/test/common/video_capturer.h"
#include "webrtc/video_engine/test/common/vcm_capturer.h"
namespace webrtc {
namespace test {
class NullCapturer : public VideoCapturer {
public:
NullCapturer() : VideoCapturer(NULL) {}
virtual ~NullCapturer() {}
virtual void Start() {}
virtual void Stop() {}
};
VideoCapturer::VideoCapturer(newapi::VideoSendStreamInput* input)
: input_(input) {}
VideoCapturer* VideoCapturer::Create(newapi::VideoSendStreamInput* input) {
// TODO(pbos): These should be specified by command-line parameters.
size_t width = 640;
size_t height = 480;
size_t target_fps = 30;
VcmCapturer* vcm_capturer = VcmCapturer::Create(input, width, height,
target_fps);
if (vcm_capturer != NULL) {
return vcm_capturer;
}
// TODO(pbos): Log a warning that this failed.
// TODO(pbos): Add a pseudocapturer which generates frames.
return new NullCapturer();
}
} // test
} // webrtc

View File

@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_CAPTURER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_CAPTURER_H_
namespace webrtc {
namespace newapi {
class VideoSendStreamInput;
} // newapi
namespace test {
class VideoCapturer {
public:
static VideoCapturer* Create(newapi::VideoSendStreamInput* input);
virtual ~VideoCapturer() {}
virtual void Start() = 0;
virtual void Stop() = 0;
protected:
explicit VideoCapturer(newapi::VideoSendStreamInput* input);
newapi::VideoSendStreamInput* input_;
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_CAPTURER_H

View File

@ -0,0 +1,63 @@
/*
* 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.
*/
#include "webrtc/video_engine/test/common/video_renderer.h"
#include "webrtc/modules/video_capture/include/video_capture_factory.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"
#ifdef WEBRTC_TEST_XV
#include "webrtc/video_engine/test/common/linux/xv_renderer.h"
#endif // WEBRTC_TEST_XV
// Platform-specific renderers preferred over NullRenderer
#ifdef WEBRTC_TEST_GLX
#include "webrtc/video_engine/test/common/linux/glx_renderer.h"
#endif // WEBRTC_TEST_GLX
// TODO(pbos): Mac renderer
// TODO(pbos): Windows renderer
// TODO(pbos): Android renderer
namespace webrtc {
namespace test {
class NullRenderer : public VideoRenderer {
virtual void RenderFrame(const I420VideoFrame& video_frame,
int time_to_render_ms) OVERRIDE {}
};
VideoRenderer* VideoRenderer::Create(const char* window_title) {
// TODO(pbos): Get these from command-line parameters.
int width = 640;
int height = 480;
#ifdef WEBRTC_TEST_XV
XvRenderer* xv_renderer = XvRenderer::Create(window_title, width, height);
if (xv_renderer != NULL) {
return xv_renderer;
}
#endif // WEBRTC_TEST_XV
#ifdef WEBRTC_TEST_GLX
GlxRenderer* glx_renderer = GlxRenderer::Create(window_title, width, height);
if (glx_renderer != NULL) {
return glx_renderer;
}
#endif // WEBRTC_TEST_GLX
// Avoid initialized-but-not-referenced errors when only building a
// NullRenderer
(void) width;
(void) height;
return new NullRenderer();
}
} // test
} // webrtc

View File

@ -0,0 +1,26 @@
/*
* 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.
*/
#ifndef WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_RENDERER_H_
#define WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_RENDERER_H_
#include "webrtc/video_engine/new_include/common.h"
namespace webrtc {
namespace test {
class VideoRenderer : public newapi::VideoRenderer {
public:
static VideoRenderer* Create(const char* window_title);
virtual ~VideoRenderer() {}
};
} // test
} // webrtc
#endif // WEBRTC_VIDEO_ENGINE_TEST_COMMON_VIDEO_RENDERER_H_

View File

@ -0,0 +1,103 @@
/*
* 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.
*/
#include <gtest/gtest.h>
#include <iostream>
#include <map>
#include "webrtc/video_engine/new_include/video_engine.h"
#include "webrtc/video_engine/test/common/direct_transport.h"
#include "webrtc/video_engine/test/common/generate_ssrcs.h"
#include "webrtc/video_engine/test/common/video_capturer.h"
#include "webrtc/video_engine/test/common/video_renderer.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class LoopbackTest : public ::testing::Test {
protected:
std::map<uint32_t, bool> reserved_ssrcs;
};
TEST_F(LoopbackTest, Test) {
test::VideoRenderer* local_preview =
test::VideoRenderer::Create("Local Preview");
test::VideoRenderer* loopback_video =
test::VideoRenderer::Create("Loopback Video");
newapi::VideoEngine* video_engine =
newapi::VideoEngine::Create(webrtc::newapi::VideoEngineConfig());
test::DirectTransport transport(NULL);
newapi::VideoCall* call = video_engine->CreateCall(&transport);
// Loopback, call sends to itself.
transport.SetReceiver(call->Receiver());
newapi::VideoSendStreamConfig send_config;
call->GetDefaultSendConfig(&send_config);
test::GenerateRandomSsrcs(&send_config, &reserved_ssrcs);
send_config.local_renderer = local_preview;
// TODO(pbos): Should be specified by command-line parameters. And not even
// visible in the test. Break it out to some get-test-defaults
// class
send_config.codec.width = 640;
send_config.codec.height = 480;
send_config.codec.minBitrate = 1000;
send_config.codec.startBitrate = 1500;
send_config.codec.maxBitrate = 2000;
newapi::VideoSendStream* send_stream = call->CreateSendStream(send_config);
test::VideoCapturer* camera =
test::VideoCapturer::Create(send_stream->Input());
newapi::VideoReceiveStreamConfig receive_config;
call->GetDefaultReceiveConfig(&receive_config);
receive_config.rtp.ssrc = send_config.rtp.ssrcs[0];
receive_config.renderer = loopback_video;
newapi::VideoReceiveStream* receive_stream =
call->CreateReceiveStream(receive_config);
receive_stream->StartReceive();
send_stream->StartSend();
camera->Start();
// TODO(pbos): Run this time limited (optionally), so it can run automated.
std::cout << ">> Press ENTER to continue..." << std::endl;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
receive_stream->StopReceive();
send_stream->StopSend();
// Stop sending
delete camera;
call->DestroyReceiveStream(receive_stream);
call->DestroySendStream(send_stream);
delete call;
delete video_engine;
delete loopback_video;
delete local_preview;
}
} // webrtc
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,115 @@
# 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.
{
'variables': {
'xv_renderer%': 0,
},
'conditions': [
['OS=="linux"', {
'variables': {
'glx_renderer%': 1,
},
}, {
# OS != "linux"
'variables': {
'glx_renderer%': 0,
},
}],
],
'targets': [
{
'target_name': 'video_tests_common',
'type': 'static_library',
'sources': [
'common/generate_ssrcs.h',
'common/vcm_capturer.h',
'common/vcm_capturer.cc',
'common/video_capturer.cc',
'common/video_capturer.h',
'common/video_renderer.cc',
'common/video_renderer.h',
],
'conditions': [
['glx_renderer==1', {
'defines': [
'WEBRTC_TEST_GLX',
],
'sources' : [
'common/gl/gl_renderer.cc',
'common/gl/gl_renderer.h',
'common/linux/glx_renderer.cc',
'common/linux/glx_renderer.h',
],
}],
['xv_renderer==1', {
'defines': [
'WEBRTC_TEST_XV',
],
'sources': [
'common/linux/xv_renderer.cc',
'common/linux/xv_renderer.h',
],
}],
],
'direct_dependent_settings': {
'conditions': [
['OS=="linux"', {
'libraries': [
'-lXext',
'-lX11',
'-lGL',
],
}],
['xv_renderer==1', {
'libraries': [
'-lXv',
],
}],
#TODO(pbos) : These dependencies should not have to be here, they
# aren't used by test code directly, only by components
# used by the tests.
['OS=="android"', {
'libraries' : [
'-lGLESv2', '-llog',
],
}],
['OS=="mac"', {
'xcode_settings' : {
'OTHER_LDFLAGS' : [
'-framework Foundation',
'-framework AppKit',
'-framework Cocoa',
'-framework OpenGL',
'-framework CoreVideo',
'-framework CoreAudio',
'-framework AudioToolbox',
],
},
}],
],
},
'dependencies': [
'<(webrtc_root)/modules/modules.gyp:video_capture_module',
'video_engine_core',
],
},
{
'target_name': 'video_loopback',
'type': 'executable',
'sources': [
'loopback.cc',
],
'dependencies': [
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(webrtc_root)/modules/modules.gyp:video_capture_module',
'video_tests_common',
],
},
],
}

View File

@ -17,6 +17,7 @@
'includes': [
'test/libvietest/libvietest.gypi',
'test/auto_test/vie_auto_test.gypi',
'test/tests.gypi',
],
'conditions': [
['OS=="android"', {

View File

@ -128,6 +128,19 @@
'vie_render_manager.cc',
'vie_sender.cc',
'vie_sync_module.cc',
# New VideoEngine API
'new_include/common.h',
'new_include/video_engine.h',
'new_include/video_receive_stream.h',
'new_include/video_send_stream.h',
'internal/video_engine.cc',
'internal/video_call.cc',
'internal/video_call.h',
'internal/video_receive_stream.cc',
'internal/video_receive_stream.h',
'internal/video_send_stream.cc',
'internal/video_send_stream.h',
], # source
# TODO(jschuh): Bug 1348: fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],