From fe6315e468103dd5a9a4012f1bab1923668e9ca9 Mon Sep 17 00:00:00 2001 From: falsycat Date: Thu, 28 Jul 2022 00:59:44 +0900 Subject: [PATCH] temp --- blocky/CMakeLists.txt | 11 +- blocky/args.hh | 92 ++++++++++++ blocky/bytes.hh | 75 ---------- blocky/common.hh | 53 +------ blocky/embed.cc | 10 ++ blocky/embed.hh | 114 --------------- blocky/extract.cc | 10 ++ blocky/extract.hh | 65 --------- blocky/features.hh | 105 -------------- blocky/main.cc | 304 +--------------------------------------- blocky/video_decoder.hh | 179 ----------------------- blocky/video_encoder.hh | 82 ----------- 12 files changed, 128 insertions(+), 972 deletions(-) create mode 100644 blocky/args.hh delete mode 100644 blocky/bytes.hh create mode 100644 blocky/embed.cc delete mode 100644 blocky/embed.hh create mode 100644 blocky/extract.cc delete mode 100644 blocky/extract.hh delete mode 100644 blocky/features.hh delete mode 100644 blocky/video_decoder.hh delete mode 100644 blocky/video_encoder.hh diff --git a/blocky/CMakeLists.txt b/blocky/CMakeLists.txt index af0e8b0..87c9609 100644 --- a/blocky/CMakeLists.txt +++ b/blocky/CMakeLists.txt @@ -3,14 +3,11 @@ target_compile_options(blocky PRIVATE ${BLOCKY_C_FLAGS}) target_sources(blocky PUBLIC - main.cc - - bytes.hh + args.hh common.hh - embed.hh - extract.hh - video_encoder.hh - video_decoder.hh + embed.cc + extract.cc + main.cc ) target_link_libraries(blocky PUBLIC diff --git a/blocky/args.hh b/blocky/args.hh new file mode 100644 index 0000000..00a879e --- /dev/null +++ b/blocky/args.hh @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "common.hh" + + +namespace blky::args { + +using namespace ::args; + + +struct uvec2_Reader final { + void operator()(const std::string&, const std::string& value, uvec2& dst) { + char _; + if (3 != sscanf(value.c_str(), "%" PRIu32 "%c%" PRIu32, &dst.x, &_, &dst.y)) { + throw std::runtime_error {"invalid uvec2 specification: "+value}; + } + } +}; + + +/* ---- root parser ---- */ +static inline ArgumentParser parser { + "blocky is a command line tool for data hiding of video" +}; +static inline Group commands { parser, "COMMAND:" }; +static inline HelpFlag help { parser, "help", "display this help menu", {'h', "help"}, Options::Global }; + + +/* ---- group: key ---- */ +static inline Group key { "key information:" }; +static inline ValueFlag block_num { + key, "8x8", "number of blocks", {"block-num"}, {8, 8} +}; +static inline ValueFlag feat_bits { + key, "1", "bits per each step", {"feat-bits"}, 1 +}; +static inline ValueFlag seed { + key, "123", "random seed for hopping", {"seed"}, 123 +}; +static inline ValueFlag utime { + key, "10", "duration of each step (frames)", {"utime"}, 10 +}; + + +/* ---- group: stream source ---- */ +static inline Group stream { "stream source (choose one):", Group::Validators::AtMostOne }; +static inline Flag stream_stdin { + stream, "stdin", "load from stdin (default)", {"stdin"}, true +}; +static inline Flag stream_stdin_hex { + stream, "stdin-hex", "load from stdin as HEX (e.g 'FF00'", {"stdin-hex"} +}; + + +/* ---- command: embed ---- */ +static inline Group embed {}; +static inline Positional embed_dst { + embed, "dst", "destination video path", Options::Required +}; +static inline Positional embed_src { + embed, "src", "source video path", Options::Required +}; +static inline Command command_embed { commands, "embed", "embed stream to video", [](auto& p) { + p.Add(embed); + p.Add(stream); + p.Add(key); + p.Parse(); + Cmd_Embed(); +}}; + + +/* ---- command: extract ---- */ +static inline Group extract {}; +static inline Positional extract_src { + extract, "src", "source video path", Options::Required +}; +static inline Command command_extract { commands, "extract", "extract stream from video", [](auto& p) { + p.Add(extract); + p.Add(key); + p.Parse(); + Cmd_Extract(); +}}; + +} // namespace blky::args diff --git a/blocky/bytes.hh b/blocky/bytes.hh deleted file mode 100644 index 95adcd9..0000000 --- a/blocky/bytes.hh +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "common.hh" - - -namespace blky { - -std::vector BytesEncoder( - const std::vector& bytes, - std::tuple& block_num, - uint8_t feat_bits, - uint32_t block_idx, - uint64_t seed) { - const uint32_t block_num_all = std::get<0>(block_num)*std::get<1>(block_num); - if (block_num_all == 0) throw std::runtime_error {"block num is zero"}; - - blky_encoder_t enc = {}; - enc.block_num = block_num_all; - enc.feat_bits = feat_bits; - enc.block_index = block_idx; - enc.seed = seed; - - std::vector ret; - for (auto c : bytes) { - blky_encoder_feed(&enc, c); - - uint32_t feat; - while (blky_encoder_pop(&enc, &feat, false)) { - ret.push_back(feat); - } - } - - uint32_t feat; - if (blky_encoder_pop(&enc, &feat, true)) { - ret.push_back(feat); - } - return ret; -} - -std::vector BytesDecoder( - const std::vector& features, - std::tuple& block_num, - uint8_t feat_bits, - uint64_t seed) { - const uint32_t block_num_all = std::get<0>(block_num)*std::get<1>(block_num); - if (block_num_all == 0) throw std::runtime_error {"block num is zero"}; - - blky_decoder_t de = {}; - de.block_num = block_num_all; - de.feat_bits = feat_bits; - de.seed = seed; - - std::vector ret; - for (auto c : features) { - if (!blky_decoder_feed(&de, c)) { - throw std::runtime_error {"path corruption"}; - } - - uint8_t feat; - while (blky_decoder_pop(&de, &feat, false)) { - ret.push_back(feat); - } - } - uint8_t feat; - if (blky_decoder_pop(&de, &feat, true)) { - ret.push_back(feat); - } - return ret; -} - -} // namespace blky diff --git a/blocky/common.hh b/blocky/common.hh index 9788a04..c539f9f 100644 --- a/blocky/common.hh +++ b/blocky/common.hh @@ -1,59 +1,20 @@ #pragma once -extern "C" { -# include -} - -#include #include #include -#include -#include -#include namespace blky { -enum DataFlow { - kBytes, - kFeatures, - kFeatureProbs, - kVideo, -}; - -static inline const std::string kDataFlowList = "bytes/features/video"; -static inline const std::unordered_map kDataFlowMap = { - {"bytes", kBytes}, - {"features", kFeatures}, - {"feature-probs", kFeatureProbs}, - {"video", kVideo}, -}; +struct uvec2 final { uint32_t x, y; }; -template -std::vector ReadAll(auto& ist) noexcept { - std::vector ret; - for (;;) { - T v; - ist >> v; - if (ist.eof()) return ret; - ret.push_back(v); - } -} +/* ---- global state accessors ---- */ +std::istream& GetStream(); -static uint8_t ToHex(char c) { - if (!std::isxdigit(c)) throw std::runtime_error {"not xdigit"}; - return static_cast(std::isalpha(c)? std::tolower(c)-'a'+0xA: c-'0'); -} + +/* ---- command handlers ---- */ +void Cmd_Embed(); +void Cmd_Extract(); } // namespace blky - - -namespace args { - -auto& operator>>(auto& ist, std::tuple& v) { - ist >> std::get<0>(v) >> std::get<1>(v); - return ist; -} - -} // namespace args diff --git a/blocky/embed.cc b/blocky/embed.cc new file mode 100644 index 0000000..68c8d5c --- /dev/null +++ b/blocky/embed.cc @@ -0,0 +1,10 @@ +#include "common.hh" + + +namespace blky { + +void Cmd_Embed() { + // TODO +} + +} // namespace blky diff --git a/blocky/embed.hh b/blocky/embed.hh deleted file mode 100644 index 9bd9047..0000000 --- a/blocky/embed.hh +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "video_decoder.hh" -#include "video_encoder.hh" - - -namespace blky { - -void Embed(const std::vector& features, - const std::string& dst_path, - const std::string& video_path, - const std::tuple& div, - uint32_t utime) { - assert(features.size()); - - const uint32_t div_x = std::get<0>(div); - const uint32_t div_y = std::get<1>(div); - - VideoDecoder dec {video_path}; - std::optional enc; - - std::vector Y; - std::vector U; - std::vector V; - - uint32_t last_feat = UINT32_MAX; - std::vector feat_pix; - for (uint32_t time = 0; dec.Decode();) { - const auto& src = dec.frame(); - if (src.iBufferStatus != 1) continue; - ++time; - - const uint32_t w = static_cast(src.UsrData.sSystemBuffer.iWidth); - const uint32_t h = static_cast(src.UsrData.sSystemBuffer.iHeight); - - const uint32_t stride_y = static_cast(src.UsrData.sSystemBuffer.iStride[0]); - const uint32_t stride_uv = static_cast(src.UsrData.sSystemBuffer.iStride[1]); - - const uint8_t* const* srcp = src.pDst; - - // copy buffer to modify - Y.resize(w*h); - U.resize(w*h/2/2); - V.resize(w*h/2/2); - for (uint32_t y = 0; y < h; ++y) { - std::memcpy(Y.data()+y*w, srcp[0]+stride_y*y, w); - } - for (uint32_t y = 0; y < h/2; ++y) { - std::memcpy(U.data()+y*(w/2), srcp[1]+stride_uv*y, w/2); - std::memcpy(V.data()+y*(w/2), srcp[2]+stride_uv*y, w/2); - } - - // embed a feature to the buffer - const uint32_t feat = features[(time/utime)%features.size()]; - - const uint32_t feat_x = feat%div_x; - const uint32_t feat_y = feat/div_x; - - const uint32_t feat_size_x = w/div_x; - const uint32_t feat_size_y = h/div_y; - - const uint32_t feat_offset_x = feat_x*feat_size_x; - const uint32_t feat_offset_y = feat_y*feat_size_y; - - if (feat != last_feat) { - feat_pix.resize(feat_size_x*feat_size_y); - for (uint32_t y = 0; y < feat_size_y; ++y) { - const uint32_t ay = y+feat_offset_y; - std::memcpy(feat_pix.data()+y*feat_size_x, Y.data()+ay*w+feat_offset_x, feat_size_x); - //std::memcpy(feat_pix.data()+(y/2)*(feat_size_x/2), U.data()+(ay/2)*(w/2)+feat_offset_x/2, feat_size_x/2); - //std::memcpy(feat_pix.data()+(y/2)*(feat_size_x/2)+feat_pix.size()/2, V.data()+(ay/2)*(w/2)+feat_offset_x/2, feat_size_x/2); - } - last_feat = feat; - if (enc) enc->ForceIntraFrame(); - } - for (uint32_t y = 0; y < feat_size_y; ++y) { - const uint32_t ay = y+feat_offset_y; - std::memcpy(Y.data()+ay*w+feat_offset_x, feat_pix.data()+y*feat_size_x, feat_size_x); - //std::memcpy(U.data()+(ay/2)*(w/2)+feat_offset_x/2, feat_pix.data()+(y/2)*(feat_size_x/2), feat_size_x/2); - //std::memcpy(V.data()+(ay/2)*(w/2)+feat_offset_x/2, feat_pix.data()+(y/2)*(feat_size_x/2)+feat_pix.size()/2, feat_size_x/2); - } - - // create an encoder if not yet - if (!enc) { - SEncParamBase param = {}; - param.iUsageType = CAMERA_VIDEO_REAL_TIME; - param.iPicWidth = static_cast(w); - param.iPicHeight = static_cast(h); - param.fMaxFrameRate = 30; - param.iTargetBitrate = 5000000; - enc.emplace(dst_path, param); - } - - // encode - SSourcePicture dst = {}; - dst.iColorFormat = videoFormatI420; - dst.pData[0] = Y.data(); - dst.pData[1] = U.data(); - dst.pData[2] = V.data(); - dst.iStride[0] = static_cast(w); - dst.iStride[1] = static_cast(w/2); - dst.iStride[2] = static_cast(w/2); - dst.iPicWidth = static_cast(w); - dst.iPicHeight = static_cast(h); - dst.uiTimeStamp = static_cast(src.uiOutYuvTimeStamp); - enc->Encode(dst); - } -} - -} // namespace blky diff --git a/blocky/extract.cc b/blocky/extract.cc new file mode 100644 index 0000000..653bed1 --- /dev/null +++ b/blocky/extract.cc @@ -0,0 +1,10 @@ +#include "common.hh" + + +namespace blky { + +void Cmd_Extract() { + // TODO +} + +} // namespace blky diff --git a/blocky/extract.hh b/blocky/extract.hh deleted file mode 100644 index bb3d186..0000000 --- a/blocky/extract.hh +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "common.hh" -#include "video_decoder.hh" - - -namespace blky { - -std::vector Extract( - VideoDecoder& dec, - std::tuple block_num, - std::tuple sensor_num, - uint32_t utime) { - std::vector ret; - - blky_extractor_t ex = {}; - ex.block_num_x = std::get<0>(block_num); - ex.block_num_y = std::get<1>(block_num); - ex.sensor_num_block_x = std::get<0>(sensor_num); - ex.sensor_num_block_y = std::get<1>(sensor_num); - ex.samples_per_pix = 1; - ex.pix_stride = 1; - ex.utime = utime; - ex.correl_max_var = 0.3; - ex.correl_min_avg = 0.8; - - blky_extractor_init(&ex); - while (dec.Decode()) { - const auto& frame = dec.frame(); - if (frame.iBufferStatus != 1) { - continue; - } - - const uint32_t w = static_cast(frame.UsrData.sSystemBuffer.iWidth); - const uint32_t h = static_cast(frame.UsrData.sSystemBuffer.iHeight); - - const uint32_t stride_y = static_cast(frame.UsrData.sSystemBuffer.iStride[0]); - //const uint32_t stride_uv = static_cast(frame.UsrData.sSystemBuffer.iStride[1]); - - const uint8_t* const* srcp = frame.pDst; - - const double wf = static_cast(w) / static_cast(stride_y); - const double verts[8] = { - 0, 0, - 0, 1, - wf, 1, - wf, 0, - }; - if (blky_extractor_feed(&ex, srcp[0], stride_y, h, verts)) { - const size_t psize = ret.size(); - ret.resize(ret.size() + ex.block_num); - std::memcpy(ret.data() + psize, ex.probs, ex.block_num * sizeof(ret[0])); - } - } - blky_extractor_deinit(&ex); - - return ret; -} - -} // namespace blky diff --git a/blocky/features.hh b/blocky/features.hh deleted file mode 100644 index 91dd697..0000000 --- a/blocky/features.hh +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "common.hh" - - -namespace blky { - -std::vector PathfindFeatures( - const std::vector& probs, - std::tuple& block_num, - uint8_t feat_bits, - uint64_t seed) { - const uint32_t num = std::get<0>(block_num) * std::get<1>(block_num); - if (num == 0) throw std::runtime_error {"number of blocks is zero"}; - - const uint64_t dur = probs.size()/num; - if (probs.size() == 0) { - throw std::runtime_error {"size of probability matrix is empty"}; - } - if (dur*num != probs.size()) { - throw std::runtime_error {"size of probability matrix is mismatch"}; - } - - blky_pathfinder_t pf = {}; - pf.block_num = num; - pf.feat_bits = feat_bits; - pf.seed = seed; - - blky_pathfinder_init(&pf); - - for (uint64_t t = 0; t < dur; ++t) { - blky_pathfinder_feed(&pf, probs.data()+t*num); - } - assert(pf.step_last); - - uint32_t max_idx = 0; - double max_prob = -1; - for (uint32_t i = 0; i < num; ++i) { - if (max_prob < pf.probs[i]) { - max_prob = pf.probs[i]; - max_idx = i; - } - } - - std::vector ret; - blky_pathfinder_step_t* step = pf.step_last; - uint32_t idx = max_idx; - for (;;) { - ret.push_back(idx); - if (!step) break; - idx = step->indices[idx]; - step = step->prev; - } - std::reverse(ret.begin(), ret.end()); - - blky_pathfinder_deinit(&pf); - return ret; -} - -std::vector GenerateFeatureProbs( - const std::vector& features, - std::tuple& block_num, - double false_positive, - double false_negative, - uint64_t seed, - bool normalize) { - const uint32_t num = std::get<0>(block_num) * std::get<1>(block_num); - if (num == 0) throw std::runtime_error {"number of blocks is zero"}; - - std::vector ret; - for (auto c : features) { - const auto begin = ret.size(); - - double sum = 0; - for (uint32_t bi = 0; bi < num; ++bi) { - seed = blky_numeric_xorshift64(seed); - const double prob1 = static_cast(seed%1000)/1000.; - - seed = blky_numeric_xorshift64(seed); - const double prob2 = static_cast(seed%1000)/1000.; - - seed = blky_numeric_xorshift64(seed); - double fprob; - if ((c == bi && prob1 >= false_negative) || prob2 < false_positive) { - fprob = static_cast(seed%200)/1000. + .8; - } else { - fprob = static_cast(seed%800)/1000.; - } - ret.push_back(fprob); - sum += fprob; - } - if (normalize) { - for (size_t i = begin; i < ret.size(); ++i) { - ret[i] /= sum; - } - } - } - return ret; -} - -} // namespace blky diff --git a/blocky/main.cc b/blocky/main.cc index afd544d..0346a98 100644 --- a/blocky/main.cc +++ b/blocky/main.cc @@ -1,319 +1,25 @@ -#include #include -#include #include -#include -#include -#include "common.hh" -#include "bytes.hh" -#include "embed.hh" -#include "extract.hh" -#include "features.hh" - -#include - -#include "video_decoder.hh" -#include "video_encoder.hh" +#include "args.hh" -using namespace blky; - - -args::ArgumentParser parser( - "liblocky command line tool", - "liblocky allow you to embed a bit array into video data secretly"); - -args::MapFlag from { - parser, kDataFlowList, "input layer specifier", {"from"}, kDataFlowMap, args::Options::Required}; - -args::MapFlag to { - parser, kDataFlowList, "output layer specifier", {"to"}, kDataFlowMap, args::Options::Required}; - -args::Group src_group { - parser, "source specifier", args::Group::Validators::Xor, args::Options::Required}; -args::Flag src_stdin {src_group, "src-stdin", "read from stdin", {"src-stdin", "stdin"}}; -args::Flag src_stdin_hex {src_group, "src-stdin-hex", "read hex text from stdin", {"src-stdin-hex", "stdin-hex"}}; -args::ValueFlag src_video {src_group, "path", "video input", {"src-video"}}; - -args::Group dst_group { - parser, "destination specifier", args::Group::Validators::Xor, args::Options::Required}; -args::Flag dst_stdout {dst_group, "dst-stdout", "write to stdout", {"dst-stdout", "stdout"}}; -args::Flag dst_stdout_hex {dst_group, "dst-stdout-hex", "write to stdout as hex text", {"dst-stdout-hex", "stdout-hex"}}; -args::ValueFlag dst_video {dst_group, "path", "video output", {"dst-video"}}; - -args::Group param_group { - parser, "general parameters", args::Group::Validators::DontCare -}; -args::ValueFlag> param_block_num { - param_group, - "int>0,int>0", - "number of features", - {"feature-num"}, - {8, 8} -}; -args::ValueFlag param_block_first { - param_group, - "int>=0", - "an index of first block where feature will be embedded. used when encoding", - {"feature-first-index"}, - 0 -}; -args::ValueFlag param_feat_bits { - param_group, - "int>0", - "number of bits that can be represented by a single feature", - {"feature-bits"}, - 1 -}; -args::ValueFlag param_seed { - param_group, - "int>0", - "seed number for hopping randomization", - {"seed"}, - 123 -}; -args::ValueFlag param_video { - param_group, - "path", - "a video file where information is embed", - {"path"}, -}; -args::ValueFlag param_utime { - param_group, - "int>0", - "a duration (milliseconds) of features", - {"utime"}, - 10 -}; -args::ValueFlag> param_sensor_num { - param_group, - "int>0,int>0", - "number of sensors (for extraction)", - {"sensor-num"}, - {16, 16} -}; - -args::Group probgen_group { - parser, "params for feature probability generator", args::Group::Validators::DontCare -}; -args::ValueFlag probgen_false_positive { - probgen_group, - "0<=double<=1", - "false positive ratio in feature probability generation", - {"probgen-false-positive"}, - 0 -}; -args::ValueFlag probgen_false_negative { - probgen_group, - "0<=double<=1", - "false negative ratio in feature probability generation", - {"probgen-false-negative"}, - 0 -}; -args::ValueFlag probgen_seed { - probgen_group, - "int>0", - "random seed", - {"probgen-seed"}, - 1 -}; -args::Flag probgen_normalize { - probgen_group, - "probgen-normalize", - "normalize probabilities", - {"probgen-normalize"}, -}; - - -std::vector bytes; -std::vector features; -std::vector feature_probs; -std::optional decoder; +using namespace ::blky::args; int main(int argc, char** argv) try { parser.ParseCLI(argc, argv); - // read input - switch (args::get(from)) { - case kBytes: - if (src_stdin) { - std::string temp; - std::cin >> temp; - bytes = {temp.begin(), temp.end()}; - } else if (src_stdin_hex) { - for (;;) { - char buf[2]; - std::cin >> buf[0] >> buf[1]; - if (std::cin.eof()) break; - bytes.push_back(static_cast((ToHex(buf[0]) << 4) | ToHex(buf[1]))); - } - } else { - throw std::runtime_error {"invalid source format for bytes"}; - } - break; - - case kFeatures: - if (src_stdin) { - features = ReadAll(std::cin); - } else { - throw std::runtime_error {"invalid source format for features"}; - } - break; - - case kFeatureProbs: - if (src_stdin) { - feature_probs = ReadAll(std::cin); - } else { - throw std::runtime_error {"invalid source format for feature probs"}; - } - break; - - case kVideo: - if (src_video) { - decoder.emplace(args::get(src_video)); - } else { - throw std::runtime_error {"invalid source format for video"}; - } - } - - if (args::get(from) < args::get(to)) { - // execute encoding - switch (args::get(from)) { - case kBytes: - if (args::get(to) == kBytes) break; - features = BytesEncoder( - bytes, - args::get(param_block_num), - args::get(param_feat_bits), - args::get(param_block_first), - args::get(param_seed)); - /* fallthrough */ - - case kFeatures: - if (args::get(to) == kFeatures) break; - if (args::get(to) == kFeatureProbs) { - feature_probs = GenerateFeatureProbs( - features, - args::get(param_block_num), - args::get(probgen_false_positive), - args::get(probgen_false_negative), - args::get(probgen_seed), - probgen_normalize); - break; - } - assert(dst_video); - Embed( - features, - args::get(dst_video), - args::get(param_video), - args::get(param_block_num), - args::get(param_utime)); - /* fallthrough */ - - case kVideo: - if (args::get(to) == kVideo) break; - assert(false); - - case kFeatureProbs: - throw std::runtime_error("couldn't start flow from the data"); - } - - } else if (args::get(from) > args::get(to)) { - // execute decoding - switch (args::get(from)) { - case kVideo: - if (args::get(to) == kVideo) break; - if (!decoder) { - throw std::runtime_error {"decoder is empty"}; - } - feature_probs = Extract( - *decoder, - args::get(param_block_num), - args::get(param_sensor_num), - args::get(param_utime)); - /* fallthrough */ - - case kFeatureProbs: - if (args::get(to) == kFeatureProbs) break; - features = PathfindFeatures( - feature_probs, - args::get(param_block_num), - args::get(param_feat_bits), - args::get(param_seed)); - /* fallthrough */ - - case kFeatures: - if (args::get(to) == kFeatures) break; - bytes = BytesDecoder( - features, - args::get(param_block_num), - args::get(param_feat_bits), - args::get(param_seed)); - /* fallthrough */ - - case kBytes: - if (args::get(to) == kBytes) break; - assert(false); - } - } - - // output - switch (args::get(to)) { - case kBytes: - if (dst_stdout) { - std::cout << std::string {bytes.begin(), bytes.end()} << std::endl; - } else if (dst_stdout_hex) { - for (auto c : bytes) { - std::cout << std::hex << (int) c; - } - std::cout << std::endl; - } else { - throw std::runtime_error {"invalid destination format for bytes"}; - } - break; - - case kFeatures: - if (dst_stdout) { - for (auto& f : features) std::cout << f << "\n"; - } else { - throw std::runtime_error {"invalid destination format for features"}; - } - break; - - case kFeatureProbs: - if (dst_stdout) { - const auto size = args::get(param_block_num); - const auto cols = std::get<0>(size) * std::get<1>(size); - for (size_t i = 0; i < feature_probs.size();) { - for (size_t j = 0; i < feature_probs.size() && j < cols; ++i, ++j) { - std::cout << feature_probs[i] << " "; - } - std::cout << "\n"; - } - } else { - throw std::runtime_error {"invalid destination format for feature probs"}; - } - break; - - case kVideo: - break; - } - return 0; - -} catch (const args::Help&) { +} catch (const Help&) { std::cout << parser << std::endl; return 0; -} catch (const args::ParseError& e) { +} catch (const ParseError& e) { std::cerr << e.what() << std::endl; - std::cerr << parser << std::endl; return 1; -} catch (const args::ValidationError& e) { +} catch (const ValidationError& e) { std::cerr << e.what() << std::endl; - std::cerr << parser << std::endl; return 1; } catch (const std::runtime_error& e) { diff --git a/blocky/video_decoder.hh b/blocky/video_decoder.hh deleted file mode 100644 index 7e5becc..0000000 --- a/blocky/video_decoder.hh +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - - -class VideoDecoder final { - public: - VideoDecoder() = delete; - VideoDecoder(const std::string& path) : - file_(path, std::ifstream::binary | std::ifstream::ate), - size_(static_cast(file_.tellg())) { - // init objects - SDecodingParam dparam = {}; - dparam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; - dparam.eEcActiveIdc = ERROR_CON_SLICE_COPY; - - WelsCreateDecoder(&decoder_); - decoder_->Initialize(&dparam); - - int lv = WELS_LOG_DEBUG; - decoder_->SetOption(DECODER_OPTION_TRACE_LEVEL, &lv); - - demuxer_ = {}; - MP4D_open(&demuxer_, ReadCallback, this, static_cast(size_)); - - // find video track - track_ = SIZE_MAX; - for (size_t i = 0; i < demuxer_.track_count; ++i) { - if (demuxer_.track[i].handler_type == MP4D_HANDLER_TYPE_VIDE) { - if (track_ != SIZE_MAX) { - throw std::runtime_error {"there are many video tracks"}; - } - track_ = i; - } - } - if (track_ == SIZE_MAX) { - throw std::runtime_error {"there is no video track"}; - } - - // setup decoder - std::vector temp_; - - for (size_t i = 0;; ++i) { - int size; - auto sps = static_cast(MP4D_read_sps( - &demuxer_, - static_cast(track_), - static_cast(i), - &size)); - if (!sps) break; - - temp_.resize(static_cast(4+size)); - temp_[0] = 0, temp_[1] = 0, temp_[2] = 0, temp_[3] = 1; - std::memcpy(&temp_[4], sps, static_cast(size)); - - if (decoder_->DecodeFrameNoDelay(temp_.data(), static_cast(temp_.size()), yuv_, &frame_)) { - throw std::runtime_error {"failed to decode SPS"}; - } - } - for (size_t i = 0;; ++i) { - int size; - auto pps = static_cast(MP4D_read_pps( - &demuxer_, - static_cast(track_), - static_cast(i), - &size)); - if (!pps) break; - - temp_.resize(static_cast(4+size)); - temp_[0] = 0, temp_[1] = 0, temp_[2] = 0, temp_[3] = 1; - std::memcpy(&temp_[4], pps, static_cast(size)); - - if (decoder_->DecodeFrameNoDelay(temp_.data(), static_cast(temp_.size()), yuv_, &frame_)) { - throw std::runtime_error {"failed to decode SPS"}; - } - } - temp_.clear(); - } - ~VideoDecoder() noexcept { - decoder_->Uninitialize(); - WelsDestroyDecoder(decoder_); - - MP4D_close(&demuxer_); - } - VideoDecoder(const VideoDecoder&) = delete; - VideoDecoder(VideoDecoder&&) = delete; - VideoDecoder& operator=(const VideoDecoder&) = delete; - VideoDecoder& operator=(VideoDecoder&&) = delete; - - bool Decode() { - if (temp_consumed_ >= temp_.size()) { - if (count_ >= demuxer_.track[track_].sample_count) { - return false; - } - - unsigned size, time, dur; - const auto off = MP4D_frame_offset( - &demuxer_, - static_cast(track_), - static_cast(count_), - &size, &time, &dur); - - assert(size > 0); - temp_.resize(size); - temp_consumed_ = 0; - - file_.seekg(static_cast(off)); - assert(file_); - file_.read((char*) temp_.data(), size); - assert(file_); - - Decode(); - ++count_; - return true; - - } else { - auto& i = temp_consumed_; - - const uint32_t nal_size = 4 + - static_cast((temp_[i+0] << 24) | - (temp_[i+1] << 16) | - (temp_[i+2] << 8) | - (temp_[i+3] << 0)); - temp_[i ] = 0; - temp_[i+1] = 0; - temp_[i+2] = 0; - temp_[i+3] = 1; - if (decoder_->DecodeFrameNoDelay(temp_.data()+i, static_cast(nal_size), yuv_, &frame_)) { - throw std::runtime_error {"failed to decode a frame"}; - } - i += nal_size; - return true; - } - } - - const SBufferInfo& frame() const noexcept { return frame_; } - const uint8_t* const* yuv() const noexcept { return yuv_; } - - private: - std::ifstream file_; - size_t size_; - - ISVCDecoder* decoder_; - MP4D_demux_t demuxer_; - - size_t track_; - - uint8_t* yuv_[3] = {0}; - SBufferInfo frame_ = {}; - size_t count_ = 0; - - size_t temp_consumed_ = 0; - std::vector temp_; - - - static int ReadCallback(int64_t off, void* buf, size_t size, void* ptr) noexcept { - auto self = (VideoDecoder*) ptr; - - auto n = self->size_ - static_cast(off) - size; - if (size < n) n = size; - - self->file_.seekg(off); - assert(self->file_); - - self->file_.read((char*) buf, static_cast(n)); - assert(self->file_); - return 0; - } -}; diff --git a/blocky/video_encoder.hh b/blocky/video_encoder.hh deleted file mode 100644 index 0645a79..0000000 --- a/blocky/video_encoder.hh +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include - -#include - - -class VideoEncoder final { - public: - VideoEncoder() = delete; - VideoEncoder(const std::string& path, const SEncParamBase& p) : - file_(path, std::ofstream::binary), fps_(p.fMaxFrameRate) { - if (WelsCreateSVCEncoder(&encoder_)) { - throw std::runtime_error {"failed to init openh264 encoder"}; - } - - muxer_ = MP4E_open(false, false, this, WriteCallback); - if (MP4E_STATUS_OK != mp4_h26x_write_init(&writer_, muxer_, p.iPicWidth, p.iPicHeight, false)) { - throw std::runtime_error {"failed to init h26x writer"}; - } - - encoder_->Initialize(&p); - - int lv = WELS_LOG_DEBUG; - encoder_->SetOption(ENCODER_OPTION_TRACE_LEVEL, &lv); - int fmt = videoFormatI420; - encoder_->SetOption(ENCODER_OPTION_DATAFORMAT, &fmt); - } - ~VideoEncoder() noexcept { - encoder_->Uninitialize(); - WelsDestroySVCEncoder(encoder_); - - MP4E_close(muxer_); - mp4_h26x_write_close(&writer_); - } - - void Encode(const SSourcePicture& pic) { - SFrameBSInfo info; - if (cmResultSuccess != encoder_->EncodeFrame(&pic, &info)) { - throw std::runtime_error {"failed to encode a frame"}; - } - if (info.eFrameType == videoFrameTypeSkip) return; - - for (size_t i = 0; i < static_cast(info.iLayerNum); ++i) { - const auto& lay = info.sLayerInfo[i]; - - uint8_t* buf = lay.pBsBuf; - for (size_t j = 0; j < static_cast(lay.iNalCount); ++j) { - mp4_h26x_write_nal(&writer_, buf, lay.pNalLengthInByte[j], static_cast(90000./fps_)); - buf += lay.pNalLengthInByte[j]; - } - } - } - void ForceIntraFrame() noexcept { - encoder_->ForceIntraFrame(true); - } - - private: - std::ofstream file_; - - ISVCEncoder* encoder_; - MP4E_mux_t* muxer_; - mp4_h26x_writer_t writer_; - - double fps_; - - - static int WriteCallback(int64_t off, const void* buf, size_t size, void* ptr) noexcept { - auto self = (VideoEncoder*) ptr; - self->file_.seekp(off); - assert(self->file_); - self->file_.write(static_cast(buf), static_cast(size)); - return !self->file_; - } -};