Remove fake cricket::VideoCapturer devices.

Changes rtc_media to depend on rtc_base_approved instead of rtc_base.

BUG=
R=pthatcher@webrtc.org

Review URL: https://codereview.webrtc.org/1676503002 .

Cr-Commit-Position: refs/heads/master@{#11507}
This commit is contained in:
Peter Boström 2016-02-05 19:40:34 +01:00
parent 7cd94f66eb
commit 50fca62809
11 changed files with 4 additions and 1118 deletions

View File

@ -25,7 +25,6 @@ char kTSanDefaultSuppressions[] =
// Split up suppressions covered previously by thread.cc and messagequeue.cc.
"race:rtc::MessageQueue::Quit\n"
"race:FileVideoCapturerTest::VideoCapturerListener::OnFrameCaptured\n"
"race:vp8cx_remove_encoder_threads\n"
"race:third_party/libvpx_new/source/libvpx/vp9/common/vp9_scan.h\n"

View File

@ -35,10 +35,9 @@
#include "webrtc/base/windowpicker.h"
#include "webrtc/base/windowpickerfactory.h"
#include "webrtc/media/base/mediacommon.h"
#include "webrtc/media/base/videocapturer.h"
#include "webrtc/media/base/videocapturerfactory.h"
#include "webrtc/media/devices/deviceinfo.h"
#include "webrtc/media/devices/filevideocapturer.h"
#include "webrtc/media/devices/yuvframescapturer.h"
#ifdef HAVE_WEBRTC_VIDEO
#include "webrtc/media/webrtc/webrtcvideocapturerfactory.h"
@ -154,27 +153,6 @@ bool DeviceManager::GetVideoCaptureDevice(const std::string& name,
}
}
// If |name| is a valid name for a file or yuvframedevice,
// return a fake video capturer device.
if (GetFakeVideoCaptureDevice(name, out)) {
return true;
}
return false;
}
bool DeviceManager::GetFakeVideoCaptureDevice(const std::string& name,
Device* out) const {
if (rtc::Filesystem::IsFile(name)) {
*out = FileVideoCapturer::CreateFileVideoCapturerDevice(name);
return true;
}
if (name == YuvFramesCapturer::kYuvFrameDeviceName) {
*out = YuvFramesCapturer::CreateYuvFramesCapturerDevice();
return true;
}
return false;
}
@ -190,16 +168,12 @@ void DeviceManager::ClearVideoCaptureDeviceMaxFormat(
}
VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
VideoCapturer* capturer = MaybeConstructFakeVideoCapturer(device);
if (capturer) {
return capturer;
}
if (!video_device_capturer_factory_) {
LOG(LS_ERROR) << "No video capturer factory for devices.";
return NULL;
}
capturer = video_device_capturer_factory_->Create(device);
cricket::VideoCapturer* capturer =
video_device_capturer_factory_->Create(device);
if (!capturer) {
return NULL;
}
@ -213,29 +187,6 @@ VideoCapturer* DeviceManager::CreateVideoCapturer(const Device& device) const {
return capturer;
}
VideoCapturer* DeviceManager::MaybeConstructFakeVideoCapturer(
const Device& device) const {
// TODO(hellner): Throw out the creation of a file video capturer once the
// refactoring is completed.
if (FileVideoCapturer::IsFileVideoCapturerDevice(device)) {
FileVideoCapturer* capturer = new FileVideoCapturer;
if (!capturer->Init(device)) {
delete capturer;
return NULL;
}
LOG(LS_INFO) << "Created file video capturer " << device.name;
capturer->set_repeat(FileVideoCapturer::kForever);
return capturer;
}
if (YuvFramesCapturer::IsYuvFramesCapturerDevice(device)) {
YuvFramesCapturer* capturer = new YuvFramesCapturer();
capturer->Init();
return capturer;
}
return NULL;
}
bool DeviceManager::GetWindows(
std::vector<rtc::WindowDescription>* descriptions) {
if (!window_picker_) {

View File

@ -193,8 +193,6 @@ class DeviceManager : public DeviceManagerInterface {
// The exclusion_list MUST be a NULL terminated list.
static bool ShouldDeviceBeIgnored(const std::string& device_name,
const char* const exclusion_list[]);
bool GetFakeVideoCaptureDevice(const std::string& name, Device* out) const;
VideoCapturer* MaybeConstructFakeVideoCapturer(const Device& device) const;
bool initialized_;
rtc::scoped_ptr<

View File

@ -45,7 +45,6 @@
#include "webrtc/media/base/screencastid.h"
#include "webrtc/media/base/testutils.h"
#include "webrtc/media/base/videocapturerfactory.h"
#include "webrtc/media/devices/filevideocapturer.h"
#include "webrtc/media/devices/v4llookup.h"
#ifdef WEBRTC_LINUX
@ -202,16 +201,6 @@ TEST(DeviceManagerTest, GetVideoDeviceIds) {
}
}
TEST(DeviceManagerTest, GetVideoDeviceIds_File) {
scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());
EXPECT_TRUE(dm->Init());
Device device;
const std::string test_file =
cricket::GetTestFilePath("captured-320x240-2s-48.frames");
EXPECT_TRUE(dm->GetVideoCaptureDevice(test_file, &device));
EXPECT_TRUE(cricket::FileVideoCapturer::IsFileVideoCapturerDevice(device));
}
TEST(DeviceManagerTest, VerifyDevicesListsAreCleared) {
const std::string imaginary("_NOT A REAL DEVICE_");
scoped_ptr<DeviceManagerInterface> dm(DeviceManagerFactory::Create());

View File

@ -1,385 +0,0 @@
/*
* libjingle
* Copyright 2004 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.
*/
// Implementation of VideoRecorder and FileVideoCapturer.
#include "webrtc/media/devices/filevideocapturer.h"
#include "webrtc/base/bytebuffer.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
namespace cricket {
/////////////////////////////////////////////////////////////////////
// Implementation of class VideoRecorder
/////////////////////////////////////////////////////////////////////
bool VideoRecorder::Start(const std::string& filename, bool write_header) {
Stop();
write_header_ = write_header;
int err;
if (!video_file_.Open(filename, "wb", &err)) {
LOG(LS_ERROR) << "Unable to open file " << filename << " err=" << err;
return false;
}
return true;
}
void VideoRecorder::Stop() {
video_file_.Close();
}
bool VideoRecorder::RecordFrame(const CapturedFrame& frame) {
if (rtc::SS_CLOSED == video_file_.GetState()) {
LOG(LS_ERROR) << "File not opened yet";
return false;
}
uint32_t size = 0;
if (!frame.GetDataSize(&size)) {
LOG(LS_ERROR) << "Unable to calculate the data size of the frame";
return false;
}
if (write_header_) {
// Convert the frame header to bytebuffer.
rtc::ByteBuffer buffer;
buffer.WriteUInt32(frame.width);
buffer.WriteUInt32(frame.height);
buffer.WriteUInt32(frame.fourcc);
buffer.WriteUInt32(frame.pixel_width);
buffer.WriteUInt32(frame.pixel_height);
// Elapsed time is deprecated.
const uint64_t dummy_elapsed_time = 0;
buffer.WriteUInt64(dummy_elapsed_time);
buffer.WriteUInt64(frame.time_stamp);
buffer.WriteUInt32(size);
// Write the bytebuffer to file.
if (rtc::SR_SUCCESS != video_file_.Write(buffer.Data(),
buffer.Length(),
NULL,
NULL)) {
LOG(LS_ERROR) << "Failed to write frame header";
return false;
}
}
// Write the frame data to file.
if (rtc::SR_SUCCESS != video_file_.Write(frame.data,
size,
NULL,
NULL)) {
LOG(LS_ERROR) << "Failed to write frame data";
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////
// Definition of private class FileReadThread that periodically reads
// frames from a file.
///////////////////////////////////////////////////////////////////////
class FileVideoCapturer::FileReadThread
: public rtc::Thread, public rtc::MessageHandler {
public:
explicit FileReadThread(FileVideoCapturer* capturer)
: capturer_(capturer),
finished_(false) {
}
virtual ~FileReadThread() {
Stop();
}
// Override virtual method of parent Thread. Context: Worker Thread.
virtual void Run() {
// Read the first frame and start the message pump. The pump runs until
// Stop() is called externally or Quit() is called by OnMessage().
int waiting_time_ms = 0;
if (capturer_ && capturer_->ReadFrame(true, &waiting_time_ms)) {
PostDelayed(waiting_time_ms, this);
Thread::Run();
}
rtc::CritScope cs(&crit_);
finished_ = true;
}
// Override virtual method of parent MessageHandler. Context: Worker Thread.
virtual void OnMessage(rtc::Message* /*pmsg*/) {
int waiting_time_ms = 0;
if (capturer_ && capturer_->ReadFrame(false, &waiting_time_ms)) {
PostDelayed(waiting_time_ms, this);
} else {
Quit();
}
}
// Check if Run() is finished.
bool Finished() const {
rtc::CritScope cs(&crit_);
return finished_;
}
private:
FileVideoCapturer* capturer_;
rtc::CriticalSection crit_;
bool finished_;
RTC_DISALLOW_COPY_AND_ASSIGN(FileReadThread);
};
/////////////////////////////////////////////////////////////////////
// Implementation of class FileVideoCapturer
/////////////////////////////////////////////////////////////////////
static const int64_t kNumNanoSecsPerMilliSec = 1000000;
const char* FileVideoCapturer::kVideoFileDevicePrefix = "video-file:";
FileVideoCapturer::FileVideoCapturer()
: frame_buffer_size_(0),
file_read_thread_(NULL),
repeat_(0),
last_frame_timestamp_ns_(0),
ignore_framerate_(false) {
}
FileVideoCapturer::~FileVideoCapturer() {
Stop();
delete[] static_cast<char*>(captured_frame_.data);
}
bool FileVideoCapturer::Init(const Device& device) {
if (!FileVideoCapturer::IsFileVideoCapturerDevice(device)) {
return false;
}
std::string filename(device.name);
if (IsRunning()) {
LOG(LS_ERROR) << "The file video capturer is already running";
return false;
}
// Open the file.
int err;
if (!video_file_.Open(filename, "rb", &err)) {
LOG(LS_ERROR) << "Unable to open the file " << filename << " err=" << err;
return false;
}
// Read the first frame's header to determine the supported format.
CapturedFrame frame;
if (rtc::SR_SUCCESS != ReadFrameHeader(&frame)) {
LOG(LS_ERROR) << "Failed to read the first frame header";
video_file_.Close();
return false;
}
// Seek back to the start of the file.
if (!video_file_.SetPosition(0)) {
LOG(LS_ERROR) << "Failed to seek back to beginning of the file";
video_file_.Close();
return false;
}
// Enumerate the supported formats. We have only one supported format. We set
// the frame interval to kMinimumInterval here. In Start(), if the capture
// format's interval is greater than kMinimumInterval, we use the interval;
// otherwise, we use the timestamp in the file to control the interval.
VideoFormat format(frame.width, frame.height, VideoFormat::kMinimumInterval,
frame.fourcc);
std::vector<VideoFormat> supported;
supported.push_back(format);
// TODO(thorcarpenter): Report the actual file video format as the supported
// format. Do not use kMinimumInterval as it conflicts with video adaptation.
SetId(device.id);
SetSupportedFormats(supported);
// TODO(wuwang): Design an E2E integration test for video adaptation,
// then remove the below call to disable the video adapter.
set_enable_video_adapter(false);
return true;
}
bool FileVideoCapturer::Init(const std::string& filename) {
return Init(FileVideoCapturer::CreateFileVideoCapturerDevice(filename));
}
CaptureState FileVideoCapturer::Start(const VideoFormat& capture_format) {
if (IsRunning()) {
LOG(LS_ERROR) << "The file video capturer is already running";
return CS_FAILED;
}
if (rtc::SS_CLOSED == video_file_.GetState()) {
LOG(LS_ERROR) << "File not opened yet";
return CS_NO_DEVICE;
} else if (!video_file_.SetPosition(0)) {
LOG(LS_ERROR) << "Failed to seek back to beginning of the file";
return CS_FAILED;
}
SetCaptureFormat(&capture_format);
// Create a thread to read the file.
file_read_thread_ = new FileReadThread(this);
bool ret = file_read_thread_->Start();
if (ret) {
LOG(LS_INFO) << "File video capturer '" << GetId() << "' started";
return CS_RUNNING;
} else {
LOG(LS_ERROR) << "File video capturer '" << GetId() << "' failed to start";
return CS_FAILED;
}
}
bool FileVideoCapturer::IsRunning() {
return file_read_thread_ && !file_read_thread_->Finished();
}
void FileVideoCapturer::Stop() {
if (file_read_thread_) {
file_read_thread_->Stop();
file_read_thread_ = NULL;
LOG(LS_INFO) << "File video capturer '" << GetId() << "' stopped";
}
SetCaptureFormat(NULL);
}
bool FileVideoCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) {
if (!fourccs) {
return false;
}
fourccs->push_back(GetSupportedFormats()->at(0).fourcc);
return true;
}
rtc::StreamResult FileVideoCapturer::ReadFrameHeader(
CapturedFrame* frame) {
// We first read kFrameHeaderSize bytes from the file stream to a memory
// buffer, then construct a bytebuffer from the memory buffer, and finally
// read the frame header from the bytebuffer.
char header[CapturedFrame::kFrameHeaderSize];
rtc::StreamResult sr;
size_t bytes_read;
int error;
sr = video_file_.Read(header,
CapturedFrame::kFrameHeaderSize,
&bytes_read,
&error);
LOG(LS_VERBOSE) << "Read frame header: stream_result = " << sr
<< ", bytes read = " << bytes_read << ", error = " << error;
if (rtc::SR_SUCCESS == sr) {
if (CapturedFrame::kFrameHeaderSize != bytes_read) {
return rtc::SR_EOS;
}
rtc::ByteBuffer buffer(header, CapturedFrame::kFrameHeaderSize);
buffer.ReadUInt32(reinterpret_cast<uint32_t*>(&frame->width));
buffer.ReadUInt32(reinterpret_cast<uint32_t*>(&frame->height));
buffer.ReadUInt32(&frame->fourcc);
buffer.ReadUInt32(&frame->pixel_width);
buffer.ReadUInt32(&frame->pixel_height);
// Elapsed time is deprecated.
uint64_t dummy_elapsed_time;
buffer.ReadUInt64(&dummy_elapsed_time);
buffer.ReadUInt64(reinterpret_cast<uint64_t*>(&frame->time_stamp));
buffer.ReadUInt32(&frame->data_size);
}
return sr;
}
// Executed in the context of FileReadThread.
bool FileVideoCapturer::ReadFrame(bool first_frame, int* wait_time_ms) {
uint32_t start_read_time_ms = rtc::Time();
// 1. Signal the previously read frame to downstream.
if (!first_frame) {
captured_frame_.time_stamp =
kNumNanoSecsPerMilliSec * static_cast<int64_t>(start_read_time_ms);
SignalFrameCaptured(this, &captured_frame_);
}
// 2. Read the next frame.
if (rtc::SS_CLOSED == video_file_.GetState()) {
LOG(LS_ERROR) << "File not opened yet";
return false;
}
// 2.1 Read the frame header.
rtc::StreamResult result = ReadFrameHeader(&captured_frame_);
if (rtc::SR_EOS == result) { // Loop back if repeat.
if (repeat_ != kForever) {
if (repeat_ > 0) {
--repeat_;
} else {
return false;
}
}
if (video_file_.SetPosition(0)) {
result = ReadFrameHeader(&captured_frame_);
}
}
if (rtc::SR_SUCCESS != result) {
LOG(LS_ERROR) << "Failed to read the frame header";
return false;
}
// 2.2 Reallocate memory for the frame data if necessary.
if (frame_buffer_size_ < captured_frame_.data_size) {
frame_buffer_size_ = captured_frame_.data_size;
delete[] static_cast<char*>(captured_frame_.data);
captured_frame_.data = new char[frame_buffer_size_];
}
// 2.3 Read the frame adata.
if (rtc::SR_SUCCESS != video_file_.Read(captured_frame_.data,
captured_frame_.data_size,
NULL, NULL)) {
LOG(LS_ERROR) << "Failed to read frame data";
return false;
}
// 3. Decide how long to wait for the next frame.
*wait_time_ms = 0;
// If the capture format's interval is not kMinimumInterval, we use it to
// control the rate; otherwise, we use the timestamp in the file to control
// the rate.
if (!first_frame && !ignore_framerate_) {
int64_t interval_ns =
GetCaptureFormat()->interval > VideoFormat::kMinimumInterval
? GetCaptureFormat()->interval
: captured_frame_.time_stamp - last_frame_timestamp_ns_;
int interval_ms = static_cast<int>(interval_ns / kNumNanoSecsPerMilliSec);
interval_ms -= rtc::Time() - start_read_time_ms;
if (interval_ms > 0) {
*wait_time_ms = interval_ms;
}
}
// Keep the original timestamp read from the file.
last_frame_timestamp_ns_ = captured_frame_.time_stamp;
return true;
}
} // namespace cricket

View File

@ -1,160 +0,0 @@
/*
* libjingle
* Copyright 2004 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 file contains two classes, VideoRecorder and FileVideoCapturer.
// VideoRecorder records the captured frames into a file. The file stores a
// sequence of captured frames; each frame has a header defined in struct
// CapturedFrame, followed by the frame data.
//
// FileVideoCapturer, a subclass of VideoCapturer, is a simulated video capturer
// that periodically reads images from a previously recorded file.
#ifndef WEBRTC_MEDIA_DEVICES_FILEVIDEOCAPTURER_H_
#define WEBRTC_MEDIA_DEVICES_FILEVIDEOCAPTURER_H_
#include <string>
#include <vector>
#include "webrtc/base/stream.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/media/base/videocapturer.h"
namespace rtc {
class FileStream;
}
namespace cricket {
// Utility class to record the frames captured by a video capturer into a file.
class VideoRecorder {
public:
VideoRecorder() {}
~VideoRecorder() { Stop(); }
// Start the recorder by opening the specified file. Return true if the file
// is opened successfully. write_header should normally be true; false means
// write raw frame pixel data to file without any headers.
bool Start(const std::string& filename, bool write_header);
// Stop the recorder by closing the file.
void Stop();
// Record a video frame to the file. Return true if the frame is written to
// the file successfully. This method needs to be called after Start() and
// before Stop().
bool RecordFrame(const CapturedFrame& frame);
private:
rtc::FileStream video_file_;
bool write_header_;
RTC_DISALLOW_COPY_AND_ASSIGN(VideoRecorder);
};
// Simulated video capturer that periodically reads frames from a file.
class FileVideoCapturer : public VideoCapturer {
public:
static const int kForever = -1;
FileVideoCapturer();
virtual ~FileVideoCapturer();
// Determines if the given device is actually a video file, to be captured
// with a FileVideoCapturer.
static bool IsFileVideoCapturerDevice(const Device& device) {
return rtc::starts_with(device.id.c_str(), kVideoFileDevicePrefix);
}
// Creates a fake device for the given filename.
static Device CreateFileVideoCapturerDevice(const std::string& filename) {
std::stringstream id;
id << kVideoFileDevicePrefix << filename;
return Device(filename, id.str());
}
// Set how many times to repeat reading the file. Repeat forever if the
// parameter is kForever; no repeat if the parameter is 0 or
// less than -1.
void set_repeat(int repeat) { repeat_ = repeat; }
// If ignore_framerate is true, file is read as quickly as possible. If
// false, read rate is controlled by the timestamps in the video file
// (thus simulating camera capture). Default value set to false.
void set_ignore_framerate(bool ignore_framerate) {
ignore_framerate_ = ignore_framerate;
}
// Initializes the capturer with the given file.
bool Init(const std::string& filename);
// Initializes the capturer with the given device. This should only be used
// if IsFileVideoCapturerDevice returned true for the given device.
bool Init(const Device& device);
// Override virtual methods of parent class VideoCapturer.
virtual CaptureState Start(const VideoFormat& capture_format);
virtual void Stop();
virtual bool IsRunning();
virtual bool IsScreencast() const { return false; }
protected:
// Override virtual methods of parent class VideoCapturer.
virtual bool GetPreferredFourccs(std::vector<uint32_t>* fourccs);
// Read the frame header from the file stream, video_file_.
rtc::StreamResult ReadFrameHeader(CapturedFrame* frame);
// Read a frame and determine how long to wait for the next frame. If the
// frame is read successfully, Set the output parameter, wait_time_ms and
// return true. Otherwise, do not change wait_time_ms and return false.
bool ReadFrame(bool first_frame, int* wait_time_ms);
// Return the CapturedFrame - useful for extracting contents after reading
// a frame. Should be used only while still reading a file (i.e. only while
// the CapturedFrame object still exists).
const CapturedFrame* frame() const {
return &captured_frame_;
}
private:
class FileReadThread; // Forward declaration, defined in .cc.
static const char* kVideoFileDevicePrefix;
rtc::FileStream video_file_;
CapturedFrame captured_frame_;
// The number of bytes allocated buffer for captured_frame_.data.
uint32_t frame_buffer_size_;
FileReadThread* file_read_thread_;
int repeat_; // How many times to repeat the file.
int64_t last_frame_timestamp_ns_; // Timestamp of last read frame.
bool ignore_framerate_;
RTC_DISALLOW_COPY_AND_ASSIGN(FileVideoCapturer);
};
} // namespace cricket
#endif // WEBRTC_MEDIA_DEVICES_FILEVIDEOCAPTURER_H_

View File

@ -1,204 +0,0 @@
/*
* libjingle
* Copyright 2004 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 <stdio.h>
#include <string>
#include <vector>
#include "webrtc/base/gunit.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
#include "webrtc/media/base/testutils.h"
#include "webrtc/media/devices/filevideocapturer.h"
namespace {
class FileVideoCapturerTest : public testing::Test {
public:
virtual void SetUp() {
capturer_.reset(new cricket::FileVideoCapturer);
}
bool OpenFile(const std::string& filename) {
return capturer_->Init(cricket::GetTestFilePath(filename));
}
protected:
class VideoCapturerListener : public sigslot::has_slots<> {
public:
VideoCapturerListener()
: frame_count_(0),
frame_width_(0),
frame_height_(0),
resolution_changed_(false) {
}
void OnFrameCaptured(cricket::VideoCapturer* capturer,
const cricket::CapturedFrame* frame) {
++frame_count_;
if (1 == frame_count_) {
frame_width_ = frame->width;
frame_height_ = frame->height;
} else if (frame_width_ != frame->width ||
frame_height_ != frame->height) {
resolution_changed_ = true;
}
}
int frame_count() const { return frame_count_; }
int frame_width() const { return frame_width_; }
int frame_height() const { return frame_height_; }
bool resolution_changed() const { return resolution_changed_; }
private:
int frame_count_;
int frame_width_;
int frame_height_;
bool resolution_changed_;
};
rtc::scoped_ptr<cricket::FileVideoCapturer> capturer_;
cricket::VideoFormat capture_format_;
};
TEST_F(FileVideoCapturerTest, TestNotOpened) {
EXPECT_EQ("", capturer_->GetId());
EXPECT_TRUE(capturer_->GetSupportedFormats()->empty());
EXPECT_EQ(NULL, capturer_->GetCaptureFormat());
EXPECT_FALSE(capturer_->IsRunning());
}
TEST_F(FileVideoCapturerTest, TestInvalidOpen) {
EXPECT_FALSE(OpenFile("NotmeNotme"));
}
TEST_F(FileVideoCapturerTest, TestOpen) {
EXPECT_TRUE(OpenFile("captured-320x240-2s-48.frames"));
EXPECT_NE("", capturer_->GetId());
EXPECT_TRUE(NULL != capturer_->GetSupportedFormats());
EXPECT_EQ(1U, capturer_->GetSupportedFormats()->size());
EXPECT_EQ(NULL, capturer_->GetCaptureFormat()); // not started yet
EXPECT_FALSE(capturer_->IsRunning());
}
TEST_F(FileVideoCapturerTest, TestLargeSmallDesiredFormat) {
EXPECT_TRUE(OpenFile("captured-320x240-2s-48.frames"));
// desired format with large resolution.
cricket::VideoFormat desired(
3200, 2400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY);
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &capture_format_));
EXPECT_EQ(320, capture_format_.width);
EXPECT_EQ(240, capture_format_.height);
// Desired format with small resolution.
desired.width = 0;
desired.height = 0;
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &capture_format_));
EXPECT_EQ(320, capture_format_.width);
EXPECT_EQ(240, capture_format_.height);
}
TEST_F(FileVideoCapturerTest, TestSupportedAsDesiredFormat) {
EXPECT_TRUE(OpenFile("captured-320x240-2s-48.frames"));
// desired format same as the capture format supported by the file
cricket::VideoFormat desired = capturer_->GetSupportedFormats()->at(0);
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &capture_format_));
EXPECT_TRUE(desired == capture_format_);
// desired format same as the supported capture format except the fourcc
desired.fourcc = cricket::FOURCC_ANY;
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &capture_format_));
EXPECT_NE(capture_format_.fourcc, desired.fourcc);
// desired format with minimum interval
desired.interval = cricket::VideoFormat::kMinimumInterval;
EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &capture_format_));
}
TEST_F(FileVideoCapturerTest, TestNoRepeat) {
EXPECT_TRUE(OpenFile("captured-320x240-2s-48.frames"));
VideoCapturerListener listener;
capturer_->SignalFrameCaptured.connect(
&listener, &VideoCapturerListener::OnFrameCaptured);
capturer_->set_repeat(0);
capture_format_ = capturer_->GetSupportedFormats()->at(0);
EXPECT_EQ(cricket::CS_RUNNING, capturer_->Start(capture_format_));
EXPECT_TRUE_WAIT(!capturer_->IsRunning(), 20000);
EXPECT_EQ(48, listener.frame_count());
}
TEST_F(FileVideoCapturerTest, TestRepeatForever) {
// Start the capturer_ with 50 fps and read no less than 150 frames.
EXPECT_TRUE(OpenFile("captured-320x240-2s-48.frames"));
VideoCapturerListener listener;
capturer_->SignalFrameCaptured.connect(
&listener, &VideoCapturerListener::OnFrameCaptured);
capturer_->set_repeat(cricket::FileVideoCapturer::kForever);
capture_format_ = capturer_->GetSupportedFormats()->at(0);
capture_format_.interval = cricket::VideoFormat::FpsToInterval(50);
EXPECT_EQ(cricket::CS_RUNNING, capturer_->Start(capture_format_));
EXPECT_TRUE(NULL != capturer_->GetCaptureFormat());
EXPECT_TRUE(capture_format_ == *capturer_->GetCaptureFormat());
EXPECT_TRUE_WAIT(!capturer_->IsRunning() ||
listener.frame_count() >= 150, 20000);
capturer_->Stop();
EXPECT_FALSE(capturer_->IsRunning());
EXPECT_GE(listener.frame_count(), 150);
EXPECT_FALSE(listener.resolution_changed());
EXPECT_EQ(listener.frame_width(), capture_format_.width);
EXPECT_EQ(listener.frame_height(), capture_format_.height);
}
// See: https://code.google.com/p/webrtc/issues/detail?id=2409
TEST_F(FileVideoCapturerTest, DISABLED_TestPartialFrameHeader) {
EXPECT_TRUE(OpenFile("1.frame_plus_1.byte"));
VideoCapturerListener listener;
capturer_->SignalFrameCaptured.connect(
&listener, &VideoCapturerListener::OnFrameCaptured);
capturer_->set_repeat(0);
capture_format_ = capturer_->GetSupportedFormats()->at(0);
EXPECT_EQ(cricket::CS_RUNNING, capturer_->Start(capture_format_));
EXPECT_TRUE_WAIT(!capturer_->IsRunning(), 1000);
EXPECT_EQ(1, listener.frame_count());
}
TEST_F(FileVideoCapturerTest, TestFileDevices) {
cricket::Device not_a_file("I'm a camera", "with an id");
EXPECT_FALSE(
cricket::FileVideoCapturer::IsFileVideoCapturerDevice(not_a_file));
const std::string test_file =
cricket::GetTestFilePath("captured-320x240-2s-48.frames");
cricket::Device file_device =
cricket::FileVideoCapturer::CreateFileVideoCapturerDevice(test_file);
EXPECT_TRUE(
cricket::FileVideoCapturer::IsFileVideoCapturerDevice(file_device));
EXPECT_TRUE(capturer_->Init(file_device));
EXPECT_EQ(file_device.id, capturer_->GetId());
}
} // unnamed namespace

View File

@ -1,199 +0,0 @@
/*
* libjingle
* Copyright 2004 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 "webrtc/media/devices/yuvframescapturer.h"
#include "webrtc/base/bytebuffer.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace cricket {
///////////////////////////////////////////////////////////////////////
// Definition of private class YuvFramesThread that periodically generates
// frames.
///////////////////////////////////////////////////////////////////////
class YuvFramesCapturer::YuvFramesThread
: public rtc::Thread, public rtc::MessageHandler {
public:
explicit YuvFramesThread(YuvFramesCapturer* capturer)
: capturer_(capturer),
finished_(false) {
}
virtual ~YuvFramesThread() {
Stop();
}
// Override virtual method of parent Thread. Context: Worker Thread.
virtual void Run() {
// Read the first frame and start the message pump. The pump runs until
// Stop() is called externally or Quit() is called by OnMessage().
int waiting_time_ms = 0;
if (capturer_) {
capturer_->ReadFrame(true);
PostDelayed(waiting_time_ms, this);
Thread::Run();
}
rtc::CritScope cs(&crit_);
finished_ = true;
}
// Override virtual method of parent MessageHandler. Context: Worker Thread.
virtual void OnMessage(rtc::Message* /*pmsg*/) {
int waiting_time_ms = 0;
if (capturer_) {
capturer_->ReadFrame(false);
PostDelayed(waiting_time_ms, this);
} else {
Quit();
}
}
// Check if Run() is finished.
bool Finished() const {
rtc::CritScope cs(&crit_);
return finished_;
}
private:
YuvFramesCapturer* capturer_;
rtc::CriticalSection crit_;
bool finished_;
RTC_DISALLOW_COPY_AND_ASSIGN(YuvFramesThread);
};
/////////////////////////////////////////////////////////////////////
// Implementation of class YuvFramesCapturer.
/////////////////////////////////////////////////////////////////////
const char* YuvFramesCapturer::kYuvFrameDeviceName = "YuvFramesGenerator";
// TODO(shaowei): allow width_ and height_ to be configurable.
YuvFramesCapturer::YuvFramesCapturer()
: frames_generator_thread(NULL),
width_(640),
height_(480),
frame_index_(0),
barcode_interval_(1) {
}
YuvFramesCapturer::~YuvFramesCapturer() {
Stop();
delete[] static_cast<char*>(captured_frame_.data);
}
void YuvFramesCapturer::Init() {
int size = width_ * height_;
int qsize = size / 4;
frame_generator_ = new YuvFrameGenerator(width_, height_, true);
frame_data_size_ = size + 2 * qsize;
captured_frame_.data = new char[frame_data_size_];
captured_frame_.fourcc = FOURCC_IYUV;
captured_frame_.pixel_height = 1;
captured_frame_.pixel_width = 1;
captured_frame_.width = width_;
captured_frame_.height = height_;
captured_frame_.data_size = frame_data_size_;
// Enumerate the supported formats. We have only one supported format.
VideoFormat format(width_, height_, VideoFormat::kMinimumInterval,
FOURCC_IYUV);
std::vector<VideoFormat> supported;
supported.push_back(format);
SetSupportedFormats(supported);
}
CaptureState YuvFramesCapturer::Start(const VideoFormat& capture_format) {
if (IsRunning()) {
LOG(LS_ERROR) << "Yuv Frame Generator is already running";
return CS_FAILED;
}
SetCaptureFormat(&capture_format);
barcode_reference_timestamp_millis_ =
static_cast<int64_t>(rtc::Time()) * 1000;
// Create a thread to generate frames.
frames_generator_thread = new YuvFramesThread(this);
bool ret = frames_generator_thread->Start();
if (ret) {
LOG(LS_INFO) << "Yuv Frame Generator started";
return CS_RUNNING;
} else {
LOG(LS_ERROR) << "Yuv Frame Generator failed to start";
return CS_FAILED;
}
}
bool YuvFramesCapturer::IsRunning() {
return frames_generator_thread && !frames_generator_thread->Finished();
}
void YuvFramesCapturer::Stop() {
if (frames_generator_thread) {
frames_generator_thread->Stop();
frames_generator_thread = NULL;
LOG(LS_INFO) << "Yuv Frame Generator stopped";
}
SetCaptureFormat(NULL);
}
bool YuvFramesCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) {
if (!fourccs) {
return false;
}
fourccs->push_back(GetSupportedFormats()->at(0).fourcc);
return true;
}
// Executed in the context of YuvFramesThread.
void YuvFramesCapturer::ReadFrame(bool first_frame) {
// 1. Signal the previously read frame to downstream.
if (!first_frame) {
SignalFrameCaptured(this, &captured_frame_);
}
uint8_t* buffer = new uint8_t[frame_data_size_];
frame_generator_->GenerateNextFrame(buffer, GetBarcodeValue());
frame_index_++;
memmove(captured_frame_.data, buffer, frame_data_size_);
delete[] buffer;
}
int32_t YuvFramesCapturer::GetBarcodeValue() {
if (barcode_reference_timestamp_millis_ == -1 ||
frame_index_ % barcode_interval_ != 0) {
return -1;
}
int64_t now_millis = static_cast<int64_t>(rtc::Time()) * 1000;
return static_cast<int32_t>(now_millis - barcode_reference_timestamp_millis_);
}
} // namespace cricket

View File

@ -1,98 +0,0 @@
/*
* libjingle
* Copyright 2010 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 WEBRTC_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_
#define WEBRTC_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_
#include <string>
#include <vector>
#include "webrtc/base/stream.h"
#include "webrtc/base/stringutils.h"
#include "webrtc/media/base/videocapturer.h"
#include "webrtc/media/base/yuvframegenerator.h"
namespace rtc {
class FileStream;
}
namespace cricket {
// Simulated video capturer that periodically reads frames from a file.
class YuvFramesCapturer : public VideoCapturer {
public:
YuvFramesCapturer();
YuvFramesCapturer(int width, int height);
virtual ~YuvFramesCapturer();
static const char* kYuvFrameDeviceName;
static Device CreateYuvFramesCapturerDevice() {
std::stringstream id;
id << kYuvFrameDeviceName;
return Device(id.str(), id.str());
}
static bool IsYuvFramesCapturerDevice(const Device& device) {
return rtc::starts_with(device.id.c_str(), kYuvFrameDeviceName);
}
void Init();
// Override virtual methods of parent class VideoCapturer.
virtual CaptureState Start(const VideoFormat& capture_format);
virtual void Stop();
virtual bool IsRunning();
virtual bool IsScreencast() const { return false; }
protected:
// Override virtual methods of parent class VideoCapturer.
virtual bool GetPreferredFourccs(std::vector<uint32_t>* fourccs);
// Read a frame and determine how long to wait for the next frame.
void ReadFrame(bool first_frame);
private:
class YuvFramesThread; // Forward declaration, defined in .cc.
YuvFrameGenerator* frame_generator_;
CapturedFrame captured_frame_;
YuvFramesThread* frames_generator_thread;
int width_;
int height_;
uint32_t frame_data_size_;
uint32_t frame_index_;
int64_t barcode_reference_timestamp_millis_;
int32_t barcode_interval_;
int32_t GetBarcodeValue();
RTC_DISALLOW_COPY_AND_ASSIGN(YuvFramesCapturer);
};
} // namespace cricket
#endif // WEBRTC_MEDIA_DEVICES_YUVFRAMESCAPTURER_H_

View File

@ -13,7 +13,7 @@
'target_name': 'rtc_media',
'type': 'static_library',
'dependencies': [
'<(webrtc_root)/base/base.gyp:rtc_base',
'<(webrtc_root)/base/base.gyp:rtc_base_approved',
'<(webrtc_root)/common.gyp:webrtc_common',
'<(webrtc_root)/modules/modules.gyp:video_render_module',
'<(webrtc_root)/webrtc.gyp:webrtc',
@ -80,11 +80,7 @@
'devices/devicemanager.cc',
'devices/devicemanager.h',
'devices/dummydevicemanager.h',
'devices/filevideocapturer.cc',
'devices/filevideocapturer.h',
'devices/videorendererfactory.h',
'devices/yuvframescapturer.cc',
'devices/yuvframescapturer.h',
'sctp/sctpdataengine.cc',
'sctp/sctpdataengine.h',
'webrtc/nullwebrtcvideoengine.h',

View File

@ -90,7 +90,6 @@
'base/videoengine_unittest.h',
'base/videoframe_unittest.h',
'devices/dummydevicemanager_unittest.cc',
'devices/filevideocapturer_unittest.cc',
'sctp/sctpdataengine_unittest.cc',
'webrtc/nullwebrtcvideoengine_unittest.cc',
'webrtc/simulcast_unittest.cc',