diff --git a/webrtc/tools/frame_cutter/frame_cutter.cc b/webrtc/tools/frame_cutter/frame_cutter.cc index f89bbf3783..a1550d0275 100644 --- a/webrtc/tools/frame_cutter/frame_cutter.cc +++ b/webrtc/tools/frame_cutter/frame_cutter.cc @@ -19,22 +19,31 @@ // 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" + 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" + " --in_path=input.yuv --width=320 --height=240 --f=60 --interval=1 --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." + "--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." + "--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." + "--f(int): First frame to cut.\n" + " Default: -1\n" + "--interval(int): Set to 1 if every frame between f and l should be " + "deleted. Set it to 2 if every second frame should be deleted, " + "and so on...Frame numbering between the limits start with 1 and frames " + "read between and including the limits with number n where " + "n % interval != 0 will be kept.\n" + "Example: If the clip have frames with the numbers 1 to 10, and you set f=2" + " , l=7 and interval=2, then the output clip will contain the frames with " + " number 1, 2, 4, 6, 8, 9, 10." + " Default: 1\n" + "--l(int): Last frame to cut." + " Default: -1\n" + " --out_path(string): The output file to which frames are written." " Default: output.yuv\n"; webrtc::test::CommandLineParser parser; @@ -47,6 +56,7 @@ int main(int argc, char** argv) { parser.SetFlag("width", "-1"); parser.SetFlag("height", "-1"); parser.SetFlag("f", "-1"); + parser.SetFlag("interval", "1"); parser.SetFlag("l", "-1"); parser.SetFlag("out_path", "edited_output.yuv"); parser.SetFlag("help", "false"); @@ -61,6 +71,7 @@ int main(int argc, char** argv) { 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 interval = strtol((parser.GetFlag("interval")).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(); @@ -80,7 +91,7 @@ int main(int argc, char** argv) { return -3; } - return webrtc::FrameCutter(in_path, width, height, first_frame_to_cut, - last_frame_to_cut, out_path); + return webrtc::CutFrames(in_path, width, height, first_frame_to_cut, + interval, 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 index 33597bf3cf..748970f0ec 100644 --- a/webrtc/tools/frame_cutter/frame_cutter_lib.cc +++ b/webrtc/tools/frame_cutter/frame_cutter_lib.cc @@ -21,9 +21,10 @@ 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) { +int CutFrames(const string& in_path, int width, int height, + int first_frame_to_cut, int interval, 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; @@ -44,20 +45,25 @@ int FrameCutter(const string& in_path, int width, int height, if (!out_fid) { fprintf(stderr, "Could not open output file: %s.\n", out_path.c_str()); + fclose(in_fid); return -12; } int num_frames_read = 0; + int num_frames_read_between = 0; int num_bytes_read; while ((num_bytes_read = fread(temp_buffer.get(), 1, frame_length, in_fid)) == frame_length) { + num_frames_read++; 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++; + num_frames_read_between++; + if (num_frames_read_between % interval != 0) { + fwrite(temp_buffer.get(), 1, frame_length, out_fid); + } } } if (num_bytes_read > 0 && num_bytes_read < frame_length) { diff --git a/webrtc/tools/frame_cutter/frame_cutter_lib.h b/webrtc/tools/frame_cutter/frame_cutter_lib.h index 295a5f0f83..978e105eb0 100644 --- a/webrtc/tools/frame_cutter/frame_cutter_lib.h +++ b/webrtc/tools/frame_cutter/frame_cutter_lib.h @@ -17,11 +17,15 @@ 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, +// has 10 frames (1 to 10), and you specify first_frame_to_cut = 4, +// last_frame_to_cut = 7 and interval = 1, then you will get a clip that +// contains frame 1, 2, 3, 8, 9 and 10. +// Interval specifies with what interval frames should be cut. I.e if one clip +// has 10 frames (1 to 10), and you specify first_frame_to_cut = 1, +// last_frame_to_cut = 10 and interval = 3, then you will get a clip that +// contains frame 1, 2, 4, 5, 7, 8, 10. +int CutFrames(const std::string& in_path, int width, int height, + int first_frame_to_cut, int interval, int last_frame_to_cut, const std::string& out_path); } diff --git a/webrtc/tools/frame_cutter/frame_cutter_unittest.cc b/webrtc/tools/frame_cutter/frame_cutter_unittest.cc index ad2b588c04..b9701e1920 100644 --- a/webrtc/tools/frame_cutter/frame_cutter_unittest.cc +++ b/webrtc/tools/frame_cutter/frame_cutter_unittest.cc @@ -19,7 +19,7 @@ #include "webrtc/tools/frame_cutter/frame_cutter_lib.h" using webrtc::CalcBufferSize; -using webrtc::FrameCutter; +using webrtc::CutFrames; using webrtc::kI420; using webrtc::scoped_array; using webrtc::test::OutputPath; @@ -28,80 +28,126 @@ using webrtc::test::ResourcePath; namespace webrtc { namespace test { -const int width = 352; -const int height = 288; +const int kWidth = 352; +const int kHeight = 288; -const std::string ref_video = ResourcePath("foreman_cif", "yuv"); -const std::string test_video = OutputPath() + "testvideo.yuv"; +const std::string kRefVideo = ResourcePath("foreman_cif", "yuv"); +const std::string kTestVideo = OutputPath() + "testvideo.yuv"; int num_bytes_read; -TEST(FrameCutterUnittest, ValidInPath) { - const int first_frame_to_cut = 160; - const int last_frame_to_cut = 240; +TEST(CutFramesUnittest, ValidInPath) { + const int kFirstFrameToCut = 160; + const int kInterval = 1; + const int kLastFrameToCut = 240; - int result = FrameCutter(ref_video, width, height, first_frame_to_cut, - last_frame_to_cut, test_video); + int result = CutFrames(kRefVideo, kWidth, kHeight, kFirstFrameToCut, + kInterval, kLastFrameToCut, kTestVideo); EXPECT_EQ(0, result); - FILE* ref_video_fid = fopen(ref_video.c_str(), "rb"); + FILE* ref_video_fid = fopen(kRefVideo.c_str(), "rb"); ASSERT_TRUE(ref_video_fid != NULL); - FILE* test_video_fid = fopen(test_video.c_str(), "rb"); + FILE* test_video_fid = fopen(kTestVideo.c_str(), "rb"); ASSERT_TRUE(test_video_fid != NULL); - const int frame_size =CalcBufferSize(kI420, width, height); + const int kFrameSize = CalcBufferSize(kI420, kWidth, kHeight); - scoped_array ref_buffer(new int[frame_size]); - scoped_array test_buffer(new int[frame_size]); + scoped_array ref_buffer(new int[kFrameSize]); + scoped_array test_buffer(new int[kFrameSize]); - for (int i = 0; i < first_frame_to_cut; ++i) { - num_bytes_read = fread(ref_buffer.get(), 1, frame_size, ref_video_fid); - EXPECT_EQ(frame_size, num_bytes_read); + for (int i = 1; i < kFirstFrameToCut; ++i) { + num_bytes_read = fread(ref_buffer.get(), 1, kFrameSize, ref_video_fid); + EXPECT_EQ(kFrameSize, num_bytes_read); - num_bytes_read = fread(test_buffer.get(), 1, frame_size, test_video_fid); - EXPECT_EQ(frame_size, num_bytes_read); + num_bytes_read = fread(test_buffer.get(), 1, kFrameSize, test_video_fid); + EXPECT_EQ(kFrameSize, num_bytes_read); - EXPECT_EQ(0, memcmp(ref_buffer.get(), test_buffer.get(), frame_size)); + EXPECT_EQ(0, memcmp(ref_buffer.get(), test_buffer.get(), kFrameSize)); } // 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.get(), 1, frame_size, ref_video_fid); - EXPECT_EQ(frame_size, num_bytes_read); + for (int i = kFirstFrameToCut; i <= kLastFrameToCut; ++i) { + num_bytes_read = fread(ref_buffer.get(), 1, kFrameSize, ref_video_fid); + EXPECT_EQ(kFrameSize, num_bytes_read); } while (!feof(test_video_fid) && !feof(ref_video_fid)) { - num_bytes_read = fread(ref_buffer.get(), 1, frame_size, ref_video_fid); + num_bytes_read = fread(ref_buffer.get(), 1, kFrameSize, ref_video_fid); if (!feof(ref_video_fid)) { - EXPECT_EQ(frame_size, num_bytes_read); + EXPECT_EQ(kFrameSize, num_bytes_read); } - num_bytes_read = fread(test_buffer.get(), 1, frame_size, test_video_fid); + num_bytes_read = fread(test_buffer.get(), 1, kFrameSize, test_video_fid); if (!feof(test_video_fid)) { - EXPECT_EQ(frame_size, num_bytes_read); + EXPECT_EQ(kFrameSize, num_bytes_read); } if (!feof(test_video_fid) && !feof(test_video_fid)) { - EXPECT_EQ(0, memcmp(ref_buffer.get(), test_buffer.get(), frame_size)); + EXPECT_EQ(0, memcmp(ref_buffer.get(), test_buffer.get(), kFrameSize)); } } + fclose(ref_video_fid); + fclose(test_video_fid); } -TEST(FrameCutterUnittest, EmptySetToCut) { - int first_frame_to_cut = 2; - int last_frame_to_cut = 1; +TEST(CutFramesUnittest, EmptySetToCut) { + const int kFirstFrameToCut = 2; + const int kInterval = 1; + const int kLastFrameToCut = 1; - int result = FrameCutter(ref_video, width, height, first_frame_to_cut, - last_frame_to_cut, test_video); + int result = CutFrames(kRefVideo, kWidth, kHeight, kFirstFrameToCut, + kInterval, kLastFrameToCut, kTestVideo); EXPECT_EQ(-10, result); } -TEST(FrameCutterUnittest, InValidInPath) { - const std::string ref_video = "PATH/THAT/DOES/NOT/EXIST"; +TEST(CutFramesUnittest, InValidInPath) { + const std::string kRefVideo = "PATH/THAT/DOES/NOT/EXIST"; - int first_frame_to_cut = 30; - int last_frame_to_cut = 120; + const int kFirstFrameToCut = 30; + const int kInterval = 1; + const int kLastFrameToCut = 120; - int result = FrameCutter(ref_video, width, height, first_frame_to_cut, - last_frame_to_cut, test_video); + int result = CutFrames(kRefVideo, kWidth, kHeight, kFirstFrameToCut, + kInterval, kLastFrameToCut, kTestVideo); EXPECT_EQ(-11, result); } + +TEST(CutFramesUnitTest, DeletingEverySecondFrame) { + const int kFirstFrameToCut = 1; + const int kInterval = 2; + const int kLastFrameToCut = 10000; + // Set kLastFrameToCut to a large value so that all frame are processed. + int result = CutFrames(kRefVideo, kWidth, kHeight, kFirstFrameToCut, + kInterval, kLastFrameToCut, kTestVideo); + EXPECT_EQ(0, result); + + FILE* original_fid = fopen(kRefVideo.c_str(), "rb"); + ASSERT_TRUE(original_fid != NULL); + FILE* edited_fid = fopen(kTestVideo.c_str(), "rb"); + ASSERT_TRUE(edited_fid != NULL); + + const int kFrameSize = CalcBufferSize(kI420, kWidth, kHeight); + + scoped_array original_buffer(new int[kFrameSize]); + scoped_array edited_buffer(new int[kFrameSize]); + + int num_frames_read = 0; + + while (!feof(original_fid) && !feof(edited_fid)) { + num_bytes_read = + fread(original_buffer.get(), 1, kFrameSize, original_fid); + if (!feof(original_fid)) { + EXPECT_EQ(kFrameSize, num_bytes_read); + num_frames_read++; + } + if (num_frames_read % kInterval != 0) { + num_bytes_read = fread(edited_buffer.get(), 1, kFrameSize, edited_fid); + if (!feof(edited_fid)) { + EXPECT_EQ(kFrameSize, num_bytes_read); + } + if (!feof(original_fid) && !feof(edited_fid)) { + EXPECT_EQ(0, memcmp(original_buffer.get(), + edited_buffer.get(), kFrameSize)); + } + } + } +} } }