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