diff --git a/webrtc/tools/frame_cutter/frame_cutter.cc b/webrtc/tools/frame_cutter/frame_cutter.cc new file mode 100644 index 0000000000..f89bbf3783 --- /dev/null +++ b/webrtc/tools/frame_cutter/frame_cutter.cc @@ -0,0 +1,86 @@ +/* + * 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 "webrtc/tools/frame_cutter/frame_cutter_lib.h" + +#include +#include +#include + +#include "webrtc/tools/simple_command_line_parser.h" + +// A command-line tool to edit a YUV-video (I420 sub-sampled). +int main(int argc, char** argv) { + std::string program_name = argv[0]; + std::string usage = "Deletes a series of frames in a yuv file. " + "Only I420 is supported!\n" + "Example usage:\n" + program_name + + " --in_path=input.yuv --width=320 --height=240 --f=60 --l=120 " + "--out_path=edited_clip.yuv\n" + "Command line flags:\n" + " --in_path(string): Path and filename to the input file\n" + " -- width(int): Width in pixels of the frames in the input file." + " Default: -1\n" + " -- height(int): Height in pixels of the frames in the input file." + " Default: -1\n" + " -- f(int): First frame to cut.\n" + " Default: -1\n" + " -- l(int): Last frame to cut.\n" + " Default: -1\n" + " -- out_path(string): The output file to which frames are written." + " Default: output.yuv\n"; + + webrtc::test::CommandLineParser parser; + + // Init the parser and set the usage message + parser.Init(argc, argv); + parser.SetUsageMessage(usage); + + parser.SetFlag("in_path", "-1"); + parser.SetFlag("width", "-1"); + parser.SetFlag("height", "-1"); + parser.SetFlag("f", "-1"); + parser.SetFlag("l", "-1"); + parser.SetFlag("out_path", "edited_output.yuv"); + parser.SetFlag("help", "false"); + + parser.ProcessFlags(); + if (parser.GetFlag("help") == "true") { + parser.PrintUsageMessage(); + } + parser.PrintEnteredFlags(); + + const char* in_path = parser.GetFlag("in_path").c_str(); + int width = strtol((parser.GetFlag("width")).c_str(), NULL, 10); + int height = strtol((parser.GetFlag("height")).c_str(), NULL, 10); + int first_frame_to_cut = strtol((parser.GetFlag("f")).c_str(), NULL, 10); + int last_frame_to_cut = strtol((parser.GetFlag("l")).c_str(), NULL, 10); + + const char* out_path = parser.GetFlag("out_path").c_str(); + + if (!strcmp(in_path, "-1")) { + fprintf(stderr, "You must specify a file to edit\n"); + return -1; + } + + if (first_frame_to_cut <= 0 || last_frame_to_cut <= 0) { + fprintf(stderr, "Error: You must specify which frames to cut!\n"); + return -2; + } + + if (width <= 0 || height <= 0) { + fprintf(stderr, "Error: width or height cannot be <= 0!\n"); + return -3; + } + + return webrtc::FrameCutter(in_path, width, height, first_frame_to_cut, + last_frame_to_cut, out_path); +} + diff --git a/webrtc/tools/frame_cutter/frame_cutter_lib.cc b/webrtc/tools/frame_cutter/frame_cutter_lib.cc new file mode 100644 index 0000000000..c387cd4bce --- /dev/null +++ b/webrtc/tools/frame_cutter/frame_cutter_lib.cc @@ -0,0 +1,74 @@ +/* + * 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 +#include + +#include + +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/typedefs.h" + +using std::string; + +namespace webrtc { + +int FrameCutter(const string& in_path, int width, int height, + int first_frame_to_cut, int last_frame_to_cut, + const string& out_path) { + if (last_frame_to_cut < first_frame_to_cut) { + fprintf(stderr, "The set of frames to cut is empty! (l < f)\n"); + return -10; + } + + FILE* in_fid = fopen(in_path.c_str() , "r"); + if (!in_fid) { + fprintf(stderr, "Could not read input file: %s.\n", in_path.c_str()); + return -11; + } + + // Frame size of I420. + int frame_length = CalcBufferSize(kI420, width, height); + + webrtc::scoped_array temp_buffer(new uint8_t[frame_length]); + + FILE* out_fid = fopen(out_path.c_str(), "w"); + + if (!out_fid) { + fprintf(stderr, "Could not open output file: %s.\n", out_path.c_str()); + return -12; + } + + int num_frames_read = 0; + int num_bytes_read; + + while ((num_bytes_read = fread(temp_buffer.get(), 1, frame_length, in_fid)) + == frame_length) { + if ((num_frames_read < first_frame_to_cut) || + (last_frame_to_cut < num_frames_read)) { + fwrite(temp_buffer.get(), 1, frame_length, out_fid); + num_frames_read++; + } else { + num_frames_read++; + } + } + if (num_bytes_read > 0 && num_bytes_read < frame_length) { + printf("Frame to small! Last frame truncated.\n"); + } + + fclose(in_fid); + fclose(out_fid); + + printf("Done editing!\n"); + return 0; +} +} + diff --git a/webrtc/tools/frame_cutter/frame_cutter_lib.h b/webrtc/tools/frame_cutter/frame_cutter_lib.h new file mode 100644 index 0000000000..295a5f0f83 --- /dev/null +++ b/webrtc/tools/frame_cutter/frame_cutter_lib.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#ifndef WEBRTC_TOOLS_FRAME_CUTTER_FRAME_CUTTER_H_ +#define WEBRTC_TOOLS_FRAME_CUTTER_FRAME_CUTTER_H_ + +#include + +namespace webrtc { + +// Frame numbering starts at 1. The set of frames to be cut includes the frame +// with the number: first_frame_to_cut and last_frame_to_cut. I.e if one clip +// has 10 frames (1 to 10), and you specify first_frame_to_cut = 4 and +// last_frame_to_cut = 7, then you will get a clip that contains frame 1, 2, 3, +// 8, 9 and 10. +int FrameCutter(const std::string& in_path, int width, int height, + int first_frame_to_cut, int last_frame_to_cut, + const std::string& out_path); +} + +#endif // WEBRTC_TOOLS_FRAME_CUTTER_FRAME_CUTTER_H_ diff --git a/webrtc/tools/frame_cutter/frame_cutter_unittest.cc b/webrtc/tools/frame_cutter/frame_cutter_unittest.cc new file mode 100644 index 0000000000..a58cc3b98a --- /dev/null +++ b/webrtc/tools/frame_cutter/frame_cutter_unittest.cc @@ -0,0 +1,104 @@ +/* + * 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 + +#include + +#include "gtest/gtest.h" +#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/test/testsupport/fileutils.h" +#include "webrtc/tools/frame_cutter/frame_cutter_lib.h" + +using webrtc::CalcBufferSize; +using webrtc::FrameCutter; +using webrtc::kI420; +using webrtc::scoped_array; +using webrtc::test::OutputPath; +using webrtc::test::ResourcePath; + +namespace webrtc { +namespace test { + +const int width = 352; +const int height = 288; + +const std::string ref_video = ResourcePath("foreman_cif", "yuv"); +const std::string test_video = OutputPath() + "testvideo.yuv"; + +int num_bytes_read; + +TEST(FrameCutterUnittest, ValidInPath) { + const int first_frame_to_cut = 160; + const int last_frame_to_cut = 240; + + int result = FrameCutter(ref_video, width, height, first_frame_to_cut, + last_frame_to_cut, test_video); + EXPECT_EQ(0, result); + + FILE* ref_video_fid = fopen(ref_video.c_str(), "r"); + ASSERT_TRUE(ref_video_fid != NULL); + FILE* test_video_fid = fopen(test_video.c_str(), "r"); + ASSERT_TRUE(test_video_fid != NULL); + + const int frame_size =CalcBufferSize(kI420, width, height); + + scoped_array ref_buffer(new int[frame_size]); + scoped_array test_buffer(new int[frame_size]); + + for (int i = 0; i < first_frame_to_cut; ++i) { + num_bytes_read = fread(ref_buffer.get(), frame_size, 1, ref_video_fid); + EXPECT_EQ(frame_size, num_bytes_read); + + num_bytes_read = fread(test_buffer.get(), frame_size, 1, test_video_fid); + EXPECT_EQ(frame_size, num_bytes_read); + + EXPECT_EQ(0, memcmp(ref_buffer.get(), test_buffer.get(), frame_size)); + } + // Do not compare the frames that have been cut. + for (int i = first_frame_to_cut; i <= last_frame_to_cut; ++i) { + num_bytes_read = fread(&ref_buffer, frame_size, 1, ref_video_fid); + EXPECT_EQ(frame_size, num_bytes_read); + } + + while (!feof(test_video_fid)) { + num_bytes_read = fread(&ref_buffer, frame_size, 1, ref_video_fid); + EXPECT_EQ(frame_size, num_bytes_read); + num_bytes_read = fread(&test_buffer, frame_size, 1, test_video_fid); + EXPECT_EQ(frame_size, num_bytes_read); + EXPECT_EQ(0, memcmp(ref_buffer.get(), test_buffer.get(), frame_size)); + } + bool are_both_files_at_the_end = + (feof(test_video_fid) && feof(test_video_fid)); + EXPECT_TRUE(are_both_files_at_the_end); +} + +TEST(FrameCutterUnittest, EmptySetToCut) { + int first_frame_to_cut = 2; + int last_frame_to_cut = 1; + + int result = FrameCutter(ref_video, width, height, first_frame_to_cut, + last_frame_to_cut, test_video); + EXPECT_EQ(-10, result); +} + +TEST(FrameCutterUnittest, InValidInPath) { + const std::string ref_video = "PATH/THAT/DOES/NOT/EXIST"; + + int first_frame_to_cut = 30; + int last_frame_to_cut = 120; + + int result = FrameCutter(ref_video, width, height, first_frame_to_cut, + last_frame_to_cut, test_video); + EXPECT_EQ(-11, result); +} +} +} diff --git a/webrtc/tools/tools.gyp b/webrtc/tools/tools.gyp index bff24a5349..8c2d100327 100644 --- a/webrtc/tools/tools.gyp +++ b/webrtc/tools/tools.gyp @@ -84,5 +84,45 @@ 'converter/rgba_to_i420_converter.cc', ], }, # rgba_to_i420_converter + { + 'target_name': 'frame_cutter_lib', + 'type': '<(library)', + 'dependencies': [ + '<(DEPTH)/webrtc/common_video/common_video.gyp:common_video', + ], + 'sources': [ + 'frame_cutter/frame_cutter_lib.cc', + 'frame_cutter/frame_cutter_lib.h', + ], + }, # frame_cutter_lib + { + 'target_name': 'frame_cutter', + 'type': 'executable', + 'dependencies': [ + 'command_line_parser', + 'frame_cutter_lib', + ], + 'sources': [ + 'frame_cutter/frame_cutter.cc', + ], + }, # frame_cutter ], + 'conditions': [ + ['include_tests==1', { + 'targets' : [ + { + 'target_name': 'tools_unittests', + 'type': 'executable', + 'dependencies': [ + 'frame_cutter_lib', + '<(webrtc_root)/test/test.gyp:test_support_main', + '<(DEPTH)/testing/gtest.gyp:gtest', + ], + 'sources': [ + 'frame_cutter/frame_cutter_unittest.cc', + ], + }, # tools_unittests + ], # targets + }], # include_tests + ], # conditions }