/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "video_engine/test/libvietest/include/vie_file_capture_device.h"

#include <assert.h>

#include "common_types.h"
#include "modules/interface/module_common_types.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/event_wrapper.h"
#include "system_wrappers/interface/tick_util.h"
#include "video_engine/include/vie_capture.h"

// This class ensures we are not exceeding the max FPS.
class FramePacemaker {
 public:
  explicit FramePacemaker(uint32_t max_fps)
      : time_per_frame_ms_(1000 / max_fps) {
    frame_start_ = webrtc::TickTime::MillisecondTimestamp();
  }

  void SleepIfNecessary(webrtc::EventWrapper* sleeper) {
    uint64_t now = webrtc::TickTime::MillisecondTimestamp();
    if (now - frame_start_ < time_per_frame_ms_) {
      sleeper->Wait(time_per_frame_ms_ - (now - frame_start_));
    }
  }

 private:
  uint64_t frame_start_;
  uint64_t time_per_frame_ms_;
};

ViEFileCaptureDevice::ViEFileCaptureDevice(
    webrtc::ViEExternalCapture* input_sink)
    : input_sink_(input_sink),
      input_file_(NULL) {
  mutex_ = webrtc::CriticalSectionWrapper::CreateCriticalSection();
}

ViEFileCaptureDevice::~ViEFileCaptureDevice() {
  delete mutex_;
}

bool ViEFileCaptureDevice::OpenI420File(const std::string& path,
                                        int width,
                                        int height) {
  webrtc::CriticalSectionScoped cs(mutex_);
  assert(input_file_ == NULL);

  input_file_ = std::fopen(path.c_str(), "rb");
  if (input_file_ == NULL) {
    return false;
  }

  frame_length_ = 3 * width * height / 2;
  width_  = width;
  height_ = height;
  return true;
}

void ViEFileCaptureDevice::ReadFileFor(uint64_t time_slice_ms,
                                       uint32_t max_fps) {
  webrtc::CriticalSectionScoped cs(mutex_);
  assert(input_file_ != NULL);

  unsigned char* frame_buffer = new unsigned char[frame_length_];

  webrtc::EventWrapper* sleeper = webrtc::EventWrapper::Create();

  uint64_t start_time_ms = webrtc::TickTime::MillisecondTimestamp();
  uint64_t elapsed_ms = 0;

  while (elapsed_ms < time_slice_ms) {
    FramePacemaker pacemaker(max_fps);
    int read = std::fread(frame_buffer, 1, frame_length_, input_file_);

    if (std::feof(input_file_)) {
      std::rewind(input_file_);
    }
    input_sink_->IncomingFrame(frame_buffer, read, width_, height_,
                               webrtc::kVideoI420,
                               webrtc::TickTime::MillisecondTimestamp());

    pacemaker.SleepIfNecessary(sleeper);
    elapsed_ms = webrtc::TickTime::MillisecondTimestamp() - start_time_ms;
  }

  delete sleeper;
  delete[] frame_buffer;
}

void ViEFileCaptureDevice::CloseFile() {
  webrtc::CriticalSectionScoped cs(mutex_);
  assert(input_file_ != NULL);

  std::fclose(input_file_);
}
