From 06955f1ede55d87bb93da098d49b6a1ae7e1fde2 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sun, 24 Oct 2010 10:07:03 +0300 Subject: [PATCH] streamtools: Refactor options parsing and RGB->I420 conversion Create helper functions to perform option expansion and RGB->I420 conversion, so to reduce code duplication (both were implemented at least twice in sightly different ways). --- streamtools/output-drv-oggenc.cpp | 22 +--------- streamtools/output-drv-rawi420.cpp | 35 ++-------------- streamtools/output-drv-x264.cpp | 47 +++------------------ streamtools/output-drv.cpp | 83 ++++++++++++++++++++++++++++++++++++++ streamtools/output-drv.hpp | 5 +++ 5 files changed, 99 insertions(+), 93 deletions(-) diff --git a/streamtools/output-drv-oggenc.cpp b/streamtools/output-drv-oggenc.cpp index 78c2b3b..0ab7d25 100644 --- a/streamtools/output-drv-oggenc.cpp +++ b/streamtools/output-drv-oggenc.cpp @@ -6,26 +6,6 @@ namespace { - std::string expand_options(const std::string& opts) - { - bool insert = true; - std::ostringstream ret; - for(size_t i = 0; i < opts.length(); i++) { - if(insert) - ret << " --"; - insert = false; - switch(opts[i]) { - case ',': - insert = true; - break; - default: - ret << opts[i]; - }; - } - ret << " "; - return ret.str(); - } - class output_driver_oggenc : public output_driver { public: @@ -47,7 +27,7 @@ namespace std::stringstream commandline; commandline << "oggenc -r -R " << a.get_rate() << " "; - commandline << expand_options(options); + commandline << expand_arguments_common(options, "--", "="); commandline << "-o " << filename << " -"; std::string s = commandline.str(); out = popen(s.c_str(), "w"); diff --git a/streamtools/output-drv-rawi420.cpp b/streamtools/output-drv-rawi420.cpp index 64e02dc..7c7b0fc 100644 --- a/streamtools/output-drv-rawi420.cpp +++ b/streamtools/output-drv-rawi420.cpp @@ -36,45 +36,18 @@ namespace const video_settings& v = get_video_settings(); framesize = 4 * v.get_width() * v.get_height(); width = v.get_width(); + height = v.get_height(); } void video_callback(uint64_t timestamp, const uint8_t* raw_rgbx_data) { - std::vector tmp(framesize * 3 / 8); - size_t primarysize = framesize / 4; - size_t offs1 = primarysize / 4; - size_t offs2 = 0; - if(uvswap) - std::swap(offs1, offs2); - Convert32To_I420Frame(raw_rgbx_data, &tmp[0], framesize / 4, width); - size_t r; - out->write((const char*)&tmp[0], primarysize); - if(!*out) { - std::stringstream str; - str << "Error writing frame to file (requested " << primarysize << ", got " << r - << ")"; - throw std::runtime_error(str.str()); - } - //Swap U and V. - out->write((const char*)&tmp[primarysize + offs1], primarysize / 4); - if(!*out) { - std::stringstream str; - str << "Error writing frame to file (requested " << primarysize / 4 << ", got " - << r << ")"; - throw std::runtime_error(str.str()); - } - out->write((const char*)&tmp[primarysize + offs2], primarysize / 4); - if(!*out) { - std::stringstream str; - str << "Error writing frame to file (requested " << primarysize / 4 << ", got " - << r << ")"; - throw std::runtime_error(str.str()); - } + I420_convert_common(raw_rgbx_data, width, height, *out, !uvswap); } private: std::ostream* out; size_t framesize; - size_t width; + uint32_t width; + uint32_t height; bool uvswap; }; diff --git a/streamtools/output-drv-x264.cpp b/streamtools/output-drv-x264.cpp index 9cb41b9..f36d85e 100644 --- a/streamtools/output-drv-x264.cpp +++ b/streamtools/output-drv-x264.cpp @@ -11,26 +11,10 @@ namespace { std::string expand_options(const std::string& opts, uint32_t rn, uint32_t rd) { - bool insert = true; std::ostringstream ret; if(rd) ret << "--fps " << rn << "/" << rd << " "; - for(size_t i = 0; i < opts.length(); i++) { - if(insert) - ret << " --"; - insert = false; - switch(opts[i]) { - case ',': - insert = true; - break; - case '=': - ret << " "; - break; - default: - ret << opts[i]; - }; - } - ret << " "; + ret << expand_arguments_common(opts, "--", " "); return ret.str(); } @@ -54,11 +38,12 @@ namespace const video_settings& v = get_video_settings(); framesize = 4 * v.get_width() * v.get_height(); width = v.get_width(); + height = v.get_height(); std::stringstream commandline; commandline << "x264 "; commandline << expand_options(options, v.get_rate_num(), v.get_rate_denum()); - commandline << "- -o " << filename << " " << v.get_width() << "x" << v.get_height(); + commandline << " - -o " << filename << " " << v.get_width() << "x" << v.get_height(); std::string s = commandline.str(); out = popen(s.c_str(), "w"); if(!out) { @@ -70,35 +55,15 @@ namespace void video_callback(uint64_t timestamp, const uint8_t* raw_rgbx_data) { - std::vector tmp(framesize * 3 / 8); - size_t primarysize = framesize / 4; - size_t offs1 = primarysize / 4; - size_t offs2 = 0; - Convert32To_I420Frame(raw_rgbx_data, &tmp[0], framesize / 4, width); - size_t r; - if((r = fwrite(&tmp[0], 1, primarysize, out)) < primarysize) { - std::stringstream str; - str << "Error writing frame to x264 (requested " << primarysize << ", got " << r << ")"; - throw std::runtime_error(str.str()); - } - //Swap U and V. - if((r = fwrite(&tmp[primarysize + offs1], 1, primarysize / 4, out)) < primarysize / 4) { - std::stringstream str; - str << "Error writing frame to x264 (requested " << primarysize / 4 << ", got " << r << ")"; - throw std::runtime_error(str.str()); - } - if((r = fwrite(&tmp[primarysize + offs2], 1, primarysize / 4, out)) < primarysize / 4) { - std::stringstream str; - str << "Error writing frame to x264 (requested " << primarysize / 4 << ", got " << r << ")"; - throw std::runtime_error(str.str()); - } + I420_convert_common(raw_rgbx_data, width, height, out, true); } private: FILE* out; std::string filename; std::string options; size_t framesize; - size_t width; + uint32_t width; + uint32_t height; }; class output_driver_x264_factory : output_driver_factory diff --git a/streamtools/output-drv.cpp b/streamtools/output-drv.cpp index f2d29b9..5230bf4 100644 --- a/streamtools/output-drv.cpp +++ b/streamtools/output-drv.cpp @@ -1,7 +1,10 @@ #include "output-drv.hpp" #include #include +#include +#include #include "dedup.hpp" +#include "rgbtorgb.hh" class audio_dyncall_null : public audio_dyncall_base { @@ -271,3 +274,83 @@ std::string get_output_driver_list() } return c; } + +std::string expand_arguments_common(std::string opts, std::string commaexpand, std::string equalsexpand) +{ + bool insert = true; + bool first = true; + std::ostringstream ret; + for(size_t i = 0; i < opts.length(); i++) { + if(insert) { + if(first) + ret << commaexpand; + else + ret << " " << commaexpand; + } + first = false; + insert = false; + switch(opts[i]) { + case ',': + insert = true; + break; + case '=': + ret << equalsexpand; + break; + default: + ret << opts[i]; + }; + } + ret << " "; + return ret.str(); +} + +namespace +{ + template + void I420_convert_common(const uint8_t* raw_rgbx_data, uint32_t width, uint32_t height, bool uvswap, + void (*writer)(T target, const uint8_t* buffer, size_t bufsize), T target) + { + size_t framesize = 4 * (size_t)width * height; + std::vector tmp(framesize * 3 / 8); + size_t primarysize = framesize / 4; + size_t offs1 = 0; + size_t offs2 = primarysize / 4; + if(uvswap) + std::swap(offs1, offs2); + Convert32To_I420Frame(raw_rgbx_data, &tmp[0], framesize / 4, width); + writer(target, &tmp[0], primarysize); + writer(target, &tmp[primarysize + offs1], primarysize / 4); + writer(target, &tmp[primarysize + offs2], primarysize / 4); + } + + void writer_stdio(FILE* target, const uint8_t* buffer, size_t bufsize) + { + size_t r; + if((r = fwrite(buffer, 1, bufsize, target)) < bufsize) { + std::stringstream str; + str << "Error writing frame to output (requested " << bufsize << ", got " << r << ")"; + throw std::runtime_error(str.str()); + } + } + + void writer_iostream(std::ostream* target, const uint8_t* buffer, size_t bufsize) + { + target->write((const char*)buffer, bufsize); + if(!*target) { + std::stringstream str; + str << "Error writing frame to output (requested " << bufsize << ")"; + throw std::runtime_error(str.str()); + } + } +} + +void I420_convert_common(const uint8_t* raw_rgbx_data, uint32_t width, uint32_t height, FILE* out, bool uvswap) +{ + I420_convert_common(raw_rgbx_data, width, height, uvswap, writer_stdio, out); +} + +void I420_convert_common(const uint8_t* raw_rgbx_data, uint32_t width, uint32_t height, std::ostream& out, + bool uvswap) +{ + I420_convert_common(raw_rgbx_data, width, height, uvswap, writer_iostream, &out); +} \ No newline at end of file diff --git a/streamtools/output-drv.hpp b/streamtools/output-drv.hpp index daf455b..a8d81c4 100644 --- a/streamtools/output-drv.hpp +++ b/streamtools/output-drv.hpp @@ -243,4 +243,9 @@ private: friend std::string get_output_driver_list(); }; +std::string expand_arguments_common(std::string spec, std::string commaexpand, std::string equalsexpand); +void I420_convert_common(const uint8_t* raw_rgbx_data, uint32_t width, uint32_t height, FILE* out, bool uvswap); +void I420_convert_common(const uint8_t* raw_rgbx_data, uint32_t width, uint32_t height, std::ostream& out, + bool uvswap); + #endif -- 2.11.4.GIT