import: safely handle unsupported files

Fixes #1191
This commit is contained in:
itsmattkc
2020-09-18 12:58:55 +10:00
parent e733d1c278
commit 8506c82a0c
7 changed files with 148 additions and 8 deletions
+28 -6
View File
@@ -477,14 +477,19 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
// Retrieve metadata about the media // Retrieve metadata about the media
avformat_find_stream_info(fmt_ctx, nullptr); avformat_find_stream_info(fmt_ctx, nullptr);
QVector<StreamPtr> streams(fmt_ctx->nb_streams);
// Dump it into the Footage object // Dump it into the Footage object
for (unsigned int i=0;i<fmt_ctx->nb_streams;i++) { for (unsigned int i=0;i<fmt_ctx->nb_streams;i++) {
AVStream* avstream = fmt_ctx->streams[i]; AVStream* avstream = fmt_ctx->streams[i];
// Find decoder for this stream, if it exists we can proceed
AVCodec* decoder = avcodec_find_decoder(avstream->codecpar->codec_id);
StreamPtr str; StreamPtr str;
if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (avstream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && decoder) {
bool image_is_still = false; bool image_is_still = false;
rational pixel_aspect_ratio; rational pixel_aspect_ratio;
@@ -564,7 +569,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
str = image_stream; str = image_stream;
} else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && decoder) {
// Create an audio stream object // Create an audio stream object
AudioStreamPtr audio_stream = std::make_shared<AudioStream>(); AudioStreamPtr audio_stream = std::make_shared<AudioStream>();
@@ -600,7 +605,7 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
str->set_type(Stream::kAttachment); str->set_type(Stream::kAttachment);
break; break;
default: default:
// We should never realistically get here, but we make an "invalid" stream just in case // Fallback to an unknown stream
str->set_type(Stream::kUnknown); str->set_type(Stream::kUnknown);
break; break;
} }
@@ -611,11 +616,27 @@ bool FFmpegDecoder::Probe(Footage *f, const QAtomicInt* cancelled)
str->set_timebase(avstream->time_base); str->set_timebase(avstream->time_base);
str->set_duration(avstream->duration); str->set_duration(avstream->duration);
f->add_stream(str); streams[i] = str;
} }
// As long as we can open the container and retrieve information, this was a successful probe // Check if we could pick up any streams in this file
result = true; bool found_valid_streams = false;
foreach (StreamPtr stream, streams) {
if (stream->type() != Stream::kUnknown) {
found_valid_streams = true;
break;
}
}
if (found_valid_streams) {
// Copy streams over
foreach (StreamPtr stream, streams) {
f->add_stream(stream);
}
result = true;
}
} }
// Free all memory // Free all memory
@@ -1330,6 +1351,7 @@ void FFmpegDecoderInstance::RemoveFirstFrame()
FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_index) : FFmpegDecoderInstance::FFmpegDecoderInstance(const char *filename, int stream_index) :
fmt_ctx_(nullptr), fmt_ctx_(nullptr),
codec_ctx_(nullptr),
opts_(nullptr), opts_(nullptr),
scale_ctx_(nullptr), scale_ctx_(nullptr),
scale_divider_(0), scale_divider_(0),
+9 -1
View File
@@ -51,6 +51,7 @@
#include "render/pixelformat.h" #include "render/pixelformat.h"
#include "render/shaderinfo.h" #include "render/shaderinfo.h"
#include "task/project/import/import.h" #include "task/project/import/import.h"
#include "task/project/import/importerrordialog.h"
#include "task/project/load/load.h" #include "task/project/load/load.h"
#include "task/project/save/save.h" #include "task/project/save/save.h"
#include "task/taskmanager.h" #include "task/taskmanager.h"
@@ -473,7 +474,14 @@ void Core::AddOpenProjectFromTask(Task *task)
void Core::ImportTaskComplete(Task* task) void Core::ImportTaskComplete(Task* task)
{ {
QUndoCommand *command = static_cast<ProjectImportTask*>(task)->GetCommand(); ProjectImportTask* import_task = static_cast<ProjectImportTask*>(task);
QUndoCommand *command = import_task->GetCommand();
if (import_task->HasInvalidFiles()) {
ProjectImportErrorDialog d(import_task->GetInvalidFiles(), main_window_);
d.exec();
}
undo_stack_.pushIfHasChildren(command); undo_stack_.pushIfHasChildren(command);
} }
+2
View File
@@ -18,5 +18,7 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES} ${OLIVE_SOURCES}
task/project/import/import.h task/project/import/import.h
task/project/import/import.cpp task/project/import/import.cpp
task/project/import/importerrordialog.h
task/project/import/importerrordialog.cpp
PARENT_SCOPE PARENT_SCOPE
) )
+4 -1
View File
@@ -122,7 +122,10 @@ void ProjectImportTask::Import(Folder *folder, const QFileInfoList &import, int
f->set_project(nullptr); f->set_project(nullptr);
if (f->status() != Footage::kInvalid) { if (f->status() == Footage::kInvalid) {
// Add to list so we can tell the user about it later
invalid_files_.append(file_info.absoluteFilePath());
} else {
// Create undoable command that adds the items to the model // Create undoable command that adds the items to the model
new ProjectViewModel::AddItemCommand(model_, new ProjectViewModel::AddItemCommand(model_,
folder, folder,
+12
View File
@@ -42,6 +42,16 @@ public:
return command_; return command_;
} }
const QStringList& GetInvalidFiles() const
{
return invalid_files_;
}
bool HasInvalidFiles() const
{
return !invalid_files_.isEmpty();
}
protected: protected:
virtual bool Run() override; virtual bool Run() override;
@@ -58,6 +68,8 @@ private:
int file_count_; int file_count_;
QStringList invalid_files_;
}; };
OLIVE_NAMESPACE_EXIT OLIVE_NAMESPACE_EXIT
@@ -0,0 +1,53 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "importerrordialog.h"
#include <QDialogButtonBox>
#include <QLabel>
#include <QListWidget>
#include <QVBoxLayout>
OLIVE_NAMESPACE_ENTER
ProjectImportErrorDialog::ProjectImportErrorDialog(const QStringList& filenames, QWidget* parent) :
QDialog(parent)
{
QVBoxLayout* layout = new QVBoxLayout(this);
setWindowTitle(tr("Import Error"));
layout->addWidget(new QLabel(tr("The following files failed to import. Olive likely does not "
"support their formats.")));
QListWidget* list_widget = new QListWidget();
foreach (const QString& s, filenames) {
list_widget->addItem(s);
}
layout->addWidget(list_widget);
QDialogButtonBox* buttons = new QDialogButtonBox();
buttons->setStandardButtons(QDialogButtonBox::Ok);
buttons->setCenterButtons(true);
connect(buttons, &QDialogButtonBox::accepted, this, &ProjectImportErrorDialog::accept);
layout->addWidget(buttons);
}
OLIVE_NAMESPACE_EXIT
@@ -0,0 +1,40 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef PROJECTIMPORTERRORDIALOG_H
#define PROJECTIMPORTERRORDIALOG_H
#include <QDialog>
#include "common/define.h"
OLIVE_NAMESPACE_ENTER
class ProjectImportErrorDialog : public QDialog
{
Q_OBJECT
public:
ProjectImportErrorDialog(const QStringList& filenames, QWidget* parent = nullptr);
};
OLIVE_NAMESPACE_EXIT
#endif // PROJECTIMPORTERRORDIALOG_H