blob: 68c0e906ffd1f51d7942f8531fe35f6564125983 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/test/video_frame_writer.h"
#include <stdint.h>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
namespace {
const base::FilePath::CharType kFrameFileName[] =
FILE_PATH_LITERAL("frame.png");
const base::FilePath::CharType kRemotingFolder[] =
FILE_PATH_LITERAL("remoting");
const base::FilePath::CharType kDumpFrameFolder[] =
FILE_PATH_LITERAL("dumped_images");
// Used to create a unique folder path.
const char kDateAndTimeFormatString[] = "%d-%d-%d_%d-%d-%d";
} // namespace
namespace remoting {
namespace test {
VideoFrameWriter::VideoFrameWriter()
: instance_creation_time_(base::Time::Now()),
frame_name_unique_number_(0) {}
VideoFrameWriter::~VideoFrameWriter() = default;
void VideoFrameWriter::WriteFrameToPath(const webrtc::DesktopFrame& frame,
const base::FilePath& image_path) {
unsigned char* frame_data = reinterpret_cast<unsigned char*>(frame.data());
std::vector<unsigned char> png_encoded_data;
if (!gfx::PNGCodec::Encode(
frame_data, gfx::PNGCodec::FORMAT_BGRA,
gfx::Size(frame.size().width(), frame.size().height()),
frame.stride(), true, std::vector<gfx::PNGCodec::Comment>(),
&png_encoded_data)) {
LOG(WARNING) << "Failed to encode frame to PNG file";
return;
}
// Dump contents (unsigned chars) to a file as a sequence of chars.
int write_bytes = base::WriteFile(
image_path, reinterpret_cast<char*>(&*png_encoded_data.begin()),
static_cast<int>(png_encoded_data.size()));
if (write_bytes != static_cast<int>(png_encoded_data.size())) {
LOG(WARNING) << "Failed to write frame to disk";
}
}
// Save video frame to path named with the |instance_creation_time|.
void VideoFrameWriter::WriteFrameToDefaultPath(
const webrtc::DesktopFrame& frame) {
base::FilePath dump_frame_file_path;
if (!GetTempDir(&dump_frame_file_path)) {
LOG(WARNING) << "Failed to retrieve temporary directory path";
return;
}
dump_frame_file_path = dump_frame_file_path.Append(kRemotingFolder);
dump_frame_file_path = dump_frame_file_path.Append(kDumpFrameFolder);
if (!CreateDirectoryIfNotExists(dump_frame_file_path)) {
return;
}
// Create a sub-folder using date and time to identify a particular test run.
dump_frame_file_path = AppendCreationDateAndTime(dump_frame_file_path);
if (!CreateDirectoryIfNotExists(dump_frame_file_path)) {
return;
}
dump_frame_file_path = dump_frame_file_path.Append(kFrameFileName);
dump_frame_file_path = dump_frame_file_path.InsertBeforeExtensionASCII(
base::StringPrintf("(%d)", ++frame_name_unique_number_));
LOG(INFO) << "Video frame dumped to: " << dump_frame_file_path.value();
WriteFrameToPath(frame, dump_frame_file_path);
}
void VideoFrameWriter::HighlightRectInFrame(webrtc::DesktopFrame* frame,
const webrtc::DesktopRect& rect) {
if (rect.left() < 0 || rect.top() < 0 ||
rect.right() >= frame->size().width() ||
rect.bottom() >= frame->size().height()) {
LOG(ERROR) << "Highlight rect lies outside of the frame.";
return;
}
// Draw vertical borders.
for (int y = rect.top(); y <= rect.bottom(); ++y) {
ShiftPixelColor(frame, rect.left(), y, 128);
ShiftPixelColor(frame, rect.right(), y, 128);
}
// Draw horizontal borders.
for (int x = rect.left(); x <= rect.right(); ++x) {
ShiftPixelColor(frame, x, rect.top(), 128);
ShiftPixelColor(frame, x, rect.bottom(), 128);
}
}
base::FilePath VideoFrameWriter::AppendCreationDateAndTime(
const base::FilePath& file_path) {
base::Time::Exploded exploded_time;
instance_creation_time_.LocalExplode(&exploded_time);
int year = exploded_time.year;
int month = exploded_time.month;
int day = exploded_time.day_of_month;
int hour = exploded_time.hour;
int minute = exploded_time.minute;
int second = exploded_time.second;
return file_path.AppendASCII(base::StringPrintf(
kDateAndTimeFormatString, year, month, day, hour, minute, second));
}
bool VideoFrameWriter::CreateDirectoryIfNotExists(
const base::FilePath& file_path) {
if (!base::DirectoryExists(file_path) && !base::CreateDirectory(file_path)) {
LOG(WARNING) << "Failed to create directory: " << file_path.value();
return false;
}
return true;
}
void VideoFrameWriter::ShiftPixelColor(webrtc::DesktopFrame* frame,
int x,
int y,
int shift_amount) {
uint8_t* frame_pos = frame->data() + y * frame->stride() +
x * webrtc::DesktopFrame::kBytesPerPixel;
frame_pos[2] = frame_pos[2] + shift_amount;
frame_pos[1] = frame_pos[1] + shift_amount;
frame_pos[0] = frame_pos[0] + shift_amount;
}
} // namespace test
} // namespace remoting