diff --git a/third_party_mods/libjingle/libjingle.gyp b/third_party_mods/libjingle/libjingle.gyp index 113482c8f5..9dbbfde663 100644 --- a/third_party_mods/libjingle/libjingle.gyp +++ b/third_party_mods/libjingle/libjingle.gyp @@ -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', diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnection_unittest.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnection_unittest.cc index b6a0bfb896..356d3d8d7f 100644 --- a/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnection_unittest.cc +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/peerconnection_unittest.cc @@ -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 OpenVideoCaptureDevice() { +webrtc::VideoCaptureModule* OpenVideoCaptureDevice() { webrtc::VideoCaptureModule::DeviceInfo* device_info( webrtc::VideoCaptureFactory::CreateDeviceInfo(0)); - talk_base::scoped_refptr video_device; + webrtc::VideoCaptureModule* video_device; const size_t kMaxDeviceNameLength = 128; const size_t kMaxUniqueIdLength = 256; @@ -66,7 +66,7 @@ talk_base::scoped_refptr 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 video_track( peer_connection_factory_->CreateLocalVideoTrack( - "video_track", - OpenVideoCaptureDevice())); + "video_track", OpenVideoFileCaptureDevice())); talk_base::scoped_refptr 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 peer_connection_; talk_base::scoped_refptr @@ -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 diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/test/filevideocapturemodule.cc b/third_party_mods/libjingle/source/talk/app/webrtc_dev/test/filevideocapturemodule.cc new file mode 100644 index 0000000000..23a8087c1b --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/test/filevideocapturemodule.cc @@ -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* capture_module = + new webrtc::RefCountImpl(); + 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_; +} diff --git a/third_party_mods/libjingle/source/talk/app/webrtc_dev/test/filevideocapturemodule.h b/third_party_mods/libjingle/source/talk/app/webrtc_dev/test/filevideocapturemodule.h new file mode 100644 index 0000000000..fa8f6924b5 --- /dev/null +++ b/third_party_mods/libjingle/source/talk/app/webrtc_dev/test/filevideocapturemodule.h @@ -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 +#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 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 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 image_; +}; + +#endif // TALK_APP_WEBRTC_TEST_FILEVIDEOCAPTUREMODULE_H_