mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
Add WriteVideoToFile to video_file_reader.
The function checks the file extension to determine YUV or Y4M format. Also adds a flag aligned_output_file to compare_videos.py, which allows saving the aligned reference video to a file. Bug: webrtc:9642 Change-Id: Ia59f5c123a1e41104756eb6b235b6581c4ffbd77 Reviewed-on: https://webrtc-review.googlesource.com/99503 Reviewed-by: Sami Kalliomäki <sakal@webrtc.org> Reviewed-by: Patrik Höglund <phoglund@webrtc.org> Commit-Queue: Paulina Hensman <phensman@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24787}
This commit is contained in:
parent
5773ad3bc8
commit
b671d46f91
8 changed files with 267 additions and 3 deletions
|
@ -73,6 +73,20 @@ rtc_static_library("video_file_reader") {
|
|||
]
|
||||
}
|
||||
|
||||
rtc_static_library("video_file_writer") {
|
||||
sources = [
|
||||
"video_file_writer.cc",
|
||||
"video_file_writer.h",
|
||||
]
|
||||
deps = [
|
||||
":video_file_reader",
|
||||
"../api/video:video_frame",
|
||||
"../api/video:video_frame_i420",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_static_library("video_quality_analysis") {
|
||||
sources = [
|
||||
"frame_analyzer/video_quality_analysis.cc",
|
||||
|
@ -101,6 +115,7 @@ rtc_executable("frame_analyzer") {
|
|||
deps = [
|
||||
":command_line_parser",
|
||||
":video_file_reader",
|
||||
":video_file_writer",
|
||||
":video_quality_analysis",
|
||||
"../rtc_base:stringutils",
|
||||
"../test:perf_test",
|
||||
|
@ -343,6 +358,7 @@ if (rtc_include_tests) {
|
|||
"sanitizers_unittest.cc",
|
||||
"simple_command_line_parser_unittest.cc",
|
||||
"video_file_reader_unittest.cc",
|
||||
"video_file_writer_unittest.cc",
|
||||
]
|
||||
|
||||
if (!build_with_chromium && is_clang) {
|
||||
|
@ -355,6 +371,7 @@ if (rtc_include_tests) {
|
|||
":frame_editing_lib",
|
||||
":reference_less_video_analysis_lib",
|
||||
":video_file_reader",
|
||||
":video_file_writer",
|
||||
":video_quality_analysis",
|
||||
"../common_video:common_video",
|
||||
"../rtc_base",
|
||||
|
|
|
@ -36,6 +36,8 @@ def _ParseArgs():
|
|||
'video (YUV).'))
|
||||
parser.add_option('--frame_analyzer', type='string',
|
||||
help='Path to the frame analyzer executable.')
|
||||
parser.add_option('--aligned_output_file', type='string',
|
||||
help='Path for output aligned YUV or Y4M file.')
|
||||
parser.add_option('--barcode_decoder', type='string',
|
||||
help=('Path to the barcode decoder script. By default, we '
|
||||
'will assume we can find it in barcode_tools/'
|
||||
|
@ -127,7 +129,7 @@ def main():
|
|||
"""The main function.
|
||||
|
||||
A simple invocation is:
|
||||
./webrtc/rtc_tools/barcode_tools/compare_videos.py
|
||||
./webrtc/rtc_tools/compare_videos.py
|
||||
--ref_video=<path_and_name_of_reference_video>
|
||||
--test_video=<path_and_name_of_test_video>
|
||||
--frame_analyzer=<path_and_name_of_the_frame_analyzer_executable>
|
||||
|
@ -165,6 +167,8 @@ def main():
|
|||
]
|
||||
if options.chartjson_result_file:
|
||||
cmd.append('--chartjson_result_file=%s' % options.chartjson_result_file)
|
||||
if options.aligned_output_file:
|
||||
cmd.append('--aligned_output_file=%s' % options.aligned_output_file)
|
||||
frame_analyzer = subprocess.Popen(cmd, stdin=_DevNull(),
|
||||
stdout=sys.stdout, stderr=sys.stderr)
|
||||
frame_analyzer.wait()
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "rtc_tools/frame_analyzer/video_temporal_aligner.h"
|
||||
#include "rtc_tools/simple_command_line_parser.h"
|
||||
#include "rtc_tools/video_file_reader.h"
|
||||
#include "rtc_tools/video_file_writer.h"
|
||||
#include "test/testsupport/perf_test.h"
|
||||
|
||||
/*
|
||||
|
@ -56,6 +57,9 @@ int main(int argc, char* argv[]) {
|
|||
" Default: test_file.yuv\n"
|
||||
" - chartjson_result_file: Where to store perf result in chartjson"
|
||||
" format. If not present, no perf result will be stored."
|
||||
" Default: None\n"
|
||||
" - aligned_output_file: Where to write aligned YUV/Y4M output file."
|
||||
" If not present, no file will be written."
|
||||
" Default: None\n";
|
||||
|
||||
webrtc::test::CommandLineParser parser;
|
||||
|
@ -69,6 +73,7 @@ int main(int argc, char* argv[]) {
|
|||
parser.SetFlag("label", "MY_TEST");
|
||||
parser.SetFlag("reference_file", "ref.yuv");
|
||||
parser.SetFlag("test_file", "test.yuv");
|
||||
parser.SetFlag("aligned_output_file", "");
|
||||
parser.SetFlag("chartjson_result_file", "");
|
||||
parser.SetFlag("help", "false");
|
||||
|
||||
|
@ -128,6 +133,14 @@ int main(int argc, char* argv[]) {
|
|||
if (!chartjson_result_file.empty()) {
|
||||
webrtc::test::WritePerfResults(chartjson_result_file);
|
||||
}
|
||||
std::string aligned_output_file = parser.GetFlag("aligned_output_file");
|
||||
if (!aligned_output_file.empty()) {
|
||||
rtc::scoped_refptr<webrtc::test::Video> reordered_video =
|
||||
webrtc::test::GenerateAlignedReferenceVideo(reference_video,
|
||||
matching_indices);
|
||||
webrtc::test::WriteVideoToFile(reordered_video, aligned_output_file,
|
||||
/*fps=*/30);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -221,8 +221,14 @@ rtc::scoped_refptr<Video> ReorderVideo(const rtc::scoped_refptr<Video>& video,
|
|||
rtc::scoped_refptr<Video> GenerateAlignedReferenceVideo(
|
||||
const rtc::scoped_refptr<Video>& reference_video,
|
||||
const rtc::scoped_refptr<Video>& test_video) {
|
||||
return ReorderVideo(new LoopingVideo(reference_video),
|
||||
FindMatchingFrameIndices(reference_video, test_video));
|
||||
return GenerateAlignedReferenceVideo(
|
||||
reference_video, FindMatchingFrameIndices(reference_video, test_video));
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<Video> GenerateAlignedReferenceVideo(
|
||||
const rtc::scoped_refptr<Video>& reference_video,
|
||||
const std::vector<size_t>& indices) {
|
||||
return ReorderVideo(new LoopingVideo(reference_video), indices);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
|
|
@ -47,6 +47,11 @@ rtc::scoped_refptr<Video> GenerateAlignedReferenceVideo(
|
|||
const rtc::scoped_refptr<Video>& reference_video,
|
||||
const rtc::scoped_refptr<Video>& test_video);
|
||||
|
||||
// As above, but using precalculated indices.
|
||||
rtc::scoped_refptr<Video> GenerateAlignedReferenceVideo(
|
||||
const rtc::scoped_refptr<Video>& reference_video,
|
||||
const std::vector<size_t>& indices);
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
|
|
66
rtc_tools/video_file_writer.cc
Normal file
66
rtc_tools/video_file_writer.cc
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 "rtc_tools/video_file_writer.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/refcountedobject.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
void WriteVideoToFile(const rtc::scoped_refptr<Video>& video,
|
||||
const std::string& file_name,
|
||||
int fps) {
|
||||
FILE* output_file = fopen(file_name.c_str(), "wb");
|
||||
if (output_file == nullptr) {
|
||||
RTC_LOG(LS_ERROR) << "Could not open file for writing: " << file_name;
|
||||
return;
|
||||
}
|
||||
|
||||
bool isY4m = rtc::ends_with(file_name.c_str(), ".y4m");
|
||||
if (isY4m) {
|
||||
fprintf(output_file, "YUV4MPEG2 W%d H%d F%d:1 C420\n", video->width(),
|
||||
video->height(), fps);
|
||||
}
|
||||
for (size_t i = 0; i < video->number_of_frames(); ++i) {
|
||||
if (isY4m) {
|
||||
std::string frame = "FRAME\n";
|
||||
fwrite(frame.c_str(), 1, 6, output_file);
|
||||
}
|
||||
rtc::scoped_refptr<I420BufferInterface> buffer = video->GetFrame(i);
|
||||
const uint8_t* data_y = buffer->DataY();
|
||||
int stride = buffer->StrideY();
|
||||
for (int i = 0; i < video->height(); ++i) {
|
||||
fwrite(data_y + i * stride, /*size=*/1, stride, output_file);
|
||||
}
|
||||
const uint8_t* data_u = buffer->DataU();
|
||||
stride = buffer->StrideU();
|
||||
for (int i = 0; i < buffer->ChromaHeight(); ++i) {
|
||||
fwrite(data_u + i * stride, /*size=*/1, stride, output_file);
|
||||
}
|
||||
const uint8_t* data_v = buffer->DataV();
|
||||
stride = buffer->StrideV();
|
||||
for (int i = 0; i < buffer->ChromaHeight(); ++i) {
|
||||
fwrite(data_v + i * stride, /*size=*/1, stride, output_file);
|
||||
}
|
||||
}
|
||||
if (ferror(output_file) != 0) {
|
||||
RTC_LOG(LS_ERROR) << "Error writing to file " << file_name;
|
||||
}
|
||||
fclose(output_file);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
30
rtc_tools/video_file_writer.h
Normal file
30
rtc_tools/video_file_writer.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 RTC_TOOLS_VIDEO_FILE_WRITER_H_
|
||||
#define RTC_TOOLS_VIDEO_FILE_WRITER_H_
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/refcount.h"
|
||||
#include "rtc_tools/video_file_reader.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
// Writes video to file, determining YUV or Y4M format from the file extension.
|
||||
void WriteVideoToFile(const rtc::scoped_refptr<Video>& video,
|
||||
const std::string& file_name,
|
||||
int fps);
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // RTC_TOOLS_VIDEO_FILE_WRITER_H_
|
123
rtc_tools/video_file_writer_unittest.cc
Normal file
123
rtc_tools/video_file_writer_unittest.cc
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <string>
|
||||
|
||||
#include "rtc_base/refcountedobject.h"
|
||||
#include "rtc_tools/video_file_reader.h"
|
||||
#include "rtc_tools/video_file_writer.h"
|
||||
#include "test/gtest.h"
|
||||
#include "test/testsupport/fileutils.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
class VideoFileWriterTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
const std::string filename =
|
||||
webrtc::test::OutputPath() + "test_video_file.y4m";
|
||||
|
||||
// Create simple test video of size 6x4.
|
||||
FILE* file = fopen(filename.c_str(), "wb");
|
||||
ASSERT_TRUE(file != nullptr);
|
||||
fprintf(file, "YUV4MPEG2 W6 H4 F60:1 C420 dummyParam\n");
|
||||
fprintf(file, "FRAME\n");
|
||||
|
||||
const int i420_size = width * height * 3 / 2;
|
||||
// First frame.
|
||||
for (int i = 0; i < i420_size; ++i)
|
||||
fputc(static_cast<char>(i), file);
|
||||
fprintf(file, "FRAME\n");
|
||||
// Second frame.
|
||||
for (int i = 0; i < i420_size; ++i)
|
||||
fputc(static_cast<char>(i + i420_size), file);
|
||||
fclose(file);
|
||||
|
||||
// Open the newly created file.
|
||||
video = webrtc::test::OpenY4mFile(filename);
|
||||
ASSERT_TRUE(video);
|
||||
}
|
||||
|
||||
// Write and read Y4M file.
|
||||
void WriteVideoY4m() {
|
||||
const std::string filename =
|
||||
webrtc::test::OutputPath() + "test_video_file2.y4m";
|
||||
webrtc::test::WriteVideoToFile(video, filename, fps);
|
||||
written_video = webrtc::test::OpenY4mFile(filename);
|
||||
ASSERT_TRUE(written_video);
|
||||
}
|
||||
|
||||
// Write and read YUV file.
|
||||
void WriteVideoYuv() {
|
||||
const std::string filename =
|
||||
webrtc::test::OutputPath() + "test_video_file2.yuv";
|
||||
webrtc::test::WriteVideoToFile(video, filename, fps);
|
||||
written_video = webrtc::test::OpenYuvFile(filename, width, height);
|
||||
ASSERT_TRUE(written_video);
|
||||
}
|
||||
|
||||
const int width = 6;
|
||||
const int height = 4;
|
||||
const int fps = 60;
|
||||
rtc::scoped_refptr<webrtc::test::Video> video;
|
||||
rtc::scoped_refptr<webrtc::test::Video> written_video;
|
||||
};
|
||||
|
||||
TEST_F(VideoFileWriterTest, TestParsingFileHeaderY4m) {
|
||||
WriteVideoY4m();
|
||||
EXPECT_EQ(video->width(), written_video->width());
|
||||
EXPECT_EQ(video->height(), written_video->height());
|
||||
}
|
||||
|
||||
TEST_F(VideoFileWriterTest, TestParsingFileHeaderYuv) {
|
||||
WriteVideoYuv();
|
||||
EXPECT_EQ(video->width(), written_video->width());
|
||||
EXPECT_EQ(video->height(), written_video->height());
|
||||
}
|
||||
|
||||
TEST_F(VideoFileWriterTest, TestParsingNumberOfFramesY4m) {
|
||||
WriteVideoY4m();
|
||||
EXPECT_EQ(video->number_of_frames(), written_video->number_of_frames());
|
||||
}
|
||||
|
||||
TEST_F(VideoFileWriterTest, TestParsingNumberOfFramesYuv) {
|
||||
WriteVideoYuv();
|
||||
EXPECT_EQ(video->number_of_frames(), written_video->number_of_frames());
|
||||
}
|
||||
|
||||
TEST_F(VideoFileWriterTest, TestPixelContentY4m) {
|
||||
WriteVideoY4m();
|
||||
int cnt = 0;
|
||||
for (const rtc::scoped_refptr<I420BufferInterface> frame : *written_video) {
|
||||
for (int i = 0; i < width * height; ++i, ++cnt)
|
||||
EXPECT_EQ(cnt, frame->DataY()[i]);
|
||||
for (int i = 0; i < width / 2 * height / 2; ++i, ++cnt)
|
||||
EXPECT_EQ(cnt, frame->DataU()[i]);
|
||||
for (int i = 0; i < width / 2 * height / 2; ++i, ++cnt)
|
||||
EXPECT_EQ(cnt, frame->DataV()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(VideoFileWriterTest, TestPixelContentYuv) {
|
||||
WriteVideoYuv();
|
||||
int cnt = 0;
|
||||
for (const rtc::scoped_refptr<I420BufferInterface> frame : *written_video) {
|
||||
for (int i = 0; i < width * height; ++i, ++cnt)
|
||||
EXPECT_EQ(cnt, frame->DataY()[i]);
|
||||
for (int i = 0; i < width / 2 * height / 2; ++i, ++cnt)
|
||||
EXPECT_EQ(cnt, frame->DataU()[i]);
|
||||
for (int i = 0; i < width / 2 * height / 2; ++i, ++cnt)
|
||||
EXPECT_EQ(cnt, frame->DataV()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
Loading…
Reference in a new issue