1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/test/video_frame_writer.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
13 #include "ui/gfx/codec/png_codec.h"
14 #include "ui/gfx/geometry/size.h"
18 const base::FilePath::CharType kFrameFileName
[] =
19 FILE_PATH_LITERAL("frame.png");
20 const base::FilePath::CharType kRemotingFolder
[] =
21 FILE_PATH_LITERAL("remoting");
22 const base::FilePath::CharType kDumpFrameFolder
[] =
23 FILE_PATH_LITERAL("dumped_images");
25 // Used to create a unique folder path.
26 const char kDateAndTimeFormatString
[] = "%d-%d-%d_%d-%d-%d";
33 VideoFrameWriter::VideoFrameWriter()
34 : instance_creation_time_(base::Time::Now()),
35 frame_name_unique_number_(0) {}
37 VideoFrameWriter::~VideoFrameWriter() {}
39 void VideoFrameWriter::WriteFrameToPath(const webrtc::DesktopFrame
& frame
,
40 const base::FilePath
& image_path
) {
41 unsigned char* frame_data
= reinterpret_cast<unsigned char*>(frame
.data());
42 std::vector
<unsigned char> png_encoded_data
;
44 if (!gfx::PNGCodec::Encode(
45 frame_data
, gfx::PNGCodec::FORMAT_BGRA
,
46 gfx::Size(frame
.size().width(), frame
.size().height()),
47 frame
.stride(), true, std::vector
<gfx::PNGCodec::Comment
>(),
49 LOG(WARNING
) << "Failed to encode frame to PNG file";
53 // Dump contents (unsigned chars) to a file as a sequence of chars.
54 int write_bytes
= base::WriteFile(
55 image_path
, reinterpret_cast<char*>(&*png_encoded_data
.begin()),
56 static_cast<int>(png_encoded_data
.size()));
57 if (write_bytes
!= static_cast<int>(png_encoded_data
.size())) {
58 LOG(WARNING
) << "Failed to write frame to disk";
62 // Save video frame to path named with the |instance_creation_time|.
63 void VideoFrameWriter::WriteFrameToDefaultPath(
64 const webrtc::DesktopFrame
& frame
) {
65 base::FilePath dump_frame_file_path
;
66 if (!GetTempDir(&dump_frame_file_path
)) {
67 LOG(WARNING
) << "Failed to retrieve temporary directory path";
71 dump_frame_file_path
= dump_frame_file_path
.Append(kRemotingFolder
);
72 dump_frame_file_path
= dump_frame_file_path
.Append(kDumpFrameFolder
);
73 if (!CreateDirectoryIfNotExists(dump_frame_file_path
)) {
77 // Create a sub-folder using date and time to identify a particular test run.
78 dump_frame_file_path
= AppendCreationDateAndTime(dump_frame_file_path
);
79 if (!CreateDirectoryIfNotExists(dump_frame_file_path
)) {
83 dump_frame_file_path
= dump_frame_file_path
.Append(kFrameFileName
);
85 dump_frame_file_path
= dump_frame_file_path
.InsertBeforeExtensionASCII(
86 base::StringPrintf("(%d)", ++frame_name_unique_number_
));
88 LOG(INFO
) << "Video frame dumped to: " << dump_frame_file_path
.value();
90 WriteFrameToPath(frame
, dump_frame_file_path
);
93 void VideoFrameWriter::HighlightRectInFrame(webrtc::DesktopFrame
* frame
,
94 const webrtc::DesktopRect
& rect
) {
95 if (rect
.left() < 0 || rect
.top() < 0 ||
96 rect
.right() >= frame
->size().width() ||
97 rect
.bottom() >= frame
->size().height()) {
98 LOG(ERROR
) << "Highlight rect lies outside of the frame.";
102 // Draw vertical borders.
103 for (int y
= rect
.top(); y
<= rect
.bottom(); ++y
) {
104 ShiftPixelColor(frame
, rect
.left(), y
, 128);
105 ShiftPixelColor(frame
, rect
.right(), y
, 128);
108 // Draw horizontal borders.
109 for (int x
= rect
.left(); x
<= rect
.right(); ++x
) {
110 ShiftPixelColor(frame
, x
, rect
.top(), 128);
111 ShiftPixelColor(frame
, x
, rect
.bottom(), 128);
115 base::FilePath
VideoFrameWriter::AppendCreationDateAndTime(
116 const base::FilePath
& file_path
) {
117 base::Time::Exploded exploded_time
;
118 instance_creation_time_
.LocalExplode(&exploded_time
);
120 int year
= exploded_time
.year
;
121 int month
= exploded_time
.month
;
122 int day
= exploded_time
.day_of_month
;
123 int hour
= exploded_time
.hour
;
124 int minute
= exploded_time
.minute
;
125 int second
= exploded_time
.second
;
127 return file_path
.AppendASCII(base::StringPrintf(
128 kDateAndTimeFormatString
, year
, month
, day
, hour
, minute
, second
));
131 bool VideoFrameWriter::CreateDirectoryIfNotExists(
132 const base::FilePath
& file_path
) {
133 if (!base::DirectoryExists(file_path
) && !base::CreateDirectory(file_path
)) {
134 LOG(WARNING
) << "Failed to create directory: " << file_path
.value();
140 void VideoFrameWriter::ShiftPixelColor(webrtc::DesktopFrame
* frame
,
144 uint8_t* frame_pos
= frame
->data() + y
* frame
->stride() +
145 x
* webrtc::DesktopFrame::kBytesPerPixel
;
146 frame_pos
[2] = frame_pos
[2] + shift_amount
;
147 frame_pos
[1] = frame_pos
[1] + shift_amount
;
148 frame_pos
[0] = frame_pos
[0] + shift_amount
;
152 } // namespace remoting