better audio IO

This commit is contained in:
itsmattkc
2018-06-22 02:32:37 -07:00
parent 72d15b9ed9
commit 26f7b5a15d
15 changed files with 254 additions and 157 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ class ExportDialog;
class ExportThread : public QThread {
Q_OBJECT
public:
void run() override;
void run();
// export parameters
QString filename;
+99 -88
View File
@@ -56,118 +56,129 @@ void PreviewGenerator::run() {
avcodec_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar);
avcodec_open2(codec_ctx[i], codec, NULL);
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
if (codec_ctx[i]->channel_layout == 0) {
codec_ctx[i]->channel_layout = guess_layout_from_channels(fmt_ctx->streams[i]->codecpar->channels);
}
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec_ctx[i]->channel_layout == 0) {
codec_ctx[i]->channel_layout = guess_layout_from_channels(fmt_ctx->streams[i]->codecpar->channels);
}
}
AVPacket packet;
bool done = true;
while (av_read_frame(fmt_ctx, &packet) >= 0) {
MediaStream* s = get_stream_from_file_index(packet.stream_index);
if (s != NULL && !s->preview_done) {
if (avcodec_send_packet(codec_ctx[packet.stream_index], &packet) >= 0) {
if (avcodec_receive_frame(codec_ctx[packet.stream_index], temp_frame) >= 0) {
if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
int dstH = 120;
int dstW = dstH * ((float)temp_frame->width/(float)temp_frame->height);
uint8_t* data = new uint8_t[dstW*dstH*3];
sws_ctx = sws_getContext(
temp_frame->width,
temp_frame->height,
static_cast<AVPixelFormat>(temp_frame->format),
dstW,
dstH,
static_cast<AVPixelFormat>(AV_PIX_FMT_RGB24),
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL
);
bool end_of_file = false;
int linesize[AV_NUM_DATA_POINTERS];
linesize[0] = dstW*3;
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize);
// get the ball rolling
av_read_frame(fmt_ctx, &packet);
avcodec_send_packet(codec_ctx[packet.stream_index], &packet);
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
while (!end_of_file) {
while (avcodec_receive_frame(codec_ctx[packet.stream_index], temp_frame) == AVERROR(EAGAIN)) {
av_packet_unref(&packet);
int read_ret = av_read_frame(fmt_ctx, &packet);
if (read_ret < 0) {
end_of_file = true;
if (read_ret != AVERROR_EOF) qDebug() << "[ERROR] Failed to read packet for preview generation";
break;
} else {
avcodec_send_packet(codec_ctx[packet.stream_index], &packet);
}
}
if (!end_of_file) {
MediaStream* s = get_stream_from_file_index(packet.stream_index);
if (s != NULL && !s->preview_done) {
if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
int dstH = 120;
int dstW = dstH * ((float)temp_frame->width/(float)temp_frame->height);
qDebug() << dstW;
uint8_t* data = new uint8_t[dstW*dstH*3];
sws_ctx = sws_getContext(
temp_frame->width,
temp_frame->height,
static_cast<AVPixelFormat>(temp_frame->format),
dstW,
dstH,
static_cast<AVPixelFormat>(AV_PIX_FMT_RGB24),
SWS_FAST_BILINEAR,
NULL,
NULL,
NULL
);
int linesize[AV_NUM_DATA_POINTERS];
linesize[0] = dstW*3;
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize);
s->video_preview = QImage(data, dstW, dstH, linesize[0], QImage::Format_RGB888);
// delete [] data;
s->preview_done = true;
s->preview_lock.unlock();
s->preview_done = true;
s->preview_lock.unlock();
sws_freeContext(sws_ctx);
} else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4;
sws_freeContext(sws_ctx);
} else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4;
AVFrame* swr_frame = av_frame_alloc();
swr_frame->channel_layout = temp_frame->channel_layout;
swr_frame->sample_rate = temp_frame->sample_rate;
swr_frame->format = AV_SAMPLE_FMT_S16;
AVFrame* swr_frame = av_frame_alloc();
swr_frame->channel_layout = temp_frame->channel_layout;
swr_frame->sample_rate = temp_frame->sample_rate;
swr_frame->format = AV_SAMPLE_FMT_S16;
swr_ctx = swr_alloc_set_opts(
NULL,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(swr_frame->format),
temp_frame->sample_rate,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(temp_frame->format),
temp_frame->sample_rate,
0,
NULL
);
swr_ctx = swr_alloc_set_opts(
NULL,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(swr_frame->format),
temp_frame->sample_rate,
temp_frame->channel_layout,
static_cast<AVSampleFormat>(temp_frame->format),
temp_frame->sample_rate,
0,
NULL
);
swr_init(swr_ctx);
swr_init(swr_ctx);
swr_convert_frame(swr_ctx, swr_frame, temp_frame);
swr_convert_frame(swr_ctx, swr_frame, temp_frame);
int channel_skip = swr_frame->channels * 2;
for (int i=0;i<swr_frame->nb_samples;i+=interval) {
for (int j=0;j<swr_frame->channels;j++) {
qint16 min = 0;
qint16 max = 0;
for (int k=j*2;k<interval;k+=channel_skip) {
qint16 sample = ((swr_frame->data[0][i+k+1] << 8) | swr_frame->data[0][i+k]);
if (sample > max) {
max = sample;
} else if (sample < min) {
min = sample;
}
int channel_skip = swr_frame->channels * 2;
for (int i=0;i<swr_frame->nb_samples;i+=interval) {
for (int j=0;j<swr_frame->channels;j++) {
qint16 min = 0;
qint16 max = 0;
for (int k=j*2;k<interval;k+=channel_skip) {
qint16 sample = ((swr_frame->data[0][i+k+1] << 8) | swr_frame->data[0][i+k]);
if (sample > max) {
max = sample;
} else if (sample < min) {
min = sample;
}
min /= 256;
max /= 256;
s->audio_preview.append(min);
s->audio_preview.append(max);
}
min /= 256;
max /= 256;
s->audio_preview.append(min);
s->audio_preview.append(max);
}
swr_free(&swr_ctx);
av_frame_free(&swr_frame);
}
} else {
qDebug() << "[ERROR] Failed to retrieve frame";
swr_free(&swr_ctx);
av_frame_free(&swr_frame);
}
} else {
qDebug() << "[ERROR] Failed to send packet";
}
}
av_packet_unref(&packet);
// check if we've got all our previews
if (media->audio_tracks.size() == 0) {
done = true;
for (int i=0;i<media->video_tracks.size();i++) {
if (!media->video_tracks.at(i)->preview_done) {
done = false;
break;
// check if we've got all our previews
if (media->audio_tracks.size() == 0) {
done = true;
for (int i=0;i<media->video_tracks.size();i++) {
if (!media->video_tracks.at(i)->preview_done) {
done = false;
break;
}
}
if (done) {
end_of_file = true;
break;
}
}
}
if (done) {
break;
}
av_packet_unref(&packet);
}
}
for (int i=0;i<media->audio_tracks.size();i++) {
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.6.2, 2018-06-21T10:36:29. -->
<!-- Written by QtCreator 4.6.2, 2018-06-22T02:31:47. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
+1 -1
View File
@@ -24,7 +24,7 @@ private slots:
void menu_select(QAction* q);
private:
Ui::EffectControls *ui;
Ui::EffectControls *ui;
Clip* clip;
};
+33 -27
View File
@@ -85,29 +85,33 @@ void Timeline::next_cut() {
long n_cut = LONG_MAX;
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
if (c->timeline_out < n_cut && c->timeline_out > playhead) {
n_cut = c->timeline_out;
seek_enabled = true;
} else if (c->timeline_in < n_cut && c->timeline_in > playhead) {
if (c->timeline_in < n_cut && c->timeline_in > playhead) {
n_cut = c->timeline_in;
seek_enabled = true;
} else if (c->timeline_out < n_cut && c->timeline_out > playhead) {
n_cut = c->timeline_out;
seek_enabled = true;
}
}
if (seek_enabled) seek(n_cut);
}
void Timeline::seek(long p) {
pause();
// reset all clip audio
for (int i=0;i<sequence->clip_count();i++) {
void Timeline::reset_all_audio() {
// reset all clip audio
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i);
c->reset_audio = true;
c->frame_sample_index = 0;
c->audio_buffer_write = 0;
}
}
clear_audio_ibuffer();
audio_ibuffer_read = 0;
}
void Timeline::seek(long p) {
pause();
reset_all_audio();
audio_ibuffer_frame = p;
playhead = p;
@@ -166,23 +170,25 @@ bool Timeline::focused() {
}
void Timeline::undo() {
if (sequence != NULL) {
current_clips.clear();
panel_effect_controls->set_clip(NULL);
sequence->undo();
ui->video_area->redraw_clips();
ui->audio_area->redraw_clips();
}
qDebug() << "[INFO] Undo/redo was so buggy, it's not been disabled. Sorry for any inconvenience";
// if (sequence != NULL) {
// current_clips.clear();
// panel_effect_controls->set_clip(NULL);
// sequence->undo();
// ui->video_area->redraw_clips();
// ui->audio_area->redraw_clips();
// }
}
void Timeline::redo() {
if (sequence != NULL) {
current_clips.clear();
panel_effect_controls->set_clip(NULL);
sequence->redo();
ui->video_area->redraw_clips();
ui->audio_area->redraw_clips();
}
qDebug() << "[INFO] Undo/redo was so buggy, it's not been disabled. Sorry for any inconvenience";
// if (sequence != NULL) {
// current_clips.clear();
// panel_effect_controls->set_clip(NULL);
// sequence->redo();
// ui->video_area->redraw_clips();
// ui->audio_area->redraw_clips();
// }
}
QString frame_to_timecode(long f) {
@@ -213,8 +219,6 @@ void Timeline::repaint_timeline() {
}
void Timeline::redraw_all_clips() {
// add current sequence to the undo stack
sequence->undo_add_current();
project_changed = true;
ui->video_area->redraw_clips();
@@ -222,6 +226,8 @@ void Timeline::redraw_all_clips() {
ui->headers->update();
panel_viewer->ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame()));
reset_all_audio();
}
void Timeline::select_all() {
+1
View File
@@ -162,6 +162,7 @@ private:
void set_tool(int tool);
long last_frame;
QVector<Clip*> clip_clipboard;
void reset_all_audio();
};
#endif // TIMELINE_H
+31 -19
View File
@@ -70,7 +70,7 @@
</property>
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -87,8 +87,8 @@
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable">
@@ -100,7 +100,7 @@
<widget class="QPushButton" name="toolEditButton">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -117,8 +117,8 @@
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable">
@@ -130,7 +130,7 @@
<widget class="QPushButton" name="toolRippleButton">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -147,8 +147,8 @@
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable">
@@ -160,7 +160,7 @@
<widget class="QPushButton" name="toolRollingButton">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -175,6 +175,12 @@
<normaloff>:/icons/rolling.png</normaloff>
<disabledoff>:/icons/rolling-disabled.png</disabledoff>:/icons/rolling.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -184,7 +190,7 @@
<widget class="QPushButton" name="toolRazorButton">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -201,8 +207,8 @@
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable">
@@ -214,7 +220,7 @@
<widget class="QPushButton" name="toolSlipButton">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -230,6 +236,12 @@
<disabledoff>:/icons/slip-disabled.png</disabledoff>
</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -239,7 +251,7 @@
<widget class="QPushButton" name="snappingButton">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -258,7 +270,7 @@
<widget class="QPushButton" name="pushButton_4">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -274,7 +286,7 @@
<widget class="QPushButton" name="pushButton_5">
<property name="maximumSize">
<size>
<width>30</width>
<width>40</width>
<height>16777215</height>
</size>
</property>
@@ -318,8 +330,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>468</width>
<height>309</height>
<width>458</width>
<height>314</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
+11 -1
View File
@@ -15,7 +15,7 @@ bool audio_device_set = false;
qint8 audio_ibuffer[audio_ibuffer_size];
int audio_ibuffer_read = 0;
QVector<int> audio_ibuffer_write;
long audio_ibuffer_frame = 0;
void init_audio() {
if (audio_device_set) {
@@ -51,4 +51,14 @@ void init_audio() {
void clear_audio_ibuffer() {
memset(audio_ibuffer, 0, audio_ibuffer_size);
audio_ibuffer_read = 0;
}
int get_buffer_offset_from_frame(long frame) {
if (frame >= audio_ibuffer_frame) {
return av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(sequence->audio_layout), ((frame-audio_ibuffer_frame)/sequence->frame_rate)*sequence->audio_frequency, AV_SAMPLE_FMT_S16, 1);
} else {
qDebug() << "[WARNING] get_buffer_offset_from_frame called incorrectly";
return 0;
}
}
+2 -1
View File
@@ -14,9 +14,10 @@ extern QIODevice* audio_io_device;
#define audio_ibuffer_size 192000
extern qint8 audio_ibuffer[audio_ibuffer_size];
extern int audio_ibuffer_read;
//extern QVector<int> audio_ibuffer_write;
extern long audio_ibuffer_frame;
void clear_audio_ibuffer();
void init_audio();
int get_buffer_offset_from_frame(long frame);
#endif // AUDIO_H
+46 -7
View File
@@ -23,7 +23,7 @@ void cache_audio_worker(Clip* c) {
// gets one frame worth of audio and sends it to the audio buffer
AVFrame* frame = c->cache_A.frames[0];
if (c->frame_sample_index == 0) {
if (c->need_new_audio_frame) {
// no more audio left in frame, get a new one
if (!c->reached_end) {
retrieve_next_frame_raw_data(c, frame);
@@ -33,6 +33,29 @@ void cache_audio_worker(Clip* c) {
swr_convert_frame(c->swr_ctx, frame, NULL);
}
c->need_new_audio_frame = false;
if (c->audio_just_reset) {
// get precise sample offset for the elected clip_in from this audio frame
float target_sts = 0;
if (c->audio_target_frame < c->timeline_in) {
target_sts = playhead_to_seconds(c, c->clip_in);
} else {
target_sts = playhead_to_seconds(c, c->audio_target_frame);
}
float frame_sts = (frame->pts * av_q2d(c->stream->time_base));
int nb_samples = qRound((target_sts - frame_sts)*c->sequence->audio_frequency);
if (nb_samples == 0) {
c->frame_sample_index = 0;
} else {
c->frame_sample_index = av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(c->sequence->audio_layout), nb_samples, AV_SAMPLE_FMT_S16, 1);
}
qDebug() << target_sts << frame_sts << nb_samples << c->frame_sample_index;
c->audio_just_reset = false;
} else {
c->frame_sample_index = 0;
}
// perform all audio effects
int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1);
for (int j=0;j<c->effects.size();j++) {
@@ -46,22 +69,35 @@ void cache_audio_worker(Clip* c) {
} else {
int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1);
if (c->audio_buffer_write == 0) c->audio_buffer_write = (((int)(audio_ibuffer_read/2))*2) + 1024;
int half_buffer = (audio_ibuffer_size/2);
if (c->audio_buffer_write == 0) {
c->audio_buffer_write = get_buffer_offset_from_frame(qMax(c->timeline_in, c->audio_target_frame));
int offset = audio_ibuffer_read - c->audio_buffer_write;
if (offset > 0) {
c->audio_buffer_write += offset;
c->frame_sample_index += offset;
while (c->frame_sample_index > nb_bytes) {
// get new frame
retrieve_next_frame_raw_data(c, frame);
nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1);
c->frame_sample_index -= nb_bytes;
}
}
}
while (c->frame_sample_index < nb_bytes) {
if (c->audio_buffer_write >= audio_ibuffer_read+half_buffer) {
if (c->audio_buffer_write >= audio_ibuffer_read+half_buffer || c->audio_buffer_write >= get_buffer_offset_from_frame(c->timeline_out)) {
written = max_write;
break;
} else {
audio_ibuffer[c->audio_buffer_write%audio_ibuffer_size] += frame->data[0][c->frame_sample_index];
c->audio_buffer_write++;
c->frame_sample_index++;
written++;
}
}
written += c->frame_sample_index;
if (c->frame_sample_index == nb_bytes) {
c->frame_sample_index = 0;
c->need_new_audio_frame = true;
}
}
}
@@ -120,7 +156,10 @@ void reset_cache(Clip* c, long target_frame) {
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// seek (target_frame represents timeline timecode in frames, not clip timecode)
swr_drop_output(c->swr_ctx, swr_get_out_samples(c->swr_ctx, 0));
av_seek_frame(c->formatCtx, c->media_stream->file_index, playhead_to_seconds(c, target_frame) / timebase, AVSEEK_FLAG_ANY);
av_seek_frame(c->formatCtx, c->media_stream->file_index, playhead_to_seconds(c, target_frame) / timebase, AVSEEK_FLAG_BACKWARD);
c->audio_target_frame = target_frame;
c->need_new_audio_frame = true;
c->audio_just_reset = true;
}
}
}
+1 -1
View File
@@ -272,13 +272,13 @@ void retrieve_next_frame_raw_data(Clip* c, AVFrame* output) {
if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
sws_scale(c->sws_ctx, c->frame->data, c->frame->linesize, 0, c->stream->codecpar->height, output->data, output->linesize);
} else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
output->pts = c->frame->pts;
ret = swr_convert_frame(c->swr_ctx, output, c->frame);
if (ret < 0) {
qDebug() << "[ERROR] Failed to resample audio." << ret;
}
}
} else if (ret == AVERROR_EOF) {
// qDebug() << "reached end triggered" << c->track;
c->reached_end = true;
} else {
qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret;
+20 -2
View File
@@ -39,13 +39,31 @@ Clip* Clip::copy() {
void Clip::init() {
reset();
clip_in = timeline_in = timeline_out = track = undeletable = 0;
clip_in = 0;
timeline_in = 0;
timeline_out = 0;
track = 0;
undeletable = 0;
texture = NULL;
pkt = new AVPacket();
}
void Clip::reset() {
cache_size = cache_A.offset = cache_B.offset = open = pkt_written = cache_A.written = cache_B.written = cache_A.unread = cache_B.unread = reached_end = reset_audio = frame_sample_index = audio_buffer_write = 0;
cache_size = false;
audio_just_reset = false;
cache_A.offset = false;
cache_B.offset = false;
open = false;
pkt_written = false;
cache_A.written = false;
cache_B.written = false;
cache_A.unread = false;
cache_B.unread = false;
reached_end = false;
reset_audio = false;
frame_sample_index = false;
audio_buffer_write = false;
need_new_audio_frame = false;
texture_frame = -1;
formatCtx = NULL;
stream = NULL;
+3
View File
@@ -86,9 +86,12 @@ struct Clip
// audio playback variables
SwrContext* swr_ctx;
bool need_new_audio_frame;
int frame_sample_index;
int audio_buffer_write;
bool reset_audio;
bool audio_just_reset;
long audio_target_frame;
};
#endif // CLIP_H
+4 -7
View File
@@ -794,17 +794,14 @@ void TimelineWidget::redraw_clips() {
clip_painter.drawImage(thumb_rect, clip->media_stream->video_preview);
}
} else {
long length = clip->media->get_length_in_frames(clip->sequence->frame_rate);
int waveform_x = ((float)clip->clip_in/(float)length) * clip->media_stream->audio_preview.size();
int waveform_width = (((float)clip->getLength()/(float)length) * clip->media_stream->audio_preview.size());
int divider = clip->media_stream->audio_channels*2;
int waveform_scaled_length = qFloor((clip->media_stream->audio_preview.size() / (length*panel_timeline->zoom))/divider)*divider;
clip_painter.setPen(QColor(80, 80, 80));
int draw_x = clip_rect.x();
int channel_height = clip_rect.height()/clip->media_stream->audio_channels;
long media_length = clip->media->get_length_in_frames(clip->sequence->frame_rate);
for (int i=0;i<clip_rect.width();i++) {
int waveform_index = qFloor((((float)i / (float)clip_rect.width()) * clip->media_stream->audio_preview.size())/divider)*divider;
int waveform_index = qFloor((((clip->clip_in + ((float) i/panel_timeline->zoom))/media_length) * clip->media_stream->audio_preview.size())/divider)*divider;
for (int j=0;j<clip->media_stream->audio_channels;j++) {
int mid = clip_rect.top()+channel_height*j+(channel_height/2);
int offset = waveform_index+(j*2);
@@ -830,7 +827,7 @@ void TimelineWidget::redraw_clips() {
clip_painter.drawText(text_rect, 0, clip->name, &text_rect);
if (clip->linked.size() > 0) {
int underline_y = CLIP_TEXT_PADDING + clip_painter.fontMetrics().height() + clip_rect.top();
int underline_width = qMin(clip_rect.width() - CLIP_TEXT_PADDING, clip_rect.left() + CLIP_TEXT_PADDING+clip_painter.fontMetrics().width(clip->name));
int underline_width = qMin(clip_rect.left() + clip_rect.width() - CLIP_TEXT_PADDING, clip_rect.left() + CLIP_TEXT_PADDING + clip_painter.fontMetrics().width(clip->name));
clip_painter.drawLine(clip_rect.left() + CLIP_TEXT_PADDING, underline_y, underline_width, underline_y);
}
-1
View File
@@ -114,7 +114,6 @@ void ViewerWidget::paintGL()
}
} else if (render_audio &&
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
playhead >= c->timeline_in &&
c->lock.tryLock()) {
// clip is not caching, start caching audio
c->lock.unlock();