check queue for retrieved frame
This commit is contained in:
+6
-11
@@ -521,12 +521,8 @@ bool Clip::IsOpen()
|
||||
}
|
||||
|
||||
void Clip::Cache(long playhead, bool scrubbing, QVector<Clip*>& nests, int playback_speed) {
|
||||
// qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
cacher.Cache(playhead, scrubbing, nests, playback_speed);
|
||||
cacher_frame = playhead;
|
||||
|
||||
// qDebug() << "Clip::Cache took" << (QDateTime::currentMSecsSinceEpoch() - time);
|
||||
}
|
||||
|
||||
bool Clip::Retrieve()
|
||||
@@ -535,13 +531,14 @@ bool Clip::Retrieve()
|
||||
|
||||
if (UsesCacher()) {
|
||||
|
||||
// qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
AVFrame* frame = cacher.Retrieve();
|
||||
|
||||
cacher.QueueLock();
|
||||
cacher.queue()->lock();
|
||||
|
||||
if (frame != nullptr) {
|
||||
// Check if we retrieved a frame (nullptr) and if the queue stil contains this frame.
|
||||
//
|
||||
// In some situations it's
|
||||
if (frame != nullptr && cacher.queue()->contains(frame)) {
|
||||
|
||||
// check if the opengl texture exists yet, create it if not
|
||||
if (texture == nullptr) {
|
||||
@@ -599,14 +596,12 @@ bool Clip::Retrieve()
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
// qDebug() << "Clip::Retrieve took" << (QDateTime::currentMSecsSinceEpoch() - time);
|
||||
|
||||
ret = true;
|
||||
} else {
|
||||
qCritical() << "Failed to retrieve frame for clip" << name();
|
||||
}
|
||||
|
||||
cacher.QueueUnlock();
|
||||
cacher.queue()->unlock();
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
+44
-54
@@ -167,7 +167,7 @@ void Cacher::CacheAudioWorker() {
|
||||
} else if (clip->media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
double timebase = av_q2d(stream->time_base);
|
||||
|
||||
frame = queue.at(0);
|
||||
frame = queue_.at(0);
|
||||
|
||||
// retrieve frame
|
||||
bool new_frame = false;
|
||||
@@ -233,7 +233,7 @@ void Cacher::CacheAudioWorker() {
|
||||
|
||||
if (reverse_audio) {
|
||||
if (loop > 1) {
|
||||
AVFrame* rev_frame = queue.at(1);
|
||||
AVFrame* rev_frame = queue_.at(1);
|
||||
if (ret != AVERROR_EOF) {
|
||||
if (loop == 2) {
|
||||
#ifdef AUDIOWARNINGS
|
||||
@@ -368,7 +368,7 @@ void Cacher::CacheAudioWorker() {
|
||||
}
|
||||
}
|
||||
|
||||
if (reverse_audio) frame = queue.at(1);
|
||||
if (reverse_audio) frame = queue_.at(1);
|
||||
|
||||
#ifdef AUDIOWARNINGS
|
||||
dout << "j" << frame_sample_index << nb_bytes;
|
||||
@@ -459,7 +459,7 @@ void Cacher::CacheVideoWorker() {
|
||||
// for efficiency, we do slightly different things for a still image
|
||||
|
||||
// if we already queued a frame, we don't actually need to cache anything, so we only retrieve a frame if not
|
||||
if (queue.size() == 0) {
|
||||
if (queue_.size() == 0) {
|
||||
|
||||
// retrieve a single frame
|
||||
|
||||
@@ -470,9 +470,9 @@ void Cacher::CacheVideoWorker() {
|
||||
|
||||
if (RetrieveFrameAndProcess(&still_image_frame) >= 0) {
|
||||
|
||||
queue.lock();
|
||||
queue.append(still_image_frame);
|
||||
queue.unlock();
|
||||
queue_.lock();
|
||||
queue_.append(still_image_frame);
|
||||
queue_.unlock();
|
||||
|
||||
SetRetrievedFrame(still_image_frame);
|
||||
}
|
||||
@@ -496,13 +496,13 @@ void Cacher::CacheVideoWorker() {
|
||||
int64_t latest_pts = INT64_MIN;
|
||||
int frames_greater_than_target = 0;
|
||||
|
||||
for (int i=0;i<queue.size();i++) {
|
||||
for (int i=0;i<queue_.size();i++) {
|
||||
// cache earliest and latest timestamps in the queue
|
||||
earliest_pts = qMin(earliest_pts, queue.at(i)->pts);
|
||||
latest_pts = qMax(latest_pts, queue.at(i)->pts);
|
||||
earliest_pts = qMin(earliest_pts, queue_.at(i)->pts);
|
||||
latest_pts = qMax(latest_pts, queue_.at(i)->pts);
|
||||
|
||||
// count upcoming frames
|
||||
if (queue.at(i)->pts > target_pts) {
|
||||
if (queue_.at(i)->pts > target_pts) {
|
||||
frames_greater_than_target++;
|
||||
}
|
||||
}
|
||||
@@ -510,16 +510,16 @@ void Cacher::CacheVideoWorker() {
|
||||
// check if the frame is within this queue or if we'll have to seek elsewhere to get it
|
||||
// (we check for one second of time after latest_pts, because if it's within that range it'll likely be faster to
|
||||
// play up to that frame than seek to it)
|
||||
if (target_pts < earliest_pts || target_pts > latest_pts + second_pts || queue.size() == 0) {
|
||||
if (target_pts < earliest_pts || target_pts > latest_pts + second_pts || queue_.size() == 0) {
|
||||
// we need to seek to retrieve this frame
|
||||
|
||||
avcodec_flush_buffers(codecCtx);
|
||||
av_seek_frame(formatCtx, clip->media_stream_index(), target_pts, AVSEEK_FLAG_BACKWARD);
|
||||
|
||||
// also we assume none of the frames in the queue are usable
|
||||
queue.lock();
|
||||
queue.clear();
|
||||
queue.unlock();
|
||||
queue_.lock();
|
||||
queue_.clear();
|
||||
queue_.unlock();
|
||||
|
||||
// reset upcoming frame count and latest pts for later calculations
|
||||
frames_greater_than_target = 0;
|
||||
@@ -595,15 +595,15 @@ void Cacher::CacheVideoWorker() {
|
||||
if (decoded_frame->pts == target_pts) {
|
||||
SetRetrievedFrame(decoded_frame);
|
||||
} else if (decoded_frame->pts > target_pts
|
||||
&& queue.size() > 0) {
|
||||
SetRetrievedFrame(queue.last());
|
||||
&& queue_.size() > 0) {
|
||||
SetRetrievedFrame(queue_.last());
|
||||
}
|
||||
}
|
||||
|
||||
// add the frame to the queue
|
||||
queue.lock();
|
||||
queue.append(decoded_frame);
|
||||
queue.unlock();
|
||||
queue_.lock();
|
||||
queue_.append(decoded_frame);
|
||||
queue_.unlock();
|
||||
|
||||
// check the amount of previous frames in the queue by using the current queue size for if we need to
|
||||
// remove any old entries (assumes the queue is chronological)
|
||||
@@ -613,13 +613,13 @@ void Cacher::CacheVideoWorker() {
|
||||
|
||||
if (decoded_frame->pts < target_pts) {
|
||||
// if this frame is before the target frame, make sure we don't add too many of them
|
||||
previous_frame_count = queue.size();
|
||||
previous_frame_count = queue_.size();
|
||||
} else {
|
||||
// if this frame is after the target frame, clean up any previous frames before it
|
||||
// TODO is there a faster way to do this?
|
||||
|
||||
for (int i=0;i<queue.size();i++) {
|
||||
if (queue.at(i)->pts > target_pts) {
|
||||
for (int i=0;i<queue_.size();i++) {
|
||||
if (queue_.at(i)->pts > target_pts) {
|
||||
break;
|
||||
} else {
|
||||
previous_frame_count++;
|
||||
@@ -630,9 +630,9 @@ void Cacher::CacheVideoWorker() {
|
||||
|
||||
// remove frames while the amount of previous frames exceeds the maximum
|
||||
while (previous_frame_count > minimum_ts) {
|
||||
queue.lock();
|
||||
queue.removeFirst();
|
||||
queue.unlock();
|
||||
queue_.lock();
|
||||
queue_.removeFirst();
|
||||
queue_.unlock();
|
||||
previous_frame_count--;
|
||||
}
|
||||
|
||||
@@ -668,14 +668,14 @@ void Cacher::CacheVideoWorker() {
|
||||
qWarning() << clip->name() << "frame had no PTS value";
|
||||
av_frame_free(&decoded_frame);
|
||||
|
||||
if (retrieve_code == AVERROR_EOF && retrieved_frame == nullptr && !queue.isEmpty()) {
|
||||
if (retrieve_code == AVERROR_EOF && retrieved_frame == nullptr && !queue_.isEmpty()) {
|
||||
// if we reached the end of the file, it's not an error but there are no more frames to retrieve
|
||||
// some formats EOF before the end of the duration that Olive calculates. In this event, we simply
|
||||
// return the last frame we retrieved
|
||||
//
|
||||
// TODO: Check duration formula
|
||||
|
||||
SetRetrievedFrame(queue.last());
|
||||
SetRetrievedFrame(queue_.last());
|
||||
|
||||
} else {
|
||||
|
||||
@@ -899,7 +899,7 @@ void Cacher::OpenWorker() {
|
||||
if (codecCtx->channel_layout == 0) codecCtx->channel_layout = av_get_default_channel_layout(stream->codecpar->channels);
|
||||
|
||||
// set up cache
|
||||
queue.append(av_frame_alloc());
|
||||
queue_.append(av_frame_alloc());
|
||||
// if (clip->reverse) {
|
||||
if (true) {
|
||||
AVFrame* reverse_frame = av_frame_alloc();
|
||||
@@ -910,7 +910,7 @@ void Cacher::OpenWorker() {
|
||||
reverse_frame->channels = av_get_channel_layout_nb_channels(clip->sequence->audio_layout);
|
||||
av_frame_get_buffer(reverse_frame, 0);
|
||||
|
||||
queue.append(reverse_frame);
|
||||
queue_.append(reverse_frame);
|
||||
}
|
||||
|
||||
snprintf(filter_args, sizeof(filter_args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%" PRIx64,
|
||||
@@ -1002,9 +1002,9 @@ void Cacher::CacheWorker() {
|
||||
|
||||
void Cacher::CloseWorker() {
|
||||
retrieved_frame = nullptr;
|
||||
queue.lock();
|
||||
queue.clear();
|
||||
queue.unlock();
|
||||
queue_.lock();
|
||||
queue_.clear();
|
||||
queue_.unlock();
|
||||
|
||||
if (frame_ != nullptr) {
|
||||
av_frame_free(&frame_);
|
||||
@@ -1075,9 +1075,9 @@ void Cacher::Open()
|
||||
void Cacher::Cache(long playhead, bool scrubbing, QVector<Clip*>& nests, int playback_speed)
|
||||
{
|
||||
if (clip->media_stream() != nullptr
|
||||
&& queue.size() > 0
|
||||
&& queue_.size() > 0
|
||||
&& clip->media_stream()->infinite_length) {
|
||||
retrieved_frame = queue.at(0);
|
||||
retrieved_frame = queue_.at(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1092,28 +1092,28 @@ void Cacher::Cache(long playhead, bool scrubbing, QVector<Clip*>& nests, int pla
|
||||
if (clip->media() != nullptr) {
|
||||
// see if we already have this frame
|
||||
retrieve_lock_.lock();
|
||||
queue.lock();
|
||||
queue_.lock();
|
||||
retrieved_frame = nullptr;
|
||||
int64_t target_pts = seconds_to_timestamp(clip, playhead_to_clip_seconds(clip, playhead_));
|
||||
for (int i=0;i<queue.size();i++) {
|
||||
for (int i=0;i<queue_.size();i++) {
|
||||
|
||||
if (queue.at(i)->pts == target_pts) {
|
||||
if (queue_.at(i)->pts == target_pts) {
|
||||
|
||||
// the queue has a frame with the exact timestamp
|
||||
|
||||
retrieved_frame = queue.at(i);
|
||||
retrieved_frame = queue_.at(i);
|
||||
wait_for_cacher_to_respond = false;
|
||||
break;
|
||||
} else if (i > 0 && queue.at(i-1)->pts < target_pts && queue.at(i)->pts > target_pts) {
|
||||
} else if (i > 0 && queue_.at(i-1)->pts < target_pts && queue_.at(i)->pts > target_pts) {
|
||||
|
||||
// the queue has a frame with a close timestamp that we'll assume is different due to a rounding error
|
||||
|
||||
retrieved_frame = queue.at(i-1);
|
||||
retrieved_frame = queue_.at(i-1);
|
||||
wait_for_cacher_to_respond = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
queue.unlock();
|
||||
queue_.unlock();
|
||||
retrieve_lock_.unlock();
|
||||
}
|
||||
|
||||
@@ -1140,8 +1140,6 @@ void Cacher::Cache(long playhead, bool scrubbing, QVector<Clip*>& nests, int pla
|
||||
|
||||
AVFrame *Cacher::Retrieve()
|
||||
{
|
||||
// qint64 time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
if (!caching_) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1160,7 +1158,6 @@ AVFrame *Cacher::Retrieve()
|
||||
} else {
|
||||
|
||||
// cacher is running, wait for it to give a frame
|
||||
// qDebug() << "====> retrieve lock waiting";
|
||||
retrieve_lock_.lock();
|
||||
retrieve_wait_.wait(&retrieve_lock_);
|
||||
retrieve_lock_.unlock();
|
||||
@@ -1169,8 +1166,6 @@ AVFrame *Cacher::Retrieve()
|
||||
|
||||
}
|
||||
|
||||
// qDebug() << "Cacher::Retrieve took" << (QDateTime::currentMSecsSinceEpoch() - time) << "and retrieved" << retrieved_frame;
|
||||
|
||||
return retrieved_frame;
|
||||
}
|
||||
|
||||
@@ -1211,14 +1206,9 @@ AVRational Cacher::media_time_base()
|
||||
return stream->time_base;
|
||||
}
|
||||
|
||||
void Cacher::QueueLock()
|
||||
ClipQueue *Cacher::queue()
|
||||
{
|
||||
queue.lock();
|
||||
}
|
||||
|
||||
void Cacher::QueueUnlock()
|
||||
{
|
||||
queue.unlock();
|
||||
return &queue_;
|
||||
}
|
||||
|
||||
int Cacher::RetrieveFrameFromDecoder(AVFrame* f) {
|
||||
|
||||
+7
-8
@@ -243,14 +243,13 @@ public:
|
||||
AVRational media_time_base();
|
||||
|
||||
/**
|
||||
* @brief Wrapper function for queue::lock()
|
||||
* @brief Get cacher queue object
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* A pointer to the cacher's internal frame queue
|
||||
*/
|
||||
void QueueLock();
|
||||
|
||||
/**
|
||||
* @brief Wrapper function for queue::unlock()
|
||||
*/
|
||||
void QueueUnlock();
|
||||
ClipQueue* queue();
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -263,7 +262,7 @@ private:
|
||||
*
|
||||
* Valid fames are cached into this, which also does memory handling when necessary.
|
||||
*/
|
||||
ClipQueue queue;
|
||||
ClipQueue queue_;
|
||||
|
||||
/**
|
||||
* @brief Main wait condition
|
||||
|
||||
@@ -98,3 +98,8 @@ bool ClipQueue::isEmpty()
|
||||
{
|
||||
return queue.isEmpty();
|
||||
}
|
||||
|
||||
bool ClipQueue::contains(AVFrame *frame)
|
||||
{
|
||||
return queue.contains(frame);
|
||||
}
|
||||
|
||||
@@ -168,6 +168,15 @@ public:
|
||||
*/
|
||||
bool isEmpty();
|
||||
|
||||
/**
|
||||
* @brief Returns whether the queue contains a frame or not
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* **TRUE** if the queue contains the specified frame, **FALSE** if not.
|
||||
*/
|
||||
bool contains(AVFrame* frame);
|
||||
|
||||
private:
|
||||
QVector<AVFrame*> queue;
|
||||
QMutex queue_lock;
|
||||
|
||||
Reference in New Issue
Block a user