many changes, mostly to export

This commit is contained in:
itsmattkc
2018-06-06 03:30:22 -07:00
parent 81bf111037
commit 0ea7c43e53
26 changed files with 404 additions and 206 deletions
+139 -91
View File
@@ -7,6 +7,8 @@
#include "panels/viewer.h"
#include "ui/viewerwidget.h"
#include "playback/playback.h"
#include "playback/audio.h"
#include "dialogs/exportdialog.h"
extern "C" {
#include <libavcodec/avcodec.h>
@@ -72,17 +74,21 @@ void ExportThread::run() {
AVCodec* vcodec;
AVCodecContext* vcodec_ctx;
AVFrame* video_frame;
AVFrame* sws_frame;
SwsContext* sws_ctx = NULL;
// AVStream* audio_stream;
// AVCodec* acodec;
// AVFrame* audio_frame;
// AVCodecContext* acodec_ctx;
uint8_t* flip_buffer;
AVStream* audio_stream;
AVCodec* acodec;
AVFrame* audio_frame;
AVFrame* swr_frame;
AVCodecContext* acodec_ctx;
AVPacket video_pkt;
// AVPacket audio_pkt;
// SwrContext* swr_ctx = NULL;
AVPacket audio_pkt;
SwrContext* swr_ctx = NULL;
int aframe_bytes;
int ret;
bool fail = false;
fail = false;
if (video_enabled) {
// initialize array contain opengl data
@@ -150,6 +156,13 @@ void ExportThread::run() {
NULL,
NULL
);
sws_frame = av_frame_alloc();
sws_frame->format = AV_PIX_FMT_YUV420P;
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];
}
}
}
@@ -157,80 +170,90 @@ void ExportThread::run() {
}
}
// if (audio_enabled && !fail) {
// audio_stream = avformat_new_stream(fmt_ctx, NULL);
// if (!audio_stream) {
// qDebug() << "[ERROR] Could not allocate output streams";
// fail = true;
// } else {
// acodec = avcodec_find_encoder((enum AVCodecID) audio_codec);
// if (!acodec) {
// qDebug() << "[ERROR] Could not find audio encoder";
// fail = true;
// } else {
// acodec_ctx = avcodec_alloc_context3(acodec);
// if (!acodec_ctx) {
// qDebug() << "[ERROR] Could not find allocate audio encoding context";
// fail = true;
// } else {
// acodec_ctx->sample_rate = audio_sampling_rate;
// acodec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
// acodec_ctx->channels = av_get_channel_layout_nb_channels(acodec_ctx->channel_layout);
// acodec_ctx->sample_fmt = acodec->sample_fmts[0];
// acodec_ctx->time_base = {1, audio_sampling_rate};
// acodec_ctx->bit_rate = audio_bitrate * 1000;
if (audio_enabled && !fail) {
audio_stream = avformat_new_stream(fmt_ctx, NULL);
if (!audio_stream) {
qDebug() << "[ERROR] Could not allocate output streams";
fail = true;
} else {
acodec = avcodec_find_encoder((enum AVCodecID) audio_codec);
if (!acodec) {
qDebug() << "[ERROR] Could not find audio encoder";
fail = true;
} else {
acodec_ctx = avcodec_alloc_context3(acodec);
if (!acodec_ctx) {
qDebug() << "[ERROR] Could not find allocate audio encoding context";
fail = true;
} else {
acodec_ctx->sample_rate = audio_sampling_rate;
acodec_ctx->channel_layout = AV_CH_LAYOUT_STEREO; // change this to support surround/mono sound in the future (this is what the user sets the output audio to)
acodec_ctx->channels = av_get_channel_layout_nb_channels(acodec_ctx->channel_layout);
acodec_ctx->sample_fmt = acodec->sample_fmts[0];
acodec_ctx->time_base = {1, audio_sampling_rate};
acodec_ctx->bit_rate = audio_bitrate * 1000;
// ret = avcodec_open2(acodec_ctx, acodec, NULL);
// if (ret < 0) {
// qDebug() << "[ERROR] Could not open output audio encoder." << ret;
// fail = true;
// } else {
// ret = avcodec_parameters_from_context(audio_stream->codecpar, acodec_ctx);
// if (ret < 0) {
// qDebug() << "[ERROR] Could not copy audio encoder parameters to output stream." << ret;
// fail = true;
// } else {
// if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
// acodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// }
ret = avcodec_open2(acodec_ctx, acodec, NULL);
if (ret < 0) {
qDebug() << "[ERROR] Could not open output audio encoder." << ret;
fail = true;
} else {
ret = avcodec_parameters_from_context(audio_stream->codecpar, acodec_ctx);
if (ret < 0) {
qDebug() << "[ERROR] Could not copy audio encoder parameters to output stream." << ret;
fail = true;
} else {
if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
acodec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
// audio_stream->time_base = acodec_ctx->time_base;
audio_stream->time_base = acodec_ctx->time_base;
// // init audio resampler context
// swr_ctx = swr_alloc_set_opts(
// NULL,
// acodec_ctx->channel_layout,
// acodec_ctx->sample_fmt,
// acodec_ctx->sample_rate,
// sequence->audio_layout,
// AV_SAMPLE_FMT_S16,
// sequence->audio_frequency,
// 0,
// NULL
// );
// swr_init(swr_ctx);
// init audio resampler context
swr_ctx = swr_alloc_set_opts(
NULL,
acodec_ctx->channel_layout,
acodec_ctx->sample_fmt,
acodec_ctx->sample_rate,
sequence->audio_layout,
AV_SAMPLE_FMT_S16,
sequence->audio_frequency,
0,
NULL
);
swr_init(swr_ctx);
// // initialize raw audio frame
// audio_frame = av_frame_alloc();
// audio_frame->nb_samples = acodec_ctx->frame_size;
// if (audio_frame->nb_samples == 0) audio_frame->nb_samples = 2048; // should probably be way smaller?
// audio_frame->format = acodec_ctx->sample_fmt;
// audio_frame->channels = acodec_ctx->channels;
// audio_frame->channel_layout = acodec_ctx->channel_layout;
// ret = av_frame_get_buffer(audio_frame, 0);
// if (ret < 0) {
// qDebug() << "[ERROR] Could not allocate audio buffer." << ret;
// }
// // av_samples_alloc(&audio_frame->data[0], NULL, av_get_channel_layout_nb_channels(audio_frame->channel_layout), audio_frame->nb_samples, acodec_ctx->sample_fmt, 0);
// av_frame_make_writable(audio_frame);
// initialize raw audio frame
audio_frame = av_frame_alloc();
audio_frame->sample_rate = sequence->audio_frequency;
audio_frame->nb_samples = acodec_ctx->frame_size;
if (audio_frame->nb_samples == 0) audio_frame->nb_samples = 2048; // should possibly be smaller?
audio_frame->format = AV_SAMPLE_FMT_S16;
audio_frame->channel_layout = AV_CH_LAYOUT_STEREO; // change this to support surround/mono sound in the future (this is whatever format they're held in the internal buffer)
audio_frame->channels = av_get_channel_layout_nb_channels(audio_frame->channel_layout);
ret = av_frame_get_buffer(audio_frame, 0);
if (ret < 0) {
qDebug() << "[ERROR] Could not allocate audio buffer." << ret;
}
// av_samples_alloc(&audio_frame->data[0], NULL, av_get_channel_layout_nb_channels(audio_frame->channel_layout), audio_frame->nb_samples, acodec_ctx->sample_fmt, 0);
av_frame_make_writable(audio_frame);
aframe_bytes = av_samples_get_buffer_size(NULL, audio_frame->channels, audio_frame->nb_samples, static_cast<AVSampleFormat>(audio_frame->format), 0);
// av_init_packet(&audio_pkt);
// }
// }
// }
// }
// }
// }
// init converted audio frame
swr_frame = av_frame_alloc();
swr_frame->channel_layout = acodec_ctx->channel_layout;
swr_frame->channels = acodec_ctx->channels;
swr_frame->sample_rate = acodec_ctx->sample_rate;
swr_frame->format = acodec_ctx->sample_fmt;
av_frame_make_writable(swr_frame);
av_init_packet(&audio_pkt);
}
}
}
}
}
}
if (!fail) {
av_dump_format(fmt_ctx, 0, c_filename, 1);
@@ -257,14 +280,10 @@ void ExportThread::run() {
fbo.bind();
QOpenGLPaintDevice fbo_dev(video_width, video_height);
QPainter painter(&fbo_dev);
painter.beginNativePainting();
painter.beginNativePainting();
AVFrame* sws_frame = av_frame_alloc();
sws_frame->format = AV_PIX_FMT_YUV420P;
sws_frame->width = video_frame->width;
sws_frame->height = video_frame->height;
av_frame_get_buffer(sws_frame, 0);
uint8_t* flip_buffer = new uint8_t[video_frame->width * video_frame->height * 4];
int written_frame_audio_bytes = 0;
long file_audio_samples = 0;
while (panel_timeline->playhead < end && !fail) {
panel_viewer->viewer_widget->paintGL();
@@ -289,6 +308,27 @@ void ExportThread::run() {
// send to encoder
if (!encode(fmt_ctx, vcodec_ctx, sws_frame, &video_pkt, video_stream)) fail = true;
}
if (audio_enabled && !fail) {
// do we need to encode more audio samples?
if (file_audio_samples <= (timecode_secs*audio_sampling_rate)) {
uint8_t* cache = (reading_audio_cache_A) ? audio_cache_A : audio_cache_B;
int copylen = qMin(aframe_bytes-written_frame_audio_bytes, audio_cache_size-audio_bytes_written);
memcpy(audio_frame->data[0]+written_frame_audio_bytes, cache+audio_bytes_written, copylen);
written_frame_audio_bytes += copylen;
audio_bytes_written += copylen;
if (written_frame_audio_bytes == aframe_bytes) {
// convert to export sample format
swr_convert_frame(swr_ctx, swr_frame, audio_frame);
swr_frame->pts = file_audio_samples;
// send to encoder
if (!encode(fmt_ctx, acodec_ctx, swr_frame, &audio_pkt, audio_stream)) fail = true;
file_audio_samples += swr_frame->nb_samples;
written_frame_audio_bytes = 0;
}
}
}
emit progress_changed(((float) panel_timeline->playhead / (float) end) * 100);
panel_timeline->playhead++;
}
@@ -297,16 +337,14 @@ void ExportThread::run() {
painter.endNativePainting();
fbo.release();
av_frame_free(&sws_frame);
if (!fail) {
// flush remaining packets
if (video_enabled) {
if (!encode(fmt_ctx, vcodec_ctx, NULL, &video_pkt, video_stream)) fail = true;
}
// if (audio_enabled) {
// if (!encode(fmt_ctx, acodec_ctx, NULL, &audio_pkt, audio_stream)) return false;
// }
if (audio_enabled) {
if (!encode(fmt_ctx, acodec_ctx, NULL, &audio_pkt, audio_stream)) fail = true;
}
}
if (!fail) {
@@ -321,16 +359,24 @@ void ExportThread::run() {
}
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);
avcodec_free_context(&acodec_ctx);
avio_closep(&fmt_ctx->pb);
avformat_free_context(fmt_ctx);
// qDebug() << "Render took: %ih %im %is\n", render_time/3600000, render_time/60000, render_time/1000;
if (sws_ctx != NULL) sws_freeContext(sws_ctx);
// if (swr_ctx != NULL) swr_free(&swr_ctx);
if (sws_ctx != NULL) {
sws_freeContext(sws_ctx);
av_frame_free(&sws_frame);
}
if (swr_ctx != NULL) {
swr_free(&swr_ctx);
av_frame_free(&swr_frame);
}
}
}
@@ -339,4 +385,6 @@ void ExportThread::run() {
panel_viewer->viewer_widget->context()->doneCurrent();
panel_viewer->viewer_widget->context()->moveToThread(qApp->thread());
panel_viewer->viewer_widget->multithreaded = true;
panel_viewer->viewer_widget->force_audio = false;
panel_viewer->viewer_widget->enable_paint = true;
}