blob: 093ed27daa4cc2944617af9011aff28dafda41ce [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 <stdint.h>
#include <stdio.h>
#include "use_aac_decoder.h"
#include "use_video_decoder.h"
#include <lib/async-loop/cpp/loop.h>
#include <lib/component/cpp/startup_context.h>
#include <lib/fxl/command_line.h>
#include <lib/fxl/log_settings_command_line.h>
#include <lib/fxl/logging.h>
#include <lib/media/test/frame_sink.h>
#include <thread>
void usage(const char* prog_name) {
printf(
"usage: %s (--aac_adts|--h264) [--imagepipe [--fps=<double>]] "
"<input_file> [<output_file>]\n",
prog_name);
}
int main(int argc, char* argv[]) {
fxl::CommandLine command_line = fxl::CommandLineFromArgcArgv(argc, argv);
if (!fxl::SetLogSettingsFromCommandLine(command_line)) {
printf("fxl::SetLogSettingsFromCommandLine() failed\n");
exit(-1);
}
if (command_line.positional_args().size() < 1 ||
command_line.positional_args().size() > 2) {
usage(command_line.argv0().c_str());
exit(-1);
}
async::Loop main_loop(&kAsyncLoopConfigAttachToThread);
fuchsia::mediacodec::CodecFactoryPtr codec_factory;
codec_factory.set_error_handler([](zx_status_t status) {
// TODO(dustingreen): get and print CodecFactory channel epitaph once that's
// possible.
FXL_LOG(ERROR) << "codec_factory failed - unexpected; status: " << status;
});
std::unique_ptr<component::StartupContext> startup_context =
component::StartupContext::CreateFromStartupInfo();
startup_context
->ConnectToEnvironmentService<fuchsia::mediacodec::CodecFactory>(
codec_factory.NewRequest());
std::string input_file = command_line.positional_args()[0];
std::string output_file;
if (command_line.positional_args().size() >= 2) {
output_file = command_line.positional_args()[1];
}
// In case of --h264 and --imagepipe, this will be non-nullptr:
std::unique_ptr<FrameSink> frame_sink;
uint8_t md[SHA256_DIGEST_LENGTH];
bool use_imagepipe = command_line.HasOption("imagepipe");
double frames_per_second = 0.0;
std::string frames_per_second_string;
if (command_line.GetOptionValue("fps", &frames_per_second_string)) {
if (!use_imagepipe) {
printf("--fps requires --imagepipe\n");
usage(command_line.argv0().c_str());
exit(-1);
}
const char* str_begin = frames_per_second_string.c_str();
char* str_end;
errno = 0;
frames_per_second = std::strtod(str_begin, &str_end);
if (str_end == str_begin ||
(frames_per_second == HUGE_VAL && errno == ERANGE)) {
printf("fps parse error\n");
usage(command_line.argv0().c_str());
exit(-1);
}
}
if (use_imagepipe) {
// We must do this part of setup on the main thread, not in use_decoder
// which runs on drive_decoder_thread. This is because we want the
// FrameSink (or rather, code it uses) to bind to loop (whether explicitly
// or implicitly), and we want that setup/binding to occur on the same
// thread as runs that loop (the current thread), as that's a typical
// assumption of setup/binding code.
// TODO(turnage): Rework to catch the first few frames using view connected
// callback.
frame_sink =
FrameSink::Create(startup_context.get(), &main_loop, frames_per_second,
[](FrameSink* _frame_sink) {});
}
// We set up a closure here just to avoid forcing the two decoder types to
// take the same parameters, but still be able to share the
// drive_decoder_thread code below.
fit::closure use_decoder;
if (command_line.HasOption("aac_adts")) {
use_decoder = [&main_loop, codec_factory = std::move(codec_factory),
input_file, output_file, &md]() mutable {
use_aac_decoder(&main_loop, std::move(codec_factory), input_file,
output_file, md);
};
} else if (command_line.HasOption("h264")) {
use_decoder = [&main_loop, codec_factory = std::move(codec_factory),
input_file, output_file, &md,
frame_sink = frame_sink.get()]() mutable {
use_h264_decoder(&main_loop, std::move(codec_factory), input_file,
output_file, md, nullptr, frame_sink);
};
} else if (command_line.HasOption("vp9")) {
use_decoder = [&main_loop, codec_factory = std::move(codec_factory),
input_file, output_file, &md,
frame_sink = frame_sink.get()]() mutable {
use_vp9_decoder(&main_loop, std::move(codec_factory), input_file,
output_file, md, nullptr, frame_sink);
};
} else {
usage(command_line.argv0().c_str());
return -1;
}
auto drive_decoder_thread = std::make_unique<std::thread>(
[use_decoder = std::move(use_decoder), &main_loop] {
use_decoder();
main_loop.Quit();
});
main_loop.Run();
drive_decoder_thread->join();
if (!frame_sink) {
printf(
"The sha256 of the output data (including data format "
"parameters) is:\n");
for (uint8_t byte : md) {
printf("%02x", byte);
}
printf("\n");
}
// ~frame_sink
// ~main_loop
return 0;
}