blob: bceda28a168b55d3e647f5ace0b541e146ca51ea [file] [log] [blame]
/* Copyright 2017 The Chromium OS 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 "tools/generate_camera_profile.h"
#include <memory>
#include <vector>
#include <base/at_exit.h>
#include <base/command_line.h>
#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/strings/string_piece.h>
#include <base/strings/string_split.h>
#include <base/strings/stringprintf.h>
#include <brillo/syslog_logging.h>
#include "cros-camera/constants.h"
#include "cros-camera/utils/camera_config.h"
constexpr char kDestinationDir[] =
"/mnt/stateful_partition/encrypted/var/cache/camera";
constexpr char kMediaProfileFileName[] = "media_profiles.xml";
constexpr char kMediaProfileDir[] = "/etc/camera";
int GetNumberOfBuiltinCameras() {
base::FileEnumerator cameras(base::FilePath("/dev"), /*recursive=*/false,
base::FileEnumerator::FILES, "camera-internal*");
int cnt = 0;
while (!cameras.Next().empty()) {
cnt++;
}
return cnt;
}
cros::Camcorder GetDefaultCamcorder() {
cros::Camcorder profile;
profile.file_format = "mp4";
profile.duration = 60;
profile.video_codec = "h264";
profile.video_bitrate = 8000000;
profile.video_width = 1280;
profile.video_height = 720;
profile.video_framerate = 30;
profile.audio_codec = "aac";
profile.audio_bitrate = 96000;
profile.audio_samplerate = 44100;
profile.audio_channels = 1;
return profile;
}
std::string GetCamcorderString(int id) {
cros::Camcorder camcorder = GetDefaultCamcorder();
std::string quality;
if (camcorder.video_height >= 2160) {
quality = "2160p";
} else if (camcorder.video_height >= 1080) {
quality = "1080p";
} else if (camcorder.video_height >= 720) {
quality = "720p";
} else if (camcorder.video_height >= 480) {
quality = "480p";
}
std::string str;
str += base::StringPrintf(" <CamcorderProfiles cameraId=\"%d\">\n", id);
for (int i = 0; i < 2; i++) {
std::string quality_str = i ? ("timelapse" + quality) : quality;
str += base::StringPrintf(" <EncoderProfile quality=\"%s\" ",
quality_str.c_str());
str +=
base::StringPrintf("fileFormat=\"%s\" duration=\"%d\">\n",
camcorder.file_format.c_str(), camcorder.duration);
str += base::StringPrintf(" <Video codec=\"%s\" bitRate=\"%d\" ",
camcorder.video_codec.c_str(),
camcorder.video_bitrate);
str += base::StringPrintf("width=\"%d\" height=\"%d\" frameRate=\"%d\" />",
camcorder.video_width, camcorder.video_height,
camcorder.video_framerate);
str += "\n";
str += base::StringPrintf(" <Audio codec=\"%s\" bitRate=\"%d\" ",
camcorder.audio_codec.c_str(),
camcorder.audio_bitrate);
str += base::StringPrintf("sampleRate=\"%d\" channels=\"%d\" />\n",
camcorder.audio_samplerate,
camcorder.audio_channels);
str += base::StringPrintf(" </EncoderProfile>\n");
}
str += base::StringPrintf(" <ImageEncoding quality=\"90\" />\n");
str += base::StringPrintf(" <ImageEncoding quality=\"80\" />\n");
str += base::StringPrintf(" <ImageEncoding quality=\"70\" />\n");
str += base::StringPrintf(" <ImageDecoding memCap=\"20000000\" />\n");
str += base::StringPrintf(" </CamcorderProfiles>\n");
return str;
}
bool GenerateCameraProfile(int num_cameras) {
const base::FilePath profile =
base::FilePath(kMediaProfileDir).Append(kMediaProfileFileName);
std::string content;
if (!base::ReadFileToString(profile, &content)) {
LOG(ERROR) << "ReadFileToString fails";
return false;
}
const std::vector<base::StringPiece> lines = base::SplitStringPiece(
content, "\n", base::WhitespaceHandling::KEEP_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
const base::FilePath generated_profile =
base::FilePath(kDestinationDir).Append(kMediaProfileFileName);
if (!base::CreateDirectory(generated_profile.DirName())) {
LOG(ERROR) << "Create directory failed";
return false;
}
base::File file(generated_profile,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
CHECK(file.IsValid());
size_t i;
for (i = 0; i < lines.size(); i++) {
file.WriteAtCurrentPos(lines[i].data(), lines[i].length());
file.WriteAtCurrentPos("\n", 1);
if (lines[i].find("</CamcorderProfiles>") != base::StringPiece::npos) {
break;
}
}
// TODO(henryhsu): Write camcorder according to correct value from
// configuration file instead of using default value.
for (int id = 1; id < num_cameras; id++) {
std::string camcorder_string = GetCamcorderString(id);
file.WriteAtCurrentPos(camcorder_string.c_str(), camcorder_string.length());
}
for (i++; i < lines.size(); i++) {
file.WriteAtCurrentPos(lines[i].data(), lines[i].length());
file.WriteAtCurrentPos("\n", 1);
}
file.Close();
return true;
}
bool HasCameraFilter() {
std::unique_ptr<cros::CameraConfig> config = cros::CameraConfig::Create(
cros::constants::kCrosCameraTestConfigPathString);
return config->HasKey(cros::constants::kCrosEnableFrontCameraOption) ||
config->HasKey(cros::constants::kCrosEnableBackCameraOption) ||
config->HasKey(cros::constants::kCrosEnableExternalCameraOption);
}
int main(int argc, char* argv[]) {
// Init CommandLine for InitLogging.
base::CommandLine::Init(argc, argv);
base::AtExitManager at_exit_manager;
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderr);
if (HasCameraFilter()) {
// If camera filter flag is presented, autotest toggling camera filter
// should be responsible for preparing media profile for ARC++.
LOG(INFO) << "Using camera filter, skip generating media profiles";
return 0;
}
LOG(INFO) << "Starting to generate media profiles";
int num_builtin_cameras = GetNumberOfBuiltinCameras();
if (!GenerateCameraProfile(num_builtin_cameras)) {
LOG(ERROR) << "Generate media profile error";
return -1;
}
return 0;
}