This commit is contained in:
itsmattkc
2018-07-04 12:51:35 +01:00
parent d7a891fdd6
commit 00959ca50a
7 changed files with 181 additions and 167 deletions
+4 -2
View File
@@ -309,6 +309,8 @@ void ExportDialog::on_pushButton_2_clicked()
void ExportDialog::render_thread_finished() {
prep_ui_for_render(false);
panel_viewer->viewer_widget->makeCurrent();
panel_viewer->viewer_widget->initializeGL();
}
void ExportDialog::prep_ui_for_render(bool rendering) {
@@ -422,6 +424,7 @@ void ExportDialog::on_pushButton_clicked()
connect(et, SIGNAL(finished()), this, SLOT(render_thread_finished()));
connect(et, SIGNAL(progress_changed(int)), this, SLOT(update_progress_bar(int)));
panel_viewer->viewer_widget->multithreaded = false;
panel_viewer->viewer_widget->enable_paint = false;
panel_viewer->viewer_widget->context()->doneCurrent();
panel_viewer->viewer_widget->context()->moveToThread(et);
@@ -451,7 +454,6 @@ void ExportDialog::update_progress_bar(int value) {
ui->progressBar->setValue(value);
}
void ExportDialog::on_renderCancel_clicked()
{
void ExportDialog::on_renderCancel_clicked() {
et->fail = true;
}
+30 -33
View File
@@ -26,7 +26,7 @@ extern "C" {
bool encode(AVFormatContext* fmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream) {
int ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
if (ret < 0/* && ret != AVERROR(EAGAIN) && frame != NULL*/) {
qDebug() << "[ERROR] Failed to send frame to encoder." << ret;
return false;
} else {
@@ -47,19 +47,17 @@ bool encode(AVFormatContext* fmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame,
}
void ExportThread::run() {
av_log_set_level(AV_LOG_DEBUG);
panel_timeline->pause();
// av_log_set_level(AV_LOG_DEBUG);
// TODO make customizable
long start = 0;
long end = sequence->getEndFrame();
if (panel_viewer->viewer_widget->context()->makeCurrent(&surface)) {
qDebug() << "make current succeeded";
} else {
qDebug() << "make current failed";
if (!panel_viewer->viewer_widget->context()->makeCurrent(&surface)) {
qDebug() << "[ERROR] Make current failed";
return;
}
panel_viewer->viewer_widget->multithreaded = false;
panel_viewer->viewer_widget->initializeOpenGLFunctions();
AVFormatContext* fmt_ctx = NULL;
QByteArray ba = filename.toLatin1();
@@ -76,8 +74,7 @@ void ExportThread::run() {
AVCodecContext* vcodec_ctx;
AVFrame* video_frame;
AVFrame* sws_frame;
SwsContext* sws_ctx = NULL;
uint8_t* flip_buffer;
SwsContext* sws_ctx = NULL;
AVStream* audio_stream;
AVCodec* acodec;
AVFrame* audio_frame;
@@ -148,7 +145,7 @@ void ExportThread::run() {
sws_ctx = sws_getContext(
video_width,
video_height,
AV_PIX_FMT_RGBA,
AV_PIX_FMT_RGBA,
video_width,
video_height,
AV_PIX_FMT_YUV420P,
@@ -163,7 +160,6 @@ void ExportThread::run() {
sws_frame->width = video_frame->width;
sws_frame->height = video_frame->height;
av_frame_get_buffer(sws_frame, 0);
flip_buffer = new uint8_t[video_frame->width * video_frame->height * 4];
}
}
}
@@ -274,27 +270,21 @@ void ExportThread::run() {
QPainter painter(&fbo_dev);
painter.beginNativePainting();
panel_viewer->viewer_widget->initializeGL();
panel_viewer->viewer_widget->flip = true;
long file_audio_samples = 0;
while (panel_timeline->playhead < end && !fail) {
panel_viewer->viewer_widget->update();
panel_viewer->viewer_widget->paintGL();
double timecode_secs = (double) panel_timeline->playhead / sequence->frame_rate;
if (video_enabled) {
// get image from opengl
glReadPixels(0, 0, video_width, video_height, GL_RGBA, GL_UNSIGNED_BYTE, flip_buffer);
// flip image vertically because opengl sucks ass
int linesize = video_width*4;
for (int i=video_height-1;i>=0;i--) {
int src_index = i*linesize;
int dst_index = (video_height-i)*linesize;
memcpy(video_frame->data[0]+dst_index, flip_buffer+src_index, linesize);
}
// get image from opengl
glReadPixels(0, 0, video_width, video_height, GL_RGBA, GL_UNSIGNED_BYTE, video_frame->data[0]);
// change pixel format
sws_scale(sws_ctx, video_frame->data, video_frame->linesize, 0, video_frame->height, sws_frame->data, sws_frame->linesize);
// qDebug() << video_frame->linesize[0] << sws_frame->linesize[0];
sws_frame->pts = round(timecode_secs/av_q2d(video_stream->time_base));
// send to encoder
@@ -331,7 +321,8 @@ void ExportThread::run() {
panel_timeline->playhead++;
}
delete [] flip_buffer;
panel_viewer->viewer_widget->flip = false;
painter.endNativePainting();
fbo.release();
@@ -365,14 +356,20 @@ void ExportThread::run() {
}
}
avcodec_close(vcodec_ctx);
avcodec_close(acodec_ctx);
av_packet_unref(&video_pkt);
av_packet_unref(&audio_pkt);
av_frame_free(&video_frame);
av_frame_free(&audio_frame);
avcodec_free_context(&vcodec_ctx);
avcodec_free_context(&acodec_ctx);
if (video_enabled) {
avcodec_close(vcodec_ctx);
av_packet_unref(&video_pkt);
av_frame_free(&video_frame);
avcodec_free_context(&vcodec_ctx);
}
if (audio_enabled) {
avcodec_close(acodec_ctx);
av_packet_unref(&audio_pkt);
av_frame_free(&audio_frame);
avcodec_free_context(&acodec_ctx);
}
avio_closep(&fmt_ctx->pb);
avformat_free_context(fmt_ctx);
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.2, 2018-07-03T20:47:05. -->
<!-- Written by QtCreator 4.6.2, 2018-07-04T12:50:34. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
+2 -2
View File
@@ -301,6 +301,8 @@ void open_clip_worker(Clip* clip) {
clip->frame = av_frame_alloc();
clip->finished_opening = true;
qDebug() << "[INFO] Clip opened on track" << clip->track;
}
@@ -360,8 +362,6 @@ void Cacher::run() {
open_clip_worker(clip);
clip->finished_opening = true;
while (caching) {
clip->can_cache.wait(&clip->lock);
if (!caching) {
+16 -10
View File
@@ -25,17 +25,23 @@ extern "C" {
bool texture_failed = false;
void open_clip(Clip* clip, bool multithreaded) {
clip->multithreaded = multithreaded;
if (multithreaded) {
// maybe keep cacher instance in memory while clip exists for performance?
clip->cacher = new Cacher(clip);
QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater()));
if (multithreaded) {
if (clip->open_lock.tryLock()) {
clip->multithreaded = true;
clip->cacher->start(QThread::LowPriority);
} else {
open_clip_worker(clip);
clip->lock.unlock();
}
// maybe keep cacher instance in memory while clip exists for performance?
clip->cacher = new Cacher(clip);
QObject::connect(clip->cacher, SIGNAL(finished()), clip->cacher, SLOT(deleteLater()));
clip->cacher->start(QThread::LowPriority);
}
} else {
clip->multithreaded = false;
clip->finished_opening = false;
clip->open = true;
open_clip_worker(clip);
}
}
void close_clip(Clip* clip) {
+125 -117
View File
@@ -22,6 +22,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : QOpenGLWidget(parent)
multithreaded = true;
enable_paint = true;
force_audio = false;
flip = false;
QSurfaceFormat format;
format.setDepthBufferSize(24);
@@ -56,141 +57,148 @@ void ViewerWidget::paintEvent(QPaintEvent *e) {
void ViewerWidget::paintGL()
{
if (multithreaded) retry_timer.stop();
bool loop = true;
while (loop) {
loop = false;
texture_failed = false;
glClear(GL_COLOR_BUFFER_BIT);
if (multithreaded) retry_timer.stop();
current_clips.clear();
glClear(GL_COLOR_BUFFER_BIT);
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
current_clips.clear();
// if clip starts within one second and/or hasn't finished yet
if (c != NULL) {
if (is_clip_active(c, panel_timeline->playhead)) {
// if thread is already working, we don't want to touch this,
// but we also don't want to hang the UI thread
if (!c->open) {
if (c->open_lock.tryLock()) {
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
// if clip starts within one second and/or hasn't finished yet
if (c != NULL) {
if (is_clip_active(c, panel_timeline->playhead)) {
// if thread is already working, we don't want to touch this,
// but we also don't want to hang the UI thread
if (!c->open) {
open_clip(c, multithreaded);
}
}
bool added = false;
for (int j=0;j<current_clips.size();j++) {
if (current_clips.at(j)->track < c->track) {
current_clips.insert(j, c);
added = true;
break;
}
}
if (!added) {
current_clips.append(c);
}
} else if (c->open) {
close_clip(c);
}
}
}
texture_failed = false;
bool render_audio = (panel_timeline->playing || force_audio);
for (int i=0;i<current_clips.size();i++) {
Clip* c = current_clips.at(i);
if (!c->finished_opening) {
qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed";
texture_failed = true;
} else if (is_clip_active(c, panel_timeline->playhead)) {
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// start preparing cache
get_clip_frame(c, panel_timeline->playhead);
if (c->texture == NULL) {
qDebug() << "[WARNING] Texture hasn't been created yet";
texture_failed = true;
} else if (panel_timeline->playhead >= c->timeline_in) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0, 1.0, 1.0, 1.0);
glLoadIdentity();
int half_width = c->sequence->width/2;
int half_height = c->sequence->height/2;
glOrtho(-half_width, half_width, half_height,- half_height, -1, 1);
int anchor_x = c->media_stream->video_width/2;
int anchor_y = c->media_stream->video_height/2;
// perform all transform effects
for (int j=0;j<c->effects.size();j++) {
c->effects.at(j)->process_gl(&anchor_x, &anchor_y);
}
if (c->opening_transition != NULL) {
int transition_progress = panel_timeline->playhead-c->timeline_in;
if (transition_progress < c->opening_transition->length) {
c->opening_transition->process_transition((float)transition_progress/(float)c->opening_transition->length);
bool added = false;
for (int j=0;j<current_clips.size();j++) {
if (current_clips.at(j)->track < c->track) {
current_clips.insert(j, c);
added = true;
break;
}
}
if (c->closing_transition != NULL) {
int transition_progress = c->closing_transition->length-(panel_timeline->playhead-c->timeline_in-c->getLength()+c->closing_transition->length);
if (transition_progress < c->closing_transition->length) {
c->closing_transition->process_transition((float)transition_progress/(float)c->closing_transition->length);
}
if (!added) {
current_clips.append(c);
}
int anchor_right = c->media_stream->video_width - anchor_x;
int anchor_bottom = c->media_stream->video_height - anchor_y;
c->texture->bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(-anchor_x, -anchor_y);
glTexCoord2f(1.0, 0.0);
glVertex2f(anchor_right, -anchor_y);
glTexCoord2f(1.0, 1.0);
glVertex2f(anchor_right, anchor_bottom);
glTexCoord2f(0.0, 1.0);
glVertex2f(-anchor_x, anchor_bottom);
glEnd();
c->texture->release();
} else if (c->open) {
close_clip(c);
}
} else if (render_audio &&
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
c->lock.tryLock()) {
// clip is not caching, start caching audio
cache_clip(c, panel_timeline->playhead, false, false, c->reset_audio);
c->lock.unlock();
}
}
}
if (panel_timeline->playing) {
int adjusted_read_index = audio_ibuffer_read%audio_ibuffer_size;
int max_write = audio_ibuffer_size - adjusted_read_index;
int actual_write = audio_io_device->write((const char*) audio_ibuffer+adjusted_read_index, max_write);
memset(audio_ibuffer+adjusted_read_index, 0, actual_write);
audio_ibuffer_read += actual_write;
if (actual_write == max_write) {
// got all the bytes, write again
actual_write = audio_io_device->write((const char*) audio_ibuffer, audio_ibuffer_size);
memset(audio_ibuffer, 0, actual_write);
bool render_audio = (panel_timeline->playing || force_audio);
for (int i=0;i<current_clips.size();i++) {
Clip* c = current_clips.at(i);
if (!c->finished_opening) {
qDebug() << "[WARNING] Tried to display clip" << i << "but it's closed";
texture_failed = true;
} else if (is_clip_active(c, panel_timeline->playhead)) {
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// start preparing cache
get_clip_frame(c, panel_timeline->playhead);
if (c->texture == NULL) {
qDebug() << "[WARNING] Texture hasn't been created yet";
texture_failed = true;
} else if (panel_timeline->playhead >= c->timeline_in) {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0, 1.0, 1.0, 1.0);
glLoadIdentity();
int half_width = c->sequence->width/2;
int half_height = c->sequence->height/2;
if (flip) {
glOrtho(-half_width, half_width, -half_height, half_height, -1, 1);
} else {
glOrtho(-half_width, half_width, half_height, -half_height, -1, 1);
}
int anchor_x = c->media_stream->video_width/2;
int anchor_y = c->media_stream->video_height/2;
// perform all transform effects
for (int j=0;j<c->effects.size();j++) {
c->effects.at(j)->process_gl(&anchor_x, &anchor_y);
}
if (c->opening_transition != NULL) {
int transition_progress = panel_timeline->playhead-c->timeline_in;
if (transition_progress < c->opening_transition->length) {
c->opening_transition->process_transition((float)transition_progress/(float)c->opening_transition->length);
}
}
if (c->closing_transition != NULL) {
int transition_progress = c->closing_transition->length-(panel_timeline->playhead-c->timeline_in-c->getLength()+c->closing_transition->length);
if (transition_progress < c->closing_transition->length) {
c->closing_transition->process_transition((float)transition_progress/(float)c->closing_transition->length);
}
}
int anchor_right = c->media_stream->video_width - anchor_x;
int anchor_bottom = c->media_stream->video_height - anchor_y;
c->texture->bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(-anchor_x, -anchor_y);
glTexCoord2f(1.0, 0.0);
glVertex2f(anchor_right, -anchor_y);
glTexCoord2f(1.0, 1.0);
glVertex2f(anchor_right, anchor_bottom);
glTexCoord2f(0.0, 1.0);
glVertex2f(-anchor_x, anchor_bottom);
glEnd();
c->texture->release();
}
} else if (render_audio &&
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
c->lock.tryLock()) {
// clip is not caching, start caching audio
cache_clip(c, panel_timeline->playhead, false, false, c->reset_audio);
c->lock.unlock();
}
}
}
if (panel_timeline->playing) {
int adjusted_read_index = audio_ibuffer_read%audio_ibuffer_size;
int max_write = audio_ibuffer_size - adjusted_read_index;
int actual_write = audio_io_device->write((const char*) audio_ibuffer+adjusted_read_index, max_write);
memset(audio_ibuffer+adjusted_read_index, 0, actual_write);
audio_ibuffer_read += actual_write;
if (actual_write == max_write) {
// got all the bytes, write again
actual_write = audio_io_device->write((const char*) audio_ibuffer, audio_ibuffer_size);
memset(audio_ibuffer, 0, actual_write);
audio_ibuffer_read += actual_write;
}
}
}
/*QPainter p(this);
p.drawText({0, 0, 200, 200}, "text!");
p.end();*/
/*QPainter p(this);
p.drawText({0, 0, 200, 200}, "text!");
p.end();*/
if (texture_failed) {
if (multithreaded) {
retry_timer.start();
} else {
paintGL();
if (texture_failed) {
if (multithreaded) {
retry_timer.start();
} else {
qDebug() << "[INFO] Texture failed - looping";
loop = true;
}
}
}
}
+3 -2
View File
@@ -19,11 +19,12 @@ public:
bool multithreaded;
bool force_audio;
bool enable_paint;
bool flip;
void paintGL();
void initializeGL();
protected:
void paintEvent(QPaintEvent *e);
void initializeGL();
// void resizeGL(int w, int h);
void paintGL();
private:
QTimer retry_timer;
QVector<Clip*> current_clips;