1
0
Nicolas Winkler преди 5 години
родител
ревизия
2cda382176
променени са 15 файла, в които са добавени 330 реда и са изтрити 215 реда
  1. 3 2
      Almond.cpp
  2. 2 0
      Almond.h
  3. 0 2
      Almond.pro
  4. 1 1
      MandelVideoGenerator.cpp
  5. 5 0
      MandelVideoGenerator.h
  6. 56 61
      MandelWidget.cpp
  7. 22 9
      MandelWidget.h
  8. 0 19
      SectionManager.cpp
  9. 0 14
      SectionManager.h
  10. 7 5
      VideoStream.cpp
  11. 1 1
      VideoStream.h
  12. 21 2
      exportdialogs.cpp
  13. 189 98
      exportvideodialog.ui
  14. 16 1
      gradientchoosedialog.cpp
  15. 7 0
      gradientchoosedialog.h

+ 3 - 2
Almond.cpp

@@ -73,9 +73,10 @@ void Almond::on_maxIterations_editingFinished()
 
 void Almond::on_chooseGradient_clicked()
 {
-    QGradient qg;
-    GradientChooseDialog gcd;
     auto response = gcd.exec();
+    auto gradient = gcd.getGradient();
+    if (gradient)
+        mw->setGradient(std::move(*gradient));
 }
 
 void Almond::on_exportVideo_clicked()

+ 2 - 0
Almond.h

@@ -6,6 +6,7 @@
 #include <Mandel.h>
 #include "MandelWidget.h"
 #include "exportdialogs.h"
+#include "gradientchoosedialog.h"
 
 #include <memory>
 
@@ -15,6 +16,7 @@ class Almond : public QMainWindow
 private:
     mnd::MandelContext mandelContext;
     std::unique_ptr<MandelWidget> mw;
+    GradientChooseDialog gcd;
 public:
     Almond(QWidget *parent = Q_NULLPTR);
 

+ 0 - 2
Almond.pro

@@ -31,7 +31,6 @@ SOURCES += \
         Gradient.cpp \
         MandelVideoGenerator.cpp \
         MandelWidget.cpp \
-        SectionManager.cpp \
         VideoStream.cpp \
         benchmarkdialog.cpp \
         exportdialogs.cpp \
@@ -45,7 +44,6 @@ HEADERS += \
         Gradient.h \
         MandelVideoGenerator.h \
         MandelWidget.h \
-        SectionManager.h \
         VideoStream.h \
         benchmarkdialog.h \
         exportdialogs.h \

+ 1 - 1
MandelVideoGenerator.cpp

@@ -18,7 +18,7 @@ void MandelVideoGenerator::generate(void)
     mi.bHeight = evi.height * 2;
     mi.maxIter = evi.maxIterations;
 
-    VideoStream vs(evi.width, evi.height, evi.path);
+    VideoStream vs(evi.width, evi.height, evi.path, evi.bitrate, evi.preset.c_str());
 
     double x = evi.end.x + evi.end.width / 2;
     double y = evi.end.y + evi.end.height / 2;

+ 5 - 0
MandelVideoGenerator.h

@@ -16,6 +16,11 @@ struct ExportVideoInfo
     int maxIterations;
 
     std::string path;
+
+    /// bitrate in kbps
+    int bitrate;
+
+    std::string preset;
 };
 
 

+ 56 - 61
MandelWidget.cpp

@@ -11,7 +11,7 @@ Texture::Texture(const Bitmap<RGBColor>& bitmap, GLint param)
     glGenTextures(1, &id);
     glBindTexture(GL_TEXTURE_2D, id);
 
-    long lineLength = (bitmap.width * 3 + 3) & ~3;
+    int lineLength = (bitmap.width * 3 + 3) & ~3;
 
     unsigned char* pixels = new unsigned char[lineLength * bitmap.height];
     for (int i = 0; i < bitmap.width; i++) {
@@ -109,24 +109,23 @@ void TextureClip::drawRect(float x, float y, float width, float height)
 
 TextureClip TextureClip::clip(float x, float y, float w, float h)
 {
-    TextureClip result(this->texture);
-    result.tx = this->tx + x * this->tw;
-    result.ty = this->ty + y * this->th;
-    result.tw = this->tw * w;
-    result.th = this->th * h;
-    return result;
+    float tx = this->tx + x * this->tw;
+    float ty = this->ty + y * this->th;
+    float tw = this->tw * w;
+    float th = this->th * h;
+    return TextureClip{ this->texture, tx, ty, tw, th };
 }
 
 
 std::shared_ptr<CellImage> TextureClip::clip(short i, short j)
 {
-    return std::make_shared<TextureClip>(clip(i * 0.5, j * 0.5, 0.5, 0.5));
+    return std::make_shared<TextureClip>(clip(i * 0.5f, j * 0.5f, 0.5f, 0.5f));
 }
 
 
 int TextureClip::getRecalcPriority() const
 {
-    return int(1.0 / tw);
+    return int(1.0f / tw);
 }
 
 
@@ -139,7 +138,10 @@ void QuadImage::drawRect(float x, float y, float width, float height)
 {
     for (int i = 0; i < 2; i++) {
         for (int j = 0; j < 2; j++) {
-            this->cells[i][j]->drawRect(x + i * 0.5 * width, y + j * 0.5 * height, width * 0.5, height * 0.5);
+            this->cells[i][j]->drawRect(x + i * 0.5f * width,
+                                        y + j * 0.5f * height,
+                                        width * 0.5f,
+                                        height * 0.5f);
         }
     }
 }
@@ -156,7 +158,7 @@ int QuadImage::getRecalcPriority() const
     return 1;
 }
 
-TexGrid::TexGrid(MandelV& owner, int level) :
+TexGrid::TexGrid(MandelView& owner, int level) :
     owner{ owner },
     level{ level },
     dpp{ owner.getDpp(level) }
@@ -166,13 +168,13 @@ TexGrid::TexGrid(MandelV& owner, int level) :
 
 std::pair<GridIndex, GridIndex> TexGrid::getCellIndices(double x, double y)
 {
-    return { ::floor(x / dpp / MandelV::chunkSize), ::floor(y / dpp / MandelV::chunkSize) };
+    return { ::floor(x / dpp / MandelView::chunkSize), ::floor(y / dpp / MandelView::chunkSize) };
 }
 
 
 std::pair<double, double> TexGrid::getPositions(GridIndex x, GridIndex y)
 {
-    return { x * dpp * MandelV::chunkSize, y * dpp * MandelV::chunkSize };
+    return { x * dpp * MandelView::chunkSize, y * dpp * MandelView::chunkSize };
 }
 
 
@@ -203,14 +205,14 @@ void TexGrid::clearCells(void)
 void Job::run(void)
 {
     auto [absX, absY] = grid->getPositions(i, j);
-    double gw = grid->dpp * MandelV::chunkSize;
+    double gw = grid->dpp * MandelView::chunkSize;
 
-    Bitmap<float> f(MandelV::chunkSize, MandelV::chunkSize);
+    Bitmap<float> f(MandelView::chunkSize, MandelView::chunkSize);
     mnd::MandelInfo mi;
     mi.view.x = absX;
     mi.view.y = absY;
     mi.view.width = mi.view.height = gw;
-    mi.bWidth = mi.bHeight = MandelV::chunkSize;
+    mi.bWidth = mi.bHeight = MandelView::chunkSize;
     mi.maxIter = maxIter;
     mndContext.getDefaultGenerator().generate(mi, f.pixels.get());
     auto* rgb = new Bitmap<RGBColor>(f.map<RGBColor>([&mi, this](float i) {
@@ -286,7 +288,7 @@ void Calcer::redirect(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp
 }
 
 
-MandelV::MandelV(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter) :
+MandelView::MandelView(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter) :
     mndContext{ mndContext },
     calcer{ mndContext, gradient, maxIter },
     gradient{ gradient },
@@ -304,22 +306,22 @@ MandelV::MandelV(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter
         }
     }
     empty = std::make_unique<Texture>(emp, GL_NEAREST);
-    connect(&calcer, &Calcer::done, this, &MandelV::cellReady);
+    connect(&calcer, &Calcer::done, this, &MandelView::cellReady);
 }
 
 
-int MandelV::getLevel(double dpp) {
+int MandelView::getLevel(double dpp) {
     return int(::log2(dpp / chunkSize));
 }
 
 
-double MandelV::getDpp(int level)
+double MandelView::getDpp(int level)
 {
     return ::pow(2, level) * chunkSize;
 }
 
 
-TexGrid& MandelV::getGrid(int level)
+TexGrid& MandelView::getGrid(int level)
 {
     auto it = levels.find(level);
     if (it != levels.end()) {
@@ -332,17 +334,17 @@ TexGrid& MandelV::getGrid(int level)
 }
 
 
-void MandelV::setMaxIter(int maxIter)
+void MandelView::setMaxIter(int maxIter)
 {
     this->maxIter = maxIter;
     calcer.setMaxIter(maxIter);
-    clear();
+    clearCells();
     emit redrawRequested();
 }
 
 
 
-void MandelV::clear(void)
+void MandelView::clearCells(void)
 {
     for(auto& [level, grid] : this->levels) {
         grid.clearCells();
@@ -350,7 +352,7 @@ void MandelV::clear(void)
 }
 
 
-void MandelV::garbageCollect(int level, GridIndex i, GridIndex j)
+void MandelView::garbageCollect(int level, GridIndex i, GridIndex j)
 {
     for(auto& [l, grid] : levels) {
         int dist = ::abs(l - level);
@@ -378,7 +380,7 @@ void MandelV::garbageCollect(int level, GridIndex i, GridIndex j)
 }
 
 
-GridElement* MandelV::searchAbove(int level, GridIndex i, GridIndex j, int recursionLevel)
+GridElement* MandelView::searchAbove(int level, GridIndex i, GridIndex j, int recursionLevel)
 {
     auto& grid = getGrid(level);
     auto& gridAbove = getGrid(level + 1);
@@ -408,7 +410,7 @@ GridElement* MandelV::searchAbove(int level, GridIndex i, GridIndex j, int recur
 }
 
 
-GridElement* MandelV::searchUnder(int level, GridIndex i, GridIndex j, int recursionLevel)
+GridElement* MandelView::searchUnder(int level, GridIndex i, GridIndex j, int recursionLevel)
 {
     if (recursionLevel == 0)
         return nullptr;
@@ -451,7 +453,7 @@ GridElement* MandelV::searchUnder(int level, GridIndex i, GridIndex j, int recur
 }
 
 
-void MandelV::paint(const mnd::MandelViewport& mvp)
+void MandelView::paint(const mnd::MandelViewport& mvp)
 {
     double dpp = mvp.width / width;
     int level = getLevel(dpp) - 1;
@@ -509,7 +511,7 @@ void MandelV::paint(const mnd::MandelViewport& mvp)
     }
 }
 
-void MandelV::cellReady(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp)
+void MandelView::cellReady(int level, GridIndex i, GridIndex j, Bitmap<RGBColor>* bmp)
 {
 
     this->getGrid(level).setCell(i, j,
@@ -547,6 +549,14 @@ MandelWidget::~MandelWidget()
 }
 
 
+void MandelWidget::setGradient(Gradient g)
+{
+    this->gradient = std::move(g);
+    this->mandelView->clearCells();
+    emit update();
+}
+
+
 void MandelWidget::initializeGL(void)
 {
     this->context()->functions()->glClearColor(0, 0, 0, 0);
@@ -559,22 +569,22 @@ void MandelWidget::initializeGL(void)
 
     //glShadeModel(GL_SMOOTH);
 
-    v = nullptr;
+    mandelView = nullptr;
     requestRecalc();
 }
 
 
 void MandelWidget::paintGL(void)
 {
-    if (v == nullptr) {
-        v = std::make_unique<MandelV>(mndContext, gradient, maxIterations);
-        QObject::connect(v.get(), &MandelV::redrawRequested, this, static_cast<void(QOpenGLWidget::*)(void)>(&QOpenGLWidget::update));
+    if (mandelView == nullptr) {
+        mandelView = std::make_unique<MandelView>(mndContext, gradient, maxIterations);
+        QObject::connect(mandelView.get(), &MandelView::redrawRequested, this, static_cast<void(QOpenGLWidget::*)(void)>(&QOpenGLWidget::update));
     }
 
     int width = this->width();
     int height = this->height();
-    v->width = width;
-    v->height = height;
+    mandelView->width = width;
+    mandelView->height = height;
 
     glViewport(0, 0, width, height);
 
@@ -591,7 +601,7 @@ void MandelWidget::paintGL(void)
     glLoadIdentity();
 
     updateAnimations();
-    v->paint(this->currentViewport);
+    mandelView->paint(this->currentViewport);
 
     if (rubberbanding)
         drawRubberband();
@@ -656,41 +666,24 @@ void MandelWidget::zoom(float scale, float x, float y)
 void MandelWidget::setMaxIterations(int maxIter)
 {
     this->maxIterations = maxIter;
-    if (v)
-        v->setMaxIter(maxIter);
+    if (mandelView)
+        mandelView->setMaxIter(maxIter);
     requestRecalc();
 }
 
 
 void MandelWidget::requestRecalc()
 {
-    //emit needsUpdate(MandelInfo{ viewport, this->width(), this->height(), maxIterations });
-    this->update();
+    emit update();
 }
 
 
 void MandelWidget::resizeGL(int width, int height)
 {
-    //glViewport(0, 0, (GLint) width, (GLint) height);
-    this->update();
+    emit update();
 }
 
 
-/*void MandelWidget::redraw(void)
-{
-    /*CpuGenerator<double> cpg;
-    MandelInfo mi;
-    mi.bWidth = this->geometry().width();//ql.geometry().width();
-    mi.bHeight = this->geometry().height(); //ql.geometry().height();
-    mi.maxIter = 250;
-    mi.view = viewport;*/
-    //update();
-    //emit needsUpdate(viewport);
-
-    //auto bitmap = cpg.generate(mi).map<uint32_t>([](RGBColor rgb) { return 255 << 24 | rgb.b << 16 | rgb.g << 8 | rgb.r; });
-//}
-
-
 void MandelWidget::resizeEvent(QResizeEvent* re)
 {
     QOpenGLWidget::resizeEvent(re);
@@ -702,9 +695,9 @@ void MandelWidget::resizeEvent(QResizeEvent* re)
     //else
     //    viewport.width = (viewport.height * aspect);
 
-    if (v.get() != nullptr) {
-        v->width = this->width();
-        v->height = this->height();
+    if (mandelView.get() != nullptr) {
+        mandelView->width = this->width();
+        mandelView->height = this->height();
     }
     //printf("resized\n");
     requestRecalc();
@@ -785,9 +778,11 @@ void MandelWidget::wheelEvent(QWheelEvent* we)
     QOpenGLWidget::wheelEvent(we);
     float x = float(we->x()) / this->width();
     float y = float(we->y()) / this->height();
-    float scale = ::pow(0.9975, we->angleDelta().y());
+    float scale = ::powf(0.9975f, we->angleDelta().y());
     //printf("scale: %f\n", double(scale));
     zoom(scale, x, y);
+    if (!we->pixelDelta().isNull())
+        this->currentViewport = this->targetViewport;
     we->accept();
 }
 

+ 22 - 9
MandelWidget.h

@@ -51,6 +51,11 @@ public:
 class CellImage
 {
 public:
+    CellImage(void) = default;
+    CellImage(CellImage&& b) = default;
+    CellImage(const CellImage& b) = default;
+    CellImage& operator=(const CellImage& b) = default;
+    CellImage& operator=(CellImage&& b) = default;
     virtual ~CellImage(void);
 
     virtual void drawRect(float x, float y, float width, float height) = 0;
@@ -64,10 +69,16 @@ class TextureClip : public CellImage
     std::shared_ptr<Texture> texture;
     float tx, ty, tw, th;
 public:
-    inline TextureClip(std::shared_ptr<Texture> tex) :
+    inline TextureClip(std::shared_ptr<Texture> tex,
+                       float tx, float ty, float tw, float th) :
         texture{ std::move(tex) },
-        tx{ 0 }, ty{ 0 }, tw{ 1 }, th{ 1 }
+        tx{ tx }, ty{ ty }, tw{ tw }, th{ th }
+    {}
+
+    inline TextureClip(std::shared_ptr<Texture> tex) :
+        TextureClip{ tex, 0.0f, 0.0f, 1.0f, 1.0f }
     {}
+
     virtual ~TextureClip(void);
 
     void drawRect(float x, float y, float width, float height);
@@ -127,19 +138,19 @@ struct GridElement
 };
 
 
-class MandelV;
+class MandelView;
 
 
 class TexGrid
 {
 public:
-    MandelV& owner;
+    MandelView& owner;
     int level;
     double dpp;
     std::unordered_map<std::pair<GridIndex, GridIndex>, std::unique_ptr<GridElement>, PairHash> cells;
 public:
     //inline TexGrid(MandelV& owner) : level{ 1.0 }, owner{ owner } {}
-    TexGrid(MandelV& owner, int level);
+    TexGrid(MandelView& owner, int level);
 
     std::pair<GridIndex, GridIndex> getCellIndices(double x, double y);
     std::pair<double, double> getPositions(GridIndex i, GridIndex j);
@@ -200,6 +211,7 @@ public:
         gradient{ gradient },
         maxIter{ maxIter }
     {
+        threadPool->setMaxThreadCount(1);
     }
 
     void setMaxIter(int maxIter);
@@ -215,7 +227,7 @@ signals:
 };
 
 
-class MandelV : public QObject
+class MandelView : public QObject
 {
     Q_OBJECT
 public:
@@ -232,7 +244,7 @@ public:
     int height;
 public:
     static const int chunkSize = 256;
-    MandelV(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter);
+    MandelView(mnd::MandelContext& mndContext, Gradient& gradient, int maxIter);
     int getLevel(double dpp);
     double getDpp(int level);
 
@@ -241,7 +253,7 @@ public:
     inline int getMaxIter(void) const { return this->maxIter; }
     void setMaxIter(int maxIter);
 
-    void clear(void);
+    void clearCells(void);
 
     void garbageCollect(int level, GridIndex i, GridIndex j);
     GridElement* searchAbove(int level, GridIndex i, GridIndex j, int recursionLevel);
@@ -275,12 +287,13 @@ private:
     mnd::MandelViewport targetViewport;
     std::chrono::time_point<std::chrono::high_resolution_clock> lastAnimUpdate;
 
-    std::unique_ptr<MandelV> v;
+    std::unique_ptr<MandelView> mandelView;
 public:
     MandelWidget(mnd::MandelContext& ctxt, QWidget* parent = nullptr);
     ~MandelWidget(void) override;
 
     inline const Gradient& getGradient(void) const { return gradient; }
+    void setGradient(Gradient g);
 
     void initializeGL(void) override;
 

+ 0 - 19
SectionManager.cpp

@@ -1,19 +0,0 @@
-#include "SectionManager.h"
-
-SectionManager::SectionManager(void)
-{
-
-}
-
-
-int SectionManager::getNextLevel(double chunkWidth)
-{
-    int level = 0;
-    double w = 1;
-    while(w >= chunkWidth) {
-        w = w / 2;
-        level++;
-    }
-    return level;
-}
-

+ 0 - 14
SectionManager.h

@@ -1,14 +0,0 @@
-#pragma once
-#ifndef SECTIONMANAGER_H
-#define SECTIONMANAGER_H
-
-
-class SectionManager
-{
-public:
-    SectionManager(void);
-
-    int getNextLevel(double chunkWidth);
-};
-
-#endif // SECTIONMANAGER_H

+ 7 - 5
VideoStream.cpp

@@ -15,7 +15,7 @@
 const uint8_t VideoStream::endcode[] = { 0, 0, 1, 0xb7 };
 
 
-VideoStream::VideoStream(int width, int height, const std::string& filename) :
+VideoStream::VideoStream(int width, int height, const std::string& filename, int bitrate, const char* preset) :
     width{ width & (~1) }, height{ height & (~1) }
 {
     // only needed with ffmpeg version < 4
@@ -37,7 +37,7 @@ VideoStream::VideoStream(int width, int height, const std::string& filename) :
     if (!pkt)
         exit(1);
 
-    codecContext->bit_rate = 4 * 1000 * 1000;
+    codecContext->bit_rate = bitrate * 1000;
     codecContext->width = width;
     codecContext->height = height;
     codecContext->time_base = AVRational{ 1, 60 };
@@ -69,7 +69,7 @@ VideoStream::VideoStream(int width, int height, const std::string& filename) :
     props->vbv_delay = UINT64_MAX;*/
 
     if (codec->id == AV_CODEC_ID_H264)
-        av_opt_set(codecContext->priv_data, "preset", "veryfast", 0);
+        av_opt_set(codecContext->priv_data, "preset", preset, 0);
 
     if (avcodec_open2(codecContext, codec, nullptr) < 0) {
         fprintf(stderr, "could not open codec\n");
@@ -129,6 +129,10 @@ void VideoStream::encode(AVFrame* frame)
         printf("encoded frame %3d\"PRId64\" (size=%5d)\n", pkt->pts, pkt->size);
         //fwrite(pkt->data, 1, pkt->size, outfile);
         //av_interleaved_write_frame(formatContext, pkt);
+
+        av_packet_rescale_ts(pkt, (AVRational){1, 25}, stream->time_base);
+        pkt->stream_index = stream->index;
+
         av_write_frame(formatContext, pkt);
         av_packet_unref(pkt);
     }
@@ -184,8 +188,6 @@ VideoStream::~VideoStream()
 
 void VideoStream::addFrame(const Bitmap<RGBColor>& frame)
 {
-    //av_frame_free(&picture);
-    //picture = av_frame_alloc();
     int retval = av_frame_make_writable(picture);
     if (retval < 0)
         exit(1);

+ 1 - 1
VideoStream.h

@@ -37,7 +37,7 @@ class VideoStream
 
     int64_t frameIndex = 0;
 public:
-    VideoStream(int width, int height, const std::string& filename);
+    VideoStream(int width, int height, const std::string& filename, int bitrate, const char* preset);
     ~VideoStream(void);
 
     void encode(AVFrame* frame);

+ 21 - 2
exportdialogs.cpp

@@ -73,6 +73,7 @@ ExportVideoDialog::ExportVideoDialog(QWidget* parent, const ExportVideoInfo& evi
     evd.maxIterations->setValidator(new QIntValidator(1, 1000000000, this));
     evd.vidWidth->setValidator(new QIntValidator(1, 10000000, this));
     evd.vidHeight->setValidator(new QIntValidator(1, 10000000, this));
+    evd.bitrate->setValidator(new QIntValidator(1, 10000000, this));
 
     evd.startX->setText(QString::number(evi.start.x));
     evd.startY->setText(QString::number(evi.start.y));
@@ -83,6 +84,21 @@ ExportVideoDialog::ExportVideoDialog(QWidget* parent, const ExportVideoInfo& evi
     evd.endY->setText(QString::number(evi.end.y));
     evd.endW->setText(QString::number(evi.end.width));
     evd.endH->setText(QString::number(evi.end.height));
+
+    auto presets = {
+        "ultrafast",
+        "superfast",
+        "veryfast",
+        "faster",
+        "fast",
+        "medium",
+        "slow",
+        "slower",
+        "veryslow",
+    };
+    for (auto& preset : presets) {
+        evd.encodingPresetBox->addItem(preset);
+    }
 }
 
 const ExportVideoInfo& ExportVideoDialog::getExportVideoInfo(void) const
@@ -103,6 +119,9 @@ void ExportVideoDialog::on_buttonBox_accepted()
     evi.width = evd.vidWidth->text().toInt();
     evi.height = evd.vidHeight->text().toInt();
     evi.maxIterations = evd.maxIterations->text().toInt();
+
+    evi.bitrate = evd.bitrate->text().toInt();
+    evi.preset = evd.encodingPresetBox->currentText().toStdString();
     /*evi.start = mnd::MandelViewport {
         evd.startX->text().toDouble(),
         evd.startY->text().toDouble(),
@@ -132,7 +151,7 @@ void ExportVideoDialog::on_pushButton_clicked()
 {
     QString saveAs = QFileDialog::getSaveFileName(this,
             tr("Save exported image"), "",
-            tr("H264 video (*.h264);;All Files (*)"));
+            tr("MP4 video (*.mp4);;All Files (*)"));
     evd.savePath->setText(saveAs);
     this->repaint();
 }
@@ -151,7 +170,7 @@ bool exportVideo(const ExportVideoInfo& evi)
     mi.bHeight = evi.height;
     mi.maxIter = evi.maxIterations;
 
-    VideoStream vs(evi.width, evi.height, evi.path);
+    VideoStream vs(evi.width, evi.height, evi.path, evi.bitrate, evi.preset.c_str());
 
     double x = evi.end.x + evi.end.width / 2;
     double y = evi.end.y + evi.end.height / 2;

+ 189 - 98
exportvideodialog.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>666</width>
-    <height>313</height>
+    <width>1263</width>
+    <height>454</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -15,112 +15,203 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <layout class="QFormLayout" name="formLayout">
-     <property name="sizeConstraint">
-      <enum>QLayout::SetMinimumSize</enum>
-     </property>
-     <item row="0" column="0">
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>Maximum iterations</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QLineEdit" name="maxIterations">
-       <property name="text">
-        <string>5000</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>Video Width</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="0">
-      <widget class="QLabel" name="label_3">
-       <property name="text">
-        <string>Video Height</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="1">
-      <widget class="QLineEdit" name="vidWidth">
-       <property name="text">
-        <string>1920</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QLineEdit" name="vidHeight">
-       <property name="text">
-        <string>1080</string>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="0">
-      <widget class="QPushButton" name="pushButton">
-       <property name="text">
-        <string>Save As</string>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="1">
-      <widget class="QLineEdit" name="savePath">
-       <property name="minimumSize">
-        <size>
-         <width>400</width>
-         <height>0</height>
-        </size>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="0">
-      <widget class="QLabel" name="label_4">
-       <property name="text">
-        <string>Start View</string>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <layout class="QFormLayout" name="formLayout">
+       <property name="sizeConstraint">
+        <enum>QLayout::SetMinimumSize</enum>
        </property>
-      </widget>
-     </item>
-     <item row="3" column="1">
-      <layout class="QHBoxLayout" name="horizontalLayout">
-       <item>
-        <widget class="QLineEdit" name="startX"/>
+       <item row="0" column="0">
+        <widget class="QLabel" name="label">
+         <property name="text">
+          <string>Maximum iterations</string>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QLineEdit" name="maxIterations">
+         <property name="minimumSize">
+          <size>
+           <width>130</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>5000</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="label_2">
+         <property name="text">
+          <string>Video Width</string>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QLineEdit" name="vidWidth">
+         <property name="minimumSize">
+          <size>
+           <width>130</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>1920</string>
+         </property>
+        </widget>
        </item>
-       <item>
-        <widget class="QLineEdit" name="startY"/>
+       <item row="2" column="0">
+        <widget class="QLabel" name="label_3">
+         <property name="text">
+          <string>Video Height</string>
+         </property>
+        </widget>
        </item>
-       <item>
-        <widget class="QLineEdit" name="startW"/>
+       <item row="2" column="1">
+        <widget class="QLineEdit" name="vidHeight">
+         <property name="minimumSize">
+          <size>
+           <width>130</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>1080</string>
+         </property>
+        </widget>
        </item>
-       <item>
-        <widget class="QLineEdit" name="startH"/>
+       <item row="3" column="0">
+        <widget class="QLabel" name="label_4">
+         <property name="text">
+          <string>Start View</string>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <item>
+          <widget class="QLineEdit" name="startX">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="startY">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="startW">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="startH">
+           <property name="minimumSize">
+            <size>
+             <width>80</width>
+             <height>0</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item row="4" column="0">
+        <widget class="QLabel" name="label_5">
+         <property name="text">
+          <string>End View</string>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="1">
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <item>
+          <widget class="QLineEdit" name="endX"/>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="endY"/>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="endW"/>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="endH"/>
+         </item>
+        </layout>
+       </item>
+       <item row="5" column="0">
+        <widget class="QPushButton" name="pushButton">
+         <property name="text">
+          <string>Save As</string>
+         </property>
+        </widget>
+       </item>
+       <item row="5" column="1">
+        <widget class="QLineEdit" name="savePath">
+         <property name="minimumSize">
+          <size>
+           <width>400</width>
+           <height>0</height>
+          </size>
+         </property>
+        </widget>
        </item>
       </layout>
      </item>
-     <item row="4" column="0">
-      <widget class="QLabel" name="label_5">
-       <property name="text">
-        <string>End View</string>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="1">
-      <layout class="QHBoxLayout" name="horizontalLayout_2">
-       <item>
-        <widget class="QLineEdit" name="endX"/>
+     <item>
+      <layout class="QFormLayout" name="formLayout_2">
+       <item row="0" column="0">
+        <widget class="QLabel" name="label_6">
+         <property name="text">
+          <string>Bitrate [kbps]</string>
+         </property>
+        </widget>
        </item>
-       <item>
-        <widget class="QLineEdit" name="endY"/>
+       <item row="0" column="1">
+        <widget class="QLineEdit" name="bitrate">
+         <property name="minimumSize">
+          <size>
+           <width>130</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="text">
+          <string>5000</string>
+         </property>
+        </widget>
        </item>
-       <item>
-        <widget class="QLineEdit" name="endW"/>
+       <item row="1" column="0">
+        <widget class="QLabel" name="label_7">
+         <property name="text">
+          <string>Encoding preset</string>
+         </property>
+        </widget>
        </item>
-       <item>
-        <widget class="QLineEdit" name="endH"/>
+       <item row="1" column="1">
+        <widget class="QComboBox" name="encodingPresetBox">
+         <property name="editable">
+          <bool>false</bool>
+         </property>
+         <property name="currentText">
+          <string/>
+         </property>
+        </widget>
        </item>
       </layout>
      </item>

+ 16 - 1
gradientchoosedialog.cpp

@@ -10,21 +10,36 @@ GradientChooseDialog::GradientChooseDialog()
     gcd.plainTextEdit->setFont(f);
 }
 
+#if 0
+
+<gradient>
+  <color r="230" g="10" b="40" p="0" />
+  <color r="30" g="230" b="80" p="100" />
+  <color r="20" g="120" b="210" p="500" />
+</gradient>
+
+#endif
+
 void GradientChooseDialog::on_buttonBox_accepted()
 {
     QDomDocument xsr;
     xsr.setContent(gcd.plainTextEdit->toPlainText());
     auto elem = xsr.documentElement();
     auto colors = xsr.elementsByTagName("color");
+    std::vector<std::pair<RGBColor, float>> colorArr;
     for (int i = 0; i < colors.length(); ++i) {
         auto child = colors.item(i).toElement();
-
         uint8_t r = child.attributeNode("r").value().toInt();
         uint8_t g = child.attributeNode("g").value().toInt();
         uint8_t b = child.attributeNode("b").value().toInt();
+        float p = child.attributeNode("p").value().toInt();
 
         printf("rgb (%s): %d, %d, %d\n", child.text().toUtf8().data(), r, g, b);
+        colorArr.push_back({ { r, g, b }, p });
     }
+
+    chosenGradient = std::make_unique<Gradient>(colorArr);
+
     printf("yee: %s\n", elem.text().toUtf8().data());
     fflush(stdout);
 }

+ 7 - 0
gradientchoosedialog.h

@@ -3,17 +3,24 @@
 
 #include <QDialog>
 #include "ui_gradientchooser.h"
+#include "Gradient.h"
+
+#include <memory>
 
 class GradientChooseDialog : public QDialog
 {
     Q_OBJECT
 private:
     Ui::GradientChooser gcd;
+    std::unique_ptr<Gradient> chosenGradient = nullptr;
 public:
     GradientChooseDialog();
 private slots:
     void on_buttonBox_accepted();
     void on_buttonBox_clicked(QAbstractButton *button);
+
+public:
+    inline std::unique_ptr<Gradient> getGradient(void) { return std::move(chosenGradient); }
 };
 
 #endif // GRADIENTCHOOSEDIALOG_H