webrtc/talk/media/devices/yuvframescapturer.cc

174 lines
5.0 KiB
C++
Raw Normal View History

#include "talk/media/devices/yuvframescapturer.h"
#include "talk/base/bytebuffer.h"
#include "talk/base/criticalsection.h"
#include "talk/base/logging.h"
#include "talk/base/thread.h"
#include "webrtc/system_wrappers/interface/clock.h"
namespace cricket {
///////////////////////////////////////////////////////////////////////
// Definition of private class YuvFramesThread that periodically generates
// frames.
///////////////////////////////////////////////////////////////////////
class YuvFramesCapturer::YuvFramesThread
: public talk_base::Thread, public talk_base::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();
}
talk_base::CritScope cs(&crit_);
finished_ = true;
}
// Override virtual method of parent MessageHandler. Context: Worker Thread.
virtual void OnMessage(talk_base::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 {
talk_base::CritScope cs(&crit_);
return finished_;
}
private:
YuvFramesCapturer* capturer_;
mutable talk_base::CriticalSection crit_;
bool finished_;
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>(talk_base::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>* 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* buffer = new uint8[frame_data_size_];
frame_generator_->GenerateNextFrame(buffer, GetBarcodeValue());
frame_index_++;
memmove(captured_frame_.data, buffer, frame_data_size_);
delete[] buffer;
}
int32 YuvFramesCapturer::GetBarcodeValue() {
if (barcode_reference_timestamp_millis_ == -1 ||
frame_index_ % barcode_interval_ != 0) {
return -1;
}
int64 now_millis = static_cast<int64>(talk_base::Time()) * 1000;
return static_cast<int32>(now_millis - barcode_reference_timestamp_millis_);
}
} // namespace cricket