Skip to content

Instantly share code, notes, and snippets.

@xenogenesi
Created November 12, 2020 08:20
Show Gist options
  • Save xenogenesi/f89d6acbb25bc9cefd4122cb659fa0f0 to your computer and use it in GitHub Desktop.
Save xenogenesi/f89d6acbb25bc9cefd4122cb659fa0f0 to your computer and use it in GitHub Desktop.
diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp
index d6899f66..ac13fa0e 100644
--- a/dialogs/exportdialog.cpp
+++ b/dialogs/exportdialog.cpp
@@ -65,6 +65,9 @@ enum ExportFormats {
FORMAT_WAV,
FORMAT_WEBM,
FORMAT_WMV,
+#ifdef EXPORT_POPEN
+ FORMAT_RAWPIPE,
+#endif
FORMAT_SIZE
};
@@ -102,6 +105,9 @@ ExportDialog::ExportDialog(QWidget *parent) :
format_strings[FORMAT_WAV] = "WAVE Audio";
format_strings[FORMAT_WEBM] = "WebM";
format_strings[FORMAT_WMV] = "Windows Media";
+#ifdef EXPORT_POPEN
+ format_strings[FORMAT_RAWPIPE] = "rawvideo to stdin";
+#endif
for (int i=0;i<FORMAT_SIZE;i++) {
formatCombobox->addItem(format_strings[i]);
@@ -140,6 +146,11 @@ void ExportDialog::format_changed(int index) {
int default_acodec = 0;
switch (index) {
+#ifdef EXPORT_POPEN
+ case FORMAT_RAWPIPE:
+ vcodecCombobox->addItem("rawpipe", COMPRESSION_RAWPIPE);
+ break;
+#endif
case FORMAT_3GPP:
add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_MPEG4);
add_codec_to_combobox(vcodecCombobox, AV_CODEC_ID_H264);
@@ -504,6 +515,11 @@ void ExportDialog::StartExport() {
ext = "wma";
}
break;
+#ifdef EXPORT_POPEN
+ case FORMAT_RAWPIPE:
+ ext = "rpp";
+ break;
+#endif
default:
qCritical() << "Invalid format - this is a bug, please inform the developers";
QMessageBox::critical(
@@ -521,8 +537,12 @@ void ExportDialog::StartExport() {
format_strings[formatCombobox->currentIndex()] + " (*." + ext + ")"
);
if (!filename.isEmpty()) {
- if (!filename.endsWith("." + ext, Qt::CaseInsensitive)) {
- filename += "." + ext;
+ if (!filename.endsWith("." + ext, Qt::CaseInsensitive)
+#ifdef EXPORT_POPEN
+ && formatCombobox->currentIndex() != FORMAT_RAWPIPE
+#endif
+ ) {
+ filename += "." + ext;
}
if (formatCombobox->currentIndex() == FORMAT_IMG) {
@@ -618,7 +638,11 @@ void ExportDialog::vcodec_changed(int index) {
if (vcodecCombobox->count() > 0) {
if (vcodecCombobox->itemData(index) == AV_CODEC_ID_H264
- || vcodecCombobox->itemData(index) == AV_CODEC_ID_H265) {
+ || vcodecCombobox->itemData(index) == AV_CODEC_ID_H265
+#ifdef EXPORT_POPEN
+ || vcodecCombobox->itemData(index) == COMPRESSION_RAWPIPE
+#endif
+ ) {
compressionTypeCombobox->setEnabled(true);
compressionTypeCombobox->addItem(tr("Quality-based (Constant Rate Factor)"), COMPRESSION_TYPE_CFR);
// compressionTypeCombobox->addItem("File size-based (Two-Pass)", COMPRESSION_TYPE_TARGETSIZE);
@@ -629,6 +653,11 @@ void ExportDialog::vcodec_changed(int index) {
compressionTypeCombobox->setEnabled(false);
}
+#ifdef EXPORT_POPEN
+ if (vcodecCombobox->itemData(index) == COMPRESSION_RAWPIPE)
+ return;
+#endif
+
// set default pix_fmt for this codec
AVCodec* codec_info = avcodec_find_encoder(static_cast<AVCodecID>(vcodecCombobox->itemData(index).toInt()));
if (codec_info == nullptr) {
@@ -670,6 +699,11 @@ void ExportDialog::comp_type_changed(int) {
}
void ExportDialog::open_advanced_video_dialog() {
+#ifdef EXPORT_POPEN
+ // FIXME prevent advanced dialog (it crash) but really should be disabled
+ if (vcodecCombobox->currentData().toInt() == COMPRESSION_RAWPIPE)
+ return;
+#endif
AdvancedVideoDialog avd(this, static_cast<AVCodecID>(vcodecCombobox->currentData().toInt()), vcodec_params);
avd.exec();
}
diff --git a/dialogs/preferencesdialog.cpp b/dialogs/preferencesdialog.cpp
index 9c4dafda..1f388551 100644
--- a/dialogs/preferencesdialog.cpp
+++ b/dialogs/preferencesdialog.cpp
@@ -52,6 +52,7 @@
#include "ui/columnedgridlayout.h"
#include "ui/mainwindow.h"
#include "dialogs/newsequencedialog.h"
+#include "rendering/exportthread.h"
KeySequenceEditor::KeySequenceEditor(QWidget* parent, QAction* a)
: QKeySequenceEdit(parent), action(a) {
@@ -261,6 +262,9 @@ void PreferencesDialog::accept() {
olive::CurrentConfig.css_path = custom_css_fn->text();
olive::CurrentConfig.recording_mode = recordingComboBox->currentIndex() + 1;
olive::CurrentConfig.img_seq_formats = imgSeqFormatEdit->text();
+#ifdef EXPORT_POPEN
+ olive::CurrentConfig.rawpipe_command = rawpipeCommand->text();
+#endif
olive::CurrentConfig.upcoming_queue_size = upcoming_queue_spinbox->value();
olive::CurrentConfig.upcoming_queue_type = upcoming_queue_type->currentIndex();
olive::CurrentConfig.previous_queue_size = previous_queue_spinbox->value();
@@ -552,6 +556,20 @@ void PreferencesDialog::setup_ui() {
row++;
+#ifdef EXPORT_POPEN
+
+ // General -> Rawpipe command
+ general_layout->addWidget(new QLabel(tr("Rawpipe export command:"), this), row, 0);
+
+ rawpipeCommand = new QLineEdit(general_tab);
+ rawpipeCommand->setText(olive::CurrentConfig.rawpipe_command);
+
+ general_layout->addWidget(rawpipeCommand, row, 1, 1, 4);
+
+ row++;
+
+#endif
+
// General -> Thumbnail and Waveform Resolution
general_layout->addWidget(new QLabel(tr("Thumbnail Resolution:"), this), row, 0);
diff --git a/dialogs/preferencesdialog.h b/dialogs/preferencesdialog.h
index e0804bb4..bb9324a7 100644
--- a/dialogs/preferencesdialog.h
+++ b/dialogs/preferencesdialog.h
@@ -36,6 +36,7 @@
#include <QTimeEdit>
#include "timeline/sequence.h"
+#include "rendering/exportthread.h"
class KeySequenceEditor;
@@ -179,6 +180,13 @@ private:
*/
QLineEdit* imgSeqFormatEdit;
+#ifdef EXPORT_POPEN
+ /**
+ * @brief UI widget for editing the command used for rawpipe codec export
+ */
+ QLineEdit* rawpipeCommand;
+#endif
+
/**
* @brief UI widget for editing the recording channels
*/
diff --git a/global/config.cpp b/global/config.cpp
index a439ba27..fc8d3b5f 100644
--- a/global/config.cpp
+++ b/global/config.cpp
@@ -27,6 +27,8 @@
#include "panels/project.h"
#include "panels/panels.h"
+#include "rendering/exportthread.h"
+
#include "debug.h"
Config olive::CurrentConfig;
@@ -40,6 +42,9 @@ Config::Config()
select_also_seeks(false),
paste_seeks(true),
img_seq_formats("jpg|jpeg|bmp|tiff|tif|psd|png|tga|jp2|gif"),
+#ifdef EXPORT_POPEN
+ rawpipe_command(""),
+#endif
rectified_waveforms(false),
default_transition_length(30),
timecode_view(olive::kTimecodeDrop),
@@ -115,6 +120,11 @@ void Config::load(QString path) {
} else if (stream.name() == "ImageSequenceFormats") {
stream.readNext();
img_seq_formats = stream.text().toString();
+#ifdef EXPORT_POPEN
+ } else if (stream.name() == "RawpipeCommand") {
+ stream.readNext();
+ rawpipe_command = stream.text().toString();
+#endif
} else if (stream.name() == "RectifiedWaveforms") {
stream.readNext();
rectified_waveforms = (stream.text() == "1");
@@ -279,6 +289,9 @@ void Config::save(QString path) {
stream.writeTextElement("SelectAlsoSeeks", QString::number(select_also_seeks));
stream.writeTextElement("PasteSeeks", QString::number(paste_seeks));
stream.writeTextElement("ImageSequenceFormats", img_seq_formats);
+#ifdef EXPORT_POPEN
+ stream.writeTextElement("RawpipeCommand", rawpipe_command);
+#endif
stream.writeTextElement("RectifiedWaveforms", QString::number(rectified_waveforms));
stream.writeTextElement("DefaultTransitionLength", QString::number(default_transition_length));
stream.writeTextElement("TimecodeView", QString::number(timecode_view));
diff --git a/global/config.h b/global/config.h
index 77c3487d..8d2b6fd3 100644
--- a/global/config.h
+++ b/global/config.h
@@ -25,6 +25,7 @@
#include <QTime>
#include "ui/styling.h"
+#include "rendering/exportthread.h"
namespace olive {
/**
@@ -216,6 +217,16 @@ struct Config {
*/
QString img_seq_formats;
+#ifdef EXPORT_POPEN
+ /**
+ * @brief Command to run while exporting with rawpipe codec option
+ *
+ * Example: ffmpeg-cuda -y -f rawvideo -s {{WIDTH}}x{{HEIGHT}} -pix_fmt rgba -r {{FPS}} -i -
+ * -an -c:v h264_nvenc -cq:v {{BITRATE}} -b:v 4000k -maxrate:v 8000k -profile:v high -bf:v 2 {{OUTPUT}}
+ */
+ QString rawpipe_command;
+#endif
+
/**
* @brief Use rectified waveforms
*
diff --git a/rendering/exportthread.cpp b/rendering/exportthread.cpp
index 36cda16b..a89237d7 100644
--- a/rendering/exportthread.cpp
+++ b/rendering/exportthread.cpp
@@ -42,6 +42,7 @@ extern "C" {
#include "rendering/renderfunctions.h"
#include "rendering/audio.h"
#include "ui/mainwindow.h"
+#include "global/config.h"
#include "global/debug.h"
ExportThread::ExportThread(const ExportParams &params,
@@ -106,6 +107,49 @@ bool ExportThread::SetupVideo() {
// if video is disabled, no setup necessary
if (!params_.video_enabled) return true;
+#ifdef EXPORT_POPEN
+ if (params_.video_codec == COMPRESSION_RAWPIPE) {
+ pipe_frame.format = AV_PIX_FMT_RGBA;
+ pipe_frame.width = olive::ActiveSequence->width;
+ pipe_frame.height = olive::ActiveSequence->height;
+ pipe_frame.data = new unsigned long[pipe_frame.width * pipe_frame.height];
+ for (unsigned long i = 0; i < pipe_frame.width * pipe_frame.height; i++) {
+ pipe_frame.data[i] = 0xffff00ff; //ABGR
+ }
+
+ QString rawpipeCmd = olive::CurrentConfig.rawpipe_command;
+ rawpipeCmd.replace("{{WIDTH}}", QString::number(pipe_frame.width));
+ rawpipeCmd.replace("{{HEIGHT}}", QString::number(pipe_frame.height));
+ rawpipeCmd.replace("{{FPS}}", QString::number(params_.video_frame_rate));
+ rawpipeCmd.replace("{{BITRATE}}", QString::number(params_.video_bitrate));
+ rawpipeCmd.replace("{{OUTPUT}}", params_.filename.toUtf8());
+
+ qDebug() << "rawpipe command: " << rawpipeCmd;
+
+#if EXPORT_POPEN == 1
+ pipe_frame.file = popen(rawpipeCmd.toUtf8().constData(), "w");
+ if (pipe_frame.file == NULL) {
+ qCritical() << "export popen failed";
+ export_error = tr("export popen failed");
+ return false;
+ }
+#elif EXPORT_POPEN == 2
+ pipe_frame.qproc = new QProcess;
+ pipe_frame.qproc->setReadChannelMode(QProcess::ForwardedChannels);
+
+ pipe_frame.qproc->start(rawpipeCmd, QIODevice::WriteOnly/*|QIODevice::Unbuffered*/);
+ if(!pipe_frame.qproc->waitForStarted()) {
+ qCritical() << "export QProcess start failed";
+ export_error = tr("export QProcess failed");
+ return false;
+ }
+#else
+#error "EXPORT_POPEN must be 1 (popen) or 2 (qprocess)"
+#endif
+ return true;
+ }
+#endif
+
// find video encoder
vcodec = avcodec_find_encoder(static_cast<enum AVCodecID>(params_.video_codec));
if (!vcodec) {
@@ -339,6 +383,9 @@ bool ExportThread::SetupAudio() {
bool ExportThread::SetupContainer() {
+#ifdef EXPORT_POPEN
+ if (params_.video_codec == COMPRESSION_RAWPIPE) return true;
+#endif
// Set up output context (using the filename as the format specification)
avformat_alloc_output_context2(&fmt_ctx, nullptr, nullptr, c_filename);
@@ -386,17 +433,21 @@ void ExportThread::Export()
return;
}
- // Write the container header based on what's been set up above
- ret = avformat_write_header(fmt_ctx, nullptr);
- if (ret < 0) {
+#ifdef EXPORT_POPEN
+ if (params_.video_codec != COMPRESSION_RAWPIPE) {
+ // Write the container header based on what's been set up above
+ ret = avformat_write_header(fmt_ctx, nullptr);
+ if (ret < 0) {
- // FFmpeg failed to write the header, so cancel the export and throw an error
+ // FFmpeg failed to write the header, so cancel the export and throw an error
- qCritical() << "Could not write output file header." << ret;
- export_error = tr("could not write output file header (%1)").arg(QString::number(ret));
+ qCritical() << "Could not write output file header." << ret;
+ export_error = tr("could not write output file header (%1)").arg(QString::number(ret));
- return;
+ return;
+ }
}
+#endif
// Count audio samples in file (used for calculating PTS)
long file_audio_samples = 0;
@@ -431,7 +482,15 @@ void ExportThread::Export()
if (params_.video_enabled) {
do {
// TODO optimize by rendering the next frame while encoding the last
- renderer->start_render(nullptr, olive::ActiveSequence.get(), 1, nullptr, video_frame->data[0], video_frame->linesize[0]/4, 0, true);
+#ifdef EXPORT_POPEN
+ if (params_.video_codec != COMPRESSION_RAWPIPE) {
+#endif
+ renderer->start_render(nullptr, olive::ActiveSequence.get(), 1, nullptr, video_frame->data[0], video_frame->linesize[0]/4, 0, true);
+#ifdef EXPORT_POPEN
+ } else {
+ renderer->start_render(nullptr, olive::ActiveSequence.get(), 1, nullptr, (GLvoid *)pipe_frame.data, pipe_frame.width, 0, true);
+ }
+#endif
// Wait for RenderThread to return
waitCond.wait(&mutex);
@@ -456,32 +515,66 @@ void ExportThread::Export()
// OpenGL buffer to
if (params_.video_enabled) {
- //
- // - I'm not sure why, but we have to alloc/free sws_frame every frame, or it breaks GIF exporting.
- // - (i.e. GIFs get stuck on the first frame)
- // - The same problem/solution can be seen here: https://stackoverflow.com/a/38997739
- // - Perhaps this is the intended way to use swscale, but it seems inefficient.
- // - Anyway, here we are.
- //
-
- // Construct destination pixel format frame
- sws_frame = av_frame_alloc();
- sws_frame->format = vcodec_ctx->pix_fmt;
- sws_frame->width = params_.video_width;
- sws_frame->height = params_.video_height;
- av_frame_get_buffer(sws_frame, 0);
-
- // Convert raw RGBA buffer to format expected by the encoder
- sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize);
- sws_frame->pts = qRound(timecode_secs/av_q2d(vcodec_ctx->time_base));
-
- // Send frame to encoder
- if (!Encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream)) {
- return;
- }
+#ifdef EXPORT_POPEN
+ if (params_.video_codec == COMPRESSION_RAWPIPE) {
+ unsigned long towrite = pipe_frame.width * 4 * pipe_frame.height, written = 0, partial;
+ char *p = (char *)pipe_frame.data;
+#if EXPORT_POPEN == 1
+ while (written < towrite) {
+ clearerr(pipe_frame.file);
+ partial = fwrite(p + written, 1, towrite - written, pipe_frame.file);
+ if (ferror(pipe_frame.file)) {
+ qCritical() << "Error: writing to pipe";
+ return;
+ }
+ written += partial;
+ }
+#elif EXPORT_POPEN == 2
+ while(written < towrite) {
+ partial = pipe_frame.qproc->write(p + written, towrite - written);
+ if (pipe_frame.qproc->error() == QProcess::WriteError) {
+ qCritical() << "Error: qprocess write error";
+ return;
+ }
+ written += partial;
+ while(pipe_frame.qproc->bytesToWrite() > 0) {
+ pipe_frame.qproc->waitForBytesWritten(-1);
+ }
+ }
+#else
+#error "EXPORT_POPEN must be 1 (popen) or 2 (qprocess)"
+#endif
+ } else {
+#endif
+ //
+ // - I'm not sure why, but we have to alloc/free sws_frame every frame, or it breaks GIF exporting.
+ // - (i.e. GIFs get stuck on the first frame)
+ // - The same problem/solution can be seen here: https://stackoverflow.com/a/38997739
+ // - Perhaps this is the intended way to use swscale, but it seems inefficient.
+ // - Anyway, here we are.
+ //
+
+ // Construct destination pixel format frame
+ sws_frame = av_frame_alloc();
+ sws_frame->format = vcodec_ctx->pix_fmt;
+ sws_frame->width = params_.video_width;
+ sws_frame->height = params_.video_height;
+ av_frame_get_buffer(sws_frame, 0);
+
+ // Convert raw RGBA buffer to format expected by the encoder
+ sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize);
+ sws_frame->pts = qRound(timecode_secs/av_q2d(vcodec_ctx->time_base));
+
+ // Send frame to encoder
+ if (!Encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream)) {
+ return;
+ }
- av_frame_free(&sws_frame);
- sws_frame = nullptr;
+ av_frame_free(&sws_frame);
+ sws_frame = nullptr;
+#ifdef EXPORT_POPEN
+ }
+#endif
}
// If we're exporting audio, copy audio from the buffer into an AVFrame for encoding
@@ -585,73 +678,98 @@ void ExportThread::Export()
return;
}
- // Flush remaining packets out of video and audio encoders by sending a null frame
- if (params_.video_enabled) {
- Encode(fmt_ctx, vcodec_ctx, nullptr, &video_pkt, video_stream);
- }
- if (params_.audio_enabled) {
- Encode(fmt_ctx, acodec_ctx, nullptr, &audio_pkt, audio_stream);
- }
+#ifdef EXPORT_POPEN
+ if (params_.video_codec != COMPRESSION_RAWPIPE) {
+#endif
+ // Flush remaining packets out of video and audio encoders by sending a null frame
+ if (params_.video_enabled) {
+ Encode(fmt_ctx, vcodec_ctx, nullptr, &video_pkt, video_stream);
+ }
+ if (params_.audio_enabled) {
+ Encode(fmt_ctx, acodec_ctx, nullptr, &audio_pkt, audio_stream);
+ }
- // Write container trailer
- ret = av_write_trailer(fmt_ctx);
- if (ret < 0) {
- qCritical() << "Could not write output file trailer." << ret;
- export_error = tr("could not write output file trailer (%1)").arg(QString::number(ret));
- return;
+ // Write container trailer
+ ret = av_write_trailer(fmt_ctx);
+ if (ret < 0) {
+ qCritical() << "Could not write output file trailer." << ret;
+ export_error = tr("could not write output file trailer (%1)").arg(QString::number(ret));
+ return;
+ }
+#ifdef EXPORT_POPEN
}
+#endif
emit ProgressChanged(100, 0);
}
void ExportThread::Cleanup()
{
- if (fmt_ctx != nullptr) {
- avio_closep(&fmt_ctx->pb);
- avformat_free_context(fmt_ctx);
- }
+#ifdef EXPORT_POPEN
+ if (params_.video_codec != COMPRESSION_RAWPIPE) {
+#endif
+ if (fmt_ctx != nullptr) {
+ avio_closep(&fmt_ctx->pb);
+ avformat_free_context(fmt_ctx);
+ }
- if (acodec_ctx != nullptr) {
- avcodec_close(acodec_ctx);
- avcodec_free_context(&acodec_ctx);
- }
+ if (acodec_ctx != nullptr) {
+ avcodec_close(acodec_ctx);
+ avcodec_free_context(&acodec_ctx);
+ }
- if (audio_frame != nullptr) {
- av_frame_free(&audio_frame);
- }
+ if (audio_frame != nullptr) {
+ av_frame_free(&audio_frame);
+ }
- if (apkt_alloc) {
- av_packet_unref(&audio_pkt);
- }
+ if (apkt_alloc) {
+ av_packet_unref(&audio_pkt);
+ }
- if (vcodec_ctx != nullptr) {
- avcodec_close(vcodec_ctx);
- avcodec_free_context(&vcodec_ctx);
- }
+ if (vcodec_ctx != nullptr) {
+ avcodec_close(vcodec_ctx);
+ avcodec_free_context(&vcodec_ctx);
+ }
- if (video_frame != nullptr) {
- av_frame_free(&video_frame);
- }
+ if (video_frame != nullptr) {
+ av_frame_free(&video_frame);
+ }
- if (vpkt_alloc) {
- av_packet_unref(&video_pkt);
- }
+ if (vpkt_alloc) {
+ av_packet_unref(&video_pkt);
+ }
- if (sws_ctx != nullptr) {
- sws_freeContext(sws_ctx);
- }
+ if (sws_ctx != nullptr) {
+ sws_freeContext(sws_ctx);
+ }
- if (swr_ctx != nullptr) {
- swr_free(&swr_ctx);
- }
+ if (swr_ctx != nullptr) {
+ swr_free(&swr_ctx);
+ }
- if (swr_frame != nullptr) {
- av_frame_free(&swr_frame);
- }
+ if (swr_frame != nullptr) {
+ av_frame_free(&swr_frame);
+ }
- if (sws_frame != nullptr) {
- av_frame_free(&sws_frame);
- }
+ if (sws_frame != nullptr) {
+ av_frame_free(&sws_frame);
+ }
+#ifdef EXPORT_POPEN
+ } else {
+#if EXPORT_POPEN == 1
+ pclose(pipe_frame.file);
+#elif EXPORT_POPEN == 2
+ pipe_frame.qproc->waitForBytesWritten(-1);
+ pipe_frame.qproc->closeWriteChannel();
+ pipe_frame.qproc->waitForFinished();
+ //pipe_frame.qproc->terminate();
+ pipe_frame.qproc->close();
+#else
+#error "EXPORT_POPEN must be 1 (popen) or 2 (qprocess)"
+#endif
+ delete [] (char *)pipe_frame.data;
+ }
+#endif
delete [] c_filename;
}
diff --git a/rendering/exportthread.h b/rendering/exportthread.h
index 32822172..21d43d9e 100644
--- a/rendering/exportthread.h
+++ b/rendering/exportthread.h
@@ -21,10 +21,15 @@
#ifndef EXPORTTHREAD_H
#define EXPORTTHREAD_H
+#define EXPORT_POPEN 2
+
#include <QThread>
#include <QOffscreenSurface>
#include <QMutex>
#include <QWaitCondition>
+#if defined(EXPORT_POPEN) && EXPORT_POPEN == 2
+#include <QProcess>
+#endif
struct AVFormatContext;
struct AVCodecContext;
@@ -37,12 +42,19 @@ struct SwrContext;
extern "C" {
#include <libavcodec/avcodec.h>
+#if defined(EXPORT_POPEN) && EXPORT_POPEN == 1
+#include <stdio.h>
+#endif
}
+
#define COMPRESSION_TYPE_CBR 0
#define COMPRESSION_TYPE_CFR 1
#define COMPRESSION_TYPE_TARGETSIZE 2
#define COMPRESSION_TYPE_TARGETBR 3
+#ifdef EXPORT_POPEN
+#define COMPRESSION_RAWPIPE 0x30000
+#endif
// structs that store parameters passed from the export dialogs to this thread
@@ -69,6 +81,23 @@ struct VideoCodecParams {
int threads;
};
+#ifdef EXPORT_POPEN
+struct PipeFrame {
+ int format;
+ unsigned short width;
+ unsigned short height;
+ unsigned long *data; // unsigned
+#if EXPORT_POPEN == 1
+ FILE *file;
+#elif EXPORT_POPEN == 2
+ QProcess *qproc;
+#else
+#error "EXPORT_POPEN must be 1 (popen) or 2 (qprocess)"
+#endif
+};
+#endif
+
+
class ExportThread : public QThread {
Q_OBJECT
public:
@@ -118,6 +147,10 @@ private:
bool vpkt_alloc;
bool apkt_alloc;
+#ifdef EXPORT_POPEN
+ struct PipeFrame pipe_frame;
+#endif
+
int aframe_bytes;
int ret;
char* c_filename;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment