From 5daf126e8d8751e7d9fe0415f658f23d644cd507 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 11 Jan 2020 03:45:58 +1100 Subject: [PATCH] completed hybrid index system --- app/codec/ffmpeg/ffmpegdecoder.cpp | 103 +++++++---------------------- app/codec/ffmpeg/ffmpegdecoder.h | 4 -- app/render/diskmanager.cpp | 17 +++++ app/render/diskmanager.h | 2 + 4 files changed, 44 insertions(+), 82 deletions(-) diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index de607b0ad..33de67d5d 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -37,16 +37,15 @@ extern "C" { #include "common/filefunctions.h" #include "common/timecodefunctions.h" #include "ffmpegcommon.h" +#include "render/diskmanager.h" #include "render/pixelservice.h" FFmpegDecoder::FFmpegDecoder() : fmt_ctx_(nullptr), codec_ctx_(nullptr), -#ifndef CACHE_EVERY_FRAME scale_ctx_(nullptr), pkt_(nullptr), frame_(nullptr), -#endif opts_(nullptr) { } @@ -149,7 +148,6 @@ bool FFmpegDecoder::Open() qFatal("Invalid output format"); } -#ifndef CACHE_EVERY_FRAME scale_ctx_ = sws_getContext(avstream_->codecpar->width, avstream_->codecpar->height, static_cast(avstream_->codecpar->format), @@ -163,7 +161,6 @@ bool FFmpegDecoder::Open() pkt_ = av_packet_alloc(); frame_ = av_frame_alloc(); -#endif } // All allocation succeeded so we set the state to open @@ -190,11 +187,13 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) return nullptr; } -#ifdef CACHE_EVERY_FRAME + // See if we stored this frame in the disk cache QFile compressed_frame(GetIndexFilename().append(QString::number(target_ts))); - if (compressed_frame.open(QFile::ReadOnly)) { + if (compressed_frame.exists() && compressed_frame.open(QFile::ReadOnly)) { + DiskManager::instance()->Accessed(compressed_frame.fileName()); + // Read data - QByteArray frame_loader = compressed_frame.readAll(); + QByteArray frame_loader = qUncompress(compressed_frame.readAll()); // Frame was valid, now we convert it to a native Olive frame FramePtr frame_container = Frame::Create(); @@ -209,7 +208,8 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) return frame_container; } -#else + + // Otherwise, we'll need to find this frame ourselves int64_t second_ts = qRound64(av_q2d(av_inv_q(avstream_->time_base))); bool got_frame = (frame_->pts == target_ts); @@ -266,9 +266,17 @@ FramePtr FFmpegDecoder::RetrieveVideo(const rational &timecode) &output_data, &output_linesize); + QFile save_frame(GetIndexFilename().append(QString::number(frame_->pts))); + if (save_frame.open(QFile::WriteOnly)) { + QByteArray compressed = qCompress(reinterpret_cast(output_frame->data()), output_frame->allocated_size()); + save_frame.write(compressed); + save_frame.close(); + + DiskManager::instance()->CreatedFile(save_frame.fileName(), QByteArray()); + } + return output_frame; } -#endif return nullptr; } @@ -318,7 +326,6 @@ void FFmpegDecoder::Close() opts_ = nullptr; } -#ifndef CACHE_EVERY_FRAME if (frame_) { av_frame_free(&frame_); frame_ = nullptr; @@ -333,7 +340,6 @@ void FFmpegDecoder::Close() sws_freeContext(scale_ctx_); scale_ctx_ = nullptr; } -#endif if (codec_ctx_) { avcodec_free_context(&codec_ctx_); @@ -644,33 +650,17 @@ void FFmpegDecoder::Index() return; } - // Allocate a packet and frame for decoding - AVPacket* pkt = av_packet_alloc(); - AVFrame* frame = av_frame_alloc(); + // Reset state + Seek(0); - if (pkt == nullptr || frame == nullptr) { - // Handle failure to allocate either - Error(QStringLiteral("Failed to allocate resources for indexing")); - } else { - // Reset state - Seek(0); - - if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - IndexVideo(pkt, frame); - } else if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - IndexAudio(pkt, frame); - } - - // Reset state - Seek(0); + if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + IndexVideo(pkt_, frame_); + } else if (avstream_->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + IndexAudio(pkt_, frame_); } - // Free resources - if (pkt != nullptr) - av_packet_free(&pkt); - - if (frame != nullptr) - av_frame_free(&frame); + // Reset state + Seek(0); } QString FFmpegDecoder::GetIndexFilename() @@ -879,51 +869,12 @@ void FFmpegDecoder::IndexVideo(AVPacket* pkt, AVFrame* frame) // Iterate through every single frame and get each timestamp // NOTE: Expects no frames to have been read so far -#ifdef CACHE_EVERY_FRAME - SwsContext* scale_ctx = sws_getContext(avstream_->codecpar->width, - avstream_->codecpar->height, - static_cast(avstream_->codecpar->format), - avstream_->codecpar->width, - avstream_->codecpar->height, - ideal_pix_fmt_, - 0, - nullptr, - nullptr, - nullptr); -#endif - int ret; while (true) { ret = GetFrame(pkt, frame); if (ret >= 0) { -#ifdef CACHE_EVERY_FRAME - // Save frame - int buffer_size = PixelService::GetBufferSize(native_pix_fmt_, avstream_->codecpar->width, avstream_->codecpar->height); - - QByteArray frame_save(buffer_size, Qt::Uninitialized); - - char* data = frame_save.data(); - int line_size = avstream_->codecpar->width * kRGBAChannels; - - // Perform pixel conversion - - sws_scale(scale_ctx, - frame->data, - frame->linesize, - 0, - avstream_->codecpar->height, - reinterpret_cast(&data), - &line_size); - - QFile compressed_frame(GetIndexFilename().append(QString::number(frame->pts))); - if (compressed_frame.open(QFile::WriteOnly)) { - compressed_frame.write(frame_save); - compressed_frame.close(); - } -#endif - frame_index_.append(frame->pts); } else { // Assume we've reached the end of the file @@ -931,10 +882,6 @@ void FFmpegDecoder::IndexVideo(AVPacket* pkt, AVFrame* frame) } } -#ifdef CACHE_EVERY_FRAME - sws_freeContext(scale_ctx); -#endif - // Save index to file SaveIndex(); } diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index 57dc1d409..a313336ef 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -33,8 +33,6 @@ extern "C" { #include "codec/decoder.h" #include "codec/waveoutput.h" -//#define CACHE_EVERY_FRAME - /** * @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder */ @@ -150,13 +148,11 @@ private: AVPixelFormat ideal_pix_fmt_; PixelFormat::Format native_pix_fmt_; -#ifndef CACHE_EVERY_FRAME SwsContext* scale_ctx_; AVPacket* pkt_; AVFrame* frame_; -#endif AVDictionary* opts_; diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index fbead0e6a..7f0e5ead8 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -93,6 +93,23 @@ void DiskManager::Accessed(const QByteArray &hash) } } +void DiskManager::Accessed(const QString &filename) +{ + for (int i=disk_data_.size()-1;i>=0;i--) { + const HashTime& h = disk_data_.at(i); + + if (h.file_name == filename) { + HashTime moved_hash = h; + + moved_hash.access_time = QDateTime::currentMSecsSinceEpoch(); + + disk_data_.removeAt(i); + disk_data_.append(moved_hash); + break; + } + } +} + void DiskManager::CreatedFile(const QString &file_name, const QByteArray &hash) { qint64 file_size = QFile(file_name).size(); diff --git a/app/render/diskmanager.h b/app/render/diskmanager.h index 370fa29cc..9a253ce59 100644 --- a/app/render/diskmanager.h +++ b/app/render/diskmanager.h @@ -15,6 +15,8 @@ public: void Accessed(const QByteArray& hash); + void Accessed(const QString& filename); + void CreatedFile(const QString& file_name, const QByteArray& hash); bool ClearDiskCache();