Files
vimix/PatternSource.cpp

178 lines
7.5 KiB
C++

/*
* This file is part of vimix - video live mixer
*
* **Copyright** (C) 2020-2021 Bruno Herbelin <bruno.herbelin@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
**/
#include <sstream>
#include <glm/gtc/matrix_transform.hpp>
#include "defines.h"
#include "ImageShader.h"
#include "Resource.h"
#include "Decorations.h"
#include "Stream.h"
#include "Visitor.h"
#include "Log.h"
#include "GstToolkit.h"
#include "PatternSource.h"
//
// Fill the list of patterns
//
// Label (for display), feature (for test), pipeline (for gstreamer), animated (true/false), available (false by default)
std::vector<pattern_descriptor> Pattern::patterns_ = {
{ "Black", "videotestsrc", "videotestsrc pattern=black", false, false },
{ "White", "videotestsrc", "videotestsrc pattern=white", false, false },
{ "Gradient", "videotestsrc", "videotestsrc pattern=gradient", false, false },
{ "Checkers 1x1 px", "videotestsrc", "videotestsrc pattern=checkers-1 ! video/x-raw,format=GRAY8 ! videoconvert", false, false },
{ "Checkers 8x8 px", "videotestsrc", "videotestsrc pattern=checkers-8 ! video/x-raw,format=GRAY8 ! videoconvert", false, false },
{ "Circles", "videotestsrc", "videotestsrc pattern=circular", false, false },
{ "Lissajous", "frei0r-src-lissajous0r", "frei0r-src-lissajous0r ratiox=0.001 ratioy=0.999 ! videoconvert", false, false },
{ "Pinwheel", "videotestsrc", "videotestsrc pattern=pinwheel", false, false },
{ "Spokes", "videotestsrc", "videotestsrc pattern=spokes", false, false },
{ "Red", "videotestsrc", "videotestsrc pattern=red", false, false },
{ "Green", "videotestsrc", "videotestsrc pattern=green", false, false },
{ "Blue", "videotestsrc", "videotestsrc pattern=blue", false, false },
{ "Color bars", "videotestsrc", "videotestsrc pattern=smpte100", false, false },
{ "RGB grid", "videotestsrc", "videotestsrc pattern=colors", false, false },
{ "SMPTE test pattern", "videotestsrc", "videotestsrc pattern=smpte", true, false },
{ "Television snow", "videotestsrc", "videotestsrc pattern=snow", true, false },
{ "Blink", "videotestsrc", "videotestsrc pattern=blink", true, false },
{ "Fresnel zone plate", "videotestsrc", "videotestsrc pattern=zone-plate kx2=XXX ky2=YYY kt=4", true, false },
{ "Chroma zone plate", "videotestsrc", "videotestsrc pattern=chroma-zone-plate kx2=XXX ky2=YYY kt=4", true, false },
{ "Bar moving", "videotestsrc", "videotestsrc pattern=bar horizontal-speed=5", true, false },
{ "Ball bouncing", "videotestsrc", "videotestsrc pattern=ball", true, false },
{ "Blob", "frei0r-src-ising0r", "frei0r-src-ising0r", true, false },
{ "Timer", "timeoverlay", "videotestsrc pattern=black ! timeoverlay halignment=center valignment=center font-desc=\"Sans, 72\" ", true, false },
{ "Clock", "clockoverlay", "videotestsrc pattern=black ! clockoverlay halignment=center valignment=center font-desc=\"Sans, 72\" ", true, false },
{ "Resolution", "textoverlay", "videotestsrc pattern=black ! textoverlay text=\"XXXX x YYYY px\" halignment=center valignment=center font-desc=\"Sans, 52\" ", false, false },
{ "Frame", "videobox", "videotestsrc pattern=black ! videobox fill=white top=-10 bottom=-10 left=-10 right=-10", false, false },
{ "Cross", "textoverlay", "videotestsrc pattern=black ! textoverlay text=\"+\" halignment=center valignment=center font-desc=\"Sans, 22\" ", false, false },
{ "Grid", "frei0r-src-test-pat-g", "frei0r-src-test-pat-g type=0.35", false, false },
{ "Point Grid", "frei0r-src-test-pat-g", "frei0r-src-test-pat-g type=0.4", false, false },
{ "Ruler", "frei0r-src-test-pat-g", "frei0r-src-test-pat-g type=0.9", false, false },
{ "RGB noise", "frei0r-filter-rgbnoise", "videotestsrc pattern=black ! frei0r-filter-rgbnoise noise=0.6", true, false },
{ "Philips test pattern", "frei0r-src-test-pat-b", "frei0r-src-test-pat-b type=0.7 ", false, false }
};
Pattern::Pattern() : Stream(), type_(UINT_MAX) // invalid pattern
{
}
pattern_descriptor Pattern::get(uint type)
{
// check availability of feature to use this pattern
if (!patterns_[type].available)
patterns_[type].available = GstToolkit::has_feature(patterns_[type].feature);
// return struct
return patterns_[type];
}
uint Pattern::count()
{
return patterns_.size();
}
glm::ivec2 Pattern::resolution()
{
return glm::ivec2( width_, height_);
}
void Pattern::open( uint pattern, glm::ivec2 res )
{
// clamp type to be sure
type_ = MIN(pattern, Pattern::patterns_.size()-1);
std::string gstreamer_pattern = Pattern::patterns_[type_].pipeline;
//
// pattern string post-processing: replace placeholders by resolution values
// XXXX, YYYY = resolution x and y
// XXX, YYY = resolution x and y / 10
//
// if there is a XXXX parameter to enter
std::string::size_type xxxx = gstreamer_pattern.find("XXXX");
if (xxxx != std::string::npos)
gstreamer_pattern = gstreamer_pattern.replace(xxxx, 4, std::to_string(res.x));
// if there is a YYYY parameter to enter
std::string::size_type yyyy = gstreamer_pattern.find("YYYY");
if (yyyy != std::string::npos)
gstreamer_pattern = gstreamer_pattern.replace(yyyy, 4, std::to_string(res.y));
// if there is a XXX parameter to enter
std::string::size_type xxx = gstreamer_pattern.find("XXX");
if (xxx != std::string::npos)
gstreamer_pattern = gstreamer_pattern.replace(xxx, 3, std::to_string(res.x/10));
// if there is a YYY parameter to enter
std::string::size_type yyy = gstreamer_pattern.find("YYY");
if (yyy != std::string::npos)
gstreamer_pattern = gstreamer_pattern.replace(yyy, 3, std::to_string(res.y/10));
// remember if the pattern is to be updated once or animated
single_frame_ = !Pattern::patterns_[type_].animated;
// (private) open stream
Stream::open(gstreamer_pattern, res.x, res.y);
}
PatternSource::PatternSource(uint64_t id) : StreamSource(id)
{
// create stream
stream_ = static_cast<Stream *>( new Pattern );
// set symbol
symbol_ = new Symbol(Symbol::PATTERN, glm::vec3(0.75f, 0.75f, 0.01f));
symbol_->scale_.y = 1.5f;
}
void PatternSource::setPattern(uint type, glm::ivec2 resolution)
{
// open gstreamer with pattern
if ( Pattern::get(type).available) {
pattern()->open( (uint) type, resolution );
Log::Notify("Creating Source with pattern '%s'", Pattern::get(type).label.c_str());
}
// revert to pattern Black if not available
else {
pattern()->open( 0, resolution );
Log::Warning("Pattern '%s' is not available in this version of vimix.", Pattern::get(type).label.c_str());
}
// play gstreamer
stream_->play(true);
// will be ready after init and one frame rendered
ready_ = false;
}
void PatternSource::accept(Visitor& v)
{
Source::accept(v);
if (!failed())
v.visit(*this);
}
Pattern *PatternSource::pattern() const
{
return dynamic_cast<Pattern *>(stream_);
}