10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// libjingle 20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Copyright 2004 Google Inc. 30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Redistribution and use in source and binary forms, with or without 50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// modification, are permitted provided that the following conditions are met: 60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 1. Redistributions of source code must retain the above copyright notice, 80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// this list of conditions and the following disclaimer. 90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 2. Redistributions in binary form must reproduce the above copyright notice, 100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// this list of conditions and the following disclaimer in the documentation 110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// and/or other materials provided with the distribution. 120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 3. The name of the author may not be used to endorse or promote products 130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// derived from this software without specific prior written permission. 140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of VideoRecorder and FileVideoCapturer. 270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/devices/filevideocapturer.h" 290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 302a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/bytebuffer.h" 312a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/criticalsection.h" 322a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/logging.h" 332a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/thread.h" 340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket { 360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org///////////////////////////////////////////////////////////////////// 380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of class VideoRecorder 390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org///////////////////////////////////////////////////////////////////// 400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoRecorder::Start(const std::string& filename, bool write_header) { 410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org Stop(); 420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org write_header_ = write_header; 430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int err; 440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!video_file_.Open(filename, "wb", &err)) { 450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Unable to open file " << filename << " err=" << err; 460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoRecorder::Stop() { 520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org video_file_.Close(); 530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoRecorder::RecordFrame(const CapturedFrame& frame) { 562a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SS_CLOSED == video_file_.GetState()) { 570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "File not opened yet"; 580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org uint32 size = 0; 620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!frame.GetDataSize(&size)) { 630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Unable to calculate the data size of the frame"; 640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (write_header_) { 680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Convert the frame header to bytebuffer. 692a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::ByteBuffer buffer; 700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt32(frame.width); 710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt32(frame.height); 720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt32(frame.fourcc); 730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt32(frame.pixel_width); 740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt32(frame.pixel_height); 750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt64(frame.elapsed_time); 760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt64(frame.time_stamp); 770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.WriteUInt32(size); 780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Write the bytebuffer to file. 802a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_SUCCESS != video_file_.Write(buffer.Data(), 810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.Length(), 820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL, 830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL)) { 840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to write frame header"; 850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Write the frame data to file. 892a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_SUCCESS != video_file_.Write(frame.data, 900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org size, 910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL, 920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL)) { 930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to write frame data"; 940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////// 1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Definition of private class FileReadThread that periodically reads 1020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// frames from a file. 1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////// 1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgclass FileVideoCapturer::FileReadThread 1052a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org : public rtc::Thread, public rtc::MessageHandler { 1060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org public: 1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org explicit FileReadThread(FileVideoCapturer* capturer) 1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org : capturer_(capturer), 1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org finished_(false) { 1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 112e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org virtual ~FileReadThread() { 113e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org Stop(); 114e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org } 115e5b49108d39835fbab2ae1c29eff4542a57a8ed5wu@webrtc.org 1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Override virtual method of parent Thread. Context: Worker Thread. 1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org virtual void Run() { 1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Read the first frame and start the message pump. The pump runs until 1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Stop() is called externally or Quit() is called by OnMessage(). 1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int waiting_time_ms = 0; 1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (capturer_ && capturer_->ReadFrame(true, &waiting_time_ms)) { 1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org PostDelayed(waiting_time_ms, this); 1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org Thread::Run(); 1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 125e940b2ee0377e350084f7d12a43d2334255d97ebwu@webrtc.org 1262a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::CritScope cs(&crit_); 1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org finished_ = true; 1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Override virtual method of parent MessageHandler. Context: Worker Thread. 1312a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org virtual void OnMessage(rtc::Message* /*pmsg*/) { 1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int waiting_time_ms = 0; 1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (capturer_ && capturer_->ReadFrame(false, &waiting_time_ms)) { 1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org PostDelayed(waiting_time_ms, this); 1350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } else { 1360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org Quit(); 1370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Check if Run() is finished. 141e940b2ee0377e350084f7d12a43d2334255d97ebwu@webrtc.org bool Finished() const { 1422a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::CritScope cs(&crit_); 143e940b2ee0377e350084f7d12a43d2334255d97ebwu@webrtc.org return finished_; 144e940b2ee0377e350084f7d12a43d2334255d97ebwu@webrtc.org } 1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org private: 1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org FileVideoCapturer* capturer_; 1482a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org mutable rtc::CriticalSection crit_; 1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org bool finished_; 1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org DISALLOW_COPY_AND_ASSIGN(FileReadThread); 1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}; 1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org///////////////////////////////////////////////////////////////////// 1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of class FileVideoCapturer 1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org///////////////////////////////////////////////////////////////////// 1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int64 kNumNanoSecsPerMilliSec = 1000000; 1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst char* FileVideoCapturer::kVideoFileDevicePrefix = "video-file:"; 1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgFileVideoCapturer::FileVideoCapturer() 1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org : frame_buffer_size_(0), 1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org file_read_thread_(NULL), 1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org repeat_(0), 1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org start_time_ns_(0), 1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org last_frame_timestamp_ns_(0), 1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org ignore_framerate_(false) { 1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgFileVideoCapturer::~FileVideoCapturer() { 1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org Stop(); 1711a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org delete[] static_cast<char*>(captured_frame_.data); 1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool FileVideoCapturer::Init(const Device& device) { 1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!FileVideoCapturer::IsFileVideoCapturerDevice(device)) { 1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::string filename(device.name); 1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (IsRunning()) { 1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "The file video capturer is already running"; 1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Open the file. 1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int err; 1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!video_file_.Open(filename, "rb", &err)) { 1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Unable to open the file " << filename << " err=" << err; 1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Read the first frame's header to determine the supported format. 1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org CapturedFrame frame; 1912a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_SUCCESS != ReadFrameHeader(&frame)) { 1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to read the first frame header"; 1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org video_file_.Close(); 1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Seek back to the start of the file. 1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!video_file_.SetPosition(0)) { 1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to seek back to beginning of the file"; 1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org video_file_.Close(); 2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Enumerate the supported formats. We have only one supported format. We set 2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // the frame interval to kMinimumInterval here. In Start(), if the capture 2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // format's interval is greater than kMinimumInterval, we use the interval; 2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // otherwise, we use the timestamp in the file to control the interval. 2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org VideoFormat format(frame.width, frame.height, VideoFormat::kMinimumInterval, 2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org frame.fourcc); 2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org std::vector<VideoFormat> supported; 2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org supported.push_back(format); 2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2127587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org // TODO(thorcarpenter): Report the actual file video format as the supported 2137587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org // format. Do not use kMinimumInterval as it conflicts with video adaptation. 2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org SetId(device.id); 2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org SetSupportedFormats(supported); 2167587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org 2177587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org // TODO(wuwang): Design an E2E integration test for video adaptation, 2187587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org // then remove the below call to disable the video adapter. 2197587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org set_enable_video_adapter(false); 2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool FileVideoCapturer::Init(const std::string& filename) { 2240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return Init(FileVideoCapturer::CreateFileVideoCapturerDevice(filename)); 2250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 2260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgCaptureState FileVideoCapturer::Start(const VideoFormat& capture_format) { 2280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (IsRunning()) { 2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "The file video capturer is already running"; 2300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return CS_FAILED; 2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2332a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SS_CLOSED == video_file_.GetState()) { 2340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "File not opened yet"; 2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return CS_NO_DEVICE; 2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } else if (!video_file_.SetPosition(0)) { 2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to seek back to beginning of the file"; 2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return CS_FAILED; 2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org SetCaptureFormat(&capture_format); 2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Create a thread to read the file. 2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org file_read_thread_ = new FileReadThread(this); 2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org start_time_ns_ = kNumNanoSecsPerMilliSec * 2452a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org static_cast<int64>(rtc::Time()); 246e940b2ee0377e350084f7d12a43d2334255d97ebwu@webrtc.org bool ret = file_read_thread_->Start(); 2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (ret) { 2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_INFO) << "File video capturer '" << GetId() << "' started"; 2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return CS_RUNNING; 2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } else { 2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "File video capturer '" << GetId() << "' failed to start"; 2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return CS_FAILED; 2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool FileVideoCapturer::IsRunning() { 2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return file_read_thread_ && !file_read_thread_->Finished(); 2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid FileVideoCapturer::Stop() { 2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (file_read_thread_) { 2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org file_read_thread_->Stop(); 2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org file_read_thread_ = NULL; 2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_INFO) << "File video capturer '" << GetId() << "' stopped"; 2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org SetCaptureFormat(NULL); 2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 2680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool FileVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) { 2700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!fourccs) { 2710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org fourccs->push_back(GetSupportedFormats()->at(0).fourcc); 2750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 2760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 2782a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgrtc::StreamResult FileVideoCapturer::ReadFrameHeader( 2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org CapturedFrame* frame) { 2800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // We first read kFrameHeaderSize bytes from the file stream to a memory 2810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // buffer, then construct a bytebuffer from the memory buffer, and finally 2820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // read the frame header from the bytebuffer. 2830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org char header[CapturedFrame::kFrameHeaderSize]; 2842a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::StreamResult sr; 2850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org size_t bytes_read; 2860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int error; 2870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org sr = video_file_.Read(header, 2880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org CapturedFrame::kFrameHeaderSize, 2890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org &bytes_read, 2900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org &error); 2910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_VERBOSE) << "Read frame header: stream_result = " << sr 2920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org << ", bytes read = " << bytes_read << ", error = " << error; 2932a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_SUCCESS == sr) { 2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (CapturedFrame::kFrameHeaderSize != bytes_read) { 2952a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org return rtc::SR_EOS; 2960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 2972a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::ByteBuffer buffer(header, CapturedFrame::kFrameHeaderSize); 2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt32(reinterpret_cast<uint32*>(&frame->width)); 2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt32(reinterpret_cast<uint32*>(&frame->height)); 3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt32(&frame->fourcc); 3010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt32(&frame->pixel_width); 3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt32(&frame->pixel_height); 3030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt64(reinterpret_cast<uint64*>(&frame->elapsed_time)); 3040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt64(reinterpret_cast<uint64*>(&frame->time_stamp)); 3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org buffer.ReadUInt32(&frame->data_size); 3060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return sr; 3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Executed in the context of FileReadThread. 3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool FileVideoCapturer::ReadFrame(bool first_frame, int* wait_time_ms) { 3132a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org uint32 start_read_time_ms = rtc::Time(); 3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // 1. Signal the previously read frame to downstream. 3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!first_frame) { 3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org captured_frame_.time_stamp = kNumNanoSecsPerMilliSec * 3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org static_cast<int64>(start_read_time_ms); 3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org captured_frame_.elapsed_time = captured_frame_.time_stamp - start_time_ns_; 3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org SignalFrameCaptured(this, &captured_frame_); 3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // 2. Read the next frame. 3242a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SS_CLOSED == video_file_.GetState()) { 3250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "File not opened yet"; 3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // 2.1 Read the frame header. 3292a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org rtc::StreamResult result = ReadFrameHeader(&captured_frame_); 3302a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_EOS == result) { // Loop back if repeat. 3312a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (repeat_ != rtc::kForever) { 3320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (repeat_ > 0) { 3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org --repeat_; 3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } else { 3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 3360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (video_file_.SetPosition(0)) { 3400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org result = ReadFrameHeader(&captured_frame_); 3410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3432a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_SUCCESS != result) { 3440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to read the frame header"; 3450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 3460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // 2.2 Reallocate memory for the frame data if necessary. 3480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (frame_buffer_size_ < captured_frame_.data_size) { 3490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org frame_buffer_size_ = captured_frame_.data_size; 3501a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org delete[] static_cast<char*>(captured_frame_.data); 3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org captured_frame_.data = new char[frame_buffer_size_]; 3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // 2.3 Read the frame adata. 3542a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org if (rtc::SR_SUCCESS != video_file_.Read(captured_frame_.data, 3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org captured_frame_.data_size, 3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org NULL, NULL)) { 3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org LOG(LS_ERROR) << "Failed to read frame data"; 3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return false; 3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // 3. Decide how long to wait for the next frame. 3620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *wait_time_ms = 0; 3630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // If the capture format's interval is not kMinimumInterval, we use it to 3650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // control the rate; otherwise, we use the timestamp in the file to control 3660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // the rate. 3670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (!first_frame && !ignore_framerate_) { 3680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int64 interval_ns = 3690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org GetCaptureFormat()->interval > VideoFormat::kMinimumInterval ? 3700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org GetCaptureFormat()->interval : 3710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org captured_frame_.time_stamp - last_frame_timestamp_ns_; 3720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org int interval_ms = static_cast<int>(interval_ns / kNumNanoSecsPerMilliSec); 3732a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org interval_ms -= rtc::Time() - start_read_time_ms; 3740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org if (interval_ms > 0) { 3750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *wait_time_ms = interval_ms; 3760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org } 3780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org // Keep the original timestamp read from the file. 3790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org last_frame_timestamp_ns_ = captured_frame_.time_stamp; 3800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org return true; 3810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} 3820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org 3830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org} // namespace cricket 384