Nicolas Winkler 5 lat temu
rodzic
commit
9255d422ac

+ 7 - 7
Almond.ui

@@ -10,7 +10,7 @@
     <x>0</x>
     <y>0</y>
     <width>1202</width>
-    <height>829</height>
+    <height>1188</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -135,8 +135,8 @@
          </property>
          <property name="sizeHint" stdset="0">
           <size>
-           <width>0</width>
-           <height>0</height>
+           <width>13</width>
+           <height>13</height>
           </size>
          </property>
         </spacer>
@@ -182,8 +182,8 @@
          </property>
          <property name="sizeHint" stdset="0">
           <size>
-           <width>0</width>
-           <height>0</height>
+           <width>13</width>
+           <height>13</height>
           </size>
          </property>
         </spacer>
@@ -239,8 +239,8 @@
          </property>
          <property name="sizeHint" stdset="0">
           <size>
-           <width>0</width>
-           <height>0</height>
+           <width>13</width>
+           <height>13</height>
           </size>
          </property>
         </spacer>

+ 8 - 2
BackgroundTask.cpp

@@ -21,8 +21,11 @@ void ImageExportTask::run(void)
         });
         emit finished(true, "Image successfully exported.");
     }
+    catch (alm::ImageExportException& ex) {
+        emit finished(false, QString("Error during image export: ") + ex.what());
+    }
     catch (...) {
-        emit finished(false, "Error occurred during image export.");
+        emit finished(false, "Unknown error occurred during image export.");
     }
 }
 
@@ -44,8 +47,11 @@ void VideoExportTask::run(void)
         mvg.generate(generator);
         emit finished(true, "Video successfully exported.");
     }
+    catch (alm::VideoExportException& ex) {
+        emit finished(false, QString("Error during video export: ") + ex.what());
+    }
     catch (...) {
-        emit finished(false, "Error occurred during video export.");
+        emit finished(false, "Unknown error occurred during video export.");
     }
 }
 

+ 4 - 4
choosegenerators.cpp

@@ -118,9 +118,9 @@ double Benchmarker::benchmarkResult(mnd::MandelGenerator& mg) const
         }, bmp);
         if (time > std::chrono::milliseconds(120)) {
             testIndex = i + 4;
-            printf("testing index for generator %s: %d\n", (mnd::toString(mg.getType()) + ", " + mnd::toString(mg.getExtension())).c_str(), testIndex);
-            printf("    w: %d, h: %d, iter: %d\n", benches[testIndex].bWidth, benches[testIndex].bHeight, benches[testIndex].maxIter);
-            fflush(stdout);
+            //printf("testing index for generator %s: %d\n", (mnd::toString(mg.getType()) + ", " + mnd::toString(mg.getExtension())).c_str(), testIndex);
+            //printf("    w: %d, h: %d, iter: %d\n", benches[testIndex].bWidth, benches[testIndex].bHeight, benches[testIndex].maxIter);
+            //fflush(stdout);
             break;
         }
         else if (time < std::chrono::milliseconds(3)) {
@@ -138,7 +138,7 @@ double Benchmarker::benchmarkResult(mnd::MandelGenerator& mg) const
             mg.generate(mi, bmp.pixels.get());
         }, bmp);
 
-        printf("%lld iterations in %lld microseconds\n\n", iters, time.count() / 1000);
+        //printf("%lld iterations in %lld microseconds\n\n", iters, time.count() / 1000);
 
         return double(iters) / time.count() * 1000;
     }

+ 7 - 0
libalmond/include/ImageExport.h

@@ -4,6 +4,7 @@
 #include "Mandel.h"
 #include "Gradient.h"
 #include <functional>
+#include <stdexcept>
 
 namespace alm
 {
@@ -15,6 +16,12 @@ namespace alm
         std::string path;
     };
 
+    struct ImageExportException :
+        std::runtime_error
+    {
+        ImageExportException(const std::string& err);
+    };
+
     /**
      * \brief generates and saves a fractal image in png format.
      * 

+ 1 - 0
libalmond/include/MandelVideoGenerator.h

@@ -2,6 +2,7 @@
 #define MANDELVIDEOGENERATOR_H
 
 #include "Mandel.h"
+#include "VideoStream.h"
 #include "Gradient.h"
 #include "Bitmap.h"
 #include <functional>

+ 19 - 8
libalmond/include/VideoStream.h

@@ -1,10 +1,10 @@
-#pragma once
+#ifndef VIDEO_STREAM_H_
+#define VIDEO_STREAM_H_
+
 #define FFMPEG_ENABLED
 #ifdef FFMPEG_ENABLED
 
-
-#ifndef VIDEO_STREAM_H_
-#define VIDEO_STREAM_H_
+#include <stdexcept>
 
 #include <string>
 #include "Bitmap.h"
@@ -19,6 +19,17 @@ extern "C" {
 #   include <libswscale/swscale.h>
 }
 
+namespace alm
+{
+    struct VideoExportException;
+}
+
+struct alm::VideoExportException :
+    public std::runtime_error
+{
+    VideoExportException(const std::string& err);
+};
+
 class VideoStream
 {
     const AVCodec* codec;
@@ -30,7 +41,6 @@ class VideoStream
     AVPacket* pkt;
     AVStream* stream;
     SwsContext* swsContext;
-    static const uint8_t endcode[];
 
     int width;
     int height;
@@ -40,11 +50,12 @@ public:
     VideoStream(int width, int height, const std::string& filename, int bitrate, int fps, const char* preset);
     ~VideoStream(void);
 
-    void encode(AVFrame* frame);
-
     void addFrame(const Bitmap<RGBColor>& frame);
+private:
+    void encode(AVFrame* frame);
 };
 
-#endif // VIDEO_STREAM_H_
 
 #endif // FFMPEG_ENABLED
+
+#endif // VIDEO_STREAM_H_

+ 14 - 4
libalmond/src/ImageExport.cpp

@@ -6,6 +6,10 @@
 namespace alm
 {
 
+ImageExportException::ImageExportException(const std::string& err) :
+    std::runtime_error{ err }
+{
+}
 
 void exportPng(const ImageExportInfo& iei, std::function<void(float)> progressCallback)
 {
@@ -17,15 +21,21 @@ void exportPng(const ImageExportInfo& iei, std::function<void(float)> progressCa
 
     mnd::MandelGenerator& generator = *iei.generator;
     FILE* file = fopen(iei.path.c_str(), "wb");
-    if(!file) exit(1);
+    if(!file)
+        throw ImageExportException{ std::string("could not open file '") + iei.path + "'" };
 
     png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-    if (!png) exit(1);
+    if (!png)
+        throw ImageExportException{ "error creating png write struct" };
 
     png_infop info = png_create_info_struct(png);
-    if (!info) exit(1);
+    if (!info)
+        throw ImageExportException{ "error creating png info struct" };
 
-    if (setjmp(png_jmpbuf(png))) exit(1);
+    if (setjmp(png_jmpbuf(png))) {
+        png_destroy_write_struct(&png, &info);
+        throw ImageExportException{ "error while creating png" };
+    }
 
     png_init_io(png, file);
 

+ 64 - 109
libalmond/src/VideoStream.cpp

@@ -2,6 +2,12 @@
 
 #include <iostream>
 
+using alm::VideoExportException;
+
+VideoExportException::VideoExportException(const std::string& err) :
+    std::runtime_error{ err }
+{
+}
 
 
 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
@@ -9,8 +15,6 @@
 #define av_frame_free  avcodec_free_frame
 #endif
 
-const uint8_t VideoStream::endcode[] = { 0, 0, 1, 0xb7 };
-
 
 VideoStream::VideoStream(int width, int height, const std::string& filename, int bitrate, int fps, const char* preset) :
     width{ width & (~1) }, height{ height & (~1) }
@@ -20,21 +24,20 @@ VideoStream::VideoStream(int width, int height, const std::string& filename, int
 
     codec = avcodec_find_encoder(AV_CODEC_ID_H264);
     if (!codec) {
-        fprintf(stderr, "invalid codec\n");
-        exit(1);
+        throw VideoExportException{ "could not find h264 encoder" };
     }
 
     AVOutputFormat* oformat = av_guess_format(nullptr, filename.c_str(), nullptr);
     if (!oformat)
         oformat = av_guess_format("mp4", nullptr, nullptr);
     if (oformat == nullptr)
-        throw "invalid format";
+        throw VideoExportException{ "invalid format" };
 
     codecContext = avcodec_alloc_context3(codec);
 
     pkt = av_packet_alloc();
     if (!pkt)
-        exit(1);
+        throw VideoExportException{ "could not allocate packet" };
 
     codecContext->bit_rate = bitrate * 1000;
     codecContext->width = width;
@@ -42,17 +45,19 @@ VideoStream::VideoStream(int width, int height, const std::string& filename, int
     codecContext->time_base = AVRational{ 1, fps };
     codecContext->framerate = AVRational{ fps, 1 };
 
-    codecContext->gop_size = 5; /* emit one intra frame every five frames */
-    codecContext->max_b_frames = 1;
+    codecContext->gop_size = 16; /* one intra frame every 16 frames */
+    codecContext->max_b_frames = 3;
     codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
 
     formatContext = avformat_alloc_context();
+    if (!formatContext)
+        throw VideoExportException{ "error allocating format context" };
     formatContext->oformat = oformat;
     formatContext->video_codec_id = oformat->video_codec;
 
     stream = avformat_new_stream(formatContext, codec);
     if (!stream)
-        throw "error";
+        throw VideoExportException{ "error creating stream" };
 
     params = avcodec_parameters_alloc();
     avcodec_parameters_from_context(params, codecContext);
@@ -71,13 +76,15 @@ VideoStream::VideoStream(int width, int height, const std::string& filename, int
         av_opt_set(codecContext->priv_data, "preset", preset, 0);
 
     if (avcodec_open2(codecContext, codec, nullptr) < 0) {
-        fprintf(stderr, "could not open codec\n");
-        exit(1);
+        throw VideoExportException{ "could not open codec" };
+    }
+    int opened = avio_open(&formatContext->pb, filename.c_str(), AVIO_FLAG_WRITE);
+    if (opened < 0) {
+        throw VideoExportException{ std::string("could not open file '") + filename + "'" };
     }
-    avio_open(&formatContext->pb, filename.c_str(), AVIO_FLAG_WRITE);
 
-    if (avformat_write_header(formatContext, NULL) < 0) {
-        throw "error";
+    if (avformat_write_header(formatContext, nullptr) < 0) {
+        throw VideoExportException{ "error writing header" };
     }
     /*file = fopen(filename.c_str(), "wb");
     if (!file) {
@@ -86,55 +93,26 @@ VideoStream::VideoStream(int width, int height, const std::string& filename, int
     }*/
 
     picture = av_frame_alloc();
-    av_frame_make_writable(picture);
+    if (!picture)
+        throw VideoExportException{ "error allocating frame" };
+    if (av_frame_make_writable(picture) < 0) {
+        throw VideoExportException{ "error making frame writeable" };
+    }
     picture->format = codecContext->pix_fmt;
     picture->width  = codecContext->width;
     picture->height = codecContext->height;
 
     int retval = av_frame_get_buffer(picture, 0);
     if (retval < 0) {
-        fprintf(stderr, "could not alloc the frame data\n");
-        exit(1);
+        throw VideoExportException{ "could not allocate frame data" };
     }
     //av_image_alloc(picture->data, picture->linesize, width, height, codecContext->pix_fmt, 32);
 
     swsContext = sws_getContext(width, height,
         AV_PIX_FMT_RGB24, width, height,
         AV_PIX_FMT_YUV420P, 0, 0, 0, 0);
-}
-
-
-void VideoStream::encode(AVFrame* frame)
-{
-    int ret;
-
-    /* send the frame to the encoder */
-    ret = avcodec_send_frame(codecContext, frame);
-    if (ret < 0) {
-        fprintf(stderr, "error sending a frame for encoding\n");
-        exit(1);
-    }
-
-    while (ret >= 0) {
-        ret = avcodec_receive_packet(codecContext, pkt);
-        //ret = avcodec_encode_video2(codecContext, pkt, picture, &gotPacket);
-        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
-            return;
-        else if (ret < 0) {
-            fprintf(stderr, "error during encoding\n");
-            exit(1);
-        }
-
-        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, 60}, stream->time_base);
-        pkt->stream_index = stream->index;
-
-        av_write_frame(formatContext, pkt);
-        av_packet_unref(pkt);
-    }
+    if (!swsContext)
+        throw VideoExportException{ "error preparing sws context" };
 }
 
 
@@ -144,44 +122,13 @@ VideoStream::~VideoStream()
     encode(nullptr);
     av_write_trailer(this->formatContext);
 
-    /* add sequence end code to have a real MPEG file */
-    //fwrite(endcode, 1, sizeof(endcode), file);
-    //fclose(file);
-
     avcodec_close(codecContext);
     avio_close(formatContext->pb);
     av_frame_unref(picture);
-    //av_free(codecContext);
     avcodec_parameters_free(&params);
     avcodec_free_context(&codecContext);
     av_frame_free(&picture);
     av_packet_free(&pkt);
-
-/*
-    AVPacket pkt;
-    av_init_packet(&pkt);
-    pkt.data = nullptr;
-    pkt.size = 0;
-
-    for (;;) {
-        avcodec_send_frame(codecContext, NULL);
-        if (avcodec_receive_packet(codecContext, &pkt) == 0) {
-            av_interleaved_write_frame(codecContext, &pkt);
-            av_packet_unref(&pkt);
-        }
-        else {
-            break;
-        }
-    }
-
-    av_write_trailer();
-    if (!(oformat->flags & AVFMT_NOFILE)) {
-        int err = avio_close(ofctx->pb);
-        if (err < 0) {
-            Debug("Failed to close file", err);
-        }
-    }*/
-
 }
 
 
@@ -189,34 +136,9 @@ void VideoStream::addFrame(const Bitmap<RGBColor>& frame)
 {
     int retval = av_frame_make_writable(picture);
     if (retval < 0)
-        exit(1);
+        throw VideoExportException{ "could not write to frame data" };
 
-    /* prepare a dummy image */
-    /* Y */
-    /*for(int y = 0; y < height; y++) {
-        for(int x = 0; x < width; x++) {
-            picture->data[0][y * picture->linesize[0] + x] = frame.get(x, y).r / 2;
-        }
-    }*/
-
-    /* Cb and Cr */
-    /*for(int y=0;y<height / 2;y++) {
-        for(int x=0;x<width / 2;x++) {
-            picture->data[1][y * picture->linesize[1] + x] = frame.get(x * 2, y * 2).g / 2;
-            picture->data[2][y * picture->linesize[2] + x] = frame.get(x * 2, y * 2).b / 2;
-        }
-    }*/
-
-    /*auto gammaCorrect = [] (const RGBColor& rgb) {
-        const float gamma = 2.2f;
-        return RGBColor {
-            uint8_t(::powf(rgb.r / 255.0f, 1.0f / gamma) * 255),
-            uint8_t(::powf(rgb.g / 255.0f, 1.0f / gamma) * 255),
-            uint8_t(::powf(rgb.b / 255.0f, 1.0f / gamma) * 255),
-        };
-    };
-
-    Bitmap<RGBColor> gammaCorrected = frame.map<RGBColor>(gammaCorrect);*/
+    /*Bitmap<RGBColor> gammaCorrected = frame.map<RGBColor>(gammaCorrect);*/
 
     const uint8_t* pixelPointer[] = { reinterpret_cast<const uint8_t*>(frame.pixels.get()), 0 };
     const int linesizeIn[] = { int(frame.width * sizeof(RGBColor)) };
@@ -230,3 +152,36 @@ void VideoStream::addFrame(const Bitmap<RGBColor>& frame)
     encode(picture);
 }
 
+
+void VideoStream::encode(AVFrame* frame)
+{
+    int ret;
+
+    ret = avcodec_send_frame(codecContext, frame);
+    if (ret < 0) {
+        throw VideoExportException{ "error encoding frame" };
+    }
+
+    while (ret >= 0) {
+        ret = avcodec_receive_packet(codecContext, pkt);
+        //ret = avcodec_encode_video2(codecContext, pkt, picture, &gotPacket);
+        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+            return;
+        else if (ret < 0) {
+            throw VideoExportException{ "error during encoding" };
+        }
+
+        //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, 60 }, stream->time_base);
+        pkt->stream_index = stream->index;
+
+        av_write_frame(formatContext, pkt);
+        av_packet_unref(pkt);
+    }
+}
+
+
+