git-svn-id: http://webrtc.googlecode.com/svn/trunk@847 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
henrike@webrtc.org 2011-10-31 20:35:13 +00:00
parent 1e10bb32b9
commit 8885d22399
4 changed files with 388 additions and 9 deletions

View File

@ -771,6 +771,7 @@
}],
], #conditions
'sources': [
'<(libjingle_mods)/source/talk/app/webrtc_dev/test/filevideocapturemodule.cc',
'<(libjingle_mods)/source/talk/app/webrtc_dev/mediastream_unittest.cc',
'<(libjingle_mods)/source/talk/app/webrtc_dev/mediastreamhandler_unittest.cc',
'<(libjingle_mods)/source/talk/app/webrtc_dev/peerconnection_unittest.cc',

View File

@ -33,6 +33,7 @@
#include "modules/video_capture/main/interface/video_capture_factory.h"
#include "talk/app/webrtc_dev/mediastream.h"
#include "talk/app/webrtc_dev/peerconnection.h"
#include "talk/app/webrtc_dev/test/filevideocapturemodule.h"
#include "talk/base/thread.h"
#include "talk/session/phone/videoframe.h"
#include "talk/session/phone/videorenderer.h"
@ -47,11 +48,10 @@ void GetAllVideoTracks(webrtc::MediaStreamInterface* media_stream,
}
}
// TODO(henrike): replace with a capture device that reads from a file/buffer.
talk_base::scoped_refptr<webrtc::VideoCaptureModule> OpenVideoCaptureDevice() {
webrtc::VideoCaptureModule* OpenVideoCaptureDevice() {
webrtc::VideoCaptureModule::DeviceInfo* device_info(
webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
talk_base::scoped_refptr<webrtc::VideoCaptureModule> video_device;
webrtc::VideoCaptureModule* video_device;
const size_t kMaxDeviceNameLength = 128;
const size_t kMaxUniqueIdLength = 256;
@ -66,7 +66,7 @@ talk_base::scoped_refptr<webrtc::VideoCaptureModule> OpenVideoCaptureDevice() {
// Try to open this device.
video_device =
webrtc::VideoCaptureFactory::Create(0, unique_id);
if (video_device.get())
if (video_device != NULL)
break;
}
delete device_info;
@ -183,8 +183,7 @@ class PeerConnectionP2PTestClient
talk_base::scoped_refptr<webrtc::LocalVideoTrackInterface> video_track(
peer_connection_factory_->CreateLocalVideoTrack(
"video_track",
OpenVideoCaptureDevice()));
"video_track", OpenVideoFileCaptureDevice()));
talk_base::scoped_refptr<webrtc::LocalMediaStreamInterface> stream =
peer_connection_factory_->CreateLocalMediaStream("stream_label");
@ -211,7 +210,7 @@ class PeerConnectionP2PTestClient
virtual void OnMessage(const std::string&) {}
virtual void OnSignalingMessage(const std::string& msg) {
if (signaling_message_receiver_ == NULL) {
ADD_FAILURE();
// Remote party may be deleted.
return;
}
signaling_message_receiver_->ReceiveMessage(msg);
@ -242,6 +241,8 @@ class PeerConnectionP2PTestClient
}
private:
static const int kFileNameSize = 256;
explicit PeerConnectionP2PTestClient(int id)
: id_(id),
peer_connection_(),
@ -264,14 +265,21 @@ class PeerConnectionP2PTestClient
return peer_connection_.get() != NULL;
}
void GenerateRecordingFileName(int track, char file_name[256]) {
void GenerateRecordingFileName(int track, char file_name[kFileNameSize]) {
if (file_name == NULL) {
return;
}
snprintf(file_name, sizeof(file_name),
snprintf(file_name, kFileNameSize,
"p2p_test_client_%d_videotrack_%d.yuv", id_, track);
}
webrtc::VideoCaptureModule* OpenVideoFileCaptureDevice() {
const char filename[] = "foreman_cif.yuv";
webrtc::VideoCaptureModule* video_device =
FileVideoCaptureModule::CreateFileVideoCaptureModule(filename);
return video_device;
}
int id_;
talk_base::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
@ -292,6 +300,8 @@ class P2PTestConductor {
return conductor;
}
~P2PTestConductor() {
clients[0]->set_signaling_message_receiver(NULL);
clients[1]->set_signaling_message_receiver(NULL);
for (int i = 0; i < kClients; ++i) {
if (clients[i] != NULL) {
// TODO(hellner): currently deleting the clients will trigger an assert

View File

@ -0,0 +1,165 @@
/*
* libjingle
* Copyright 2011, 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/app/webrtc_dev/test/filevideocapturemodule.h"
#ifdef WEBRTC_RELATIVE_PATH
#include "system_wrappers/interface/ref_count.h"
#else
#include "third_party/webrtc/files/include/ref_count.h"
#endif
FileVideoCaptureModule::~FileVideoCaptureModule() {
camera_thread_->Stop();
if (i420_file_ != NULL) fclose(i420_file_);
// The memory associated with video_capture_ is owned by impl_.
}
webrtc::VideoCaptureModule*
FileVideoCaptureModule::CreateFileVideoCaptureModule(const char* file_name) {
webrtc::RefCountImpl<FileVideoCaptureModule>* capture_module =
new webrtc::RefCountImpl<FileVideoCaptureModule>();
if (!capture_module->Init(file_name)) {
capture_module->Release();
return NULL;
}
return capture_module;
}
// TODO(henrike): deal with the rounding error.
bool FileVideoCaptureModule::SetFrameRate(int fps) {
fps_ = fps;
time_per_frame_ms_ = 1000 / fps;
return true;
}
void FileVideoCaptureModule::SetSize(int width, int height) {
width_ = width;
height_ = height;
image_.reset(new uint8[GetI420FrameLength()]);
}
FileVideoCaptureModule::FileVideoCaptureModule()
: impl_(),
i420_file_(NULL),
camera_thread_(new talk_base::Thread()),
video_capture_(NULL),
started_(false),
sent_frames_(0),
next_frame_time_(0),
time_per_frame_ms_(0),
fps_(0),
width_(0),
height_(0),
image_() {}
bool FileVideoCaptureModule::Init(const char* file_name) {
impl_ = webrtc::VideoCaptureFactory::Create(0, // id
video_capture_);
if (impl_.get() == NULL) {
return false;
}
if (video_capture_ == NULL) {
return false;
}
if (!SetFrameRate(kStartFrameRate)) {
return false;
}
SetSize(kStartWidth, kStartHeight);
i420_file_ = fopen(file_name, "rb");
if (i420_file_ == NULL) {
// Not generally unexpected but for this class it is.
ASSERT(false);
return false;
}
if (!camera_thread_->Start()) {
return false;
}
// Only one post, no need to add any data to post.
camera_thread_->Post(this);
return true;
}
// TODO(henrike): handle time wrapparound.
void FileVideoCaptureModule::GenerateNewFrame() {
if (!started_) {
next_frame_time_ = talk_base::Time();
started_ = true;
}
// Read from file.
int read = fread(image_.get(), sizeof(uint8), GetI420FrameLength(),
i420_file_);
// Loop file if end is reached.
if (read != GetI420FrameLength()) {
fseek(i420_file_, 0, SEEK_SET);
read = fread(image_.get(), sizeof(uint8), GetI420FrameLength(),
i420_file_);
if (read != GetI420FrameLength()) {
ASSERT(false);
return;
}
}
webrtc::VideoCaptureCapability capability;
capability.width = width_;
capability.height = height_;
capability.maxFPS = 0;
capability.expectedCaptureDelay = 0;
capability.rawType =webrtc:: kVideoI420;
capability.codecType = webrtc::kVideoCodecUnknown;
capability.interlaced = false;
video_capture_->IncomingFrame(image_.get(), GetI420FrameLength(),
capability, GetTimestamp());
++sent_frames_;
next_frame_time_ += time_per_frame_ms_;
const uint32 current_time = talk_base::Time();
const uint32 wait_time = (next_frame_time_ > current_time) ?
next_frame_time_ - current_time : 0;
camera_thread_->PostDelayed(wait_time, this);
}
int FileVideoCaptureModule::GetI420FrameLength() {
return width_ * height_ * 3 >> 1;
}
// TODO(henrike): use this function instead of/in addition to reading from a
// file.
void FileVideoCaptureModule::SetFrame(uint8* image) {
// Set Y plane.
memset(image, 128, width_ * height_);
// Set U plane.
int write_position = width_ * height_;
memset(&image[write_position], 64, width_ * height_ / 4);
// Set V plane.
write_position += width_ * height_ / 4;
memset(&image[write_position], 32, width_ * height_ / 4);
}
// TODO(henrike): handle timestamp wrapparound.
uint32 FileVideoCaptureModule::GetTimestamp() {
return kStartTimeStamp + sent_frames_ * time_per_frame_ms_;
}

View File

@ -0,0 +1,203 @@
/*
* libjingle
* Copyright 2011, 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.
*/
// This class implements the VideoCaptureModule interface. Instead of capturing
// frames from a camera it captures frames from a file.
#ifndef TALK_APP_WEBRTC_TEST_FILEVIDEOCAPTUREMODULE_H_
#define TALK_APP_WEBRTC_TEST_FILEVIDEOCAPTUREMODULE_H_
#include <stdio.h>
#include "talk/base/common.h"
#include "talk/base/scoped_ptr.h"
#include "talk/base/thread.h"
#include "talk/base/time.h"
#ifdef WEBRTC_RELATIVE_PATH
#include "common_types.h"
#include "modules/video_capture/main/interface/video_capture.h"
#include "modules/video_capture/main/interface/video_capture_defines.h"
#include "modules/video_capture/main/interface/video_capture_factory.h"
#include "system_wrappers/interface/ref_count.h"
#include "system_wrappers/interface/scoped_refptr.h"
#else
#include "third_party/webrtc/files/include/common_types.h"
#include "third_party/webrtc/files/include/video_capture.h"
#include "third_party/webrtc/files/include/video_capture_defines.h"
#include "third_party/webrtc/files/include/video_capture_factory.h"
#include "third_party/webrtc/files/include/ref_count.h"
#include "third_party/webrtc/files/include/scoped_refptr.h"
#endif
// TODO(henrike): replace playing file with playing a buffer.
class FileVideoCaptureModule
: public webrtc::VideoCaptureModule,
public talk_base::MessageHandler {
public:
virtual ~FileVideoCaptureModule();
static VideoCaptureModule* CreateFileVideoCaptureModule(
const char* file_name);
bool SetFrameRate(int fps);
void SetSize(int width, int height);
virtual int32_t Version(char* version,
uint32_t& remaining_buffer_in_bytes,
uint32_t& position) const {
return impl_->Version(version, remaining_buffer_in_bytes,
position);
}
virtual int32_t ChangeUniqueId(const int32_t id) {
return impl_->ChangeUniqueId(id);
}
virtual int32_t TimeUntilNextProcess() {
return impl_->TimeUntilNextProcess();
}
virtual int32_t Process() {
return impl_->Process();
}
virtual WebRtc_Word32 RegisterCaptureDataCallback(
webrtc::VideoCaptureDataCallback& dataCallback) {
return impl_->RegisterCaptureDataCallback(dataCallback);
}
virtual WebRtc_Word32 DeRegisterCaptureDataCallback() {
return impl_->DeRegisterCaptureDataCallback();
}
virtual WebRtc_Word32 RegisterCaptureCallback(
webrtc::VideoCaptureFeedBack& callBack) {
return impl_->RegisterCaptureCallback(callBack);
}
virtual WebRtc_Word32 DeRegisterCaptureCallback() {
return impl_->DeRegisterCaptureCallback();
}
virtual WebRtc_Word32 StartCapture(
const webrtc::VideoCaptureCapability& capability) {
return impl_->StartCapture(capability);
}
virtual WebRtc_Word32 StopCapture() {
return impl_->StopCapture();
}
virtual WebRtc_Word32 StartSendImage(const webrtc::VideoFrame& videoFrame,
WebRtc_Word32 frameRate = 1) {
return impl_->StartSendImage(videoFrame, frameRate = 1);
}
virtual WebRtc_Word32 StopSendImage() {
return impl_->StopSendImage();
}
virtual const WebRtc_UWord8* CurrentDeviceName() const {
return impl_->CurrentDeviceName();
}
virtual bool CaptureStarted() {
return impl_->CaptureStarted();
}
virtual WebRtc_Word32 CaptureSettings(
webrtc::VideoCaptureCapability& settings) {
return impl_->CaptureSettings(settings);
}
virtual WebRtc_Word32 SetCaptureDelay(WebRtc_Word32 delayMS) {
return impl_->SetCaptureDelay(delayMS);
}
virtual WebRtc_Word32 CaptureDelay() {
return impl_->CaptureDelay();
}
virtual WebRtc_Word32 SetCaptureRotation(
webrtc::VideoCaptureRotation rotation) {
return impl_->SetCaptureRotation(rotation);
}
virtual VideoCaptureEncodeInterface* GetEncodeInterface(
const webrtc::VideoCodec& codec) {
return impl_->GetEncodeInterface(codec);
}
virtual WebRtc_Word32 EnableFrameRateCallback(const bool enable) {
return impl_->EnableFrameRateCallback(enable);
}
virtual WebRtc_Word32 EnableNoPictureAlarm(const bool enable) {
return impl_->EnableNoPictureAlarm(enable);
}
// Inherited from MesageHandler.
virtual void OnMessage(talk_base::Message* msg) {
GenerateNewFrame();
}
protected:
FileVideoCaptureModule();
private:
bool Init(const char* file_name);
void GenerateNewFrame();
int GetI420FrameLength();
// Generate an arbitrary frame. (Will be used when file reading is replaced
// with reading a buffer).
void SetFrame(uint8* image);
uint32 GetTimestamp();
// Module interface implementation.
webrtc::scoped_refptr<VideoCaptureModule> impl_;
// File playing implementation.
static const int kStartFrameRate = 30;
// CIF
static const int kStartWidth = 352;
static const int kStartHeight = 288;
static const uint32 kStartTimeStamp = 2000;
FILE* i420_file_;
talk_base::scoped_ptr<talk_base::Thread> camera_thread_;
webrtc::VideoCaptureExternal* video_capture_;
bool started_;
int sent_frames_;
uint32 next_frame_time_;
uint32 time_per_frame_ms_;
int fps_;
int width_;
int height_;
talk_base::scoped_array<uint8> image_;
};
#endif // TALK_APP_WEBRTC_TEST_FILEVIDEOCAPTUREMODULE_H_