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
11#include <stdio.h>
12#include <stdlib.h>
13
14#include <fstream>
15
16#include "testing/gtest/include/gtest/gtest.h"
17#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
18#include "webrtc/system_wrappers/interface/scoped_ptr.h"
19#include "webrtc/test/testsupport/fileutils.h"
20#include "webrtc/tools/frame_editing/frame_editing_lib.h"
21
22namespace webrtc {
23namespace test {
24
25const int kWidth = 352;
26const int kHeight = 288;
27const int kFrameSize = CalcBufferSize(kI420, kWidth, kHeight);
28
29class FrameEditingTest : public ::testing::Test {
30 protected:
31  virtual void SetUp() {
32    reference_video_ = ResourcePath("foreman_cif", "yuv");
33    test_video_ = OutputPath() + "testvideo.yuv";
34
35    original_fid_ = fopen(reference_video_.c_str(), "rb");
36    ASSERT_TRUE(original_fid_ != NULL);
37
38    // Ensure the output file exists on disk.
39    std::ofstream(test_video_.c_str(), std::ios::out);
40    // Open the output file for reading.
41    // TODO(holmer): Figure out why this file has to be opened here (test fails
42    // if it's opened after the write operation performed in EditFrames).
43    edited_fid_ = fopen(test_video_.c_str(), "rb");
44    ASSERT_TRUE(edited_fid_ != NULL);
45
46    original_buffer_.reset(new int[kFrameSize]);
47    edited_buffer_.reset(new int[kFrameSize]);
48    num_frames_read_ = 0;
49  }
50  virtual void TearDown() {
51    fclose(original_fid_);
52    fclose(edited_fid_);
53  }
54  // Compares the frames in both streams to the end of one of the streams.
55  void CompareToTheEnd(FILE* test_video_fid, FILE* ref_video_fid,
56                       scoped_ptr<int[]>* ref_buffer,
57                       scoped_ptr<int[]>* test_buffer) {
58    while (!feof(test_video_fid) && !feof(ref_video_fid)) {
59      num_bytes_read_ = fread(ref_buffer->get(), 1, kFrameSize, ref_video_fid);
60      if (!feof(ref_video_fid)) {
61        EXPECT_EQ(kFrameSize, num_bytes_read_);
62      }
63      num_bytes_read_ = fread(test_buffer->get(), 1, kFrameSize,
64                              test_video_fid);
65      if (!feof(test_video_fid)) {
66        EXPECT_EQ(kFrameSize, num_bytes_read_);
67      }
68      if (!feof(test_video_fid) && !feof(test_video_fid)) {
69        EXPECT_EQ(0, memcmp(ref_buffer->get(), test_buffer->get(),
70                            kFrameSize));
71      }
72    }
73    // There should not be anything left in either stream.
74    EXPECT_EQ(!feof(test_video_fid), !feof(ref_video_fid));
75  }
76  std::string reference_video_;
77  std::string test_video_;
78  FILE* original_fid_;
79  FILE* edited_fid_;
80  int num_bytes_read_;
81  scoped_ptr<int[]> original_buffer_;
82  scoped_ptr<int[]> edited_buffer_;
83  int num_frames_read_;
84};
85
86TEST_F(FrameEditingTest, ValidInPath) {
87  const int kFirstFrameToProcess = 160;
88  const int kInterval = -1;
89  const int kLastFrameToProcess = 240;
90
91  int result = EditFrames(reference_video_, kWidth, kHeight,
92                          kFirstFrameToProcess, kInterval, kLastFrameToProcess,
93                          test_video_);
94  EXPECT_EQ(0, result);
95
96  for (int i = 1; i < kFirstFrameToProcess; ++i) {
97    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
98                            original_fid_);
99    EXPECT_EQ(kFrameSize, num_bytes_read_);
100
101    num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize, edited_fid_);
102    EXPECT_EQ(kFrameSize, num_bytes_read_);
103
104    EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
105                        kFrameSize));
106  }
107  // Do not compare the frames that have been cut.
108  for (int i = kFirstFrameToProcess; i <= kLastFrameToProcess; ++i) {
109    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
110                            original_fid_);
111    EXPECT_EQ(kFrameSize, num_bytes_read_);
112  }
113  CompareToTheEnd(edited_fid_, original_fid_, &original_buffer_,
114                  &edited_buffer_);
115}
116
117TEST_F(FrameEditingTest, EmptySetToCut) {
118  const int kFirstFrameToProcess = 2;
119  const int kInterval = -1;
120  const int kLastFrameToProcess = 1;
121
122  int result = EditFrames(reference_video_, kWidth, kHeight,
123                          kFirstFrameToProcess, kInterval, kLastFrameToProcess,
124                          test_video_);
125  EXPECT_EQ(-10, result);
126}
127
128TEST_F(FrameEditingTest, InValidInPath) {
129  const std::string kRefVideo_ = "PATH/THAT/DOES/NOT/EXIST";
130
131  const int kFirstFrameToProcess = 30;
132  const int kInterval = 1;
133  const int kLastFrameToProcess = 120;
134
135  int result = EditFrames(kRefVideo_, kWidth, kHeight, kFirstFrameToProcess,
136                          kInterval, kLastFrameToProcess, test_video_);
137  EXPECT_EQ(-11, result);
138}
139
140TEST_F(FrameEditingTest, DeletingEverySecondFrame) {
141  const int kFirstFrameToProcess = 1;
142  const int kInterval = -2;
143  const int kLastFrameToProcess = 10000;
144  // Set kLastFrameToProcess to a large value so that all frame are processed.
145  int result = EditFrames(reference_video_, kWidth, kHeight,
146                          kFirstFrameToProcess, kInterval, kLastFrameToProcess,
147                          test_video_);
148  EXPECT_EQ(0, result);
149
150  while (!feof(original_fid_) && !feof(edited_fid_)) {
151    num_bytes_read_ =
152        fread(original_buffer_.get(), 1, kFrameSize, original_fid_);
153    if (!feof(original_fid_)) {
154      EXPECT_EQ(kFrameSize, num_bytes_read_);
155      num_frames_read_++;
156    }
157    // We want to compare every second frame of the original to the edited.
158    // kInterval=-2 and (num_frames_read_ - 1) % kInterval  will be -1 for
159    // every second frame.
160    // num_frames_read_ - 1 because we have deleted frame number 2, 4 , 6 etc.
161    if ((num_frames_read_ - 1) % kInterval == -1) {
162      num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize,
163                              edited_fid_);
164      if (!feof(edited_fid_)) {
165        EXPECT_EQ(kFrameSize, num_bytes_read_);
166      }
167      if (!feof(original_fid_) && !feof(edited_fid_)) {
168        EXPECT_EQ(0, memcmp(original_buffer_.get(),
169                            edited_buffer_.get(), kFrameSize));
170      }
171    }
172  }
173}
174
175TEST_F(FrameEditingTest, RepeatFrames) {
176  const int kFirstFrameToProcess = 160;
177  const int kInterval = 2;
178  const int kLastFrameToProcess = 240;
179
180  int result = EditFrames(reference_video_, kWidth, kHeight,
181                          kFirstFrameToProcess, kInterval, kLastFrameToProcess,
182                          test_video_);
183  EXPECT_EQ(0, result);
184
185  for (int i = 1; i < kFirstFrameToProcess; ++i) {
186    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
187                            original_fid_);
188    EXPECT_EQ(kFrameSize, num_bytes_read_);
189
190    num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize, edited_fid_);
191    EXPECT_EQ(kFrameSize, num_bytes_read_);
192
193    EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
194                        kFrameSize));
195  }
196  // Do not compare the frames that have been repeated.
197  for (int i = kFirstFrameToProcess; i <= kLastFrameToProcess; ++i) {
198    num_bytes_read_ = fread(original_buffer_.get(), 1, kFrameSize,
199                            original_fid_);
200    EXPECT_EQ(kFrameSize, num_bytes_read_);
201    for (int i = 1; i <= kInterval; ++i) {
202      num_bytes_read_ = fread(edited_buffer_.get(), 1, kFrameSize,
203                              edited_fid_);
204      EXPECT_EQ(kFrameSize, num_bytes_read_);
205      EXPECT_EQ(0, memcmp(original_buffer_.get(), edited_buffer_.get(),
206                          kFrameSize));
207    }
208  }
209  CompareToTheEnd(edited_fid_, original_fid_, &original_buffer_,
210                  &edited_buffer_);
211}
212}  // namespace test
213}  // namespace webrtc
214