* Update libjingle to 50389769.
* Together with "Add texture support for i420 video frame." from wuchengli@chromium.org. https://webrtc-codereview.appspot.com/1413004 RISK=P1 TESTED=try bots R=fischman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1967004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4489 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
f696f253b2
commit
9dba525627
@ -235,17 +235,6 @@ bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool audio_track_exist = false;
|
|
||||||
for (size_t j = 0; j < current_streams->count(); ++j) {
|
|
||||||
if (!audio_track_exist) {
|
|
||||||
audio_track_exist = current_streams->at(j)->GetAudioTracks().size() > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (audio_track_exist && (new_stream->GetAudioTracks().size() > 0)) {
|
|
||||||
LOG(LS_ERROR) << "AddStream - Currently only one audio track is supported"
|
|
||||||
<< "per PeerConnection.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,20 +551,27 @@ TEST_F(PeerConnectionInterfaceTest, AddStreams) {
|
|||||||
AddVoiceStream(kStreamLabel2);
|
AddVoiceStream(kStreamLabel2);
|
||||||
ASSERT_EQ(2u, pc_->local_streams()->count());
|
ASSERT_EQ(2u, pc_->local_streams()->count());
|
||||||
|
|
||||||
// Fail to add another stream with audio since we already have an audio track.
|
// Test we can add multiple local streams to one peerconnection.
|
||||||
scoped_refptr<MediaStreamInterface> stream(
|
scoped_refptr<MediaStreamInterface> stream(
|
||||||
pc_factory_->CreateLocalMediaStream(kStreamLabel3));
|
pc_factory_->CreateLocalMediaStream(kStreamLabel3));
|
||||||
scoped_refptr<AudioTrackInterface> audio_track(
|
scoped_refptr<AudioTrackInterface> audio_track(
|
||||||
pc_factory_->CreateAudioTrack(
|
pc_factory_->CreateAudioTrack(
|
||||||
kStreamLabel3, static_cast<AudioSourceInterface*>(NULL)));
|
kStreamLabel3, static_cast<AudioSourceInterface*>(NULL)));
|
||||||
stream->AddTrack(audio_track.get());
|
stream->AddTrack(audio_track.get());
|
||||||
EXPECT_FALSE(pc_->AddStream(stream, NULL));
|
|
||||||
|
|
||||||
// Remove the stream with the audio track.
|
|
||||||
pc_->RemoveStream(pc_->local_streams()->at(1));
|
|
||||||
|
|
||||||
// Test that we now can add the stream with the audio track.
|
|
||||||
EXPECT_TRUE(pc_->AddStream(stream, NULL));
|
EXPECT_TRUE(pc_->AddStream(stream, NULL));
|
||||||
|
EXPECT_EQ(3u, pc_->local_streams()->count());
|
||||||
|
|
||||||
|
// Remove the third stream.
|
||||||
|
pc_->RemoveStream(pc_->local_streams()->at(2));
|
||||||
|
EXPECT_EQ(2u, pc_->local_streams()->count());
|
||||||
|
|
||||||
|
// Remove the second stream.
|
||||||
|
pc_->RemoveStream(pc_->local_streams()->at(1));
|
||||||
|
EXPECT_EQ(1u, pc_->local_streams()->count());
|
||||||
|
|
||||||
|
// Remove the first stream.
|
||||||
|
pc_->RemoveStream(pc_->local_streams()->at(0));
|
||||||
|
EXPECT_EQ(0u, pc_->local_streams()->count());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PeerConnectionInterfaceTest, RemoveStream) {
|
TEST_F(PeerConnectionInterfaceTest, RemoveStream) {
|
||||||
|
@ -835,6 +835,8 @@
|
|||||||
'media/webrtc/webrtcmediaengine.h',
|
'media/webrtc/webrtcmediaengine.h',
|
||||||
'media/webrtc/webrtcpassthroughrender.cc',
|
'media/webrtc/webrtcpassthroughrender.cc',
|
||||||
'media/webrtc/webrtcpassthroughrender.h',
|
'media/webrtc/webrtcpassthroughrender.h',
|
||||||
|
'media/webrtc/webrtctexturevideoframe.cc',
|
||||||
|
'media/webrtc/webrtctexturevideoframe.h',
|
||||||
'media/webrtc/webrtcvideocapturer.cc',
|
'media/webrtc/webrtcvideocapturer.cc',
|
||||||
'media/webrtc/webrtcvideocapturer.h',
|
'media/webrtc/webrtcvideocapturer.h',
|
||||||
'media/webrtc/webrtcvideodecoderfactory.h',
|
'media/webrtc/webrtcvideodecoderfactory.h',
|
||||||
|
@ -402,7 +402,7 @@
|
|||||||
}, # target libjingle_peerconnection_unittest
|
}, # target libjingle_peerconnection_unittest
|
||||||
],
|
],
|
||||||
'conditions': [
|
'conditions': [
|
||||||
['OS=="linux" or OS=="android"', {
|
['OS=="linux"', {
|
||||||
'targets': [
|
'targets': [
|
||||||
{
|
{
|
||||||
'target_name': 'libjingle_peerconnection_test_jar',
|
'target_name': 'libjingle_peerconnection_test_jar',
|
||||||
|
@ -57,6 +57,7 @@ class NullVideoFrame : public VideoFrame {
|
|||||||
virtual int32 GetYPitch() const { return 0; }
|
virtual int32 GetYPitch() const { return 0; }
|
||||||
virtual int32 GetUPitch() const { return 0; }
|
virtual int32 GetUPitch() const { return 0; }
|
||||||
virtual int32 GetVPitch() const { return 0; }
|
virtual int32 GetVPitch() const { return 0; }
|
||||||
|
virtual void* GetNativeHandle() const { return NULL; }
|
||||||
|
|
||||||
virtual size_t GetPixelWidth() const { return 1; }
|
virtual size_t GetPixelWidth() const { return 1; }
|
||||||
virtual size_t GetPixelHeight() const { return 1; }
|
virtual size_t GetPixelHeight() const { return 1; }
|
||||||
|
@ -66,16 +66,23 @@ class VideoFrame {
|
|||||||
size_t GetChromaWidth() const { return (GetWidth() + 1) / 2; }
|
size_t GetChromaWidth() const { return (GetWidth() + 1) / 2; }
|
||||||
size_t GetChromaHeight() const { return (GetHeight() + 1) / 2; }
|
size_t GetChromaHeight() const { return (GetHeight() + 1) / 2; }
|
||||||
size_t GetChromaSize() const { return GetUPitch() * GetChromaHeight(); }
|
size_t GetChromaSize() const { return GetUPitch() * GetChromaHeight(); }
|
||||||
|
// These can return NULL if the object is not backed by a buffer.
|
||||||
virtual const uint8 *GetYPlane() const = 0;
|
virtual const uint8 *GetYPlane() const = 0;
|
||||||
virtual const uint8 *GetUPlane() const = 0;
|
virtual const uint8 *GetUPlane() const = 0;
|
||||||
virtual const uint8 *GetVPlane() const = 0;
|
virtual const uint8 *GetVPlane() const = 0;
|
||||||
virtual uint8 *GetYPlane() = 0;
|
virtual uint8 *GetYPlane() = 0;
|
||||||
virtual uint8 *GetUPlane() = 0;
|
virtual uint8 *GetUPlane() = 0;
|
||||||
virtual uint8 *GetVPlane() = 0;
|
virtual uint8 *GetVPlane() = 0;
|
||||||
|
|
||||||
virtual int32 GetYPitch() const = 0;
|
virtual int32 GetYPitch() const = 0;
|
||||||
virtual int32 GetUPitch() const = 0;
|
virtual int32 GetUPitch() const = 0;
|
||||||
virtual int32 GetVPitch() const = 0;
|
virtual int32 GetVPitch() const = 0;
|
||||||
|
|
||||||
|
// Returns the handle of the underlying video frame. This is used when the
|
||||||
|
// frame is backed by a texture. The object should be destroyed when it is no
|
||||||
|
// longer in use, so the underlying resource can be freed.
|
||||||
|
virtual void* GetNativeHandle() const = 0;
|
||||||
|
|
||||||
// For retrieving the aspect ratio of each pixel. Usually this is 1x1, but
|
// For retrieving the aspect ratio of each pixel. Usually this is 1x1, but
|
||||||
// the aspect_ratio_idc parameter of H.264 can specify non-square pixels.
|
// the aspect_ratio_idc parameter of H.264 can specify non-square pixels.
|
||||||
virtual size_t GetPixelWidth() const = 0;
|
virtual size_t GetPixelWidth() const = 0;
|
||||||
@ -165,7 +172,7 @@ class VideoFrame {
|
|||||||
bool crop) const;
|
bool crop) const;
|
||||||
|
|
||||||
// Sets the video frame to black.
|
// Sets the video frame to black.
|
||||||
bool SetToBlack();
|
virtual bool SetToBlack();
|
||||||
|
|
||||||
// Tests if sample is valid. Returns true if valid.
|
// Tests if sample is valid. Returns true if valid.
|
||||||
static bool Validate(uint32 fourcc, int w, int h, const uint8 *sample,
|
static bool Validate(uint32 fourcc, int w, int h, const uint8 *sample,
|
||||||
|
@ -597,10 +597,8 @@ class FakeWebRtcVideoEngine
|
|||||||
channels_.erase(channel);
|
channels_.erase(channel);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
|
||||||
WEBRTC_STUB(RegisterCpuOveruseObserver,
|
WEBRTC_STUB(RegisterCpuOveruseObserver,
|
||||||
(int channel, webrtc::CpuOveruseObserver* observer));
|
(int channel, webrtc::CpuOveruseObserver* observer));
|
||||||
#endif
|
|
||||||
WEBRTC_STUB(ConnectAudioChannel, (const int, const int));
|
WEBRTC_STUB(ConnectAudioChannel, (const int, const int));
|
||||||
WEBRTC_STUB(DisconnectAudioChannel, (const int));
|
WEBRTC_STUB(DisconnectAudioChannel, (const int));
|
||||||
WEBRTC_FUNC(StartSend, (const int channel)) {
|
WEBRTC_FUNC(StartSend, (const int channel)) {
|
||||||
|
@ -161,6 +161,14 @@ class FakeWebRtcVoiceEngine
|
|||||||
}
|
}
|
||||||
bool IsInited() const { return inited_; }
|
bool IsInited() const { return inited_; }
|
||||||
int GetLastChannel() const { return last_channel_; }
|
int GetLastChannel() const { return last_channel_; }
|
||||||
|
int GetChannelFromLocalSsrc(uint32 local_ssrc) const {
|
||||||
|
for (std::map<int, Channel*>::const_iterator iter = channels_.begin();
|
||||||
|
iter != channels_.end(); ++iter) {
|
||||||
|
if (local_ssrc == iter->second->send_ssrc)
|
||||||
|
return iter->first;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
int GetNumChannels() const { return channels_.size(); }
|
int GetNumChannels() const { return channels_.size(); }
|
||||||
bool GetPlayout(int channel) {
|
bool GetPlayout(int channel) {
|
||||||
return channels_[channel]->playout;
|
return channels_[channel]->playout;
|
||||||
|
183
talk/media/webrtc/webrtctexturevideoframe.cc
Normal file
183
talk/media/webrtc/webrtctexturevideoframe.cc
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/media/webrtc/webrtctexturevideoframe.h"
|
||||||
|
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/base/stream.h"
|
||||||
|
|
||||||
|
#define UNIMPLEMENTED \
|
||||||
|
LOG(LS_ERROR) << "Call to unimplemented function "<< __FUNCTION__; \
|
||||||
|
ASSERT(false)
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
WebRtcTextureVideoFrame::WebRtcTextureVideoFrame(
|
||||||
|
webrtc::NativeHandle* handle, int width, int height, int64 elapsed_time,
|
||||||
|
int64 time_stamp)
|
||||||
|
: handle_(handle), width_(width), height_(height),
|
||||||
|
elapsed_time_(elapsed_time), time_stamp_(time_stamp) {}
|
||||||
|
|
||||||
|
WebRtcTextureVideoFrame::~WebRtcTextureVideoFrame() {}
|
||||||
|
|
||||||
|
bool WebRtcTextureVideoFrame::InitToBlack(
|
||||||
|
int w, int h, size_t pixel_width, size_t pixel_height, int64 elapsed_time,
|
||||||
|
int64 time_stamp) {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcTextureVideoFrame::Reset(
|
||||||
|
uint32 fourcc, int w, int h, int dw, int dh, uint8* sample,
|
||||||
|
size_t sample_size, size_t pixel_width, size_t pixel_height,
|
||||||
|
int64 elapsed_time, int64 time_stamp, int rotation) {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8* WebRtcTextureVideoFrame::GetYPlane() const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8* WebRtcTextureVideoFrame::GetUPlane() const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8* WebRtcTextureVideoFrame::GetVPlane() const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* WebRtcTextureVideoFrame::GetYPlane() {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* WebRtcTextureVideoFrame::GetUPlane() {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* WebRtcTextureVideoFrame::GetVPlane() {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 WebRtcTextureVideoFrame::GetYPitch() const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return width_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 WebRtcTextureVideoFrame::GetUPitch() const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return (width_ + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 WebRtcTextureVideoFrame::GetVPitch() const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return (width_ + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoFrame* WebRtcTextureVideoFrame::Copy() const {
|
||||||
|
return new WebRtcTextureVideoFrame(
|
||||||
|
handle_, width_, height_, elapsed_time_, time_stamp_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcTextureVideoFrame::MakeExclusive() {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebRtcTextureVideoFrame::CopyToBuffer(uint8* buffer, size_t size) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebRtcTextureVideoFrame::ConvertToRgbBuffer(
|
||||||
|
uint32 to_fourcc, uint8* buffer, size_t size, int stride_rgb) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcTextureVideoFrame::CopyToPlanes(
|
||||||
|
uint8* dst_y, uint8* dst_u, uint8* dst_v, int32 dst_pitch_y,
|
||||||
|
int32 dst_pitch_u, int32 dst_pitch_v) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRtcTextureVideoFrame::CopyToFrame(VideoFrame* dst) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
talk_base::StreamResult WebRtcTextureVideoFrame::Write(
|
||||||
|
talk_base::StreamInterface* stream, int* error) {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return talk_base::SR_ERROR;
|
||||||
|
}
|
||||||
|
void WebRtcTextureVideoFrame::StretchToPlanes(
|
||||||
|
uint8* dst_y, uint8* dst_u, uint8* dst_v, int32 dst_pitch_y,
|
||||||
|
int32 dst_pitch_u, int32 dst_pitch_v, size_t width, size_t height,
|
||||||
|
bool interpolate, bool vert_crop) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t WebRtcTextureVideoFrame::StretchToBuffer(
|
||||||
|
size_t dst_width, size_t dst_height, uint8* dst_buffer, size_t size,
|
||||||
|
bool interpolate, bool vert_crop) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRtcTextureVideoFrame::StretchToFrame(
|
||||||
|
VideoFrame* dst, bool interpolate, bool vert_crop) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoFrame* WebRtcTextureVideoFrame::Stretch(
|
||||||
|
size_t dst_width, size_t dst_height, bool interpolate,
|
||||||
|
bool vert_crop) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcTextureVideoFrame::SetToBlack() {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoFrame* WebRtcTextureVideoFrame::CreateEmptyFrame(
|
||||||
|
int w, int h, size_t pixel_width, size_t pixel_height, int64 elapsed_time,
|
||||||
|
int64 time_stamp) const {
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cricket
|
120
talk/media/webrtc/webrtctexturevideoframe.h
Normal file
120
talk/media/webrtc/webrtctexturevideoframe.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_MEDIA_WEBRTC_WEBRTCTEXTUREVIDEOFRAME_H_
|
||||||
|
#define TALK_MEDIA_WEBRTC_WEBRTCTEXTUREVIDEOFRAME_H_
|
||||||
|
|
||||||
|
#include "talk/base/refcount.h"
|
||||||
|
#include "talk/base/scoped_ref_ptr.h"
|
||||||
|
#include "talk/media/base/videoframe.h"
|
||||||
|
#ifdef USE_WEBRTC_DEV_BRANCH
|
||||||
|
#include "webrtc/common_video/interface/native_handle.h"
|
||||||
|
#else
|
||||||
|
#include "webrtc/common_video/interface/i420_video_frame.h"
|
||||||
|
// Define NativeHandle to an existing type so we don't need to add lots of
|
||||||
|
// USE_WEBRTC_DEV_BRANCH.
|
||||||
|
#define NativeHandle I420VideoFrame
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
// A video frame backed by the texture via a native handle.
|
||||||
|
class WebRtcTextureVideoFrame : public VideoFrame {
|
||||||
|
public:
|
||||||
|
WebRtcTextureVideoFrame(webrtc::NativeHandle* handle, int width, int height,
|
||||||
|
int64 elapsed_time, int64 time_stamp);
|
||||||
|
virtual ~WebRtcTextureVideoFrame();
|
||||||
|
|
||||||
|
// From base class VideoFrame.
|
||||||
|
virtual bool InitToBlack(int w, int h, size_t pixel_width,
|
||||||
|
size_t pixel_height, int64 elapsed_time,
|
||||||
|
int64 time_stamp);
|
||||||
|
virtual bool Reset(uint32 fourcc, int w, int h, int dw, int dh, uint8* sample,
|
||||||
|
size_t sample_size, size_t pixel_width,
|
||||||
|
size_t pixel_height, int64 elapsed_time, int64 time_stamp,
|
||||||
|
int rotation);
|
||||||
|
virtual size_t GetWidth() const { return width_; }
|
||||||
|
virtual size_t GetHeight() const { return height_; }
|
||||||
|
virtual const uint8* GetYPlane() const;
|
||||||
|
virtual const uint8* GetUPlane() const;
|
||||||
|
virtual const uint8* GetVPlane() const;
|
||||||
|
virtual uint8* GetYPlane();
|
||||||
|
virtual uint8* GetUPlane();
|
||||||
|
virtual uint8* GetVPlane();
|
||||||
|
virtual int32 GetYPitch() const;
|
||||||
|
virtual int32 GetUPitch() const;
|
||||||
|
virtual int32 GetVPitch() const;
|
||||||
|
virtual size_t GetPixelWidth() const { return 1; }
|
||||||
|
virtual size_t GetPixelHeight() const { return 1; }
|
||||||
|
virtual int64 GetElapsedTime() const { return elapsed_time_; }
|
||||||
|
virtual int64 GetTimeStamp() const { return time_stamp_; }
|
||||||
|
virtual void SetElapsedTime(int64 elapsed_time) {
|
||||||
|
elapsed_time_ = elapsed_time;
|
||||||
|
}
|
||||||
|
virtual void SetTimeStamp(int64 time_stamp) { time_stamp_ = time_stamp; }
|
||||||
|
virtual int GetRotation() const { return 0; }
|
||||||
|
virtual VideoFrame* Copy() const;
|
||||||
|
virtual bool MakeExclusive();
|
||||||
|
virtual size_t CopyToBuffer(uint8* buffer, size_t size) const;
|
||||||
|
virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8* buffer,
|
||||||
|
size_t size, int stride_rgb) const;
|
||||||
|
virtual void* GetNativeHandle() const { return handle_.get(); }
|
||||||
|
|
||||||
|
virtual bool CopyToPlanes(
|
||||||
|
uint8* dst_y, uint8* dst_u, uint8* dst_v,
|
||||||
|
int32 dst_pitch_y, int32 dst_pitch_u, int32 dst_pitch_v) const;
|
||||||
|
virtual void CopyToFrame(VideoFrame* target) const;
|
||||||
|
virtual talk_base::StreamResult Write(talk_base::StreamInterface* stream,
|
||||||
|
int* error);
|
||||||
|
virtual void StretchToPlanes(
|
||||||
|
uint8* y, uint8* u, uint8* v, int32 pitchY, int32 pitchU, int32 pitchV,
|
||||||
|
size_t width, size_t height, bool interpolate, bool crop) const;
|
||||||
|
virtual size_t StretchToBuffer(size_t w, size_t h, uint8* buffer, size_t size,
|
||||||
|
bool interpolate, bool crop) const;
|
||||||
|
virtual void StretchToFrame(VideoFrame* target, bool interpolate,
|
||||||
|
bool crop) const;
|
||||||
|
virtual VideoFrame* Stretch(size_t w, size_t h, bool interpolate,
|
||||||
|
bool crop) const;
|
||||||
|
virtual bool SetToBlack();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual VideoFrame* CreateEmptyFrame(int w, int h, size_t pixel_width,
|
||||||
|
size_t pixel_height, int64 elapsed_time,
|
||||||
|
int64 time_stamp) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The handle of the underlying video frame.
|
||||||
|
talk_base::scoped_refptr<webrtc::NativeHandle> handle_;
|
||||||
|
int width_;
|
||||||
|
int height_;
|
||||||
|
int64 elapsed_time_;
|
||||||
|
int64 time_stamp_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_MEDIA_WEBRTC_WEBRTCTEXTUREVIDEOFRAME_H_
|
84
talk/media/webrtc/webrtctexturevideoframe_unittest.cc
Normal file
84
talk/media/webrtc/webrtctexturevideoframe_unittest.cc
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/media/webrtc/webrtctexturevideoframe.h"
|
||||||
|
|
||||||
|
#include "talk/base/gunit.h"
|
||||||
|
#include "talk/media/base/videocommon.h"
|
||||||
|
|
||||||
|
class NativeHandleImpl : public webrtc::NativeHandle {
|
||||||
|
public:
|
||||||
|
NativeHandleImpl() : ref_count_(0) {}
|
||||||
|
virtual ~NativeHandleImpl() {}
|
||||||
|
virtual int32_t AddRef() { return ++ref_count_; }
|
||||||
|
virtual int32_t Release() { return --ref_count_; }
|
||||||
|
virtual void* GetHandle() { return NULL; }
|
||||||
|
|
||||||
|
int32_t ref_count() { return ref_count_; }
|
||||||
|
private:
|
||||||
|
int32_t ref_count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(WebRtcTextureVideoFrameTest, InitialValues) {
|
||||||
|
NativeHandleImpl handle;
|
||||||
|
cricket::WebRtcTextureVideoFrame frame(&handle, 640, 480, 100, 200);
|
||||||
|
EXPECT_EQ(&handle, frame.GetNativeHandle());
|
||||||
|
EXPECT_EQ(640u, frame.GetWidth());
|
||||||
|
EXPECT_EQ(480u, frame.GetHeight());
|
||||||
|
EXPECT_EQ(100, frame.GetElapsedTime());
|
||||||
|
EXPECT_EQ(200, frame.GetTimeStamp());
|
||||||
|
frame.SetElapsedTime(300);
|
||||||
|
EXPECT_EQ(300, frame.GetElapsedTime());
|
||||||
|
frame.SetTimeStamp(400);
|
||||||
|
EXPECT_EQ(400, frame.GetTimeStamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WebRtcTextureVideoFrameTest, CopyFrame) {
|
||||||
|
NativeHandleImpl handle;
|
||||||
|
cricket::WebRtcTextureVideoFrame frame1(&handle, 640, 480, 100, 200);
|
||||||
|
cricket::VideoFrame* frame2 = frame1.Copy();
|
||||||
|
EXPECT_EQ(frame1.GetNativeHandle(), frame2->GetNativeHandle());
|
||||||
|
EXPECT_EQ(frame1.GetWidth(), frame2->GetWidth());
|
||||||
|
EXPECT_EQ(frame1.GetHeight(), frame2->GetHeight());
|
||||||
|
EXPECT_EQ(frame1.GetElapsedTime(), frame2->GetElapsedTime());
|
||||||
|
EXPECT_EQ(frame1.GetTimeStamp(), frame2->GetTimeStamp());
|
||||||
|
delete frame2;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(WebRtcTextureVideoFrameTest, RefCount) {
|
||||||
|
NativeHandleImpl handle;
|
||||||
|
EXPECT_EQ(0, handle.ref_count());
|
||||||
|
cricket::WebRtcTextureVideoFrame* frame1 =
|
||||||
|
new cricket::WebRtcTextureVideoFrame(&handle, 640, 480, 100, 200);
|
||||||
|
EXPECT_EQ(1, handle.ref_count());
|
||||||
|
cricket::VideoFrame* frame2 = frame1->Copy();
|
||||||
|
EXPECT_EQ(2, handle.ref_count());
|
||||||
|
delete frame2;
|
||||||
|
EXPECT_EQ(1, handle.ref_count());
|
||||||
|
delete frame1;
|
||||||
|
EXPECT_EQ(0, handle.ref_count());
|
||||||
|
}
|
@ -51,10 +51,11 @@
|
|||||||
#include "talk/media/base/videocapturer.h"
|
#include "talk/media/base/videocapturer.h"
|
||||||
#include "talk/media/base/videorenderer.h"
|
#include "talk/media/base/videorenderer.h"
|
||||||
#include "talk/media/devices/filevideocapturer.h"
|
#include "talk/media/devices/filevideocapturer.h"
|
||||||
|
#include "talk/media/webrtc/webrtcpassthroughrender.h"
|
||||||
|
#include "talk/media/webrtc/webrtctexturevideoframe.h"
|
||||||
|
#include "talk/media/webrtc/webrtcvideocapturer.h"
|
||||||
#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
|
#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
|
||||||
#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
|
#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
|
||||||
#include "talk/media/webrtc/webrtcpassthroughrender.h"
|
|
||||||
#include "talk/media/webrtc/webrtcvideocapturer.h"
|
|
||||||
#include "talk/media/webrtc/webrtcvideoframe.h"
|
#include "talk/media/webrtc/webrtcvideoframe.h"
|
||||||
#include "talk/media/webrtc/webrtcvie.h"
|
#include "talk/media/webrtc/webrtcvie.h"
|
||||||
#include "talk/media/webrtc/webrtcvoe.h"
|
#include "talk/media/webrtc/webrtcvoe.h"
|
||||||
@ -176,12 +177,15 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
|
|||||||
explicit WebRtcRenderAdapter(VideoRenderer* renderer)
|
explicit WebRtcRenderAdapter(VideoRenderer* renderer)
|
||||||
: renderer_(renderer), width_(0), height_(0), watermark_enabled_(false) {
|
: renderer_(renderer), width_(0), height_(0), watermark_enabled_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~WebRtcRenderAdapter() {
|
virtual ~WebRtcRenderAdapter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_watermark_enabled(bool enable) {
|
void set_watermark_enabled(bool enable) {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
watermark_enabled_ = enable;
|
watermark_enabled_ = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRenderer(VideoRenderer* renderer) {
|
void SetRenderer(VideoRenderer* renderer) {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
renderer_ = renderer;
|
renderer_ = renderer;
|
||||||
@ -198,6 +202,7 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of webrtc::ExternalRenderer.
|
// Implementation of webrtc::ExternalRenderer.
|
||||||
virtual int FrameSizeChange(unsigned int width, unsigned int height,
|
virtual int FrameSizeChange(unsigned int width, unsigned int height,
|
||||||
unsigned int /*number_of_streams*/) {
|
unsigned int /*number_of_streams*/) {
|
||||||
@ -213,14 +218,18 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
|
|||||||
}
|
}
|
||||||
return renderer_->SetSize(width_, height_, 0) ? 0 : -1;
|
return renderer_->SetSize(width_, height_, 0) ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int DeliverFrame(unsigned char* buffer, int buffer_size,
|
virtual int DeliverFrame(unsigned char* buffer, int buffer_size,
|
||||||
uint32_t time_stamp, int64_t render_time) {
|
uint32_t time_stamp, int64_t render_time
|
||||||
|
#ifdef USE_WEBRTC_DEV_BRANCH
|
||||||
|
, void* handle
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
frame_rate_tracker_.Update(1);
|
frame_rate_tracker_.Update(1);
|
||||||
if (renderer_ == NULL) {
|
if (renderer_ == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
WebRtcVideoFrame video_frame;
|
|
||||||
// Convert 90K rtp timestamp to ns timestamp.
|
// Convert 90K rtp timestamp to ns timestamp.
|
||||||
int64 rtp_time_stamp_in_ns = (time_stamp / 90) *
|
int64 rtp_time_stamp_in_ns = (time_stamp / 90) *
|
||||||
talk_base::kNumNanosecsPerMillisec;
|
talk_base::kNumNanosecsPerMillisec;
|
||||||
@ -229,9 +238,26 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
|
|||||||
talk_base::kNumNanosecsPerMillisec;
|
talk_base::kNumNanosecsPerMillisec;
|
||||||
// Send the rtp timestamp to renderer as the VideoFrame timestamp.
|
// Send the rtp timestamp to renderer as the VideoFrame timestamp.
|
||||||
// and the render timestamp as the VideoFrame elapsed_time.
|
// and the render timestamp as the VideoFrame elapsed_time.
|
||||||
|
#ifdef USE_WEBRTC_DEV_BRANCH
|
||||||
|
if (handle == NULL) {
|
||||||
|
#endif
|
||||||
|
return DeliverBufferFrame(buffer, buffer_size, render_time_stamp_in_ns,
|
||||||
|
rtp_time_stamp_in_ns);
|
||||||
|
#ifdef USE_WEBRTC_DEV_BRANCH
|
||||||
|
} else {
|
||||||
|
return DeliverTextureFrame(handle, render_time_stamp_in_ns,
|
||||||
|
rtp_time_stamp_in_ns);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool IsTextureSupported() { return true; }
|
||||||
|
|
||||||
|
int DeliverBufferFrame(unsigned char* buffer, int buffer_size,
|
||||||
|
int64 elapsed_time, int64 time_stamp) {
|
||||||
|
WebRtcVideoFrame video_frame;
|
||||||
video_frame.Attach(buffer, buffer_size, width_, height_,
|
video_frame.Attach(buffer, buffer_size, width_, height_,
|
||||||
1, 1, render_time_stamp_in_ns,
|
1, 1, elapsed_time, time_stamp, 0);
|
||||||
rtp_time_stamp_in_ns, 0);
|
|
||||||
|
|
||||||
|
|
||||||
// Sanity check on decoded frame size.
|
// Sanity check on decoded frame size.
|
||||||
@ -247,18 +273,28 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DeliverTextureFrame(void* handle, int64 elapsed_time, int64 time_stamp) {
|
||||||
|
WebRtcTextureVideoFrame video_frame(
|
||||||
|
static_cast<webrtc::NativeHandle*>(handle), width_, height_,
|
||||||
|
elapsed_time, time_stamp);
|
||||||
|
return renderer_->RenderFrame(&video_frame);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int width() {
|
unsigned int width() {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
return width_;
|
return width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int height() {
|
unsigned int height() {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
return height_;
|
return height_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int framerate() {
|
int framerate() {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
return static_cast<int>(frame_rate_tracker_.units_second());
|
return static_cast<int>(frame_rate_tracker_.units_second());
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoRenderer* renderer() {
|
VideoRenderer* renderer() {
|
||||||
talk_base::CritScope cs(&crit_);
|
talk_base::CritScope cs(&crit_);
|
||||||
return renderer_;
|
return renderer_;
|
||||||
|
@ -106,6 +106,7 @@ class WebRtcVideoFrame : public VideoFrame {
|
|||||||
virtual int32 GetYPitch() const { return frame()->Width(); }
|
virtual int32 GetYPitch() const { return frame()->Width(); }
|
||||||
virtual int32 GetUPitch() const { return (frame()->Width() + 1) / 2; }
|
virtual int32 GetUPitch() const { return (frame()->Width() + 1) / 2; }
|
||||||
virtual int32 GetVPitch() const { return (frame()->Width() + 1) / 2; }
|
virtual int32 GetVPitch() const { return (frame()->Width() + 1) / 2; }
|
||||||
|
virtual void* GetNativeHandle() const { return NULL; }
|
||||||
|
|
||||||
virtual size_t GetPixelWidth() const { return pixel_width_; }
|
virtual size_t GetPixelWidth() const { return pixel_width_; }
|
||||||
virtual size_t GetPixelHeight() const { return pixel_height_; }
|
virtual size_t GetPixelHeight() const { return pixel_height_; }
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -275,7 +275,7 @@ template <class T, class E>
|
|||||||
class WebRtcMediaChannel : public T, public webrtc::Transport {
|
class WebRtcMediaChannel : public T, public webrtc::Transport {
|
||||||
public:
|
public:
|
||||||
WebRtcMediaChannel(E *engine, int channel)
|
WebRtcMediaChannel(E *engine, int channel)
|
||||||
: engine_(engine), voe_channel_(channel), sequence_number_(-1) {}
|
: engine_(engine), voe_channel_(channel) {}
|
||||||
E *engine() { return engine_; }
|
E *engine() { return engine_; }
|
||||||
int voe_channel() const { return voe_channel_; }
|
int voe_channel() const { return voe_channel_; }
|
||||||
bool valid() const { return voe_channel_ != -1; }
|
bool valid() const { return voe_channel_ != -1; }
|
||||||
@ -283,23 +283,10 @@ class WebRtcMediaChannel : public T, public webrtc::Transport {
|
|||||||
protected:
|
protected:
|
||||||
// implements Transport interface
|
// implements Transport interface
|
||||||
virtual int SendPacket(int channel, const void *data, int len) {
|
virtual int SendPacket(int channel, const void *data, int len) {
|
||||||
// We need to store the sequence number to be able to pick up
|
|
||||||
// the same sequence when the device is restarted.
|
|
||||||
// TODO(oja): Remove when WebRtc has fixed the problem.
|
|
||||||
int seq_num;
|
|
||||||
if (!GetRtpSeqNum(data, len, &seq_num)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (sequence_number() == -1) {
|
|
||||||
LOG(INFO) << "WebRtcVoiceMediaChannel sends first packet seqnum="
|
|
||||||
<< seq_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
|
talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
|
||||||
if (!T::SendPacket(&packet)) {
|
if (!T::SendPacket(&packet)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sequence_number_ = seq_num;
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,14 +295,9 @@ class WebRtcMediaChannel : public T, public webrtc::Transport {
|
|||||||
return T::SendRtcp(&packet) ? len : -1;
|
return T::SendRtcp(&packet) ? len : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sequence_number() const {
|
|
||||||
return sequence_number_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
E *engine_;
|
E *engine_;
|
||||||
int voe_channel_;
|
int voe_channel_;
|
||||||
int sequence_number_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// WebRtcVoiceMediaChannel is an implementation of VoiceMediaChannel that uses
|
// WebRtcVoiceMediaChannel is an implementation of VoiceMediaChannel that uses
|
||||||
@ -393,16 +375,24 @@ class WebRtcVoiceMediaChannel
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct WebRtcVoiceChannelInfo;
|
struct WebRtcVoiceChannelInfo;
|
||||||
|
typedef std::map<uint32, WebRtcVoiceChannelInfo> ChannelMap;
|
||||||
|
|
||||||
void SetNack(uint32 ssrc, int channel, bool nack_enabled);
|
void SetNack(uint32 ssrc, int channel, bool nack_enabled);
|
||||||
|
void SetNack(const ChannelMap& channels, bool nack_enabled);
|
||||||
bool SetSendCodec(const webrtc::CodecInst& send_codec);
|
bool SetSendCodec(const webrtc::CodecInst& send_codec);
|
||||||
|
bool SetSendCodec(int channel, const webrtc::CodecInst& send_codec);
|
||||||
bool ChangePlayout(bool playout);
|
bool ChangePlayout(bool playout);
|
||||||
bool ChangeSend(SendFlags send);
|
bool ChangeSend(SendFlags send);
|
||||||
|
bool ChangeSend(int channel, SendFlags send);
|
||||||
|
void ConfigureSendChannel(int channel);
|
||||||
|
bool DeleteChannel(int channel);
|
||||||
bool InConferenceMode() const {
|
bool InConferenceMode() const {
|
||||||
return options_.conference_mode.GetWithDefaultIfUnset(false);
|
return options_.conference_mode.GetWithDefaultIfUnset(false);
|
||||||
}
|
}
|
||||||
|
bool IsDefaultChannel(int channel_id) const {
|
||||||
|
return channel_id == voe_channel();
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::map<uint32, WebRtcVoiceChannelInfo> ChannelMap;
|
|
||||||
talk_base::scoped_ptr<WebRtcSoundclipStream> ringback_tone_;
|
talk_base::scoped_ptr<WebRtcSoundclipStream> ringback_tone_;
|
||||||
std::set<int> ringback_channels_; // channels playing ringback
|
std::set<int> ringback_channels_; // channels playing ringback
|
||||||
std::vector<AudioCodec> recv_codecs_;
|
std::vector<AudioCodec> recv_codecs_;
|
||||||
@ -415,17 +405,14 @@ class WebRtcVoiceMediaChannel
|
|||||||
SendFlags desired_send_;
|
SendFlags desired_send_;
|
||||||
SendFlags send_;
|
SendFlags send_;
|
||||||
|
|
||||||
// TODO(xians): Add support for multiple send channels.
|
// send_channels_ contains the channels which are being used for sending.
|
||||||
uint32 send_ssrc_;
|
// When the default channel (voe_channel) is used for sending, it is
|
||||||
// Weak pointer to the renderer of the local audio track. It is owned by the
|
// contained in send_channels_, otherwise not.
|
||||||
// track and will set to NULL when the track is going away or channel gets
|
ChannelMap send_channels_;
|
||||||
// deleted. Used to notify the audio track that the media channel is added
|
|
||||||
// or removed.
|
|
||||||
AudioRenderer* local_renderer_;
|
|
||||||
uint32 default_receive_ssrc_;
|
uint32 default_receive_ssrc_;
|
||||||
// Note the default channel (voe_channel()) can reside in both
|
// Note the default channel (voe_channel()) can reside in both
|
||||||
// receive_channels_ and send channel in non-conference mode and in that case
|
// receive_channels_ and send_channels_ in non-conference mode and in that
|
||||||
// it will only be there if a non-zero default_receive_ssrc_ is set.
|
// case it will only be there if a non-zero default_receive_ssrc_ is set.
|
||||||
ChannelMap receive_channels_; // for multiple sources
|
ChannelMap receive_channels_; // for multiple sources
|
||||||
// receive_channels_ can be read from WebRtc callback thread. Access from
|
// receive_channels_ can be read from WebRtc callback thread. Access from
|
||||||
// the WebRtc thread must be synchronized with edits on the worker thread.
|
// the WebRtc thread must be synchronized with edits on the worker thread.
|
||||||
|
@ -121,6 +121,18 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
void SetupForMultiSendStream() {
|
||||||
|
EXPECT_TRUE(SetupEngine());
|
||||||
|
// Remove stream added in Setup, which is corresponding to default channel.
|
||||||
|
int default_channel_num = voe_.GetLastChannel();
|
||||||
|
uint32 default_send_ssrc;
|
||||||
|
EXPECT_EQ(0, voe_.GetLocalSSRC(default_channel_num, default_send_ssrc));
|
||||||
|
EXPECT_EQ(kSsrc1, default_send_ssrc);
|
||||||
|
EXPECT_TRUE(channel_->RemoveSendStream(default_send_ssrc));
|
||||||
|
|
||||||
|
// Verify the default channel still exists.
|
||||||
|
EXPECT_EQ(0, voe_.GetLocalSSRC(default_channel_num, default_send_ssrc));
|
||||||
|
}
|
||||||
void DeliverPacket(const void* data, int len) {
|
void DeliverPacket(const void* data, int len) {
|
||||||
talk_base::Buffer packet(data, len);
|
talk_base::Buffer packet(data, len);
|
||||||
channel_->OnPacketReceived(&packet);
|
channel_->OnPacketReceived(&packet);
|
||||||
@ -205,6 +217,47 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TestSetSendRtpHeaderExtensions(int channel_id) {
|
||||||
|
std::vector<cricket::RtpHeaderExtension> extensions;
|
||||||
|
bool enable = false;
|
||||||
|
unsigned char id = 0;
|
||||||
|
|
||||||
|
// Ensure audio levels are off by default.
|
||||||
|
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
||||||
|
channel_id, enable, id));
|
||||||
|
EXPECT_FALSE(enable);
|
||||||
|
|
||||||
|
// Ensure unknown extensions won't cause an error.
|
||||||
|
extensions.push_back(cricket::RtpHeaderExtension(
|
||||||
|
"urn:ietf:params:unknowextention", 1));
|
||||||
|
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
||||||
|
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
||||||
|
channel_id, enable, id));
|
||||||
|
EXPECT_FALSE(enable);
|
||||||
|
|
||||||
|
// Ensure audio levels stay off with an empty list of headers.
|
||||||
|
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
||||||
|
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
||||||
|
channel_id, enable, id));
|
||||||
|
EXPECT_FALSE(enable);
|
||||||
|
|
||||||
|
// Ensure audio levels are enabled if the audio-level header is specified.
|
||||||
|
extensions.push_back(cricket::RtpHeaderExtension(
|
||||||
|
"urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8));
|
||||||
|
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
||||||
|
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
||||||
|
channel_id, enable, id));
|
||||||
|
EXPECT_TRUE(enable);
|
||||||
|
EXPECT_EQ(8, id);
|
||||||
|
|
||||||
|
// Ensure audio levels go back off with an empty list.
|
||||||
|
extensions.clear();
|
||||||
|
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
||||||
|
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
||||||
|
channel_id, enable, id));
|
||||||
|
EXPECT_FALSE(enable);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
cricket::FakeWebRtcVoiceEngine voe_;
|
cricket::FakeWebRtcVoiceEngine voe_;
|
||||||
cricket::FakeWebRtcVoiceEngine voe_sc_;
|
cricket::FakeWebRtcVoiceEngine voe_sc_;
|
||||||
@ -1336,43 +1389,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendRtpHeaderExtensions) {
|
|||||||
EXPECT_TRUE(SetupEngine());
|
EXPECT_TRUE(SetupEngine());
|
||||||
std::vector<cricket::RtpHeaderExtension> extensions;
|
std::vector<cricket::RtpHeaderExtension> extensions;
|
||||||
int channel_num = voe_.GetLastChannel();
|
int channel_num = voe_.GetLastChannel();
|
||||||
bool enable = false;
|
TestSetSendRtpHeaderExtensions(channel_num);
|
||||||
unsigned char id = 0;
|
|
||||||
|
|
||||||
// Ensure audio levels are off by default.
|
|
||||||
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
|
||||||
channel_num, enable, id));
|
|
||||||
EXPECT_FALSE(enable);
|
|
||||||
|
|
||||||
// Ensure unknown extentions won't cause an error.
|
|
||||||
extensions.push_back(cricket::RtpHeaderExtension(
|
|
||||||
"urn:ietf:params:unknowextention", 1));
|
|
||||||
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
|
||||||
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
|
||||||
channel_num, enable, id));
|
|
||||||
EXPECT_FALSE(enable);
|
|
||||||
|
|
||||||
// Ensure audio levels stay off with an empty list of headers.
|
|
||||||
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
|
||||||
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
|
||||||
channel_num, enable, id));
|
|
||||||
EXPECT_FALSE(enable);
|
|
||||||
|
|
||||||
// Ensure audio levels are enabled if the audio-level header is specified.
|
|
||||||
extensions.push_back(cricket::RtpHeaderExtension(
|
|
||||||
"urn:ietf:params:rtp-hdrext:ssrc-audio-level", 8));
|
|
||||||
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
|
||||||
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
|
||||||
channel_num, enable, id));
|
|
||||||
EXPECT_TRUE(enable);
|
|
||||||
EXPECT_EQ(8, id);
|
|
||||||
|
|
||||||
// Ensure audio levels go back off with an empty list.
|
|
||||||
extensions.clear();
|
|
||||||
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
|
|
||||||
EXPECT_EQ(0, voe_.GetRTPAudioLevelIndicationStatus(
|
|
||||||
channel_num, enable, id));
|
|
||||||
EXPECT_FALSE(enable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that we can create a channel and start sending/playing out on it.
|
// Test that we can create a channel and start sending/playing out on it.
|
||||||
@ -1392,9 +1409,169 @@ TEST_F(WebRtcVoiceEngineTestFake, SendAndPlayout) {
|
|||||||
EXPECT_FALSE(voe_.GetPlayout(channel_num));
|
EXPECT_FALSE(voe_.GetPlayout(channel_num));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that we can add and remove streams, and do proper send/playout.
|
// Test that we can add and remove send streams.
|
||||||
// We can receive on multiple streams, but will only send on one.
|
TEST_F(WebRtcVoiceEngineTestFake, CreateAndDeleteMultipleSendStreams) {
|
||||||
TEST_F(WebRtcVoiceEngineTestFake, SendAndPlayoutWithMultipleStreams) {
|
SetupForMultiSendStream();
|
||||||
|
|
||||||
|
static const uint32 kSsrcs4[] = {1, 2, 3, 4};
|
||||||
|
|
||||||
|
// Set the global state for sending.
|
||||||
|
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_TRUE(channel_->AddSendStream(
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
|
||||||
|
|
||||||
|
// Verify that we are in a sending state for all the created streams.
|
||||||
|
int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
|
||||||
|
EXPECT_TRUE(voe_.GetSend(channel_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the first send channel, which is the default channel. It will only
|
||||||
|
// recycle the default channel but not delete it.
|
||||||
|
EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs4[0]));
|
||||||
|
// Stream should already be Removed from the send stream list.
|
||||||
|
EXPECT_FALSE(channel_->RemoveSendStream(kSsrcs4[0]));
|
||||||
|
// But the default still exists.
|
||||||
|
EXPECT_EQ(0, voe_.GetChannelFromLocalSsrc(kSsrcs4[0]));
|
||||||
|
|
||||||
|
// Delete the rest of send channel streams.
|
||||||
|
for (unsigned int i = 1; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs4[i]));
|
||||||
|
// Stream should already be deleted.
|
||||||
|
EXPECT_FALSE(channel_->RemoveSendStream(kSsrcs4[i]));
|
||||||
|
EXPECT_EQ(-1, voe_.GetChannelFromLocalSsrc(kSsrcs4[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SetSendCodecs correctly configure the codecs in all send streams.
|
||||||
|
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsWithMultipleSendStreams) {
|
||||||
|
SetupForMultiSendStream();
|
||||||
|
|
||||||
|
static const uint32 kSsrcs4[] = {1, 2, 3, 4};
|
||||||
|
// Create send streams.
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_TRUE(channel_->AddSendStream(
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cricket::AudioCodec> codecs;
|
||||||
|
// Set ISAC(16K) and CN(16K). VAD should be activated.
|
||||||
|
codecs.push_back(kIsacCodec);
|
||||||
|
codecs.push_back(kCn16000Codec);
|
||||||
|
codecs[1].id = 97;
|
||||||
|
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
|
||||||
|
|
||||||
|
// Verify ISAC and VAD are corrected configured on all send channels.
|
||||||
|
webrtc::CodecInst gcodec;
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
|
||||||
|
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
|
||||||
|
EXPECT_STREQ("ISAC", gcodec.plname);
|
||||||
|
EXPECT_TRUE(voe_.GetVAD(channel_num));
|
||||||
|
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change to PCMU(8K) and CN(16K). VAD should not be activated.
|
||||||
|
codecs[0] = kPcmuCodec;
|
||||||
|
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
|
||||||
|
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
|
||||||
|
EXPECT_STREQ("PCMU", gcodec.plname);
|
||||||
|
EXPECT_FALSE(voe_.GetVAD(channel_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test we can SetSend on all send streams correctly.
|
||||||
|
TEST_F(WebRtcVoiceEngineTestFake, SetSendWithMultipleSendStreams) {
|
||||||
|
SetupForMultiSendStream();
|
||||||
|
|
||||||
|
static const uint32 kSsrcs4[] = {1, 2, 3, 4};
|
||||||
|
// Create the send channels and they should be a SEND_NOTHING date.
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_TRUE(channel_->AddSendStream(
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
|
||||||
|
int channel_num = voe_.GetLastChannel();
|
||||||
|
EXPECT_FALSE(voe_.GetSend(channel_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the global state for starting sending.
|
||||||
|
EXPECT_TRUE(channel_->SetSend(cricket::SEND_MICROPHONE));
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
// Verify that we are in a sending state for all the send streams.
|
||||||
|
int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
|
||||||
|
EXPECT_TRUE(voe_.GetSend(channel_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the global state for stopping sending.
|
||||||
|
EXPECT_TRUE(channel_->SetSend(cricket::SEND_NOTHING));
|
||||||
|
for (unsigned int i = 1; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
// Verify that we are in a stop state for all the send streams.
|
||||||
|
int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
|
||||||
|
EXPECT_FALSE(voe_.GetSend(channel_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test we can set the correct statistics on all send streams.
|
||||||
|
TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
|
||||||
|
SetupForMultiSendStream();
|
||||||
|
|
||||||
|
static const uint32 kSsrcs4[] = {1, 2, 3, 4};
|
||||||
|
// Create send streams.
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_TRUE(channel_->AddSendStream(
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need send codec to be set to get all stats.
|
||||||
|
std::vector<cricket::AudioCodec> codecs;
|
||||||
|
codecs.push_back(kPcmuCodec);
|
||||||
|
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
|
||||||
|
|
||||||
|
cricket::VoiceMediaInfo info;
|
||||||
|
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||||
|
EXPECT_EQ(static_cast<size_t>(ARRAY_SIZE(kSsrcs4)), info.senders.size());
|
||||||
|
|
||||||
|
// Verify the statistic information is correct.
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_EQ(kSsrcs4[i], info.senders[i].ssrc);
|
||||||
|
EXPECT_EQ(kPcmuCodec.name, info.senders[i].codec_name);
|
||||||
|
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].bytes_sent);
|
||||||
|
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].packets_sent);
|
||||||
|
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].packets_lost);
|
||||||
|
EXPECT_EQ(cricket::kFractionLostStatValue, info.senders[i].fraction_lost);
|
||||||
|
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].ext_seqnum);
|
||||||
|
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].rtt_ms);
|
||||||
|
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].jitter_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(1u, info.receivers.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we support setting certain send header extensions on multiple
|
||||||
|
// send streams.
|
||||||
|
TEST_F(WebRtcVoiceEngineTestFake,
|
||||||
|
SetSendRtpHeaderExtensionsWithMultpleSendStreams) {
|
||||||
|
SetupForMultiSendStream();
|
||||||
|
|
||||||
|
static const uint32 kSsrcs4[] = {1, 2, 3, 4};
|
||||||
|
// Create send streams.
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
EXPECT_TRUE(channel_->AddSendStream(
|
||||||
|
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SendRtpHeaderExtensions on each send channel.
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(kSsrcs4); ++i) {
|
||||||
|
int channel_num = voe_.GetChannelFromLocalSsrc(kSsrcs4[i]);
|
||||||
|
TestSetSendRtpHeaderExtensions(channel_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we can add and remove receive streams, and do proper send/playout.
|
||||||
|
// We can receive on multiple streams while sending one stream.
|
||||||
|
TEST_F(WebRtcVoiceEngineTestFake, PlayoutWithMultipleStreams) {
|
||||||
EXPECT_TRUE(SetupEngine());
|
EXPECT_TRUE(SetupEngine());
|
||||||
int channel_num1 = voe_.GetLastChannel();
|
int channel_num1 = voe_.GetLastChannel();
|
||||||
|
|
||||||
|
@ -79,9 +79,16 @@ SessionClient* SessionManager::GetClient(const std::string& content_type) {
|
|||||||
|
|
||||||
Session* SessionManager::CreateSession(const std::string& local_name,
|
Session* SessionManager::CreateSession(const std::string& local_name,
|
||||||
const std::string& content_type) {
|
const std::string& content_type) {
|
||||||
return CreateSession(local_name, local_name,
|
std::string id;
|
||||||
talk_base::ToString(talk_base::CreateRandomId64()),
|
return CreateSession(id, local_name, content_type);
|
||||||
content_type, false);
|
}
|
||||||
|
|
||||||
|
Session* SessionManager::CreateSession(const std::string& id,
|
||||||
|
const std::string& local_name,
|
||||||
|
const std::string& content_type) {
|
||||||
|
std::string sid =
|
||||||
|
id.empty() ? talk_base::ToString(talk_base::CreateRandomId64()) : id;
|
||||||
|
return CreateSession(local_name, local_name, sid, content_type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Session* SessionManager::CreateSession(
|
Session* SessionManager::CreateSession(
|
||||||
|
@ -92,6 +92,10 @@ class SessionManager : public sigslot::has_slots<> {
|
|||||||
Session *CreateSession(const std::string& local_name,
|
Session *CreateSession(const std::string& local_name,
|
||||||
const std::string& content_type);
|
const std::string& content_type);
|
||||||
|
|
||||||
|
Session *CreateSession(const std::string& id,
|
||||||
|
const std::string& local_name,
|
||||||
|
const std::string& content_type);
|
||||||
|
|
||||||
// Destroys the given session.
|
// Destroys the given session.
|
||||||
void DestroySession(Session *session);
|
void DestroySession(Session *session);
|
||||||
|
|
||||||
|
@ -59,6 +59,19 @@ V FindOrNull(const std::map<K, V>& map,
|
|||||||
return (it != map.end()) ? it->second : NULL;
|
return (it != map.end()) ? it->second : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ContentContainsCrypto(const cricket::ContentInfo* content) {
|
||||||
|
if (content != NULL) {
|
||||||
|
const cricket::MediaContentDescription* desc =
|
||||||
|
static_cast<const cricket::MediaContentDescription*>(
|
||||||
|
content->description);
|
||||||
|
if (!desc || desc->cryptos().empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Call::Call(MediaSessionClient* session_client)
|
Call::Call(MediaSessionClient* session_client)
|
||||||
@ -85,22 +98,16 @@ Call::~Call() {
|
|||||||
Session* Call::InitiateSession(const buzz::Jid& to,
|
Session* Call::InitiateSession(const buzz::Jid& to,
|
||||||
const buzz::Jid& initiator,
|
const buzz::Jid& initiator,
|
||||||
const CallOptions& options) {
|
const CallOptions& options) {
|
||||||
const SessionDescription* offer = session_client_->CreateOffer(options);
|
std::string id;
|
||||||
|
std::string initiator_name = initiator.Str();
|
||||||
|
return InternalInitiateSession(id, to, initiator_name, options);
|
||||||
|
}
|
||||||
|
|
||||||
Session* session = session_client_->CreateSession(this);
|
Session *Call::InitiateSession(const std::string& id,
|
||||||
session->set_initiator_name(initiator.Str());
|
const buzz::Jid& to,
|
||||||
|
const CallOptions& options) {
|
||||||
AddSession(session, offer);
|
std::string initiator_name;
|
||||||
session->Initiate(to.Str(), offer);
|
return InternalInitiateSession(id, to, initiator_name, options);
|
||||||
|
|
||||||
// After this timeout, terminate the call because the callee isn't
|
|
||||||
// answering
|
|
||||||
session_client_->session_manager()->signaling_thread()->Clear(this,
|
|
||||||
MSG_TERMINATECALL);
|
|
||||||
session_client_->session_manager()->signaling_thread()->PostDelayed(
|
|
||||||
send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout,
|
|
||||||
this, MSG_TERMINATECALL);
|
|
||||||
return session;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Call::IncomingSession(Session* session, const SessionDescription* offer) {
|
void Call::IncomingSession(Session* session, const SessionDescription* offer) {
|
||||||
@ -1025,4 +1032,66 @@ void Call::OnReceivedTerminateReason(Session* session,
|
|||||||
SignalReceivedTerminateReason(this, session, reason);
|
SignalReceivedTerminateReason(this, session, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(mdodd): Get ride of this method since all Hangouts are using a secure
|
||||||
|
// connection.
|
||||||
|
bool Call::secure() const {
|
||||||
|
if (session_client_->secure() == SEC_DISABLED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
MediaSessionMap::const_iterator it;
|
||||||
|
for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) {
|
||||||
|
LOG_F(LS_VERBOSE) << "session[" << i
|
||||||
|
<< "], check local and remote descriptions";
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (!SessionDescriptionContainsCrypto(
|
||||||
|
it->second.session->local_description()) ||
|
||||||
|
!SessionDescriptionContainsCrypto(
|
||||||
|
it->second.session->remote_description())) {
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_F(LS_VERBOSE) << "secure=" << ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Call::SessionDescriptionContainsCrypto(
|
||||||
|
const SessionDescription* sdesc) const {
|
||||||
|
if (sdesc == NULL) {
|
||||||
|
LOG_F(LS_VERBOSE) << "sessionDescription is NULL";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ContentContainsCrypto(sdesc->GetContentByName(CN_AUDIO)) &&
|
||||||
|
ContentContainsCrypto(sdesc->GetContentByName(CN_VIDEO));
|
||||||
|
}
|
||||||
|
|
||||||
|
Session* Call::InternalInitiateSession(const std::string& id,
|
||||||
|
const buzz::Jid& to,
|
||||||
|
const std::string& initiator_name,
|
||||||
|
const CallOptions& options) {
|
||||||
|
const SessionDescription* offer = session_client_->CreateOffer(options);
|
||||||
|
|
||||||
|
Session* session = session_client_->CreateSession(id, this);
|
||||||
|
session->set_initiator_name(initiator_name);
|
||||||
|
|
||||||
|
AddSession(session, offer);
|
||||||
|
session->Initiate(to.Str(), offer);
|
||||||
|
|
||||||
|
// After this timeout, terminate the call because the callee isn't
|
||||||
|
// answering
|
||||||
|
session_client_->session_manager()->signaling_thread()->Clear(this,
|
||||||
|
MSG_TERMINATECALL);
|
||||||
|
session_client_->session_manager()->signaling_thread()->PostDelayed(
|
||||||
|
send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout,
|
||||||
|
this, MSG_TERMINATECALL);
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cricket
|
} // namespace cricket
|
||||||
|
@ -66,6 +66,8 @@ class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
|
|||||||
// |initiator| can be empty.
|
// |initiator| can be empty.
|
||||||
Session* InitiateSession(const buzz::Jid& to, const buzz::Jid& initiator,
|
Session* InitiateSession(const buzz::Jid& to, const buzz::Jid& initiator,
|
||||||
const CallOptions& options);
|
const CallOptions& options);
|
||||||
|
Session* InitiateSession(const std::string& id, const buzz::Jid& to,
|
||||||
|
const CallOptions& options);
|
||||||
void AcceptSession(Session* session, const CallOptions& options);
|
void AcceptSession(Session* session, const CallOptions& options);
|
||||||
void RejectSession(Session* session);
|
void RejectSession(Session* session);
|
||||||
void TerminateSession(Session* session);
|
void TerminateSession(Session* session);
|
||||||
@ -100,6 +102,8 @@ class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
|
|||||||
bool has_video() const { return has_video_; }
|
bool has_video() const { return has_video_; }
|
||||||
bool has_data() const { return has_data_; }
|
bool has_data() const { return has_data_; }
|
||||||
bool muted() const { return muted_; }
|
bool muted() const { return muted_; }
|
||||||
|
bool video() const { return has_video_; }
|
||||||
|
bool secure() const;
|
||||||
bool video_muted() const { return video_muted_; }
|
bool video_muted() const { return video_muted_; }
|
||||||
const std::vector<StreamParams>* GetDataRecvStreams(Session* session) const {
|
const std::vector<StreamParams>* GetDataRecvStreams(Session* session) const {
|
||||||
MediaStreams* recv_streams = GetMediaStreams(session);
|
MediaStreams* recv_streams = GetMediaStreams(session);
|
||||||
@ -222,6 +226,11 @@ class Call : public talk_base::MessageHandler, public sigslot::has_slots<> {
|
|||||||
void ContinuePlayDTMF();
|
void ContinuePlayDTMF();
|
||||||
bool StopScreencastWithoutSendingUpdate(Session* session, uint32 ssrc);
|
bool StopScreencastWithoutSendingUpdate(Session* session, uint32 ssrc);
|
||||||
bool StopAllScreencastsWithoutSendingUpdate(Session* session);
|
bool StopAllScreencastsWithoutSendingUpdate(Session* session);
|
||||||
|
bool SessionDescriptionContainsCrypto(const SessionDescription* sdesc) const;
|
||||||
|
Session* InternalInitiateSession(const std::string& id,
|
||||||
|
const buzz::Jid& to,
|
||||||
|
const std::string& initiator_name,
|
||||||
|
const CallOptions& options);
|
||||||
|
|
||||||
uint32 id_;
|
uint32 id_;
|
||||||
MediaSessionClient* session_client_;
|
MediaSessionClient* session_client_;
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include "talk/media/sctp/sctpdataengine.h"
|
#include "talk/media/sctp/sctpdataengine.h"
|
||||||
#endif
|
#endif
|
||||||
#include "talk/session/media/soundclip.h"
|
#include "talk/session/media/soundclip.h"
|
||||||
|
#include "talk/session/media/srtpfilter.h"
|
||||||
|
|
||||||
namespace cricket {
|
namespace cricket {
|
||||||
|
|
||||||
@ -138,8 +139,15 @@ void ChannelManager::Construct(MediaEngineInterface* me,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChannelManager::~ChannelManager() {
|
ChannelManager::~ChannelManager() {
|
||||||
if (initialized_)
|
if (initialized_) {
|
||||||
Terminate();
|
Terminate();
|
||||||
|
// If srtp is initialized (done by the Channel) then we must call
|
||||||
|
// srtp_shutdown to free all crypto kernel lists. But we need to make sure
|
||||||
|
// shutdown always called at the end, after channels are destroyed.
|
||||||
|
// ChannelManager d'tor is always called last, it's safe place to call
|
||||||
|
// shutdown.
|
||||||
|
ShutdownSrtp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelManager::SetVideoRtxEnabled(bool enable) {
|
bool ChannelManager::SetVideoRtxEnabled(bool enable) {
|
||||||
|
@ -220,8 +220,13 @@ void MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Session *MediaSessionClient::CreateSession(Call *call) {
|
Session *MediaSessionClient::CreateSession(Call *call) {
|
||||||
|
std::string id;
|
||||||
|
return CreateSession(id, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
Session *MediaSessionClient::CreateSession(const std::string& id, Call* call) {
|
||||||
const std::string& type = NS_JINGLE_RTP;
|
const std::string& type = NS_JINGLE_RTP;
|
||||||
Session *session = session_manager_->CreateSession(jid().Str(), type);
|
Session *session = session_manager_->CreateSession(id, jid().Str(), type);
|
||||||
session_map_[session->id()] = call;
|
session_map_[session->id()] = call;
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,7 @@ class MediaSessionClient : public SessionClient, public sigslot::has_slots<> {
|
|||||||
void OnSessionState(BaseSession *session, BaseSession::State state);
|
void OnSessionState(BaseSession *session, BaseSession::State state);
|
||||||
void OnSessionDestroy(Session *session);
|
void OnSessionDestroy(Session *session);
|
||||||
Session *CreateSession(Call *call);
|
Session *CreateSession(Call *call);
|
||||||
|
Session *CreateSession(const std::string& id, Call* call);
|
||||||
Call *FindCallByRemoteName(const std::string &remote_name);
|
Call *FindCallByRemoteName(const std::string &remote_name);
|
||||||
|
|
||||||
buzz::Jid jid_;
|
buzz::Jid jid_;
|
||||||
|
@ -97,6 +97,15 @@ void EnableSrtpDebugging() {
|
|||||||
#endif // HAVE_SRTP
|
#endif // HAVE_SRTP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: This is called from ChannelManager D'tor.
|
||||||
|
void ShutdownSrtp() {
|
||||||
|
#ifdef HAVE_SRTP
|
||||||
|
// If srtp_dealloc is not executed then this will clear all existing sessions.
|
||||||
|
// This should be called when application is shutting down.
|
||||||
|
SrtpSession::Terminate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
SrtpFilter::SrtpFilter()
|
SrtpFilter::SrtpFilter()
|
||||||
: state_(ST_INIT),
|
: state_(ST_INIT),
|
||||||
signal_silent_time_in_ms_(0) {
|
signal_silent_time_in_ms_(0) {
|
||||||
@ -621,6 +630,17 @@ bool SrtpSession::Init() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrtpSession::Terminate() {
|
||||||
|
if (inited_) {
|
||||||
|
int err = srtp_shutdown();
|
||||||
|
if (err) {
|
||||||
|
LOG(LS_ERROR) << "srtp_shutdown failed. err=" << err;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inited_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
|
void SrtpSession::HandleEvent(const srtp_event_data_t* ev) {
|
||||||
switch (ev->event) {
|
switch (ev->event) {
|
||||||
case event_ssrc_collision:
|
case event_ssrc_collision:
|
||||||
|
@ -65,6 +65,7 @@ class SrtpSession;
|
|||||||
class SrtpStat;
|
class SrtpStat;
|
||||||
|
|
||||||
void EnableSrtpDebugging();
|
void EnableSrtpDebugging();
|
||||||
|
void ShutdownSrtp();
|
||||||
|
|
||||||
// Class to transform SRTP to/from RTP.
|
// Class to transform SRTP to/from RTP.
|
||||||
// Initialize by calling SetSend with the local security params, then call
|
// Initialize by calling SetSend with the local security params, then call
|
||||||
@ -208,6 +209,9 @@ class SrtpSession {
|
|||||||
// Update the silent threshold (in ms) for signaling errors.
|
// Update the silent threshold (in ms) for signaling errors.
|
||||||
void set_signal_silent_time(uint32 signal_silent_time_in_ms);
|
void set_signal_silent_time(uint32 signal_silent_time_in_ms);
|
||||||
|
|
||||||
|
// Calls srtp_shutdown if it's initialized.
|
||||||
|
static void Terminate();
|
||||||
|
|
||||||
sigslot::repeater3<uint32, SrtpFilter::Mode, SrtpFilter::Error>
|
sigslot::repeater3<uint32, SrtpFilter::Mode, SrtpFilter::Error>
|
||||||
SignalSrtpError;
|
SignalSrtpError;
|
||||||
|
|
||||||
|
@ -119,6 +119,27 @@ const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[] = "muc_lite";
|
|||||||
const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast";
|
const char STR_MUC_ROOM_FEATURE_BROADCAST[] = "broadcast";
|
||||||
const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc";
|
const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[] = "muc_muvc";
|
||||||
|
|
||||||
|
const char STR_ID_TYPE_CONVERSATION[] = "conversation";
|
||||||
|
const char NS_GOOGLE_MUC_HANGOUT[] = "google:muc#hangout";
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE =
|
||||||
|
{ NS_GOOGLE_MUC_HANGOUT, "invite" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE =
|
||||||
|
{ NS_GOOGLE_MUC_HANGOUT, "invite-type" };
|
||||||
|
const StaticQName QN_ATTR_CREATE_ACTIVITY =
|
||||||
|
{ STR_EMPTY, "create-activity" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC =
|
||||||
|
{ NS_GOOGLE_MUC_HANGOUT, "public" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE =
|
||||||
|
{ NS_GOOGLE_MUC_HANGOUT, "invitee" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_STATUS =
|
||||||
|
{ NS_GOOGLE_MUC_HANGOUT, "notification-status" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE = {
|
||||||
|
NS_GOOGLE_MUC_HANGOUT, "notification-type" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT = {
|
||||||
|
NS_GOOGLE_MUC_HANGOUT, "hangout-start-context" };
|
||||||
|
const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID = {
|
||||||
|
NS_GOOGLE_MUC_HANGOUT, "conversation-id" };
|
||||||
|
|
||||||
const StaticQName QN_STREAM_STREAM = { NS_STREAM, STR_STREAM };
|
const StaticQName QN_STREAM_STREAM = { NS_STREAM, STR_STREAM };
|
||||||
const StaticQName QN_STREAM_FEATURES = { NS_STREAM, "features" };
|
const StaticQName QN_STREAM_FEATURES = { NS_STREAM, "features" };
|
||||||
const StaticQName QN_STREAM_ERROR = { NS_STREAM, "error" };
|
const StaticQName QN_STREAM_ERROR = { NS_STREAM, "error" };
|
||||||
|
@ -112,6 +112,17 @@ extern const char STR_MUC_ROOM_FEATURE_HANGOUT_LITE[];
|
|||||||
extern const char STR_MUC_ROOM_FEATURE_BROADCAST[];
|
extern const char STR_MUC_ROOM_FEATURE_BROADCAST[];
|
||||||
extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[];
|
extern const char STR_MUC_ROOM_FEATURE_MULTI_USER_VC[];
|
||||||
|
|
||||||
|
extern const char STR_ID_TYPE_CONVERSATION[];
|
||||||
|
extern const char NS_GOOGLE_MUC_HANGOUT[];
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE;
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITE_TYPE;
|
||||||
|
extern const StaticQName QN_ATTR_CREATE_ACTIVITY;
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_PUBLIC;
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_INVITEE;
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_NOTIFICATION_TYPE;
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_HANGOUT_START_CONTEXT;
|
||||||
|
extern const StaticQName QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID;
|
||||||
|
|
||||||
extern const StaticQName QN_STREAM_STREAM;
|
extern const StaticQName QN_STREAM_STREAM;
|
||||||
extern const StaticQName QN_STREAM_FEATURES;
|
extern const StaticQName QN_STREAM_FEATURES;
|
||||||
extern const StaticQName QN_STREAM_ERROR;
|
extern const StaticQName QN_STREAM_ERROR;
|
||||||
|
@ -49,12 +49,20 @@ void MucRoomDiscoveryTask::HandleResult(const XmlElement* stanza) {
|
|||||||
std::map<std::string, std::string> extended_info;
|
std::map<std::string, std::string> extended_info;
|
||||||
const XmlElement* identity = query->FirstNamed(QN_DISCO_IDENTITY);
|
const XmlElement* identity = query->FirstNamed(QN_DISCO_IDENTITY);
|
||||||
if (identity == NULL || !identity->HasAttr(QN_NAME)) {
|
if (identity == NULL || !identity->HasAttr(QN_NAME)) {
|
||||||
SignalResult(this, false, "", features, extended_info);
|
SignalResult(this, false, "", "", features, extended_info);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string name(identity->Attr(QN_NAME));
|
const std::string name(identity->Attr(QN_NAME));
|
||||||
|
|
||||||
|
// Get the conversation id
|
||||||
|
const XmlElement* convIdElement =
|
||||||
|
identity->FirstNamed(QN_GOOGLE_MUC_HANGOUT_CONVERSATION_ID);
|
||||||
|
std::string conversation_id;
|
||||||
|
if (convIdElement != NULL) {
|
||||||
|
conversation_id = convIdElement->BodyText();
|
||||||
|
}
|
||||||
|
|
||||||
for (const XmlElement* feature = query->FirstNamed(QN_DISCO_FEATURE);
|
for (const XmlElement* feature = query->FirstNamed(QN_DISCO_FEATURE);
|
||||||
feature != NULL; feature = feature->NextNamed(QN_DISCO_FEATURE)) {
|
feature != NULL; feature = feature->NextNamed(QN_DISCO_FEATURE)) {
|
||||||
features.insert(feature->Attr(QN_VAR));
|
features.insert(feature->Attr(QN_VAR));
|
||||||
@ -69,7 +77,7 @@ void MucRoomDiscoveryTask::HandleResult(const XmlElement* stanza) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalResult(this, true, name, features, extended_info);
|
SignalResult(this, true, name, conversation_id, features, extended_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace buzz
|
} // namespace buzz
|
||||||
|
@ -41,10 +41,11 @@ class MucRoomDiscoveryTask : public IqTask {
|
|||||||
MucRoomDiscoveryTask(XmppTaskParentInterface* parent,
|
MucRoomDiscoveryTask(XmppTaskParentInterface* parent,
|
||||||
const Jid& room_jid);
|
const Jid& room_jid);
|
||||||
|
|
||||||
// Signal (exists, name, features, extended_info)
|
// Signal (exists, name, conversationId, features, extended_info)
|
||||||
sigslot::signal5<MucRoomDiscoveryTask*,
|
sigslot::signal6<MucRoomDiscoveryTask*,
|
||||||
bool,
|
bool,
|
||||||
const std::string&,
|
const std::string&,
|
||||||
|
const std::string&,
|
||||||
const std::set<std::string>&,
|
const std::set<std::string>&,
|
||||||
const std::map<std::string, std::string>& > SignalResult;
|
const std::map<std::string, std::string>& > SignalResult;
|
||||||
|
|
||||||
|
@ -43,10 +43,12 @@ class MucRoomDiscoveryListener : public sigslot::has_slots<> {
|
|||||||
void OnResult(buzz::MucRoomDiscoveryTask* task,
|
void OnResult(buzz::MucRoomDiscoveryTask* task,
|
||||||
bool exists,
|
bool exists,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
|
const std::string& conversation_id,
|
||||||
const std::set<std::string>& features,
|
const std::set<std::string>& features,
|
||||||
const std::map<std::string, std::string>& extended_info) {
|
const std::map<std::string, std::string>& extended_info) {
|
||||||
last_exists = exists;
|
last_exists = exists;
|
||||||
last_name = name;
|
last_name = name;
|
||||||
|
last_conversation_id = conversation_id;
|
||||||
last_features = features;
|
last_features = features;
|
||||||
last_extended_info = extended_info;
|
last_extended_info = extended_info;
|
||||||
}
|
}
|
||||||
@ -58,6 +60,7 @@ class MucRoomDiscoveryListener : public sigslot::has_slots<> {
|
|||||||
|
|
||||||
bool last_exists;
|
bool last_exists;
|
||||||
std::string last_name;
|
std::string last_name;
|
||||||
|
std::string last_conversation_id;
|
||||||
std::set<std::string> last_features;
|
std::set<std::string> last_features;
|
||||||
std::map<std::string, std::string> last_extended_info;
|
std::map<std::string, std::string> last_extended_info;
|
||||||
int error_count;
|
int error_count;
|
||||||
@ -67,7 +70,8 @@ class MucRoomDiscoveryTaskTest : public testing::Test {
|
|||||||
public:
|
public:
|
||||||
MucRoomDiscoveryTaskTest() :
|
MucRoomDiscoveryTaskTest() :
|
||||||
room_jid("muc-jid-ponies@domain.com"),
|
room_jid("muc-jid-ponies@domain.com"),
|
||||||
room_name("ponies") {
|
room_name("ponies"),
|
||||||
|
conversation_id("test_conversation_id") {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void SetUp() {
|
virtual void SetUp() {
|
||||||
@ -87,6 +91,7 @@ class MucRoomDiscoveryTaskTest : public testing::Test {
|
|||||||
MucRoomDiscoveryListener* listener;
|
MucRoomDiscoveryListener* listener;
|
||||||
buzz::Jid room_jid;
|
buzz::Jid room_jid;
|
||||||
std::string room_name;
|
std::string room_name;
|
||||||
|
std::string conversation_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) {
|
TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) {
|
||||||
@ -107,12 +112,16 @@ TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) {
|
|||||||
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
|
EXPECT_EQ(expected_iq, xmpp_client->sent_stanzas()[0]->Str());
|
||||||
|
|
||||||
EXPECT_EQ("", listener->last_name);
|
EXPECT_EQ("", listener->last_name);
|
||||||
|
EXPECT_EQ("", listener->last_conversation_id);
|
||||||
|
|
||||||
std::string response_iq =
|
std::string response_iq =
|
||||||
"<iq xmlns='jabber:client'"
|
"<iq xmlns='jabber:client'"
|
||||||
" from='muc-jid-ponies@domain.com' id='0' type='result'>"
|
" from='muc-jid-ponies@domain.com' id='0' type='result'>"
|
||||||
" <info:query xmlns:info='http://jabber.org/protocol/disco#info'>"
|
" <info:query xmlns:info='http://jabber.org/protocol/disco#info'>"
|
||||||
" <info:identity name='ponies'/>"
|
" <info:identity name='ponies'>"
|
||||||
|
" <han:conversation-id xmlns:han='google:muc#hangout'>"
|
||||||
|
"test_conversation_id</han:conversation-id>"
|
||||||
|
" </info:identity>"
|
||||||
" <info:feature var='feature1'/>"
|
" <info:feature var='feature1'/>"
|
||||||
" <info:feature var='feature2'/>"
|
" <info:feature var='feature2'/>"
|
||||||
" <data:x xmlns:data='jabber:x:data'>"
|
" <data:x xmlns:data='jabber:x:data'>"
|
||||||
@ -126,6 +135,7 @@ TEST_F(MucRoomDiscoveryTaskTest, TestDiscovery) {
|
|||||||
|
|
||||||
EXPECT_EQ(true, listener->last_exists);
|
EXPECT_EQ(true, listener->last_exists);
|
||||||
EXPECT_EQ(room_name, listener->last_name);
|
EXPECT_EQ(room_name, listener->last_name);
|
||||||
|
EXPECT_EQ(conversation_id, listener->last_conversation_id);
|
||||||
EXPECT_EQ(2U, listener->last_features.size());
|
EXPECT_EQ(2U, listener->last_features.size());
|
||||||
EXPECT_EQ(1U, listener->last_features.count("feature1"));
|
EXPECT_EQ(1U, listener->last_features.count("feature1"));
|
||||||
EXPECT_EQ(2U, listener->last_extended_info.size());
|
EXPECT_EQ(2U, listener->last_extended_info.size());
|
||||||
|
@ -46,6 +46,11 @@ struct MucRoomInfo {
|
|||||||
|
|
||||||
class MucRoomLookupTask : public IqTask {
|
class MucRoomLookupTask : public IqTask {
|
||||||
public:
|
public:
|
||||||
|
enum IdType {
|
||||||
|
ID_TYPE_CONVERSATION,
|
||||||
|
ID_TYPE_HANGOUT
|
||||||
|
};
|
||||||
|
|
||||||
static MucRoomLookupTask*
|
static MucRoomLookupTask*
|
||||||
CreateLookupTaskForRoomName(XmppTaskParentInterface* parent,
|
CreateLookupTaskForRoomName(XmppTaskParentInterface* parent,
|
||||||
const Jid& lookup_server_jid,
|
const Jid& lookup_server_jid,
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'interface/i420_video_frame.h',
|
'interface/i420_video_frame.h',
|
||||||
|
'interface/texture_video_frame.h',
|
||||||
'i420_video_frame.cc',
|
'i420_video_frame.cc',
|
||||||
'jpeg/include/jpeg.h',
|
'jpeg/include/jpeg.h',
|
||||||
'jpeg/data_manager.cc',
|
'jpeg/data_manager.cc',
|
||||||
@ -65,6 +66,7 @@
|
|||||||
'libyuv/scaler.cc',
|
'libyuv/scaler.cc',
|
||||||
'plane.h',
|
'plane.h',
|
||||||
'plane.cc',
|
'plane.cc',
|
||||||
|
'texture_video_frame.cc'
|
||||||
],
|
],
|
||||||
# Silence jpeg struct padding warnings.
|
# Silence jpeg struct padding warnings.
|
||||||
'msvs_disabled_warnings': [ 4324, ],
|
'msvs_disabled_warnings': [ 4324, ],
|
||||||
@ -88,6 +90,7 @@
|
|||||||
'libyuv/libyuv_unittest.cc',
|
'libyuv/libyuv_unittest.cc',
|
||||||
'libyuv/scaler_unittest.cc',
|
'libyuv/scaler_unittest.cc',
|
||||||
'plane_unittest.cc',
|
'plane_unittest.cc',
|
||||||
|
'texture_video_frame_unittest.cc'
|
||||||
],
|
],
|
||||||
# Disable warnings to enable Win64 build, issue 1323.
|
# Disable warnings to enable Win64 build, issue 1323.
|
||||||
'msvs_disabled_warnings': [
|
'msvs_disabled_warnings': [
|
||||||
|
@ -142,6 +142,8 @@ void I420VideoFrame::ResetSize() {
|
|||||||
v_plane_.ResetSize();
|
v_plane_.ResetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* I420VideoFrame::native_handle() const { return NULL; }
|
||||||
|
|
||||||
int I420VideoFrame::CheckDimensions(int width, int height,
|
int I420VideoFrame::CheckDimensions(int width, int height,
|
||||||
int stride_y, int stride_u, int stride_v) {
|
int stride_y, int stride_u, int stride_v) {
|
||||||
int half_width = (width + 1) / 2;
|
int half_width = (width + 1) / 2;
|
||||||
@ -179,5 +181,4 @@ Plane* I420VideoFrame::GetPlane(PlaneType type) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
// Storing and handling of YUV (I420) video frames.
|
// Storing and handling of YUV (I420) video frames.
|
||||||
|
|
||||||
#include "webrtc/common_video/plane.h"
|
#include "webrtc/common_video/plane.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
|
||||||
#include "webrtc/typedefs.h"
|
#include "webrtc/typedefs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -49,74 +50,81 @@ class I420VideoFrame {
|
|||||||
// If required size is bigger than the allocated one, new buffers of adequate
|
// If required size is bigger than the allocated one, new buffers of adequate
|
||||||
// size will be allocated.
|
// size will be allocated.
|
||||||
// Return value: 0 on success ,-1 on error.
|
// Return value: 0 on success ,-1 on error.
|
||||||
int CreateEmptyFrame(int width, int height,
|
virtual int CreateEmptyFrame(int width, int height,
|
||||||
int stride_y, int stride_u, int stride_v);
|
int stride_y, int stride_u, int stride_v);
|
||||||
|
|
||||||
// CreateFrame: Sets the frame's members and buffers. If required size is
|
// CreateFrame: Sets the frame's members and buffers. If required size is
|
||||||
// bigger than allocated one, new buffers of adequate size will be allocated.
|
// bigger than allocated one, new buffers of adequate size will be allocated.
|
||||||
// Return value: 0 on success ,-1 on error.
|
// Return value: 0 on success ,-1 on error.
|
||||||
int CreateFrame(int size_y, const uint8_t* buffer_y,
|
virtual int CreateFrame(int size_y, const uint8_t* buffer_y,
|
||||||
int size_u, const uint8_t* buffer_u,
|
int size_u, const uint8_t* buffer_u,
|
||||||
int size_v, const uint8_t* buffer_v,
|
int size_v, const uint8_t* buffer_v,
|
||||||
int width, int height,
|
int width, int height,
|
||||||
int stride_y, int stride_u, int stride_v);
|
int stride_y, int stride_u, int stride_v);
|
||||||
|
|
||||||
// Copy frame: If required size is bigger than allocated one, new buffers of
|
// Copy frame: If required size is bigger than allocated one, new buffers of
|
||||||
// adequate size will be allocated.
|
// adequate size will be allocated.
|
||||||
// Return value: 0 on success ,-1 on error.
|
// Return value: 0 on success ,-1 on error.
|
||||||
int CopyFrame(const I420VideoFrame& videoFrame);
|
virtual int CopyFrame(const I420VideoFrame& videoFrame);
|
||||||
|
|
||||||
// Swap Frame.
|
// Swap Frame.
|
||||||
void SwapFrame(I420VideoFrame* videoFrame);
|
virtual void SwapFrame(I420VideoFrame* videoFrame);
|
||||||
|
|
||||||
// Get pointer to buffer per plane.
|
// Get pointer to buffer per plane.
|
||||||
uint8_t* buffer(PlaneType type);
|
virtual uint8_t* buffer(PlaneType type);
|
||||||
// Overloading with const.
|
// Overloading with const.
|
||||||
const uint8_t* buffer(PlaneType type) const;
|
virtual const uint8_t* buffer(PlaneType type) const;
|
||||||
|
|
||||||
// Get allocated size per plane.
|
// Get allocated size per plane.
|
||||||
int allocated_size(PlaneType type) const;
|
virtual int allocated_size(PlaneType type) const;
|
||||||
|
|
||||||
// Get allocated stride per plane.
|
// Get allocated stride per plane.
|
||||||
int stride(PlaneType type) const;
|
virtual int stride(PlaneType type) const;
|
||||||
|
|
||||||
// Set frame width.
|
// Set frame width.
|
||||||
int set_width(int width);
|
virtual int set_width(int width);
|
||||||
|
|
||||||
// Set frame height.
|
// Set frame height.
|
||||||
int set_height(int height);
|
virtual int set_height(int height);
|
||||||
|
|
||||||
// Get frame width.
|
// Get frame width.
|
||||||
int width() const {return width_;}
|
virtual int width() const {return width_;}
|
||||||
|
|
||||||
// Get frame height.
|
// Get frame height.
|
||||||
int height() const {return height_;}
|
virtual int height() const {return height_;}
|
||||||
|
|
||||||
// Set frame timestamp (90kHz).
|
// Set frame timestamp (90kHz).
|
||||||
void set_timestamp(uint32_t timestamp) {timestamp_ = timestamp;}
|
virtual void set_timestamp(uint32_t timestamp) {timestamp_ = timestamp;}
|
||||||
|
|
||||||
// Get frame timestamp (90kHz).
|
// Get frame timestamp (90kHz).
|
||||||
uint32_t timestamp() const {return timestamp_;}
|
virtual uint32_t timestamp() const {return timestamp_;}
|
||||||
|
|
||||||
// Set render time in miliseconds.
|
// Set render time in miliseconds.
|
||||||
void set_render_time_ms(int64_t render_time_ms) {render_time_ms_ =
|
virtual void set_render_time_ms(int64_t render_time_ms) {render_time_ms_ =
|
||||||
render_time_ms;}
|
render_time_ms;}
|
||||||
|
|
||||||
// Get render time in miliseconds.
|
// Get render time in miliseconds.
|
||||||
int64_t render_time_ms() const {return render_time_ms_;}
|
virtual int64_t render_time_ms() const {return render_time_ms_;}
|
||||||
|
|
||||||
// Return true if underlying plane buffers are of zero size, false if not.
|
// Return true if underlying plane buffers are of zero size, false if not.
|
||||||
bool IsZeroSize() const;
|
virtual bool IsZeroSize() const;
|
||||||
|
|
||||||
// Reset underlying plane buffers sizes to 0. This function doesn't
|
// Reset underlying plane buffers sizes to 0. This function doesn't
|
||||||
// clear memory.
|
// clear memory.
|
||||||
void ResetSize();
|
virtual void ResetSize();
|
||||||
|
|
||||||
|
// Return the handle of the underlying video frame. This is used when the
|
||||||
|
// frame is backed by a texture. The object should be destroyed when it is no
|
||||||
|
// longer in use, so the underlying resource can be freed.
|
||||||
|
virtual void* native_handle() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Verifies legality of parameters.
|
||||||
|
// Return value: 0 on success, -1 on error.
|
||||||
|
virtual int CheckDimensions(int width, int height,
|
||||||
|
int stride_y, int stride_u, int stride_v);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Verifies legality of parameters.
|
|
||||||
// Return value: 0 on success ,-1 on error.
|
|
||||||
int CheckDimensions(int width, int height,
|
|
||||||
int stride_y, int stride_u, int stride_v);
|
|
||||||
// Get the pointer to a specific plane.
|
// Get the pointer to a specific plane.
|
||||||
const Plane* GetPlane(PlaneType type) const;
|
const Plane* GetPlane(PlaneType type) const;
|
||||||
// Overloading with non-const.
|
// Overloading with non-const.
|
||||||
|
36
webrtc/common_video/interface/native_handle.h
Normal file
36
webrtc/common_video/interface/native_handle.h
Normal 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 COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_
|
||||||
|
#define COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_
|
||||||
|
|
||||||
|
#include "webrtc/typedefs.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// A class to store an opaque handle of the underlying video frame. This is used
|
||||||
|
// when the frame is backed by a texture. WebRTC carries the handle in
|
||||||
|
// TextureVideoFrame. This object keeps a reference to the handle. The reference
|
||||||
|
// is cleared when the object is destroyed. It is important to destroy the
|
||||||
|
// object as soon as possible so the texture can be recycled.
|
||||||
|
class NativeHandle {
|
||||||
|
public:
|
||||||
|
virtual ~NativeHandle() {}
|
||||||
|
// For scoped_refptr
|
||||||
|
virtual int32_t AddRef() = 0;
|
||||||
|
virtual int32_t Release() = 0;
|
||||||
|
|
||||||
|
// Gets the handle.
|
||||||
|
virtual void* GetHandle() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // COMMON_VIDEO_INTERFACE_NATIVEHANDLE_H_
|
72
webrtc/common_video/interface/texture_video_frame.h
Normal file
72
webrtc/common_video/interface/texture_video_frame.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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 COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H
|
||||||
|
#define COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H
|
||||||
|
|
||||||
|
// TextureVideoFrame class
|
||||||
|
//
|
||||||
|
// Storing and handling of video frames backed by textures.
|
||||||
|
|
||||||
|
#include "webrtc/common_video/interface/i420_video_frame.h"
|
||||||
|
#include "webrtc/common_video/interface/native_handle.h"
|
||||||
|
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
|
||||||
|
#include "webrtc/typedefs.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class TextureVideoFrame : public I420VideoFrame {
|
||||||
|
public:
|
||||||
|
TextureVideoFrame(NativeHandle* handle,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
uint32_t timestamp,
|
||||||
|
int64_t render_time_ms);
|
||||||
|
virtual ~TextureVideoFrame();
|
||||||
|
|
||||||
|
// I420VideoFrame implementation
|
||||||
|
virtual int CreateEmptyFrame(int width,
|
||||||
|
int height,
|
||||||
|
int stride_y,
|
||||||
|
int stride_u,
|
||||||
|
int stride_v) OVERRIDE;
|
||||||
|
virtual int CreateFrame(int size_y,
|
||||||
|
const uint8_t* buffer_y,
|
||||||
|
int size_u,
|
||||||
|
const uint8_t* buffer_u,
|
||||||
|
int size_v,
|
||||||
|
const uint8_t* buffer_v,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int stride_y,
|
||||||
|
int stride_u,
|
||||||
|
int stride_v) OVERRIDE;
|
||||||
|
virtual int CopyFrame(const I420VideoFrame& videoFrame) OVERRIDE;
|
||||||
|
virtual void SwapFrame(I420VideoFrame* videoFrame) OVERRIDE;
|
||||||
|
virtual uint8_t* buffer(PlaneType type) OVERRIDE;
|
||||||
|
virtual const uint8_t* buffer(PlaneType type) const OVERRIDE;
|
||||||
|
virtual int allocated_size(PlaneType type) const OVERRIDE;
|
||||||
|
virtual int stride(PlaneType type) const OVERRIDE;
|
||||||
|
virtual bool IsZeroSize() const OVERRIDE;
|
||||||
|
virtual void ResetSize() OVERRIDE;
|
||||||
|
virtual void* native_handle() const OVERRIDE;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int CheckDimensions(
|
||||||
|
int width, int height, int stride_y, int stride_u, int stride_v) OVERRIDE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// An opaque handle that stores the underlying video frame.
|
||||||
|
scoped_refptr<NativeHandle> handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // COMMON_VIDEO_INTERFACE_TEXTURE_VIDEO_FRAME_H
|
108
webrtc/common_video/texture_video_frame.cc
Normal file
108
webrtc/common_video/texture_video_frame.cc
Normal 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/common_video/interface/texture_video_frame.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "webrtc/system_wrappers/interface/trace.h"
|
||||||
|
|
||||||
|
#define NOTREACHED() \
|
||||||
|
do { \
|
||||||
|
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1, "Not reached"); \
|
||||||
|
assert(false); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
TextureVideoFrame::TextureVideoFrame(NativeHandle* handle,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
uint32_t timestamp,
|
||||||
|
int64_t render_time_ms)
|
||||||
|
: handle_(handle) {
|
||||||
|
set_width(width);
|
||||||
|
set_height(height);
|
||||||
|
set_timestamp(timestamp);
|
||||||
|
set_render_time_ms(render_time_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureVideoFrame::~TextureVideoFrame() {}
|
||||||
|
|
||||||
|
int TextureVideoFrame::CreateEmptyFrame(int width,
|
||||||
|
int height,
|
||||||
|
int stride_y,
|
||||||
|
int stride_u,
|
||||||
|
int stride_v) {
|
||||||
|
NOTREACHED();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextureVideoFrame::CreateFrame(int size_y,
|
||||||
|
const uint8_t* buffer_y,
|
||||||
|
int size_u,
|
||||||
|
const uint8_t* buffer_u,
|
||||||
|
int size_v,
|
||||||
|
const uint8_t* buffer_v,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int stride_y,
|
||||||
|
int stride_u,
|
||||||
|
int stride_v) {
|
||||||
|
NOTREACHED();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextureVideoFrame::CopyFrame(const I420VideoFrame& videoFrame) {
|
||||||
|
NOTREACHED();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureVideoFrame::SwapFrame(I420VideoFrame* videoFrame) {
|
||||||
|
NOTREACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* TextureVideoFrame::buffer(PlaneType type) {
|
||||||
|
NOTREACHED();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* TextureVideoFrame::buffer(PlaneType type) const {
|
||||||
|
NOTREACHED();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextureVideoFrame::allocated_size(PlaneType type) const {
|
||||||
|
NOTREACHED();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextureVideoFrame::stride(PlaneType type) const {
|
||||||
|
NOTREACHED();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextureVideoFrame::IsZeroSize() const {
|
||||||
|
NOTREACHED();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureVideoFrame::ResetSize() {
|
||||||
|
NOTREACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* TextureVideoFrame::native_handle() const { return handle_.get(); }
|
||||||
|
|
||||||
|
int TextureVideoFrame::CheckDimensions(
|
||||||
|
int width, int height, int stride_y, int stride_u, int stride_v) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
58
webrtc/common_video/texture_video_frame_unittest.cc
Normal file
58
webrtc/common_video/texture_video_frame_unittest.cc
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* 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 "testing/gtest/include/gtest/gtest.h"
|
||||||
|
#include "webrtc/common_video/interface/native_handle.h"
|
||||||
|
#include "webrtc/common_video/interface/texture_video_frame.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class NativeHandleImpl : public NativeHandle {
|
||||||
|
public:
|
||||||
|
NativeHandleImpl() : ref_count_(0) {}
|
||||||
|
virtual ~NativeHandleImpl() {}
|
||||||
|
virtual int32_t AddRef() { return ++ref_count_; }
|
||||||
|
virtual int32_t Release() { return --ref_count_; }
|
||||||
|
virtual void* GetHandle() { return NULL; }
|
||||||
|
|
||||||
|
int32_t ref_count() { return ref_count_; }
|
||||||
|
private:
|
||||||
|
int32_t ref_count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(TestTextureVideoFrame, InitialValues) {
|
||||||
|
NativeHandleImpl handle;
|
||||||
|
TextureVideoFrame frame(&handle, 640, 480, 100, 10);
|
||||||
|
EXPECT_EQ(640, frame.width());
|
||||||
|
EXPECT_EQ(480, frame.height());
|
||||||
|
EXPECT_EQ(100u, frame.timestamp());
|
||||||
|
EXPECT_EQ(10, frame.render_time_ms());
|
||||||
|
EXPECT_EQ(&handle, frame.native_handle());
|
||||||
|
|
||||||
|
EXPECT_EQ(0, frame.set_width(320));
|
||||||
|
EXPECT_EQ(320, frame.width());
|
||||||
|
EXPECT_EQ(0, frame.set_height(240));
|
||||||
|
EXPECT_EQ(240, frame.height());
|
||||||
|
frame.set_timestamp(200);
|
||||||
|
EXPECT_EQ(200u, frame.timestamp());
|
||||||
|
frame.set_render_time_ms(20);
|
||||||
|
EXPECT_EQ(20, frame.render_time_ms());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestTextureVideoFrame, RefCount) {
|
||||||
|
NativeHandleImpl handle;
|
||||||
|
EXPECT_EQ(0, handle.ref_count());
|
||||||
|
TextureVideoFrame *frame = new TextureVideoFrame(&handle, 640, 480, 100, 200);
|
||||||
|
EXPECT_EQ(1, handle.ref_count());
|
||||||
|
delete frame;
|
||||||
|
EXPECT_EQ(0, handle.ref_count());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "webrtc/common_video/interface/texture_video_frame.h"
|
||||||
#include "webrtc/modules/interface/module_common_types.h"
|
#include "webrtc/modules/interface/module_common_types.h"
|
||||||
#include "webrtc/system_wrappers/interface/tick_util.h"
|
#include "webrtc/system_wrappers/interface/tick_util.h"
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
#include "webrtc/system_wrappers/interface/trace.h"
|
||||||
@ -48,6 +49,16 @@ VideoFramesQueue::~VideoFramesQueue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoFramesQueue::AddFrame(const I420VideoFrame& newFrame) {
|
int32_t VideoFramesQueue::AddFrame(const I420VideoFrame& newFrame) {
|
||||||
|
if (newFrame.native_handle() != NULL) {
|
||||||
|
_incomingFrames.PushBack(new TextureVideoFrame(
|
||||||
|
static_cast<NativeHandle*>(newFrame.native_handle()),
|
||||||
|
newFrame.width(),
|
||||||
|
newFrame.height(),
|
||||||
|
newFrame.timestamp(),
|
||||||
|
newFrame.render_time_ms()));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
I420VideoFrame* ptrFrameToAdd = NULL;
|
I420VideoFrame* ptrFrameToAdd = NULL;
|
||||||
// Try to re-use a VideoFrame. Only allocate new memory if it is necessary.
|
// Try to re-use a VideoFrame. Only allocate new memory if it is necessary.
|
||||||
if (!_emptyFrames.Empty()) {
|
if (!_emptyFrames.Empty()) {
|
||||||
@ -113,12 +124,17 @@ I420VideoFrame* VideoFramesQueue::FrameToRecord() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoFramesQueue::ReturnFrame(I420VideoFrame* ptrOldFrame) {
|
int32_t VideoFramesQueue::ReturnFrame(I420VideoFrame* ptrOldFrame) {
|
||||||
ptrOldFrame->set_timestamp(0);
|
// No need to reuse texture frames because they do not allocate memory.
|
||||||
ptrOldFrame->set_width(0);
|
if (ptrOldFrame->native_handle() == NULL) {
|
||||||
ptrOldFrame->set_height(0);
|
ptrOldFrame->set_timestamp(0);
|
||||||
ptrOldFrame->set_render_time_ms(0);
|
ptrOldFrame->set_width(0);
|
||||||
ptrOldFrame->ResetSize();
|
ptrOldFrame->set_height(0);
|
||||||
_emptyFrames.PushBack(ptrOldFrame);
|
ptrOldFrame->set_render_time_ms(0);
|
||||||
|
ptrOldFrame->ResetSize();
|
||||||
|
_emptyFrames.PushBack(ptrOldFrame);
|
||||||
|
} else {
|
||||||
|
delete ptrOldFrame;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,8 @@ int32_t IncomingVideoStream::RenderFrame(const uint32_t stream_id,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true == mirror_frames_enabled_) {
|
// Mirroring is not supported if the frame is backed by a texture.
|
||||||
|
if (true == mirror_frames_enabled_ && video_frame.native_handle() == NULL) {
|
||||||
transformed_video_frame_.CreateEmptyFrame(video_frame.width(),
|
transformed_video_frame_.CreateEmptyFrame(video_frame.width(),
|
||||||
video_frame.height(),
|
video_frame.height(),
|
||||||
video_frame.stride(kYPlane),
|
video_frame.stride(kYPlane),
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "webrtc/common_video/interface/texture_video_frame.h"
|
||||||
#include "webrtc/modules/interface/module_common_types.h"
|
#include "webrtc/modules/interface/module_common_types.h"
|
||||||
#include "webrtc/system_wrappers/interface/tick_util.h"
|
#include "webrtc/system_wrappers/interface/tick_util.h"
|
||||||
#include "webrtc/system_wrappers/interface/trace.h"
|
#include "webrtc/system_wrappers/interface/trace.h"
|
||||||
@ -47,6 +48,16 @@ int32_t VideoRenderFrames::AddFrame(I420VideoFrame* new_frame) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_frame->native_handle() != NULL) {
|
||||||
|
incoming_frames_.PushBack(new TextureVideoFrame(
|
||||||
|
static_cast<NativeHandle*>(new_frame->native_handle()),
|
||||||
|
new_frame->width(),
|
||||||
|
new_frame->height(),
|
||||||
|
new_frame->timestamp(),
|
||||||
|
new_frame->render_time_ms()));
|
||||||
|
return incoming_frames_.GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
// Get an empty frame
|
// Get an empty frame
|
||||||
I420VideoFrame* frame_to_add = NULL;
|
I420VideoFrame* frame_to_add = NULL;
|
||||||
if (!empty_frames_.Empty()) {
|
if (!empty_frames_.Empty()) {
|
||||||
@ -103,10 +114,7 @@ I420VideoFrame* VideoRenderFrames::FrameToRender() {
|
|||||||
// This is the oldest one so far and it's OK to render.
|
// This is the oldest one so far and it's OK to render.
|
||||||
if (render_frame) {
|
if (render_frame) {
|
||||||
// This one is older than the newly found frame, remove this one.
|
// This one is older than the newly found frame, remove this one.
|
||||||
render_frame->ResetSize();
|
ReturnFrame(render_frame);
|
||||||
render_frame->set_timestamp(0);
|
|
||||||
render_frame->set_render_time_ms(0);
|
|
||||||
empty_frames_.PushFront(render_frame);
|
|
||||||
}
|
}
|
||||||
render_frame = oldest_frame_in_list;
|
render_frame = oldest_frame_in_list;
|
||||||
incoming_frames_.Erase(item);
|
incoming_frames_.Erase(item);
|
||||||
@ -122,10 +130,15 @@ I420VideoFrame* VideoRenderFrames::FrameToRender() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) {
|
int32_t VideoRenderFrames::ReturnFrame(I420VideoFrame* old_frame) {
|
||||||
old_frame->ResetSize();
|
// No need to reuse texture frames because they do not allocate memory.
|
||||||
old_frame->set_timestamp(0);
|
if (old_frame->native_handle() == NULL) {
|
||||||
old_frame->set_render_time_ms(0);
|
old_frame->ResetSize();
|
||||||
empty_frames_.PushBack(old_frame);
|
old_frame->set_timestamp(0);
|
||||||
|
old_frame->set_render_time_ms(0);
|
||||||
|
empty_frames_.PushBack(old_frame);
|
||||||
|
} else {
|
||||||
|
delete old_frame;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,13 @@ class WEBRTC_DLLEXPORT ExternalRenderer {
|
|||||||
// RTP timestamp in 90kHz.
|
// RTP timestamp in 90kHz.
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
// Wallclock render time in miliseconds
|
// Wallclock render time in miliseconds
|
||||||
int64_t render_time) = 0;
|
int64_t render_time,
|
||||||
|
// Handle of the underlying video frame,
|
||||||
|
void* handle) = 0;
|
||||||
|
|
||||||
|
// Returns true if the renderer supports textures. DeliverFrame can be called
|
||||||
|
// with NULL |buffer| and non-NULL |handle|.
|
||||||
|
virtual bool IsTextureSupported() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~ExternalRenderer() {}
|
virtual ~ExternalRenderer() {}
|
||||||
|
@ -117,7 +117,8 @@ int VideoReceiveStream::FrameSizeChange(unsigned int width, unsigned int height,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int VideoReceiveStream::DeliverFrame(uint8_t* frame, int buffer_size,
|
int VideoReceiveStream::DeliverFrame(uint8_t* frame, int buffer_size,
|
||||||
uint32_t timestamp, int64_t render_time) {
|
uint32_t timestamp, int64_t render_time,
|
||||||
|
void* /*handle*/) {
|
||||||
if (config_.renderer == NULL) {
|
if (config_.renderer == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -142,6 +143,8 @@ int VideoReceiveStream::DeliverFrame(uint8_t* frame, int buffer_size,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VideoReceiveStream::IsTextureSupported() { return false; }
|
||||||
|
|
||||||
int VideoReceiveStream::SendPacket(int /*channel*/,
|
int VideoReceiveStream::SendPacket(int /*channel*/,
|
||||||
const void* packet,
|
const void* packet,
|
||||||
int length) {
|
int length) {
|
||||||
|
@ -46,7 +46,9 @@ class VideoReceiveStream : public newapi::VideoReceiveStream,
|
|||||||
virtual int FrameSizeChange(unsigned int width, unsigned int height,
|
virtual int FrameSizeChange(unsigned int width, unsigned int height,
|
||||||
unsigned int /*number_of_streams*/) OVERRIDE;
|
unsigned int /*number_of_streams*/) OVERRIDE;
|
||||||
virtual int DeliverFrame(uint8_t* frame, int buffer_size, uint32_t timestamp,
|
virtual int DeliverFrame(uint8_t* frame, int buffer_size, uint32_t timestamp,
|
||||||
int64_t render_time) OVERRIDE;
|
int64_t render_time, void* /*handle*/) OVERRIDE;
|
||||||
|
|
||||||
|
virtual bool IsTextureSupported() OVERRIDE;
|
||||||
|
|
||||||
virtual int SendPacket(int /*channel*/, const void* packet, int length)
|
virtual int SendPacket(int /*channel*/, const void* packet, int length)
|
||||||
OVERRIDE;
|
OVERRIDE;
|
||||||
|
@ -588,7 +588,7 @@ int FrameDropDetector::GetNumberOfFramesDroppedAt(State state) {
|
|||||||
|
|
||||||
int FrameDropMonitoringRemoteFileRenderer::DeliverFrame(
|
int FrameDropMonitoringRemoteFileRenderer::DeliverFrame(
|
||||||
unsigned char *buffer, int buffer_size, uint32_t time_stamp,
|
unsigned char *buffer, int buffer_size, uint32_t time_stamp,
|
||||||
int64_t render_time) {
|
int64_t render_time, void* /*handle*/) {
|
||||||
// |render_time| provides the ideal render time for this frame. If that time
|
// |render_time| provides the ideal render time for this frame. If that time
|
||||||
// has already passed we will render it immediately.
|
// has already passed we will render it immediately.
|
||||||
int64_t report_render_time_us = render_time * 1000;
|
int64_t report_render_time_us = render_time * 1000;
|
||||||
@ -600,7 +600,7 @@ int FrameDropMonitoringRemoteFileRenderer::DeliverFrame(
|
|||||||
frame_drop_detector_->ReportFrameState(FrameDropDetector::kRendered,
|
frame_drop_detector_->ReportFrameState(FrameDropDetector::kRendered,
|
||||||
time_stamp, report_render_time_us);
|
time_stamp, report_render_time_us);
|
||||||
return ViEToFileRenderer::DeliverFrame(buffer, buffer_size,
|
return ViEToFileRenderer::DeliverFrame(buffer, buffer_size,
|
||||||
time_stamp, render_time);
|
time_stamp, render_time, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FrameDropMonitoringRemoteFileRenderer::FrameSizeChange(
|
int FrameDropMonitoringRemoteFileRenderer::FrameSizeChange(
|
||||||
|
@ -223,10 +223,11 @@ class FrameDropMonitoringRemoteFileRenderer : public ViEToFileRenderer {
|
|||||||
|
|
||||||
// Implementation of ExternalRenderer:
|
// Implementation of ExternalRenderer:
|
||||||
int FrameSizeChange(unsigned int width, unsigned int height,
|
int FrameSizeChange(unsigned int width, unsigned int height,
|
||||||
unsigned int number_of_streams);
|
unsigned int number_of_streams) OVERRIDE;
|
||||||
int DeliverFrame(unsigned char* buffer, int buffer_size,
|
int DeliverFrame(unsigned char* buffer, int buffer_size,
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
int64_t render_time);
|
int64_t render_time,
|
||||||
|
void* handle) OVERRIDE;
|
||||||
private:
|
private:
|
||||||
FrameDropDetector* frame_drop_detector_;
|
FrameDropDetector* frame_drop_detector_;
|
||||||
};
|
};
|
||||||
|
@ -58,7 +58,8 @@ public:
|
|||||||
|
|
||||||
virtual int DeliverFrame(unsigned char* buffer, int bufferSize,
|
virtual int DeliverFrame(unsigned char* buffer, int bufferSize,
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
int64_t render_time) {
|
int64_t render_time,
|
||||||
|
void* /*handle*/) {
|
||||||
if (bufferSize != CalcBufferSize(webrtc::kI420, _width, _height)) {
|
if (bufferSize != CalcBufferSize(webrtc::kI420, _width, _height)) {
|
||||||
ViETest::Log("Incorrect render buffer received, of length = %d\n",
|
ViETest::Log("Incorrect render buffer received, of length = %d\n",
|
||||||
bufferSize);
|
bufferSize);
|
||||||
@ -67,6 +68,8 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool IsTextureSupported() { return false; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ViEAutoTestExternalRenderer()
|
virtual ~ViEAutoTestExternalRenderer()
|
||||||
{
|
{
|
||||||
|
@ -123,7 +123,8 @@ void ViEToFileRenderer::ForgetOutputFile() {
|
|||||||
int ViEToFileRenderer::DeliverFrame(unsigned char *buffer,
|
int ViEToFileRenderer::DeliverFrame(unsigned char *buffer,
|
||||||
int buffer_size,
|
int buffer_size,
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
int64_t render_time) {
|
int64_t render_time,
|
||||||
|
void* /*handle*/) {
|
||||||
webrtc::CriticalSectionScoped lock(frame_queue_cs_.get());
|
webrtc::CriticalSectionScoped lock(frame_queue_cs_.get());
|
||||||
test::Frame* frame;
|
test::Frame* frame;
|
||||||
if (free_frame_queue_.empty()) {
|
if (free_frame_queue_.empty()) {
|
||||||
@ -146,6 +147,8 @@ int ViEToFileRenderer::DeliverFrame(unsigned char *buffer,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ViEToFileRenderer::IsTextureSupported() { return false; }
|
||||||
|
|
||||||
int ViEToFileRenderer::FrameSizeChange(unsigned int width,
|
int ViEToFileRenderer::FrameSizeChange(unsigned int width,
|
||||||
unsigned int height,
|
unsigned int height,
|
||||||
unsigned int number_of_streams) {
|
unsigned int number_of_streams) {
|
||||||
|
@ -35,7 +35,8 @@ class ExternalRendererEffectFilter : public webrtc::ViEEffectFilter {
|
|||||||
return renderer_->DeliverFrame(frame_buffer,
|
return renderer_->DeliverFrame(frame_buffer,
|
||||||
size,
|
size,
|
||||||
time_stamp90KHz,
|
time_stamp90KHz,
|
||||||
webrtc::TickTime::MillisecondTimestamp());
|
webrtc::TickTime::MillisecondTimestamp(),
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -55,12 +55,15 @@ class ViEToFileRenderer: public webrtc::ExternalRenderer {
|
|||||||
|
|
||||||
// Implementation of ExternalRenderer:
|
// Implementation of ExternalRenderer:
|
||||||
int FrameSizeChange(unsigned int width, unsigned int height,
|
int FrameSizeChange(unsigned int width, unsigned int height,
|
||||||
unsigned int number_of_streams);
|
unsigned int number_of_streams) OVERRIDE;
|
||||||
|
|
||||||
int DeliverFrame(unsigned char* buffer,
|
int DeliverFrame(unsigned char* buffer,
|
||||||
int buffer_size,
|
int buffer_size,
|
||||||
uint32_t time_stamp,
|
uint32_t time_stamp,
|
||||||
int64_t render_time);
|
int64_t render_time,
|
||||||
|
void* handle) OVERRIDE;
|
||||||
|
|
||||||
|
bool IsTextureSupported() OVERRIDE;
|
||||||
|
|
||||||
const std::string GetFullOutputPath() const;
|
const std::string GetFullOutputPath() const;
|
||||||
|
|
||||||
|
@ -1684,18 +1684,21 @@ int32_t ViEChannel::FrameToRender(
|
|||||||
}
|
}
|
||||||
decoder_reset_ = false;
|
decoder_reset_ = false;
|
||||||
}
|
}
|
||||||
if (effect_filter_) {
|
// Post processing is not supported if the frame is backed by a texture.
|
||||||
unsigned int length = CalcBufferSize(kI420,
|
if (video_frame.native_handle() == NULL) {
|
||||||
video_frame.width(),
|
if (effect_filter_) {
|
||||||
video_frame.height());
|
unsigned int length = CalcBufferSize(kI420,
|
||||||
scoped_array<uint8_t> video_buffer(new uint8_t[length]);
|
video_frame.width(),
|
||||||
ExtractBuffer(video_frame, length, video_buffer.get());
|
video_frame.height());
|
||||||
effect_filter_->Transform(length, video_buffer.get(),
|
scoped_array<uint8_t> video_buffer(new uint8_t[length]);
|
||||||
video_frame.timestamp(), video_frame.width(),
|
ExtractBuffer(video_frame, length, video_buffer.get());
|
||||||
video_frame.height());
|
effect_filter_->Transform(length, video_buffer.get(),
|
||||||
}
|
video_frame.timestamp(), video_frame.width(),
|
||||||
if (color_enhancement_) {
|
video_frame.height());
|
||||||
VideoProcessingModule::ColorEnhancement(&video_frame);
|
}
|
||||||
|
if (color_enhancement_) {
|
||||||
|
VideoProcessingModule::ColorEnhancement(&video_frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t arr_ofCSRC[kRtpCsrcSize];
|
uint32_t arr_ofCSRC[kRtpCsrcSize];
|
||||||
|
@ -56,7 +56,7 @@ void ViEFrameProviderBase::DeliverFrame(
|
|||||||
|
|
||||||
// Deliver the frame to all registered callbacks.
|
// Deliver the frame to all registered callbacks.
|
||||||
if (frame_callbacks_.size() > 0) {
|
if (frame_callbacks_.size() > 0) {
|
||||||
if (frame_callbacks_.size() == 1) {
|
if (frame_callbacks_.size() == 1 || video_frame->native_handle() != NULL) {
|
||||||
// We don't have to copy the frame.
|
// We don't have to copy the frame.
|
||||||
frame_callbacks_.front()->DeliverFrame(id_, video_frame, num_csrcs, CSRC);
|
frame_callbacks_.front()->DeliverFrame(id_, video_frame, num_csrcs, CSRC);
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,6 +169,21 @@ int ViEExternalRendererImpl::SetViEExternalRenderer(
|
|||||||
int32_t ViEExternalRendererImpl::RenderFrame(
|
int32_t ViEExternalRendererImpl::RenderFrame(
|
||||||
const uint32_t stream_id,
|
const uint32_t stream_id,
|
||||||
I420VideoFrame& video_frame) {
|
I420VideoFrame& video_frame) {
|
||||||
|
if (video_frame.native_handle() != NULL) {
|
||||||
|
NotifyFrameSizeChange(stream_id, video_frame);
|
||||||
|
|
||||||
|
if (external_renderer_->IsTextureSupported()) {
|
||||||
|
external_renderer_->DeliverFrame(NULL,
|
||||||
|
0,
|
||||||
|
video_frame.timestamp(),
|
||||||
|
video_frame.render_time_ms(),
|
||||||
|
video_frame.native_handle());
|
||||||
|
} else {
|
||||||
|
// TODO(wuchengli): readback the pixels and deliver the frame.
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
VideoFrame* out_frame = converted_frame_.get();
|
VideoFrame* out_frame = converted_frame_.get();
|
||||||
|
|
||||||
// Convert to requested format.
|
// Convert to requested format.
|
||||||
@ -218,21 +233,28 @@ int32_t ViEExternalRendererImpl::RenderFrame(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (external_renderer_width_ != video_frame.width() ||
|
NotifyFrameSizeChange(stream_id, video_frame);
|
||||||
external_renderer_height_ != video_frame.height()) {
|
|
||||||
external_renderer_width_ = video_frame.width();
|
|
||||||
external_renderer_height_ = video_frame.height();
|
|
||||||
external_renderer_->FrameSizeChange(external_renderer_width_,
|
|
||||||
external_renderer_height_, stream_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_frame) {
|
if (out_frame) {
|
||||||
external_renderer_->DeliverFrame(out_frame->Buffer(),
|
external_renderer_->DeliverFrame(out_frame->Buffer(),
|
||||||
out_frame->Length(),
|
out_frame->Length(),
|
||||||
video_frame.timestamp(),
|
video_frame.timestamp(),
|
||||||
video_frame.render_time_ms());
|
video_frame.render_time_ms(),
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ViEExternalRendererImpl::NotifyFrameSizeChange(
|
||||||
|
const uint32_t stream_id,
|
||||||
|
I420VideoFrame& video_frame) {
|
||||||
|
if (external_renderer_width_ != video_frame.width() ||
|
||||||
|
external_renderer_height_ != video_frame.height()) {
|
||||||
|
external_renderer_width_ = video_frame.width();
|
||||||
|
external_renderer_height_ = video_frame.height();
|
||||||
|
external_renderer_->FrameSizeChange(
|
||||||
|
external_renderer_width_, external_renderer_height_, stream_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -36,6 +36,8 @@ class ViEExternalRendererImpl : public VideoRenderCallback {
|
|||||||
I420VideoFrame& video_frame);
|
I420VideoFrame& video_frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void NotifyFrameSizeChange(const uint32_t stream_id,
|
||||||
|
I420VideoFrame& video_frame);
|
||||||
ExternalRenderer* external_renderer_;
|
ExternalRenderer* external_renderer_;
|
||||||
RawVideoType external_renderer_format_;
|
RawVideoType external_renderer_format_;
|
||||||
int external_renderer_width_;
|
int external_renderer_width_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user