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 { class ExportThread : public QThread {
Q_OBJECT Q_OBJECT
public: public:
void run() override; void run();
// export parameters // export parameters
QString filename; 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_parameters_to_context(codec_ctx[i], fmt_ctx->streams[i]->codecpar);
avcodec_open2(codec_ctx[i], codec, NULL); avcodec_open2(codec_ctx[i], codec, NULL);
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec_ctx[i]->channel_layout == 0) {
if (codec_ctx[i]->channel_layout == 0) { codec_ctx[i]->channel_layout = guess_layout_from_channels(fmt_ctx->streams[i]->codecpar->channels);
codec_ctx[i]->channel_layout = guess_layout_from_channels(fmt_ctx->streams[i]->codecpar->channels);
}
} }
} }
AVPacket packet; AVPacket packet;
bool done = true; 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( bool end_of_file = false;
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]; // get the ball rolling
linesize[0] = dstW*3; av_read_frame(fmt_ctx, &packet);
sws_scale(sws_ctx, temp_frame->data, temp_frame->linesize, 0, temp_frame->height, &data, linesize); 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; // delete [] data;
s->preview_done = true; s->preview_done = true;
s->preview_lock.unlock(); s->preview_lock.unlock();
sws_freeContext(sws_ctx); sws_freeContext(sws_ctx);
} else if (fmt_ctx->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { } 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; int interval = qFloor((temp_frame->sample_rate/WAVEFORM_RESOLUTION)/4)*4;
AVFrame* swr_frame = av_frame_alloc(); AVFrame* swr_frame = av_frame_alloc();
swr_frame->channel_layout = temp_frame->channel_layout; swr_frame->channel_layout = temp_frame->channel_layout;
swr_frame->sample_rate = temp_frame->sample_rate; swr_frame->sample_rate = temp_frame->sample_rate;
swr_frame->format = AV_SAMPLE_FMT_S16; swr_frame->format = AV_SAMPLE_FMT_S16;
swr_ctx = swr_alloc_set_opts( swr_ctx = swr_alloc_set_opts(
NULL, NULL,
temp_frame->channel_layout, temp_frame->channel_layout,
static_cast<AVSampleFormat>(swr_frame->format), static_cast<AVSampleFormat>(swr_frame->format),
temp_frame->sample_rate, temp_frame->sample_rate,
temp_frame->channel_layout, temp_frame->channel_layout,
static_cast<AVSampleFormat>(temp_frame->format), static_cast<AVSampleFormat>(temp_frame->format),
temp_frame->sample_rate, temp_frame->sample_rate,
0, 0,
NULL 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; int channel_skip = swr_frame->channels * 2;
for (int i=0;i<swr_frame->nb_samples;i+=interval) { for (int i=0;i<swr_frame->nb_samples;i+=interval) {
for (int j=0;j<swr_frame->channels;j++) { for (int j=0;j<swr_frame->channels;j++) {
qint16 min = 0; qint16 min = 0;
qint16 max = 0; qint16 max = 0;
for (int k=j*2;k<interval;k+=channel_skip) { 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]); qint16 sample = ((swr_frame->data[0][i+k+1] << 8) | swr_frame->data[0][i+k]);
if (sample > max) { if (sample > max) {
max = sample; max = sample;
} else if (sample < min) { } else if (sample < min) {
min = sample; 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) {
// check if we've got all our previews done = true;
if (media->audio_tracks.size() == 0) { for (int i=0;i<media->video_tracks.size();i++) {
done = true; if (!media->video_tracks.at(i)->preview_done) {
for (int i=0;i<media->video_tracks.size();i++) { done = false;
if (!media->video_tracks.at(i)->preview_done) { break;
done = false; }
break; }
if (done) {
end_of_file = true;
break;
}
} }
} }
if (done) { av_packet_unref(&packet);
break;
}
} }
} }
for (int i=0;i<media->audio_tracks.size();i++) { 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"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!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> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
+1 -1
View File
@@ -24,7 +24,7 @@ private slots:
void menu_select(QAction* q); void menu_select(QAction* q);
private: private:
Ui::EffectControls *ui; Ui::EffectControls *ui;
Clip* clip; Clip* clip;
}; };
+33 -27
View File
@@ -85,29 +85,33 @@ void Timeline::next_cut() {
long n_cut = LONG_MAX; long n_cut = LONG_MAX;
for (int i=0;i<sequence->clip_count();i++) { for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i); Clip* c = sequence->get_clip(i);
if (c->timeline_out < n_cut && c->timeline_out > playhead) { if (c->timeline_in < n_cut && c->timeline_in > playhead) {
n_cut = c->timeline_out;
seek_enabled = true;
} else if (c->timeline_in < n_cut && c->timeline_in > playhead) {
n_cut = c->timeline_in; n_cut = c->timeline_in;
seek_enabled = true; 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); if (seek_enabled) seek(n_cut);
} }
void Timeline::seek(long p) { void Timeline::reset_all_audio() {
pause(); // reset all clip audio
for (int i=0;i<sequence->clip_count();i++) {
// reset all clip audio
for (int i=0;i<sequence->clip_count();i++) {
Clip* c = sequence->get_clip(i); Clip* c = sequence->get_clip(i);
c->reset_audio = true; c->reset_audio = true;
c->frame_sample_index = 0; c->frame_sample_index = 0;
c->audio_buffer_write = 0; c->audio_buffer_write = 0;
} }
clear_audio_ibuffer(); clear_audio_ibuffer();
audio_ibuffer_read = 0; }
void Timeline::seek(long p) {
pause();
reset_all_audio();
audio_ibuffer_frame = p;
playhead = p; playhead = p;
@@ -166,23 +170,25 @@ bool Timeline::focused() {
} }
void Timeline::undo() { void Timeline::undo() {
if (sequence != NULL) { qDebug() << "[INFO] Undo/redo was so buggy, it's not been disabled. Sorry for any inconvenience";
current_clips.clear(); // if (sequence != NULL) {
panel_effect_controls->set_clip(NULL); // current_clips.clear();
sequence->undo(); // panel_effect_controls->set_clip(NULL);
ui->video_area->redraw_clips(); // sequence->undo();
ui->audio_area->redraw_clips(); // ui->video_area->redraw_clips();
} // ui->audio_area->redraw_clips();
// }
} }
void Timeline::redo() { void Timeline::redo() {
if (sequence != NULL) { qDebug() << "[INFO] Undo/redo was so buggy, it's not been disabled. Sorry for any inconvenience";
current_clips.clear(); // if (sequence != NULL) {
panel_effect_controls->set_clip(NULL); // current_clips.clear();
sequence->redo(); // panel_effect_controls->set_clip(NULL);
ui->video_area->redraw_clips(); // sequence->redo();
ui->audio_area->redraw_clips(); // ui->video_area->redraw_clips();
} // ui->audio_area->redraw_clips();
// }
} }
QString frame_to_timecode(long f) { QString frame_to_timecode(long f) {
@@ -213,8 +219,6 @@ void Timeline::repaint_timeline() {
} }
void Timeline::redraw_all_clips() { void Timeline::redraw_all_clips() {
// add current sequence to the undo stack
sequence->undo_add_current();
project_changed = true; project_changed = true;
ui->video_area->redraw_clips(); ui->video_area->redraw_clips();
@@ -222,6 +226,8 @@ void Timeline::redraw_all_clips() {
ui->headers->update(); ui->headers->update();
panel_viewer->ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame())); panel_viewer->ui->endTimecode->setText(frame_to_timecode(sequence->getEndFrame()));
reset_all_audio();
} }
void Timeline::select_all() { void Timeline::select_all() {
+1
View File
@@ -162,6 +162,7 @@ private:
void set_tool(int tool); void set_tool(int tool);
long last_frame; long last_frame;
QVector<Clip*> clip_clipboard; QVector<Clip*> clip_clipboard;
void reset_all_audio();
}; };
#endif // TIMELINE_H #endif // TIMELINE_H
+31 -19
View File
@@ -70,7 +70,7 @@
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -87,8 +87,8 @@
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
<width>16</width> <width>20</width>
<height>16</height> <height>20</height>
</size> </size>
</property> </property>
<property name="checkable"> <property name="checkable">
@@ -100,7 +100,7 @@
<widget class="QPushButton" name="toolEditButton"> <widget class="QPushButton" name="toolEditButton">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -117,8 +117,8 @@
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
<width>16</width> <width>20</width>
<height>16</height> <height>20</height>
</size> </size>
</property> </property>
<property name="checkable"> <property name="checkable">
@@ -130,7 +130,7 @@
<widget class="QPushButton" name="toolRippleButton"> <widget class="QPushButton" name="toolRippleButton">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -147,8 +147,8 @@
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
<width>16</width> <width>20</width>
<height>16</height> <height>20</height>
</size> </size>
</property> </property>
<property name="checkable"> <property name="checkable">
@@ -160,7 +160,7 @@
<widget class="QPushButton" name="toolRollingButton"> <widget class="QPushButton" name="toolRollingButton">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -175,6 +175,12 @@
<normaloff>:/icons/rolling.png</normaloff> <normaloff>:/icons/rolling.png</normaloff>
<disabledoff>:/icons/rolling-disabled.png</disabledoff>:/icons/rolling.png</iconset> <disabledoff>:/icons/rolling-disabled.png</disabledoff>:/icons/rolling.png</iconset>
</property> </property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -184,7 +190,7 @@
<widget class="QPushButton" name="toolRazorButton"> <widget class="QPushButton" name="toolRazorButton">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -201,8 +207,8 @@
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
<width>16</width> <width>20</width>
<height>16</height> <height>20</height>
</size> </size>
</property> </property>
<property name="checkable"> <property name="checkable">
@@ -214,7 +220,7 @@
<widget class="QPushButton" name="toolSlipButton"> <widget class="QPushButton" name="toolSlipButton">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -230,6 +236,12 @@
<disabledoff>:/icons/slip-disabled.png</disabledoff> <disabledoff>:/icons/slip-disabled.png</disabledoff>
</iconset> </iconset>
</property> </property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -239,7 +251,7 @@
<widget class="QPushButton" name="snappingButton"> <widget class="QPushButton" name="snappingButton">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -258,7 +270,7 @@
<widget class="QPushButton" name="pushButton_4"> <widget class="QPushButton" name="pushButton_4">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -274,7 +286,7 @@
<widget class="QPushButton" name="pushButton_5"> <widget class="QPushButton" name="pushButton_5">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>30</width> <width>40</width>
<height>16777215</height> <height>16777215</height>
</size> </size>
</property> </property>
@@ -318,8 +330,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>468</width> <width>458</width>
<height>309</height> <height>314</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
+11 -1
View File
@@ -15,7 +15,7 @@ bool audio_device_set = false;
qint8 audio_ibuffer[audio_ibuffer_size]; qint8 audio_ibuffer[audio_ibuffer_size];
int audio_ibuffer_read = 0; int audio_ibuffer_read = 0;
QVector<int> audio_ibuffer_write; long audio_ibuffer_frame = 0;
void init_audio() { void init_audio() {
if (audio_device_set) { if (audio_device_set) {
@@ -51,4 +51,14 @@ void init_audio() {
void clear_audio_ibuffer() { void clear_audio_ibuffer() {
memset(audio_ibuffer, 0, audio_ibuffer_size); 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 #define audio_ibuffer_size 192000
extern qint8 audio_ibuffer[audio_ibuffer_size]; extern qint8 audio_ibuffer[audio_ibuffer_size];
extern int audio_ibuffer_read; extern int audio_ibuffer_read;
//extern QVector<int> audio_ibuffer_write; extern long audio_ibuffer_frame;
void clear_audio_ibuffer(); void clear_audio_ibuffer();
void init_audio(); void init_audio();
int get_buffer_offset_from_frame(long frame);
#endif // AUDIO_H #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 // gets one frame worth of audio and sends it to the audio buffer
AVFrame* frame = c->cache_A.frames[0]; 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 // no more audio left in frame, get a new one
if (!c->reached_end) { if (!c->reached_end) {
retrieve_next_frame_raw_data(c, frame); 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); 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 // perform all audio effects
int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1); 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++) { for (int j=0;j<c->effects.size();j++) {
@@ -46,22 +69,35 @@ void cache_audio_worker(Clip* c) {
} else { } else {
int nb_bytes = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, static_cast<AVSampleFormat>(frame->format), 1); 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); 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) { 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; written = max_write;
break; break;
} else { } else {
audio_ibuffer[c->audio_buffer_write%audio_ibuffer_size] += frame->data[0][c->frame_sample_index]; audio_ibuffer[c->audio_buffer_write%audio_ibuffer_size] += frame->data[0][c->frame_sample_index];
c->audio_buffer_write++; c->audio_buffer_write++;
c->frame_sample_index++; c->frame_sample_index++;
written++;
} }
} }
written += c->frame_sample_index;
if (c->frame_sample_index == nb_bytes) { 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) { } else if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// seek (target_frame represents timeline timecode in frames, not clip timecode) // 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)); 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) { 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); 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) { } 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); ret = swr_convert_frame(c->swr_ctx, output, c->frame);
if (ret < 0) { if (ret < 0) {
qDebug() << "[ERROR] Failed to resample audio." << ret; qDebug() << "[ERROR] Failed to resample audio." << ret;
} }
} }
} else if (ret == AVERROR_EOF) { } else if (ret == AVERROR_EOF) {
// qDebug() << "reached end triggered" << c->track;
c->reached_end = true; c->reached_end = true;
} else { } else {
qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret; qDebug() << "[WARNING] Raw frame data could not be retrieved." << ret;
+20 -2
View File
@@ -39,13 +39,31 @@ Clip* Clip::copy() {
void Clip::init() { void Clip::init() {
reset(); 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; texture = NULL;
pkt = new AVPacket(); pkt = new AVPacket();
} }
void Clip::reset() { 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; texture_frame = -1;
formatCtx = NULL; formatCtx = NULL;
stream = NULL; stream = NULL;
+3
View File
@@ -86,9 +86,12 @@ struct Clip
// audio playback variables // audio playback variables
SwrContext* swr_ctx; SwrContext* swr_ctx;
bool need_new_audio_frame;
int frame_sample_index; int frame_sample_index;
int audio_buffer_write; int audio_buffer_write;
bool reset_audio; bool reset_audio;
bool audio_just_reset;
long audio_target_frame;
}; };
#endif // CLIP_H #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); clip_painter.drawImage(thumb_rect, clip->media_stream->video_preview);
} }
} else { } 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 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)); clip_painter.setPen(QColor(80, 80, 80));
int draw_x = clip_rect.x();
int channel_height = clip_rect.height()/clip->media_stream->audio_channels; 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++) { 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++) { for (int j=0;j<clip->media_stream->audio_channels;j++) {
int mid = clip_rect.top()+channel_height*j+(channel_height/2); int mid = clip_rect.top()+channel_height*j+(channel_height/2);
int offset = waveform_index+(j*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); clip_painter.drawText(text_rect, 0, clip->name, &text_rect);
if (clip->linked.size() > 0) { if (clip->linked.size() > 0) {
int underline_y = CLIP_TEXT_PADDING + clip_painter.fontMetrics().height() + clip_rect.top(); 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); 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 && } else if (render_audio &&
c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
playhead >= c->timeline_in &&
c->lock.tryLock()) { c->lock.tryLock()) {
// clip is not caching, start caching audio // clip is not caching, start caching audio
c->lock.unlock(); c->lock.unlock();