1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10#include "webrtc/video_engine/test/libvietest/include/vie_file_capture_device.h"
11
12#include <assert.h>
13
14#include "webrtc/common_types.h"
15#include "webrtc/modules/interface/module_common_types.h"
16#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
17#include "webrtc/system_wrappers/interface/event_wrapper.h"
18#include "webrtc/system_wrappers/interface/tick_util.h"
19#include "webrtc/video_engine/include/vie_capture.h"
20
21// This class ensures we are not exceeding the max FPS.
22class FramePacemaker {
23 public:
24  explicit FramePacemaker(uint32_t max_fps)
25      : time_per_frame_ms_(1000 / max_fps) {
26    frame_start_ = webrtc::TickTime::MillisecondTimestamp();
27  }
28
29  void SleepIfNecessary(webrtc::EventWrapper* sleeper) {
30    uint64_t now = webrtc::TickTime::MillisecondTimestamp();
31    if (now - frame_start_ < time_per_frame_ms_) {
32      sleeper->Wait(time_per_frame_ms_ - (now - frame_start_));
33    }
34  }
35
36 private:
37  uint64_t frame_start_;
38  uint64_t time_per_frame_ms_;
39};
40
41ViEFileCaptureDevice::ViEFileCaptureDevice(
42    webrtc::ViEExternalCapture* input_sink)
43    : input_sink_(input_sink),
44      input_file_(NULL) {
45  mutex_ = webrtc::CriticalSectionWrapper::CreateCriticalSection();
46}
47
48ViEFileCaptureDevice::~ViEFileCaptureDevice() {
49  delete mutex_;
50}
51
52bool ViEFileCaptureDevice::OpenI420File(const std::string& path,
53                                        int width,
54                                        int height) {
55  webrtc::CriticalSectionScoped cs(mutex_);
56  assert(input_file_ == NULL);
57
58  input_file_ = fopen(path.c_str(), "rb");
59  if (input_file_ == NULL) {
60    return false;
61  }
62
63  frame_length_ = 3 * width * height / 2;
64  width_  = width;
65  height_ = height;
66  return true;
67}
68
69void ViEFileCaptureDevice::ReadFileFor(uint64_t time_slice_ms,
70                                       uint32_t max_fps) {
71  webrtc::CriticalSectionScoped cs(mutex_);
72  assert(input_file_ != NULL);
73
74  unsigned char* frame_buffer = new unsigned char[frame_length_];
75
76  webrtc::EventWrapper* sleeper = webrtc::EventWrapper::Create();
77
78  uint64_t start_time_ms = webrtc::TickTime::MillisecondTimestamp();
79  uint64_t elapsed_ms = 0;
80
81  while (elapsed_ms < time_slice_ms) {
82    FramePacemaker pacemaker(max_fps);
83    int read = fread(frame_buffer, 1, frame_length_, input_file_);
84
85    if (feof(input_file_)) {
86      rewind(input_file_);
87    }
88    input_sink_->IncomingFrame(frame_buffer, read, width_, height_,
89                               webrtc::kVideoI420,
90                               webrtc::TickTime::MillisecondTimestamp());
91
92    pacemaker.SleepIfNecessary(sleeper);
93    elapsed_ms = webrtc::TickTime::MillisecondTimestamp() - start_time_ms;
94  }
95
96  delete sleeper;
97  delete[] frame_buffer;
98}
99
100void ViEFileCaptureDevice::CloseFile() {
101  webrtc::CriticalSectionScoped cs(mutex_);
102  assert(input_file_ != NULL);
103
104  fclose(input_file_);
105}
106