// Copyright (c) 2010 The WebM 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 <objbase.h> | |
#include "makewebmcmdline.hpp" | |
#include <iostream> | |
#include <iomanip> | |
#include <algorithm> | |
#include <cassert> | |
#include <cstring> | |
#include <sstream> | |
#include <windows.h> | |
#include <uuids.h> | |
#include "versionhandling.hpp" | |
#include "vp8encoderidl.h" | |
using std::wcout; | |
using std::endl; | |
using std::boolalpha; | |
using std::wstring; | |
using std::dec; | |
CmdLine::CmdLine() : | |
m_input(0), | |
m_audio_input(0), | |
m_output(0), | |
m_usage(false), | |
m_list(false), | |
m_version(false), | |
m_script(false), | |
m_verbose(false), | |
m_no_video(false), | |
m_require_audio(false), | |
m_no_audio(false), | |
m_live(false), | |
m_deadline(-1), | |
m_target_bitrate(-1), | |
m_min_quantizer(-1), | |
m_max_quantizer(-1), | |
m_undershoot_pct(-1), | |
m_overshoot_pct(-1), | |
m_decoder_buffer_size(-1), | |
m_decoder_buffer_initial_size(-1), | |
m_decoder_buffer_optimal_size(-1), | |
m_keyframe_frequency(-1), | |
m_keyframe_mode(-2), | |
m_keyframe_min_interval(-1), | |
m_keyframe_max_interval(-1), | |
m_thread_count(-1), | |
m_error_resilient(-1), | |
m_end_usage(-1), | |
m_lag_in_frames(-1), | |
m_token_partitions(-1), | |
m_two_pass(-1), | |
m_dropframe_thresh(-1), | |
m_resize_allowed(-1), | |
m_resize_up_thresh(-1), | |
m_resize_down_thresh(-1), | |
m_two_pass_vbr_bias_pct(-1), | |
m_two_pass_vbr_minsection_pct(-1), | |
m_two_pass_vbr_maxsection_pct(-1), | |
m_save_graph_file_ptr(0), | |
m_auto_alt_ref(-1), | |
m_arnr_maxframes(-1), | |
m_arnr_strength(-1), | |
m_arnr_type(-1), | |
m_ogg_to_webm(-1), | |
m_cpu_used(-17) | |
{ | |
} | |
int CmdLine::Parse(int argc, wchar_t* argv[]) | |
{ | |
m_argv = argv; | |
if (argc <= 1) //program-name only | |
{ | |
PrintUsage(); | |
return 1; //soft error | |
} | |
//more ideas: | |
//require video outpin | |
//require audio outpin | |
//make video connection optional | |
//make audio connection optional | |
//verbose mode | |
//terse mode | |
//quiet | |
//very quite | |
//warnings vs. errors | |
//treat warnings as errors | |
wchar_t** const argv_end = argv + argc; | |
assert(*argv_end == 0); | |
--argc; //throw away program name | |
assert(argc >= 1); | |
wchar_t** i = argv + 1; | |
assert(i < argv_end); | |
for (;;) | |
{ | |
const int n = Parse(i); | |
if (n < 0) //error | |
return n; | |
if (n == 0) //arg, not switch | |
{ | |
--argc; | |
assert(argc >= 0); | |
++i; | |
assert(i <= argv_end); | |
} | |
else //switch | |
{ | |
argc -= n; | |
assert(argc >= 0); | |
assert((i + n) <= argv_end); | |
std::rotate(i, i + n, argv_end + 1); | |
} | |
if (argc <= 0) | |
break; | |
} | |
assert(*i == 0); | |
wchar_t** const j = i; //args end | |
i = argv + 1; //args begin | |
if (m_usage) | |
{ | |
PrintUsage(); | |
return 1; //soft error | |
} | |
if (m_version) | |
{ | |
PrintVersion(); | |
return 1; //soft error | |
} | |
if (m_input == 0) //not specified as switch | |
{ | |
if (i >= j) //no args remain | |
{ | |
if (m_list) | |
ListArgs(); | |
else | |
wcout << "No input filename specified." << endl; | |
return 1; //error | |
} | |
m_input = *i++; | |
assert(m_input); | |
} | |
if (m_output == 0) //not specified as switch | |
{ | |
#if 0 | |
if (i >= j) //no args remain | |
{ | |
if (m_list) | |
ListArgs(); | |
else | |
wcout << "No output filename specified." << endl; | |
return 1; //error | |
} | |
m_output = *i++; | |
assert(m_output); | |
#else | |
if (i >= j) //no args remain | |
SynthesizeOutput(); | |
else | |
m_output = *i++; | |
assert(m_output); | |
#endif | |
} | |
if (m_save_graph_file_ptr) //had a request | |
{ | |
if (m_two_pass >= 1) //two-pass requested | |
{ | |
wcout << L"Unable to save GraphEdit storage file" | |
<< L" in two-pass mode." | |
<< endl; | |
return 1; | |
} | |
if (wcslen(m_save_graph_file_ptr) == 0) //request, but no filename | |
SynthesizeSaveGraph(); | |
} | |
if (i < j) //not all args consumed | |
{ | |
if (m_list) | |
ListArgs(); | |
else | |
wcout << L"Too many command-line arguments." << endl; | |
return 1; | |
} | |
if (m_list) | |
{ | |
ListArgs(); | |
//TODO: we should have a dedicated arg to say, "build the graph, | |
//but don't run it", something like --build-only or --dry-run | |
//if (!m_verbose) | |
// return 1; //soft error | |
return 1; | |
} | |
return 0; | |
} | |
bool CmdLine::IsSwitch(const wchar_t* arg) | |
{ | |
assert(arg); | |
switch (*arg) | |
{ | |
case L'/': //windows-style switch | |
case L'-': //unix-style switch | |
return true; | |
default: | |
return false; //this is an arg, not a switch | |
} | |
} | |
int CmdLine::Parse(wchar_t** i) | |
{ | |
assert(i); | |
const wchar_t* arg = *i; | |
assert(arg); | |
switch (*arg) | |
{ | |
case L'/': //windows-style switch | |
return ParseWindows(i); | |
case L'-': //unix-style switch | |
if (*++arg == L'-') //long-form | |
return ParseLong(i); | |
else | |
return ParseShort(i); | |
default: | |
return 0; //this is an arg, not a switch | |
} | |
} | |
int CmdLine::ParseWindows(wchar_t** i) | |
{ | |
assert(i); | |
const wchar_t* arg = *i; | |
assert(arg); | |
assert(*arg == L'/'); | |
++arg; | |
if (*arg == L'\0') | |
{ | |
wcout << L"Slash cannot stand alone as switch indicator." | |
<< endl; | |
return -1; //error | |
} | |
const wchar_t* end = arg; | |
while ((*end != L'\0') && (*end != L':')) | |
++end; | |
const size_t len = end - arg; | |
//TODO: we special-case the following switches. | |
//Is this the best approach here? | |
if (len != 1) | |
return ParseLongPost(i, arg, len); | |
const bool has_value = (arg[len] == L':'); | |
if (*arg == L'V') | |
{ | |
if (has_value) | |
{ | |
wcout << "Version option does not accept a value." << endl; | |
return -1; //error | |
} | |
m_version = true; | |
return 1; | |
} | |
if (*arg == L'v') //verbose | |
{ | |
if (has_value) | |
{ | |
wcout << "Verbose option does not accept a value." << endl; | |
return -1; //error | |
} | |
m_verbose = true; | |
return 1; | |
} | |
return ParseLongPost(i, arg, len); | |
} | |
int CmdLine::ParseShort(wchar_t** i) | |
{ | |
assert(i); | |
const wchar_t* arg = *i; | |
assert(arg); | |
assert(*arg == L'-'); | |
const wchar_t c = *++arg; | |
assert(c != L'-'); | |
if (c == L'\0') | |
{ | |
wcout << L"Hyphen cannot stand alone as switch indicator." | |
<< endl; | |
return -1; | |
} | |
switch (c) | |
{ | |
case L'i': | |
case L'I': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"input", len) != 0) | |
{ | |
wcout << L"Unknown switch: " << *i | |
<< L"\nUse -i or --input to specify input filename." | |
<< endl; | |
return -1; //error | |
} | |
} | |
m_input = *++i; | |
if (m_input == 0) | |
{ | |
wcout << L"No value specified for input filename switch." | |
<< endl; | |
return -1; //error | |
} | |
return 2; | |
case L'o': | |
case L'O': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"output", len) != 0) | |
{ | |
wcout << L"Unknown switch: " << *i | |
<< L"\nUse -o or --output " | |
<< L"to specify output filename." | |
<< endl; | |
return -1; //error | |
} | |
} | |
m_output = *++i; | |
if (m_output == 0) | |
{ | |
wcout << L"No value specified for output filename switch." | |
<< endl; | |
return -1; //error | |
} | |
return 2; | |
case L'?': | |
++arg; //throw away '?' | |
if (*arg == L'?') //-?? | |
{ | |
m_verbose = true; | |
++arg; | |
} | |
if (*arg != L'\0') | |
{ | |
wcout << L"Unknown switch: " << *i | |
<< L"\nUse -? by itself to get usage info." | |
<< endl; | |
return -1; | |
} | |
m_usage = true; | |
return 1; | |
case L'h': | |
case L'H': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"help", len) == 0) | |
__noop; | |
else if (_wcsnicmp(arg, L"hh", len) == 0) | |
m_verbose = true; | |
else | |
{ | |
wcout << L"Unknown switch: " << *i | |
<< L"\nIf help info was desired, " | |
<< L"specify the -h or --help switches." | |
<< endl; | |
return -1; | |
} | |
} | |
m_usage = true; | |
return 1; | |
case L'u': | |
case L'U': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"usage", len) != 0) | |
{ | |
wcout << L"Unknown switch: " << *i | |
<< L"\nIf usage info was desired, " | |
<< L"specify the -u or --usage switches." | |
<< endl; | |
return -1; | |
} | |
} | |
m_usage = true; | |
return 1; | |
case L'l': | |
case L'L': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"list", len) != 0) | |
{ | |
wcout << L"Unknown switch: " << *i | |
<< L"\nIf list info was desired, " | |
<< L"specify the -l or --list switches." | |
<< endl; | |
return -1; //error | |
} | |
} | |
m_list = true; | |
return 1; | |
case L'V': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"version", len) != 0) | |
{ | |
wcout << "Unknown switch: " << *i | |
<< L"\nIf version info was desired, " | |
<< L"specify the -v or --version switches." | |
<< L"\nIf verbosity was desired, " | |
<< L"specify the -V or --verbose switches." | |
<< endl; | |
return -1; //error | |
} | |
} | |
m_version = true; | |
return 1; | |
case L'v': | |
if (*(arg + 1) != L'\0') | |
{ | |
const size_t len = wcslen(arg); | |
if (_wcsnicmp(arg, L"verbose", len) != 0) | |
{ | |
wcout << "Unknown switch: " << *i | |
<< L"\nIf verbosity was desired, " | |
<< L"specify the -V or --verbose switches." | |
<< L"\nIf version info was desired, " | |
<< L"specify the -v or --version switches." | |
<< endl; | |
return -1; //error | |
} | |
} | |
m_verbose = true; | |
return 1; | |
default: | |
wcout << L"Unknown switch: " << *i | |
<< L"\nUse -h to get usage info." | |
<< endl; | |
return -1; | |
} | |
} | |
int CmdLine::ParseLong(wchar_t** i) | |
{ | |
assert(i); | |
const wchar_t* arg = *i; | |
assert(arg); | |
assert(*arg == L'-'); | |
++arg; | |
assert(arg); | |
assert(*arg == L'-'); | |
const wchar_t* end = ++arg; | |
while ((*end != L'\0') && (*end != L'=')) | |
++end; | |
const size_t len = end - arg; | |
if (len == 0) | |
{ | |
wcout << L"Double-hyphen cannot stand alone as switch indicator." | |
<< endl; | |
return -1; //error | |
} | |
return ParseLongPost(i, arg, len); | |
} | |
int CmdLine::ParseLongPost( | |
wchar_t** i, | |
const wchar_t* arg, | |
size_t len) | |
{ | |
const bool has_value = (arg[len] != L'\0'); //L':' or L'=" | |
// -h help | |
// -hh verbose help | |
// /h help | |
// /hh verbose help | |
// --h help | |
// --help help | |
// --hh verbose help | |
const wchar_t* const param = *i; | |
if ((_wcsnicmp(arg, L"help", len) == 0) || | |
(_wcsnicmp(arg, L"hh", len) == 0) || | |
(_wcsnicmp(arg, L"?", len) == 0) || | |
(_wcsnicmp(arg, L"??", len) == 0)) | |
{ | |
if (has_value) | |
{ | |
wcout << "Help switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_usage = true; | |
if (_wcsicmp(arg, L"hh") == 0) | |
m_verbose = true; | |
else if (wcscmp(arg, L"??") == 0) | |
m_verbose = true; | |
else if (wcscmp(arg, L"?") == 0) | |
{ | |
if (*param == L'-') //long-form | |
m_verbose = true; | |
} | |
return 1; | |
} | |
// -? help | |
// /? help | |
// --? verbose help | |
// -?? verbose help | |
// /?? verbose help | |
// --?? verbose help | |
if (wcsncmp(arg, L"?", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "Help switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_usage = true; | |
m_verbose = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"list", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << L"List switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_list = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"no-video", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "The no-video switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_no_video = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"no-audio", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "The no-audio switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_no_audio = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"live", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "The live switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_live = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"require-audio", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "Require-audio option does not accept a value." << endl; | |
return -1; //error | |
} | |
m_require_audio = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"script-mode", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "Script-mode switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_script = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"usage", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << "Usage switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_usage = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"verbose", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << L"Verbose switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_verbose = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"version", len) == 0) | |
{ | |
if (has_value) | |
{ | |
wcout << L"Version switch does not accept a value." << endl; | |
return -1; //error | |
} | |
m_version = true; | |
return 1; | |
} | |
if (_wcsnicmp(arg, L"input", len) == 0) | |
{ | |
if (has_value) | |
{ | |
m_input = arg + len + 1; | |
if (wcslen(m_input) == 0) | |
{ | |
wcout << "Empty value specified for input filename switch." | |
<< endl; | |
return -1; //error | |
} | |
return 1; | |
} | |
m_input = *++i; | |
if (m_input == 0) | |
{ | |
wcout << "No filename specified for input switch." << endl; | |
return -1; //error | |
} | |
return 2; | |
} | |
if (_wcsnicmp(arg, L"audio-input", len) == 0) | |
{ | |
if (has_value) | |
{ | |
m_audio_input = arg + len + 1; | |
if (wcslen(m_audio_input) == 0) | |
{ | |
wcout << "Empty value specified for audio input " | |
<< "filename switch." | |
<< endl; | |
return -1; //error | |
} | |
return 1; | |
} | |
m_audio_input = *++i; | |
if (m_audio_input == 0) | |
{ | |
wcout << "No filename specified for audio input switch." << endl; | |
return -1; //error | |
} | |
return 2; | |
} | |
if (_wcsnicmp(arg, L"output", len) == 0) | |
{ | |
if (has_value) | |
{ | |
m_output = arg + len + 1; | |
if (wcslen(m_output) == 0) | |
{ | |
wcout << "Empty value specified for output filename switch." | |
<< endl; | |
return -1; //error | |
} | |
return 1; | |
} | |
m_output = *++i; | |
if (m_output == 0) | |
{ | |
wcout << "No filename specified for output switch." << endl; | |
return -1; //error | |
} | |
return 2; | |
} | |
if (_wcsnicmp(arg, L"deadline", len) == 0) | |
{ | |
int n; | |
const wchar_t* value; | |
size_t value_length; | |
if (has_value) | |
{ | |
value = arg + len + 1; | |
value_length = wcslen(value); | |
if (value_length == 0) | |
{ | |
wcout << "Empty value specified for deadline switch." << endl; | |
return -1; //error | |
} | |
n = 1; | |
} | |
else | |
{ | |
value = *++i; | |
if (value == 0) | |
{ | |
wcout << "No value specified for deadline switch." << endl; | |
return -1; //error | |
} | |
value_length = wcslen(value); | |
n = 2; | |
} | |
if ((_wcsnicmp(value, L"infinite", value_length) == 0) || | |
(_wcsnicmp(value, L"best", value_length) == 0)) | |
{ | |
m_deadline = kDeadlineBestQuality; | |
} | |
else if ((_wcsnicmp(value, L"realtime", value_length) == 0) || | |
(_wcsnicmp(value, L"real-time", value_length) == 0)) | |
{ | |
m_deadline = kDeadlineRealtime; | |
} | |
else if (_wcsnicmp(value, L"good", value_length) == 0) | |
m_deadline = kDeadlineGoodQuality; | |
else | |
{ | |
std::wistringstream is(value); | |
if (!(is >> m_deadline) || !is.eof()) | |
{ | |
wcout << "Bad value specified for deadline switch." << endl; | |
return -1; //error | |
} | |
if (m_deadline < 0) | |
{ | |
wcout << "Value specified for deadline out-of-range " | |
<< "(too small)." | |
<< endl; | |
return -1; //error | |
} | |
} | |
return n; | |
} | |
int status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"decoder-buffer-size", | |
m_decoder_buffer_size, | |
0, | |
-1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"decoder-buffer-initial-size", | |
m_decoder_buffer_initial_size, | |
0, | |
-1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"decoder-buffer-optimal-size", | |
m_decoder_buffer_optimal_size, | |
0, | |
-1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"dropframe-threshold", | |
m_dropframe_thresh, | |
0, | |
100); | |
if (status) | |
return status; | |
if (_wcsnicmp(arg, L"end-usage", len) == 0) | |
{ | |
int n; | |
const wchar_t* value; | |
size_t value_length; | |
if (has_value) | |
{ | |
value = arg + len + 1; | |
value_length = wcslen(value); | |
if (value_length == 0) | |
{ | |
wcout << "Empty value specified for end-usage switch." | |
<< endl; | |
return -1; //error | |
} | |
n = 1; | |
} | |
else | |
{ | |
value = *++i; | |
if (value == 0) | |
{ | |
wcout << "No value specified for end-usage switch." << endl; | |
return -1; //error | |
} | |
value_length = wcslen(value); | |
n = 2; | |
} | |
if ((_wcsnicmp(value, L"VBR", value_length) == 0) || | |
(_wcsnicmp(value, L"variable", value_length) == 0)) | |
{ | |
m_end_usage = kEndUsageVBR; | |
} | |
else if ((_wcsnicmp(value, L"CBR", value_length) == 0) || | |
(_wcsnicmp(value, L"constant", value_length) == 0)) | |
{ | |
m_end_usage = kEndUsageCBR; | |
} | |
else | |
{ | |
std::wistringstream is(value); | |
if (!(is >> m_end_usage) || !is.eof()) | |
{ | |
wcout << "Bad value specified for end-usage switch." << endl; | |
return -1; //error | |
} | |
if (m_end_usage < 0) | |
{ | |
wcout << "Value specified for end-usage switch out-of-range " | |
<< "(too small)." | |
<< endl; | |
return -1; //error | |
} | |
if (m_end_usage > 1) | |
{ | |
wcout << "Value specified for end-usage switch out-of-range " | |
<< "(too large)." | |
<< endl; | |
return -1; //error | |
} | |
} | |
return n; | |
} | |
if (_wcsnicmp(arg, L"error-resilient", len) == 0) | |
{ | |
int n; | |
const wchar_t* value; | |
size_t value_length; | |
if (has_value) | |
{ | |
value = arg + len + 1; | |
value_length = wcslen(value); | |
if (value_length == 0) | |
{ | |
wcout << "Empty value specified for error-resilient switch." | |
<< endl; | |
return -1; //error | |
} | |
n = 1; | |
} | |
else | |
{ | |
value = *++i; | |
if (value == 0) | |
{ | |
wcout << "No value specified for error-resilient switch." | |
<< endl; | |
return -1; //error | |
} | |
value_length = wcslen(value); | |
n = 2; | |
} | |
if ((_wcsnicmp(value, L"true", value_length) == 0) || | |
(_wcsnicmp(value, L"enabled", value_length) == 0)) | |
{ | |
m_error_resilient = 1; | |
} | |
else if ((_wcsnicmp(value, L"false", value_length) == 0) || | |
(_wcsnicmp(value, L"disabled", value_length) == 0)) | |
{ | |
m_error_resilient = 0; | |
} | |
else | |
{ | |
std::wistringstream is(value); | |
if (!(is >> m_error_resilient) || !is.eof()) | |
{ | |
wcout << "Bad value specified for error-resilient switch." | |
<< endl; | |
return -1; //error | |
} | |
if (m_error_resilient < 0) | |
{ | |
wcout << "Value specified for error-resilient switch " | |
<< "out-of-range (too small)." | |
<< endl; | |
return -1; //error | |
} | |
} | |
return n; | |
} | |
if (_wcsnicmp(arg, L"keyframe-frequency", len) == 0) | |
{ | |
int n; | |
const wchar_t* value; | |
size_t value_length; | |
if (has_value) | |
{ | |
value = arg + len + 1; | |
value_length = wcslen(value); | |
if (value_length == 0) | |
{ | |
wcout << "Empty value specified for " | |
<< "keyframe-frequency switch." | |
<< endl; | |
return -1; //error | |
} | |
n = 1; | |
} | |
else | |
{ | |
value = *++i; | |
if (value == 0) | |
{ | |
wcout << "No value specified for keyframe-frequency switch." | |
<< endl; | |
return -1; //error | |
} | |
value_length = wcslen(value); | |
n = 2; | |
} | |
std::wistringstream is(value); | |
if (!(is >> m_keyframe_frequency) || !is.eof()) | |
{ | |
wcout << "Bad value specified for keyframe-frequency switch." | |
<< endl; | |
return -1; //error | |
} | |
if (m_keyframe_frequency < 0) | |
{ | |
wcout << "Value for keyframe-frequency is out-of-range " | |
<< "(too small)." | |
<< endl; | |
return -1; //error | |
} | |
return n; | |
} | |
if (_wcsnicmp(arg, L"keyframe-mode", len) == 0) | |
{ | |
int n; | |
const wchar_t* value; | |
size_t value_length; | |
if (has_value) | |
{ | |
value = arg + len + 1; | |
value_length = wcslen(value); | |
if (value_length == 0) | |
{ | |
wcout << "Empty value specified for keyframe-mode switch." | |
<< endl; | |
return -1; //error | |
} | |
n = 1; | |
} | |
else | |
{ | |
value = *++i; | |
if (value == 0) | |
{ | |
wcout << "No value specified for keyframe-mode switch." | |
<< endl; | |
return -1; //error | |
} | |
value_length = wcslen(value); | |
n = 2; | |
} | |
if (_wcsnicmp(value, L"auto", value_length) == 0) | |
{ | |
m_keyframe_mode = kKeyframeModeAuto; | |
} | |
else if ((_wcsnicmp(value, L"disabled", value_length) == 0) || | |
(_wcsnicmp(value, L"fixed", value_length) == 0)) | |
{ | |
m_keyframe_mode = kKeyframeModeDisabled; | |
} | |
else if (_wcsnicmp(value, L"default", value_length) == 0) | |
{ | |
m_keyframe_mode = kKeyframeModeDefault; | |
} | |
else | |
{ | |
std::wistringstream is(value); | |
if (!(is >> m_keyframe_mode) || !is.eof()) | |
{ | |
wcout << "Bad value specified for keyframe-mode switch." | |
<< endl; | |
return -1; //error | |
} | |
if (m_keyframe_mode < -1) | |
{ | |
wcout << "Value for keyframe-mode is out-of-range " | |
<< "(too small)." | |
<< endl; | |
return -1; //error | |
} | |
if (m_keyframe_mode > 1) | |
{ | |
wcout << "Value for keyframe-mode is out-of-range " | |
<< "(too large)." | |
<< endl; | |
return -1; //error | |
} | |
} | |
return n; | |
} | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"keyframe-min-interval", | |
m_keyframe_min_interval, | |
0, | |
-1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"keyframe-max-interval", | |
m_keyframe_max_interval, | |
0, | |
-1); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"lag-in-frames", m_lag_in_frames, 0, -1); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"min-quantizer", m_min_quantizer, 0, 63); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"max-quantizer", m_max_quantizer, 0, 63); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"ogg-to-webm", m_ogg_to_webm, 0, 1, 1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"resize-allowed", | |
m_resize_allowed, | |
0, | |
1, | |
1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"resize-up-threshold", | |
m_resize_up_thresh, | |
0, | |
100); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"resize-down-threshold", | |
m_resize_down_thresh, | |
0, | |
100); | |
if (status) | |
return status; | |
if (_wcsnicmp(arg, L"save-graph", len) == 0) | |
{ | |
const wchar_t*& f = m_save_graph_file_ptr; | |
if (has_value) | |
{ | |
f = arg + len + 1; | |
return 1; | |
} | |
f = *++i; | |
if ((f == 0) || IsSwitch(f)) //no value specified | |
{ | |
f = L""; | |
return 1; | |
} | |
return 2; | |
} | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"target-bitrate", | |
m_target_bitrate, | |
0, | |
-1); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"thread-count", m_thread_count, 0, -1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"token-partitions", | |
m_token_partitions, | |
0, | |
3); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"two-pass", m_two_pass, 0, 1, 1); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"two-pass-vbr-bias-pct", | |
m_two_pass_vbr_bias_pct, | |
0, | |
100); | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"two-pass-vbr-minsection-pct", | |
m_two_pass_vbr_minsection_pct, | |
0, | |
1000); //? | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"two-pass-vbr-maxsection-pct", | |
m_two_pass_vbr_maxsection_pct, | |
0, | |
1000); //? | |
if (status) | |
return status; | |
status = ParseOpt( | |
i, | |
arg, | |
len, | |
L"undershoot-pct", | |
m_undershoot_pct, | |
0, | |
100); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"overshoot-pct", m_overshoot_pct, 0, 100); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"auto-alt-ref", m_auto_alt_ref, 0, 1); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"arnr-maxframes", m_arnr_maxframes, 0, 15); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"arnr-strength", m_arnr_strength, 0, 6, 3); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"arnr-type", m_arnr_type, 1, 3); | |
if (status) | |
return status; | |
status = ParseOpt(i, arg, len, L"cpu-used", m_cpu_used, -16, 16); | |
if (status) | |
return status; | |
wcout << "Unknown switch: " << *i | |
<< "\nUse /help or --help to get usage info." | |
<< endl; | |
return -1; //error | |
} | |
const wchar_t* CmdLine::GetInputFileName() const | |
{ | |
return m_input; | |
} | |
const wchar_t* CmdLine::GetAudioInputFileName() const | |
{ | |
return m_audio_input; | |
} | |
const wchar_t* CmdLine::GetOutputFileName() const | |
{ | |
return m_output; | |
} | |
const wchar_t* CmdLine::GetSaveGraphFile() const | |
{ | |
return m_save_graph_file_ptr; | |
} | |
bool CmdLine::ScriptMode() const | |
{ | |
return m_script; | |
} | |
bool CmdLine::GetList() const | |
{ | |
return m_list; | |
} | |
bool CmdLine::GetVerbose() const | |
{ | |
return m_verbose; | |
} | |
bool CmdLine::GetNoVideo() const | |
{ | |
return m_no_video; | |
} | |
bool CmdLine::GetRequireAudio() const | |
{ | |
return m_require_audio; | |
} | |
bool CmdLine::GetNoAudio() const | |
{ | |
return m_no_audio; | |
} | |
bool CmdLine::GetLive() const | |
{ | |
return m_live; | |
} | |
int CmdLine::GetDeadline() const | |
{ | |
return m_deadline; | |
} | |
int CmdLine::GetTargetBitrate() const | |
{ | |
return m_target_bitrate; | |
} | |
int CmdLine::GetMinQuantizer() const | |
{ | |
return m_min_quantizer; | |
} | |
int CmdLine::GetMaxQuantizer() const | |
{ | |
return m_max_quantizer; | |
} | |
int CmdLine::GetUndershootPct() const | |
{ | |
return m_undershoot_pct; | |
} | |
int CmdLine::GetOvershootPct() const | |
{ | |
return m_overshoot_pct; | |
} | |
int CmdLine::GetDecoderBufferSize() const | |
{ | |
return m_decoder_buffer_size; | |
} | |
int CmdLine::GetDecoderBufferInitialSize() const | |
{ | |
return m_decoder_buffer_initial_size; | |
} | |
int CmdLine::GetDecoderBufferOptimalSize() const | |
{ | |
return m_decoder_buffer_optimal_size; | |
} | |
int CmdLine::GetKeyframeMode() const | |
{ | |
return m_keyframe_mode; | |
} | |
int CmdLine::GetKeyframeMinInterval() const | |
{ | |
return m_keyframe_min_interval; | |
} | |
int CmdLine::GetKeyframeMaxInterval() const | |
{ | |
return m_keyframe_max_interval; | |
} | |
double CmdLine::GetKeyframeFrequency() const | |
{ | |
return m_keyframe_frequency; | |
} | |
int CmdLine::GetThreadCount() const | |
{ | |
return m_thread_count; | |
} | |
int CmdLine::GetErrorResilient() const | |
{ | |
return m_error_resilient; | |
} | |
int CmdLine::GetDropframeThreshold() const | |
{ | |
return m_dropframe_thresh; | |
} | |
int CmdLine::GetResizeAllowed() const | |
{ | |
return m_resize_allowed; | |
} | |
int CmdLine::GetResizeUpThreshold() const | |
{ | |
return m_resize_up_thresh; | |
} | |
int CmdLine::GetResizeDownThreshold() const | |
{ | |
return m_resize_down_thresh; | |
} | |
int CmdLine::GetEndUsage() const | |
{ | |
return m_end_usage; | |
} | |
int CmdLine::GetLagInFrames() const | |
{ | |
return m_lag_in_frames; | |
} | |
int CmdLine::GetTokenPartitions() const | |
{ | |
return m_token_partitions; | |
} | |
int CmdLine::GetTwoPass() const | |
{ | |
return m_two_pass; | |
} | |
int CmdLine::GetTwoPassVbrBiasPct() const | |
{ | |
return m_two_pass_vbr_bias_pct; | |
} | |
int CmdLine::GetTwoPassVbrMinsectionPct() const | |
{ | |
return m_two_pass_vbr_minsection_pct; | |
} | |
int CmdLine::GetTwoPassVbrMaxsectionPct() const | |
{ | |
return m_two_pass_vbr_maxsection_pct; | |
} | |
int CmdLine::GetAutoAltRef() const | |
{ | |
return m_auto_alt_ref; | |
} | |
int CmdLine::GetARNRMaxFrames() const | |
{ | |
return m_arnr_maxframes; | |
} | |
int CmdLine::GetARNRStrength() const | |
{ | |
return m_arnr_strength; | |
} | |
int CmdLine::GetARNRType() const | |
{ | |
return m_arnr_type; | |
} | |
int CmdLine::GetOggToWebm() const | |
{ | |
return m_ogg_to_webm; | |
} | |
int CmdLine::GetCPUUsed() const | |
{ | |
return m_cpu_used; | |
} | |
void CmdLine::PrintVersion() const | |
{ | |
wcout << "makewebm "; | |
wchar_t* fname; | |
const errno_t e = _get_wpgmptr(&fname); | |
e; | |
assert(e == 0); | |
assert(fname); | |
VersionHandling::GetVersion(fname, wcout); | |
wcout << endl; | |
} | |
void CmdLine::PrintUsage() const | |
{ | |
wcout << L"usage: makewebm <opts> <args>\n"; | |
wcout << L" -i, --input input filename\n" | |
<< L" --audio-input audio input filename\n" | |
<< L" -o, --output output filename\n" | |
<< L" --deadline " | |
<< L"max time for frame encode (in microseconds)\n" | |
<< L" --decoder-buffer-size " | |
<< L"buffer size (in milliseconds)\n" | |
<< L" --decoder-buffer-initial-size " | |
<< L"before playback (in milliseconds)\n" | |
<< L" --decoder-buffer-optimal-size " | |
<< L"desired size (in milliseconds)\n" | |
<< L" --dropframe-threshold temporal resampling\n" | |
<< L" --end-usage {\"VBR\"|\"CBR\"}\n" | |
<< L" --error-resilient " | |
<< L"defend against lossy or noisy links\n" | |
<< L" --keyframe-frequency " | |
<< L"time (in sec) between keyframes\n" | |
<< L" --keyframe-mode {\"disabled\"|\"auto\"}\n" | |
<< L" --keyframe-min-interval " | |
<< L"min distance between keyframes\n" | |
<< L" --keyframe-max-interval " | |
<< L"max distable between keyframes\n" | |
<< L" --lag-in-frames " | |
<< L"consume frames before producing\n" | |
<< L" --min-quantizer " | |
<< L"min (best quality) quantizer\n" | |
<< L" --max-quantizer " | |
<< L"max (worst quality) quantizer\n" | |
<< L" --no-video " | |
<< L"do not render video (if present)\n" | |
<< L" --require-audio " | |
<< L"quit if no audio encoder available\n" | |
<< L" --no-audio " | |
<< L"do not render audio (if present)\n" | |
<< L" --resize-allowed spatial resampling\n" | |
<< L" --resize-up-threshold " | |
<< L"spatial resampling up threshold\n" | |
<< L" --resize-down-threshold " | |
<< L"spatial resampling down threshold\n" | |
<< L" --script-mode " | |
<< L"print progress in script-friendly way\n" | |
<< L" --save-graph " | |
<< L"save graph as GraphEdit storage file (*.grf)\n" | |
<< L" --target-bitrate " | |
<< L"target bandwidth (in kilobits/second)\n" | |
<< L" --thread-count " | |
<< L"number of threads to use for VP8 encoding\n" | |
<< L" --token-partitions number of sub-streams\n" | |
<< L" --two-pass two-pass encoding\n" | |
<< L" --two-pass-vbr-bias-pct CBR/VBR bias\n" | |
<< L" --two-pass-vbr-minsection-pct minimum bitrate\n" | |
<< L" --two-pass-vbr-maxsection-pct maximum bitrate\n" | |
<< L" --undershoot-pct " | |
<< L"percent of target bitrate for easier frames\n" | |
<< L" --overshoot-pct " | |
<< L"percent of target bitrate for harder frames\n" | |
<< L" --auto-alt-ref " | |
<< L"encoder may create alternate reference frames\n" | |
<< L" --arnr-maxframes " | |
<< L"max number of frames to use on filter\n" | |
<< L" --arnr-strength strength of filter\n" | |
<< L" --arnr-type type of filter\n" | |
<< L" --live live mode WebM output\n" | |
<< L" --cpu-used encoder speed\n" | |
<< L" -l, --list " | |
<< L"print switch values, but do not run app\n" | |
<< L" -v, --verbose " | |
<< L"print verbose list or usage info\n" | |
<< L" -V, --version print version information\n" | |
<< L" -?, -h, --help print usage\n" | |
<< L" -??, -hh, --? print verbose usage\n"; | |
if (!m_verbose) | |
{ | |
wcout << endl; | |
return; | |
} | |
wcout << L'\n' | |
<< L"The order of appearance of switches and arguments\n" | |
<< L"on the command line does not matter.\n" | |
<< L'\n' | |
<< L"Long-form switches may be abbreviated, and are " | |
<< L"case-insensitive.\n" | |
<< L"They may also be specified using Windows-style syntax, " | |
<< L"using a\n" | |
<< L"forward slash for the switch.\n"; | |
wcout << L'\n' | |
<< L"The input filename must be specified, as either a switch\n" | |
<< L"value or as a command-line argument.\n" | |
<< L'\n' | |
<< L"The output filename may be specified as either a switch\n" | |
<< L"value or command-line argument, but it may also be omitted.\n" | |
<< L"If omitted, its value is synthesized from the input " | |
<< L"filename.\n"; | |
wcout << L'\n' | |
<< L"The deadline value specifies the maximum amount of time\n" | |
<< L"(in microseconds) allowed for VP8 encoding of a video frame.\n" | |
<< L"The following distinguished values are also defined:\n" | |
<< L" 0 (or \"best\", or \"infinite\") means take as long as\n" | |
<< L" necessary to achieve best quality\n" | |
<< L" 1 (or \"realtime\") means real-time encoding\n" | |
<< L" 1000000 (or \"good\") means good quality (the default)\n"; | |
wcout << '\n' | |
<< "TODO: MORE PARAMS TO BE DESCRIBED HERE\n"; | |
wcout << endl; | |
} | |
void CmdLine::ListArgs() const | |
{ | |
wcout << L"input : "; | |
if (m_input == 0) | |
wcout << "(no input specified)\n"; | |
else | |
{ | |
wcout << L"\""; | |
if (m_verbose) | |
wcout << GetPath(m_input); | |
else | |
wcout << m_input; | |
wcout << L"\"\n"; | |
} | |
wcout << L"audio-input: "; | |
if (m_audio_input == 0) | |
wcout << "(no audio input specified)\n"; | |
else | |
{ | |
wcout << L"\""; | |
if (m_verbose) | |
wcout << GetPath(m_audio_input); | |
else | |
wcout << m_audio_input; | |
wcout << L"\"\n"; | |
} | |
wcout << L"output : "; | |
if (m_output == 0) | |
wcout << "(no output specified)\n"; | |
else | |
{ | |
wcout << L"\""; | |
if (m_verbose) | |
wcout << GetPath(m_output); | |
else | |
wcout << m_output; | |
wcout << L"\"\n"; | |
} | |
wcout << L"save-graph : "; | |
if (m_save_graph_file_ptr == 0) | |
wcout << "(no save graph file requested)\n"; | |
else if (wcslen(m_save_graph_file_ptr) == 0) | |
wcout << "(will be synthesized from output filename)\n"; | |
else | |
wcout << m_save_graph_file_ptr << L'\n'; | |
wcout << L"script-mode : " << boolalpha << m_script << L'\n'; | |
wcout << L"verbose : " << boolalpha << m_verbose << L'\n'; | |
wcout << L"no-video : " << boolalpha << m_no_video << L'\n'; | |
wcout << L"require-audio: " << boolalpha << m_require_audio << L'\n'; | |
wcout << L"no-audio : " << boolalpha << m_no_audio << L'\n'; | |
wcout << L"live : " << boolalpha << m_live << L'\n'; | |
if (m_deadline >= 0) | |
{ | |
wcout << L"deadline : " << m_deadline; | |
//if (m_verbose) | |
{ | |
if (m_deadline == kDeadlineBestQuality) | |
wcout << " (best quality)"; | |
else if (m_deadline == kDeadlineRealtime) | |
wcout << " (real-time)"; | |
else if (m_deadline == kDeadlineGoodQuality) | |
wcout << " (good quality)"; | |
} | |
wcout << L'\n'; //complete output of deadline value | |
} | |
if (m_decoder_buffer_size >= 0) | |
{ | |
wcout << L"decoder-buffer-size: " << m_decoder_buffer_size; | |
if (m_decoder_buffer_size == 0) | |
wcout << " (use encoder default)"; | |
wcout << L'\n'; | |
} | |
if (m_decoder_buffer_initial_size >= 0) | |
{ | |
wcout << L"decoder-buffer-initial-size: " | |
<< m_decoder_buffer_initial_size; | |
if (m_decoder_buffer_initial_size == 0) | |
wcout << " (use encoder default)"; | |
wcout << L'\n'; | |
} | |
if (m_decoder_buffer_optimal_size >= 0) | |
{ | |
wcout << L"decoder-buffer-optimal-size: " | |
<< m_decoder_buffer_optimal_size; | |
if (m_decoder_buffer_optimal_size == 0) | |
wcout << " (use encoder default)"; | |
wcout << L'\n'; | |
} | |
if (m_end_usage >= 0) | |
{ | |
wcout << L"end-usage: "; | |
switch (m_end_usage) | |
{ | |
case kEndUsageVBR: | |
default: | |
wcout << "VBR"; | |
break; | |
case kEndUsageCBR: | |
wcout << "CBR"; | |
break; | |
} | |
wcout << L'\n'; | |
} | |
if (m_error_resilient >= 0) | |
{ | |
wcout << L"error-resilient: " << m_error_resilient; | |
if (m_error_resilient == 0) | |
wcout << " (disabled)"; | |
else | |
wcout << " (enabled)"; | |
wcout << L'\n'; | |
} | |
if (m_lag_in_frames >= 0) | |
{ | |
wcout << L"lag-in-frames: " << m_lag_in_frames; | |
if (m_lag_in_frames == 0) | |
wcout << " (disabled)"; | |
wcout << L'\n'; | |
} | |
if (m_min_quantizer >= 0) | |
wcout << L"min-quantizer: " << m_min_quantizer << L'\n'; | |
if (m_max_quantizer >= 0) | |
wcout << L"max-quantizer: " << m_max_quantizer << L'\n'; | |
if (m_target_bitrate >= 0) | |
{ | |
wcout << L"target-bitrate: " << m_target_bitrate; | |
if (m_target_bitrate == 0) | |
wcout << " (use encoder default)"; | |
wcout << L'\n'; | |
} | |
if (m_thread_count >= 0) | |
{ | |
wcout << L"thread-count: " << m_thread_count; | |
if (m_thread_count == 0) | |
wcout << L" (use encoder default)"; | |
wcout << L'\n'; | |
} | |
if (m_token_partitions >= 0) | |
wcout << L"token-partitions: " << m_token_partitions << L'\n'; | |
if (m_two_pass >= 0) | |
wcout << L"two-pass: " << m_two_pass << L'\n'; | |
if (m_two_pass_vbr_bias_pct >= 0) | |
wcout << L"two-pass-vbr-bias-pct: " | |
<< m_two_pass_vbr_bias_pct | |
<< L'\n'; | |
if (m_two_pass_vbr_minsection_pct >= 0) | |
wcout << L"two-pass-vbr-minsection-pct: " | |
<< m_two_pass_vbr_minsection_pct | |
<< L'\n'; | |
if (m_two_pass_vbr_maxsection_pct >= 0) | |
wcout << L"two-pass-vbr-maxsection-pct: " | |
<< m_two_pass_vbr_maxsection_pct | |
<< L'\n'; | |
if (m_undershoot_pct >= 0) | |
wcout << L"undershoot-pct: " << m_undershoot_pct << L'\n'; | |
if (m_overshoot_pct >= 0) | |
wcout << L"overshoot-pct : " << m_overshoot_pct << L'\n'; | |
if (m_keyframe_frequency >= 0) | |
{ | |
wcout << L"keyframe-frequency: " | |
<< std::fixed | |
<< std::setprecision(3) | |
<< m_keyframe_frequency | |
<< L'\n'; | |
} | |
if (m_keyframe_mode >= kKeyframeModeDefault) | |
{ | |
wcout << L"keyframe-mode: " << m_keyframe_mode; | |
switch (m_keyframe_mode) | |
{ | |
case kKeyframeModeDefault: | |
default: | |
wcout << L" (use encoder default)"; | |
break; | |
case kKeyframeModeDisabled: | |
wcout << L" (disabled)"; | |
break; | |
case kKeyframeModeAuto: | |
wcout << L" (auto)"; | |
break; | |
} | |
wcout << L'\n'; | |
} | |
else if (m_keyframe_frequency >= 0) | |
{ | |
wcout << L"keyframe-mode: 1 (auto implied by keyframe-frequency)" | |
<< endl; | |
} | |
if (m_keyframe_min_interval >= 0) | |
wcout << L"keyframe-min-interval: " | |
<< m_keyframe_min_interval | |
<< L'\n'; | |
else if (m_keyframe_frequency >= 0) | |
wcout << L"keyframe-min-interval: (determined from framerate)" | |
<< L'\n'; | |
if (m_keyframe_max_interval >= 0) | |
wcout << L"keyframe-max-interval: " | |
<< m_keyframe_max_interval | |
<< L'\n'; | |
else | |
wcout << L"keyframe-max-interval: (determined from framerate)" | |
<< L'\n'; | |
if (m_auto_alt_ref >= 0) | |
wcout << L"auto-alt-ref: " << m_auto_alt_ref << L'\n'; | |
if (m_arnr_maxframes >= 0) | |
wcout << L"arnr-maxframes: " << m_arnr_maxframes << L'\n'; | |
if (m_arnr_strength >= 0) | |
wcout << L"arnr-strength: " << m_arnr_strength << L'\n'; | |
if (m_arnr_type >= 0) | |
wcout << L"arnr-type: " << m_arnr_type << L'\n'; | |
if (m_cpu_used >= -16) | |
wcout << L"cpu-used: " << m_cpu_used << L'\n'; | |
wcout << endl; | |
} | |
std::wstring CmdLine::GetPath(const wchar_t* filename) | |
{ | |
assert(filename); | |
//using std::wstring; | |
//wstring path; | |
//wstring::size_type filepos; | |
DWORD buflen = _MAX_PATH + 1; | |
for (;;) | |
{ | |
const DWORD cb = buflen * sizeof(wchar_t); | |
wchar_t* const buf = (wchar_t*)_malloca(cb); | |
wchar_t* ptr; | |
const DWORD n = GetFullPathName(filename, buflen, buf, &ptr); | |
if (n == 0) //error | |
{ | |
const DWORD e = GetLastError(); | |
e; | |
return filename; //best we can do | |
} | |
if (n < buflen) | |
{ | |
//path = buf; | |
//filepos = ptr - buf; | |
//break; | |
return buf; | |
} | |
buflen = 2 * buflen + 1; | |
} | |
//return path; | |
} | |
void CmdLine::SynthesizeOutput() | |
{ | |
wstring& path = m_synthesized_output; | |
path = GetPath(m_input); | |
const wstring::size_type pos = path.rfind(L'.'); | |
const wstring::size_type len = path.length(); | |
if (pos == wstring::npos) //no ext | |
path.append(L".webm"); | |
else if (_wcsicmp(path.c_str() + pos, L".webm") == 0) //match | |
path.replace(pos, len, L"_remux.webm"); | |
else | |
path.replace(pos, len, L".webm"); | |
m_output = path.c_str(); | |
} | |
void CmdLine::SynthesizeSaveGraph() | |
{ | |
wstring& path = m_save_graph_file_str; | |
path = GetPath(m_output); | |
const wstring::size_type pos = path.rfind(L'.'); | |
const wstring::size_type len = path.length(); | |
if (pos == wstring::npos) //weird: no ext | |
path.append(L".grf"); | |
else if (_wcsicmp(path.c_str() + pos, L".grf") == 0) //weird: match | |
path.replace(pos, len, L"_graph.grf"); | |
else | |
path.replace(pos, len, L".grf"); //typical | |
m_save_graph_file_ptr = m_save_graph_file_str.c_str(); | |
} | |
int CmdLine::ParseOpt( | |
wchar_t** i, | |
const wchar_t* arg, | |
size_t len, | |
const wchar_t* name, | |
int& value, | |
int min, | |
int max, | |
int optional) const | |
{ | |
if (_wcsnicmp(arg, name, len) != 0) //not a match | |
return 0; //keep parsing | |
const bool has_value = (arg[len] != L'\0'); //L':' or L'=" | |
const bool is_required = (optional == kValueIsRequired); | |
int n; | |
const wchar_t* str_value; | |
size_t str_value_length; | |
if (has_value) | |
{ | |
str_value = arg + len + 1; | |
str_value_length = wcslen(str_value); | |
if (str_value_length == 0) | |
{ | |
if (is_required) | |
{ | |
wcout << "Empty value specified for " | |
<< name | |
<< " switch." | |
<< endl; | |
return -1; //error | |
} | |
str_value = 0; //means "use optional value" | |
} | |
n = 1; | |
} | |
else | |
{ | |
str_value = *++i; | |
if (str_value) | |
{ | |
if (IsSwitch(str_value) || !iswdigit(*str_value)) | |
{ | |
//potential optional found | |
if (is_required) | |
{ | |
wcout << "No value specified for " | |
<< name | |
<< " switch." | |
<< endl; | |
return -1; //error | |
} | |
str_value = 0; //yes, optional was found | |
n = 1; | |
} | |
else | |
{ | |
str_value_length = wcslen(str_value); | |
n = 2; | |
} | |
} | |
else if (is_required) | |
{ | |
wcout << "No value specified for " << name << " switch." << endl; | |
return -1; //error | |
} | |
else | |
n = 1; //optional value will be used | |
} | |
if (str_value == 0) | |
{ | |
assert(!is_required); | |
value = optional; | |
return n; | |
} | |
std::wistringstream is(str_value); | |
if (!(is >> value) || !is.eof()) | |
{ | |
wcout << "Bad value specified for " << name << " switch." << endl; | |
return -1; //error | |
} | |
if (value < min) | |
{ | |
wcout << "Value for " << name | |
<< " is out-of-range (too small)." | |
<< endl; | |
return -1; //error | |
} | |
if ((max >= min) && (value > max)) | |
{ | |
wcout << "Value for " << name | |
<< " is out-of-range (too large)." | |
<< endl; | |
return -1; //error | |
} | |
return n; //success | |
} |