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:
parent
7cd94f66eb
commit
50fca62809
@ -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"
|
||||
|
||||
|
||||
@ -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_) {
|
||||
|
||||
@ -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<
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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',
|
||||
|
||||
@ -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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user