added probe on import functionality

This commit is contained in:
itsmattkc
2019-06-27 08:51:44 -07:00
parent d133ee9832
commit 955f80c622
14 changed files with 231 additions and 33 deletions
+27
View File
@@ -37,6 +37,33 @@ public:
Stream* stream();
void set_stream(Stream* fs);
/**
* @brief Probe a footage file and dump metadata about it
*
* When a Footage file is imported, we'll need to know whether Olive is equipped with a decoder for utilizing it
* and metadata should be retrieved about it if so. For this purpose, the Footage object is passed through all
* Probe() functions of available deocders until one returns TRUE. A FALSE return means the Decoder was unable to
* parse this file and the next should be tried.
*
* Probe() differs from Open() since it focuses on a file as a whole rather than one particular stream. Probe()
* should be able to be run directly without calling Open() or Close() and should free its memory before returning.
*
* Probe() will never be called on an object that is also used for decoding. In other words, it will never be called
* alongside Open() or Close() externally, so Probe() can use variables that would otherwise be used for decoding
* without conflict.
*
* @param f
*
* A Footage object to probe. The Footage object will have a valid filename and will be empty prior to being sent
* to this function (i.e. Footage::Clear() will not have to be called).
*
* @return
*
* TRUE if the Decoder was able to decode this file. FALSE if not. This function should have filled the Footage
* object with metadata if it returns TRUE. Otherwise, the Footage object should be untouched.
*/
virtual bool Probe(Footage* f) = 0;
/**
* @brief Open media/allocate memory
*
+97
View File
@@ -100,6 +100,14 @@ bool FFmpegDecoder::Open()
return true;
}
FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &length)
{
Q_UNUSED(timecode)
Q_UNUSED(length)
return nullptr;
}
void FFmpegDecoder::Close()
{
if (opts_ != nullptr) {
@@ -120,6 +128,95 @@ void FFmpegDecoder::Close()
open_ = false;
}
bool FFmpegDecoder::Probe(Footage *f)
{
int error_code;
// Convert QString to a C strng
QByteArray ba = f->filename().toUtf8();
const char* filename = ba.constData();
// Open file in a format context
error_code = avformat_open_input(&fmt_ctx_, filename, nullptr, nullptr);
// Handle format context error
if (error_code == 0) {
// Retrieve metadata about the media
av_dump_format(fmt_ctx_, stream()->index(), filename, 0);
// Dump it into the Footage object
for (unsigned int i=0;i<fmt_ctx_->nb_streams;i++) {
avstream_ = fmt_ctx_->streams[i];
Stream* str;
if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// Create a video stream object
VideoStream* video_stream = new VideoStream();
video_stream->set_width(avstream_->codecpar->width);
video_stream->set_height(avstream_->codecpar->height);
str = video_stream;
} else if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
// Create an audio stream object
AudioStream* audio_stream = new AudioStream();
audio_stream->set_layout(avstream_->codecpar->channel_layout);
audio_stream->set_channels(avstream_->codecpar->channels);
audio_stream->set_sample_rate(avstream_->codecpar->sample_rate);
str = audio_stream;
} else {
// This is data we can't utilize at the moment, but we make a Stream object anyway to keep parity with the file
str = new Stream();
// Set the correct codec type based on FFmpeg's result
switch (avstream_->codecpar->codec_type) {
case AVMEDIA_TYPE_UNKNOWN:
str->set_type(Stream::kUnknown);
break;
case AVMEDIA_TYPE_DATA:
str->set_type(Stream::kData);
break;
case AVMEDIA_TYPE_SUBTITLE:
str->set_type(Stream::kSubtitle);
break;
case AVMEDIA_TYPE_ATTACHMENT:
str->set_type(Stream::kAttachment);
break;
// We should never realistically get here, but we make an "invalid" stream just in case
// We don't use a "default:" in case more AVMEDIA_TYPEs get introduced in later APIs that need handling
case AVMEDIA_TYPE_NB:
case AVMEDIA_TYPE_VIDEO:
case AVMEDIA_TYPE_AUDIO:
str->set_type(Stream::kUnknown);
break;
}
}
str->set_index(avstream_->index);
str->set_timebase(avstream_->time_base);
f->add_stream(str);
}
}
// Free all memory
Close();
return false;
}
void FFmpegDecoder::FFmpegErr(int error_code)
{
char err[1024];
+3
View File
@@ -10,7 +10,10 @@ class FFmpegDecoder : public Decoder
public:
FFmpegDecoder();
virtual bool Probe(Footage *f) override;
virtual bool Open() override;
virtual FramePtr Retrieve(const rational &timecode, const rational &length = 0) override;
virtual void Close() override;
protected:
+17 -1
View File
@@ -1,8 +1,24 @@
#include "probeserver.h"
#include <QApplication>
#include <QDebug>
#include "decoder/ffmpeg/ffmpegdecoder.h"
bool olive::Probe(Footage *f)
bool olive::ProbeMedia(Footage *f)
{
// Check for a valid filename
if (f->filename().isEmpty()) {
qWarning() << QCoreApplication::translate("ProbeMedia", "Tried to probe media with an empty filename");
return false;
}
FFmpegDecoder ff_dec;
// Pass footage through FFmpeg's probe function
if (ff_dec.Probe(f)) {
return true;
}
return false;
}
+1 -1
View File
@@ -5,7 +5,7 @@
namespace olive {
bool Probe(Footage* f);
bool ProbeMedia(Footage* f);
}