ffmpegdecoder: if data is less than duration, fill remainder with 0s

Fixes bug where random/uninitialzed audio values may appear in some
circumstances.

Also switches swr_convert_frame to swr_convert for a small
optimization/improvement, no need to use AVFrame struct when we're only
interested in samples.
This commit is contained in:
itsmattkc
2020-03-18 19:05:02 +11:00
parent 79bc9594b9
commit d4d969872f
+54 -35
View File
@@ -440,9 +440,13 @@ FramePtr FFmpegDecoder::RetrieveAudio(const rational &timecode, const rational &
audio_frame->set_sample_count(input_params.time_to_samples(length));
audio_frame->allocate();
input.read(input_params.time_to_bytes(timecode),
audio_frame->data(),
audio_frame->allocated_size());
qint64 actual_read = input.read(input_params.time_to_bytes(timecode),
audio_frame->data(),
audio_frame->allocated_size());
if (actual_read < audio_frame->allocated_size()) {
memset(audio_frame->data() + actual_read, 0, audio_frame->allocated_size() - actual_read);
}
input.close();
@@ -725,6 +729,8 @@ void FFmpegDecoder::UnconditionalAudioIndex(const QAtomicInt* cancelled)
avstream_->codecpar->sample_rate,
0,
nullptr);
swr_init(resampler);
} else {
dst_sample_fmt = src_sample_fmt;
}
@@ -739,6 +745,8 @@ void FFmpegDecoder::UnconditionalAudioIndex(const QAtomicInt* cancelled)
int ret;
if (wave_out.open()) {
bool success = false;
while (true) {
// Check if we have a `cancelled` ptr and its value
if (cancelled && *cancelled) {
@@ -748,45 +756,56 @@ void FFmpegDecoder::UnconditionalAudioIndex(const QAtomicInt* cancelled)
ret = GetFrame(pkt, frame);
if (ret < 0) {
break;
} else {
AVFrame* data_frame;
if (resampler != nullptr) {
// We must need to resample this (mainly just convert from planar to packed if necessary)
data_frame = av_frame_alloc();
data_frame->sample_rate = frame->sample_rate;
data_frame->channel_layout = frame->channel_layout;
data_frame->channels = frame->channels;
data_frame->format = dst_sample_fmt;
av_frame_make_writable(data_frame);
ret = swr_convert_frame(resampler, data_frame, frame);
if (ret != 0) {
char err_str[50];
av_strerror(ret, err_str, 50);
qWarning() << "libswresample failed with error:" << ret << err_str;
}
if (ret == AVERROR_EOF) {
success = true;
} else {
char err_str[50];
av_strerror(ret, err_str, 50);
qWarning() << "Failed to index:" << ret << err_str;
}
break;
} else {
char* data;
int nb_samples;
if (resampler) {
nb_samples = swr_get_out_samples(resampler, frame->nb_samples);
data = new char[wave_params.samples_to_bytes(nb_samples)];
// We must need to resample this (mainly just convert from planar to packed if necessary)
nb_samples = swr_convert(resampler,
reinterpret_cast<uint8_t**>(&data),
nb_samples,
const_cast<const uint8_t**>(frame->data),
frame->nb_samples);
if (nb_samples < 0) {
char err_str[50];
av_strerror(nb_samples, err_str, 50);
qWarning() << "libswresample failed with error:" << nb_samples << err_str;
break;
}
} else {
// No resampling required, we can write directly from te frame buffer
data_frame = frame;
data = reinterpret_cast<char*>(frame->data[0]);
nb_samples = frame->nb_samples;
}
int buffer_sz = av_samples_get_buffer_size(nullptr,
avstream_->codecpar->channels,
data_frame->nb_samples,
dst_sample_fmt,
0); // FIXME: Documentation unclear - should this be 0 or 1?
// Write packed WAV data to the disk cache
wave_out.write(reinterpret_cast<char*>(data_frame->data[0]), buffer_sz);
wave_out.write(data, wave_params.samples_to_bytes(nb_samples));
audio_stream->set_index_length(wave_params.bytes_to_time(wave_out.data_length()));
// If we allocated an output for the resampler, delete it here
if (data_frame != frame) {
av_frame_free(&data_frame);
if (data != reinterpret_cast<char*>(frame->data[0])) {
delete [] data;
}
SignalIndexProgress(frame->pts);
@@ -795,12 +814,12 @@ void FFmpegDecoder::UnconditionalAudioIndex(const QAtomicInt* cancelled)
wave_out.close();
if (cancelled && *cancelled) {
if (success) {
audio_stream->set_index_done(true);
} else {
// Audio index didn't complete, delete it
QFile(GetIndexFilename()).remove();
audio_stream->clear_index();
} else {
audio_stream->set_index_done(true);
}
} else {
qWarning() << "Failed to open WAVE output for indexing";