ffmpegdecoder: improved index reliability

This commit is contained in:
itsmattkc
2020-02-15 23:39:33 +11:00
parent 53106e1847
commit 3efbcc28ef
5 changed files with 79 additions and 49 deletions
+47 -44
View File
@@ -292,31 +292,7 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode)
input_linesize[i] = frame_->linesize[i];
}
QFile save_frame(GetIndexFilename().append(QString::number(frame_->pts)));
if (save_frame.open(QFile::WriteOnly)) {
// Save frame to media index
int cached_buffer_sz = av_image_get_buffer_size(static_cast<AVPixelFormat>(frame_->format),
frame_->width,
frame_->height,
1);
QByteArray cached_frame(cached_buffer_sz, Qt::Uninitialized);
av_image_copy_to_buffer(reinterpret_cast<uint8_t*>(cached_frame.data()),
cached_frame.size(),
frame_->data,
frame_->linesize,
static_cast<AVPixelFormat>(frame_->format),
frame_->width,
frame_->height,
1);
save_frame.write(qCompress(cached_frame, 1));
save_frame.close();
DiskManager::instance()->CreatedFile(save_frame.fileName(), QByteArray());
}
CacheFrameToDisk(frame_);
break;
}
}
@@ -887,6 +863,8 @@ void FFmpegDecoder::UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame)
ret = GetFrame(pkt, frame);
if (ret >= 0) {
//CacheFrameToDisk(frame);
video_stream->append_frame_index(frame->pts);
} else {
// Assume we've reached the end of the file
@@ -894,6 +872,8 @@ void FFmpegDecoder::UnconditionalVideoIndex(AVPacket* pkt, AVFrame* frame)
}
}
video_stream->append_frame_index(VideoStream::kEndTimestamp);
// Save index to file
if (!video_stream->save_frame_index(GetIndexFilename())) {
qWarning() << QStringLiteral("Failed to save index for %1").arg(stream()->footage()->filename());
@@ -953,25 +933,19 @@ int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts)
bool index_is_being_created = false;
// Check if the frame index has been populated
if (video_stream->is_frame_index_empty()) {
// Check if an index is being created right now
if (video_stream->index_process_lock()->tryLock()) {
// If not, check if one is being created right now
if (video_stream->index_process_lock()->tryLock()) {
// If not, make an index
// If not, check if the frame index has been populated
if (!video_stream->is_frame_index_ready()) {
// If not, make a frame index
ValidateVideoIndex();
video_stream->index_process_lock()->unlock();
// If the index is still empty, the video must just be empty
if (video_stream->is_frame_index_empty()) {
return -1;
}
} else {
// The index is being created in another thread, wait until we have more information
index_is_being_created = true;
}
video_stream->index_process_lock()->unlock();
} else {
index_is_being_created = true;
}
int64_t closest_ts = -1;
@@ -987,7 +961,7 @@ int64_t FFmpegDecoder::GetClosestTimestampInIndex(const int64_t &ts)
closest_ts = video_stream->get_closest_timestamp_in_frame_index(ts);
} while (index_is_being_created);
} while (closest_ts < 0 && index_is_being_created);
return closest_ts;
}
@@ -996,11 +970,11 @@ void FFmpegDecoder::ValidateVideoIndex()
{
VideoStreamPtr video_stream = std::static_pointer_cast<VideoStream>(stream());
if (video_stream->is_frame_index_empty()) {
if (!video_stream->is_frame_index_ready()) {
video_stream->load_frame_index(GetIndexFilename());
}
if (video_stream->is_frame_index_empty()) {
if (!video_stream->is_frame_index_ready()) {
// Reset state
Seek(0);
@@ -1015,3 +989,32 @@ void FFmpegDecoder::Seek(int64_t timestamp)
avcodec_flush_buffers(codec_ctx_);
av_seek_frame(fmt_ctx_, avstream_->index, timestamp, AVSEEK_FLAG_BACKWARD);
}
void FFmpegDecoder::CacheFrameToDisk(AVFrame *f)
{
QFile save_frame(GetIndexFilename().append(QString::number(f->pts)));
if (save_frame.open(QFile::WriteOnly)) {
// Save frame to media index
int cached_buffer_sz = av_image_get_buffer_size(static_cast<AVPixelFormat>(f->format),
f->width,
f->height,
1);
QByteArray cached_frame(cached_buffer_sz, Qt::Uninitialized);
av_image_copy_to_buffer(reinterpret_cast<uint8_t*>(cached_frame.data()),
cached_frame.size(),
f->data,
f->linesize,
static_cast<AVPixelFormat>(f->format),
f->width,
f->height,
1);
save_frame.write(qCompress(cached_frame, 1));
save_frame.close();
DiskManager::instance()->CreatedFile(save_frame.fileName(), QByteArray());
}
}
+2
View File
@@ -119,6 +119,8 @@ private:
void Seek(int64_t timestamp);
void CacheFrameToDisk(AVFrame* f);
AVFormatContext* fmt_ctx_;
AVCodecContext* codec_ctx_;
AVStream* avstream_;
+25 -4
View File
@@ -22,6 +22,8 @@
#include <QFile>
const int64_t VideoStream::kEndTimestamp = AV_NOPTS_VALUE;
VideoStream::VideoStream()
{
set_type(kVideo);
@@ -48,12 +50,22 @@ int64_t VideoStream::get_closest_timestamp_in_frame_index(const int64_t &ts)
{
QMutexLocker locker(&index_access_lock_);
if (frame_index_.isEmpty()) {
return -1;
}
if (ts <= 0) {
return frame_index_.first();
}
int index_size = frame_index_.size();
if (frame_index_.last() == kEndTimestamp) {
index_size--;
}
// Use index to find closest frame in file
for (int i=0;i<frame_index_.size();i++) {
for (int i=0;i<index_size;i++) {
int64_t this_ts = frame_index_.at(i);
if (this_ts == ts) {
@@ -63,7 +75,13 @@ int64_t VideoStream::get_closest_timestamp_in_frame_index(const int64_t &ts)
}
}
return frame_index_.last();
if (frame_index_.last() == kEndTimestamp) {
// Index is done
return frame_index_.last();
} else {
// Index is not done yet
return -1;
}
}
void VideoStream::clear_frame_index()
@@ -80,11 +98,11 @@ void VideoStream::append_frame_index(const int64_t &ts)
frame_index_.append(ts);
}
bool VideoStream::is_frame_index_empty()
bool VideoStream::is_frame_index_ready()
{
QMutexLocker locker(&index_access_lock_);
return frame_index_.isEmpty();
return !frame_index_.isEmpty() && frame_index_.last() == VideoStream::kEndTimestamp;
}
int64_t VideoStream::last_frame_index_timestamp()
@@ -110,6 +128,8 @@ bool VideoStream::load_frame_index(const QString &s)
index_file.size());
index_file.close();
return true;
}
return false;
@@ -127,6 +147,7 @@ bool VideoStream::save_frame_index(const QString &s)
frame_index_.size() * static_cast<int>(sizeof(int64_t)));
index_file.close();
return true;
}
+4 -1
View File
@@ -28,6 +28,8 @@ class VideoStream : public ImageStream
public:
VideoStream();
static const int64_t kEndTimestamp;
virtual QString description() const override;
/**
@@ -41,7 +43,8 @@ public:
int64_t get_closest_timestamp_in_frame_index(const int64_t& ts);
void clear_frame_index();
void append_frame_index(const int64_t& ts);
bool is_frame_index_empty();
//bool is_frame_index_empty();
bool is_frame_index_ready();
int64_t last_frame_index_timestamp();
bool load_frame_index(const QString& s);
+1
View File
@@ -75,6 +75,7 @@ void TaskManager::CreateInstance()
void TaskManager::DestroyInstance()
{
delete instance_;
instance_ = nullptr;
}
TaskManager *TaskManager::instance()