diff --git a/app/codec/ffmpeg/ffmpegdecoder.cpp b/app/codec/ffmpeg/ffmpegdecoder.cpp index a7040cd19..8b4dde3e5 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.cpp +++ b/app/codec/ffmpeg/ffmpegdecoder.cpp @@ -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(frame_->format), - frame_->width, - frame_->height, - 1); - - QByteArray cached_frame(cached_buffer_sz, Qt::Uninitialized); - - av_image_copy_to_buffer(reinterpret_cast(cached_frame.data()), - cached_frame.size(), - frame_->data, - frame_->linesize, - static_cast(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(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(f->format), + f->width, + f->height, + 1); + + QByteArray cached_frame(cached_buffer_sz, Qt::Uninitialized); + + av_image_copy_to_buffer(reinterpret_cast(cached_frame.data()), + cached_frame.size(), + f->data, + f->linesize, + static_cast(f->format), + f->width, + f->height, + 1); + + save_frame.write(qCompress(cached_frame, 1)); + save_frame.close(); + + DiskManager::instance()->CreatedFile(save_frame.fileName(), QByteArray()); + } +} diff --git a/app/codec/ffmpeg/ffmpegdecoder.h b/app/codec/ffmpeg/ffmpegdecoder.h index 553518884..ff27b63fa 100644 --- a/app/codec/ffmpeg/ffmpegdecoder.h +++ b/app/codec/ffmpeg/ffmpegdecoder.h @@ -119,6 +119,8 @@ private: void Seek(int64_t timestamp); + void CacheFrameToDisk(AVFrame* f); + AVFormatContext* fmt_ctx_; AVCodecContext* codec_ctx_; AVStream* avstream_; diff --git a/app/project/item/footage/videostream.cpp b/app/project/item/footage/videostream.cpp index 196dee576..ef08b1adc 100644 --- a/app/project/item/footage/videostream.cpp +++ b/app/project/item/footage/videostream.cpp @@ -22,6 +22,8 @@ #include +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(sizeof(int64_t))); index_file.close(); + return true; } diff --git a/app/project/item/footage/videostream.h b/app/project/item/footage/videostream.h index 2940cfd26..ac899aa21 100644 --- a/app/project/item/footage/videostream.h +++ b/app/project/item/footage/videostream.h @@ -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); diff --git a/app/task/taskmanager.cpp b/app/task/taskmanager.cpp index 66413aa71..7fd21ebc0 100644 --- a/app/task/taskmanager.cpp +++ b/app/task/taskmanager.cpp @@ -75,6 +75,7 @@ void TaskManager::CreateInstance() void TaskManager::DestroyInstance() { delete instance_; + instance_ = nullptr; } TaskManager *TaskManager::instance()