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