From: Good Guy Date: Mon, 14 Sep 2020 01:33:21 +0000 (-0600) Subject: rework rev vid caching, rework vid read_frame, rework framecache, tweak cached transi... X-Git-Tag: 2020-09~8 X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=commitdiff_plain;h=2441cb0cb7f655fad2f76c982f2ac93897d09dbe rework rev vid caching, rework vid read_frame, rework framecache, tweak cached transitions --- diff --git a/cinelerra-5.1/cinelerra/ffmpeg.C b/cinelerra-5.1/cinelerra/ffmpeg.C index f0eea9c5..7dca62a6 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.C +++ b/cinelerra-5.1/cinelerra/ffmpeg.C @@ -1226,15 +1226,22 @@ int FFVideoStream::load(VFrame *vframe, int64_t pos) ret = read_frame(frame); if( ret > 0 ) { if( frame->key_frame && seeking < 0 ) { - seeking = 1; - ffmpeg->purge_cache(); - } - if( ffmpeg->get_use_cache() && seeking > 0 && curr_pos < pos ) { - VFrame *cache_frame = ffmpeg->new_cache_frame(vframe, curr_pos); - if( cache_frame ) { - ret = convert_cmodel(cache_frame, frame); - ffmpeg->put_cache_frame(); + int use_cache = ffmpeg->get_use_cache(); + if( use_cache < 0 ) { +// for reverse read, reload file frame_cache from keyframe to pos + ffmpeg->purge_cache(); + seeking = 1; } + else + seeking = 0; + } + if( seeking > 0 && curr_pos < pos ) { + int vw =vframe->get_w(), vh = vframe->get_h(); + int vcolor_model = vframe->get_color_model(); + VFrame *cache_frame = new VFrame(vw, vh, vcolor_model); + ret = convert_cmodel(cache_frame, frame); + if( ret > 0 ) + ffmpeg->put_cache_frame(cache_frame, curr_pos); } ++curr_pos; } @@ -2233,14 +2240,9 @@ int FFMPEG::scan_options(const char *options, AVDictionary *&opts, AVStream *st) return ret; } -VFrame *FFMPEG::new_cache_frame(VFrame *vframe, int64_t position) -{ - return file_base->file->new_cache_frame(vframe, position, 0); -} - -void FFMPEG::put_cache_frame() +void FFMPEG::put_cache_frame(VFrame *frame, int64_t position) { - return file_base->file->put_cache_frame(); + file_base->file->put_cache_frame(frame, position, 0); } int FFMPEG::get_use_cache() diff --git a/cinelerra-5.1/cinelerra/ffmpeg.h b/cinelerra-5.1/cinelerra/ffmpeg.h index 9ceef154..2e1f201f 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.h +++ b/cinelerra-5.1/cinelerra/ffmpeg.h @@ -368,8 +368,7 @@ public: static double to_secs(int64_t time, AVRational time_base); int info(char *text, int len); - VFrame *new_cache_frame(VFrame *vframe, int64_t position); - void put_cache_frame(); + void put_cache_frame(VFrame *frame, int64_t position); int get_use_cache(); void purge_cache(); diff --git a/cinelerra-5.1/cinelerra/file.C b/cinelerra-5.1/cinelerra/file.C index 6459ebe8..9828d6ec 100644 --- a/cinelerra-5.1/cinelerra/file.C +++ b/cinelerra-5.1/cinelerra/file.C @@ -344,17 +344,16 @@ int File::delete_oldest() return frame_cache->delete_oldest(); } -// create cache frame using input vframe as template -VFrame *File::new_cache_frame(VFrame *vframe, int64_t position, int first_frame) +int File::get_cache_frame(VFrame *frame, int64_t position) { - return frame_cache->new_cache_frame(position, - vframe->get_w(), vframe->get_h(), vframe->get_color_model(), - current_layer, asset->frame_rate, first_frame); + return frame_cache->get_cache_frame(frame, position, + current_layer, asset->frame_rate); } -void File::put_cache_frame() +void File::put_cache_frame(VFrame *frame, int64_t position, int use_copy) { - return frame_cache->put_cache_frame(); + frame_cache->put_cache_frame(frame, + position, current_layer, asset->frame_rate, use_copy); } int File::get_use_cache() @@ -1168,52 +1167,52 @@ int File::read_frame(VFrame *frame, int is_thread) if( debug ) PRINT_TRACE int result = 0; int supported_colormodel = colormodel_supported(frame->get_color_model()); - int advance_position = 1; - int cache_active = use_cache || asset->single_frame ? 1 : 0; + int do_read = 1; +// if reverse playback reading, use_cache is -1 + int cache_active = asset->single_frame ? 1 : use_cache; int64_t cache_position = !asset->single_frame ? current_frame : -1; // Test cache - if( cache_active && frame_cache->get_frame(frame, cache_position, - current_layer, asset->frame_rate) ) { -// Can't advance position if cache used. -//printf("File::read_frame %d\n", __LINE__); - advance_position = 0; + if( cache_active ) { + if( get_cache_frame(frame, cache_position) ) { + do_read = 0; + } + else if( cache_active < 0 && frame_cache->cache_items() > 0 ) { +// reverse reading and cache miss, clear cache for new readahead + purge_cache(); + } } -// Need temp - else if( frame->get_color_model() != BC_COMPRESSED && - (supported_colormodel != frame->get_color_model() || - (!file->can_scale_input() && - (frame->get_w() != asset->width || - frame->get_h() != asset->height))) ) { - -// printf("File::read_frame %d\n", __LINE__); -// Can't advance position here because it needs to be added to cache - if( temp_frame ) { - if( !temp_frame->params_match(asset->width, asset->height, supported_colormodel) ) { - delete temp_frame; - temp_frame = 0; +// Need to read + if( do_read ) { + VFrame *vframe = frame; + if( frame->get_color_model() != BC_COMPRESSED && + (supported_colormodel != frame->get_color_model() || + (!file->can_scale_input() && + (frame->get_w() != asset->width || + frame->get_h() != asset->height))) ) { + if( temp_frame ) { + if( !temp_frame->params_match(asset->width, asset->height, + supported_colormodel) ) { + delete temp_frame; temp_frame = 0; + } + } + if( !temp_frame ) { + temp_frame = new VFrame(asset->width, asset->height, + supported_colormodel, 0); + temp_frame->clear_frame(); } - } - if( !temp_frame ) { - temp_frame = new VFrame(asset->width, asset->height, supported_colormodel, 0); - temp_frame->clear_frame(); + temp_frame->copy_stacks(frame); + vframe = temp_frame; } - -// printf("File::read_frame %d\n", __LINE__); - temp_frame->copy_stacks(frame); - result = file->read_frame(temp_frame); - if( !result ) - frame->transfer_from(temp_frame); - else if( result && frame->get_status() > 0 ) - frame->set_status(-1); -//printf("File::read_frame %d\n", __LINE__); - } - else { -// Can't advance position here because it needs to be added to cache -//printf("File::read_frame %d\n", __LINE__); - result = file->read_frame(frame); - if( result && frame->get_status() > 0 ) + result = file->read_frame(vframe); + if( !result ) { + if( frame != vframe ) + frame->transfer_from(vframe); + if( cache_active > 0 ) + put_cache_frame(frame, cache_position, 1); + } + else if( frame->get_status() > 0 ) frame->set_status(-1); //for( int i = 0; i < 100 * 1000; i++ ) ((float*)frame->get_rows()[0])[i] = 1.0; } @@ -1221,12 +1220,9 @@ int File::read_frame(VFrame *frame, int is_thread) if( result && !current_frame ) frame->clear_frame(); - if( cache_active && advance_position && frame->get_status() > 0 ) - frame_cache->put_frame(frame, cache_position, - current_layer, asset->frame_rate, 1, 0); //printf("File::read_frame %d\n", __LINE__); - if( advance_position ) current_frame++; + if( do_read ) current_frame++; if( debug ) PRINT_TRACE return 0; } diff --git a/cinelerra-5.1/cinelerra/file.h b/cinelerra-5.1/cinelerra/file.h index e0cf4fa3..d09ca7ef 100644 --- a/cinelerra-5.1/cinelerra/file.h +++ b/cinelerra-5.1/cinelerra/file.h @@ -236,10 +236,9 @@ public: // Get nearest colormodel that can be decoded without a temporary frame. // Used by read_frame. int colormodel_supported(int colormodel); -// create frame_cache vframe for position, use template vframe -// clear cache if first frame is a read miss - VFrame *new_cache_frame(VFrame *vframe, int64_t position, int first_frame); - void put_cache_frame(); + + int get_cache_frame(VFrame *vframe, int64_t position); + void put_cache_frame(VFrame *frame, int64_t position, int use_copy); int get_use_cache(); // stubs for now diff --git a/cinelerra-5.1/cinelerra/framecache.C b/cinelerra-5.1/cinelerra/framecache.C index be6be51c..4f1a8eb0 100644 --- a/cinelerra-5.1/cinelerra/framecache.C +++ b/cinelerra-5.1/cinelerra/framecache.C @@ -79,160 +79,119 @@ FrameCache::~FrameCache() } -// Returns 1 if frame exists in cache and copies it to the frame argument. -int FrameCache::get_frame(VFrame *frame, - int64_t position, - int layer, - double frame_rate, - int source_id) -{ - lock->lock("FrameCache::get_frame"); - FrameCacheItem *result = 0; - - if(frame_exists(frame, - position, - layer, - frame_rate, - &result, - source_id)) - { - if(result->data) - { -// Frame may have come from the readahead thread. -// Those frames are in the codec color model. -// But to pass frame_exists, they must be identical. -// BC_CModels::transfer(frame->get_rows(), -// result->data->get_rows(), -// result->data->get_y(), -// result->data->get_u(), -// result->data->get_v(), -// frame->get_y(), -// frame->get_u(), -// frame->get_v(), -// 0, -// 0, -// result->data->get_w(), -// result->data->get_h(), -// 0, -// 0, -// frame->get_w(), -// frame->get_h(), -// result->data->get_color_model(), -// frame->get_color_model(), -// 0, -// result->data->get_w(), -// frame->get_w()); - -// no context data since keyframe updates may vary input - frame->copy_from(result->data); - } - result->age = get_age(); - } - - - - - lock->unlock(); - if(result) return 1; - return 0; -} - - -VFrame* FrameCache::get_frame_ptr(int64_t position, - int layer, - double frame_rate, - int color_model, - int w, - int h, - int source_id) +VFrame* FrameCache::get_frame_ptr(int64_t position, int layer, double frame_rate, + int color_model, int w, int h, int source_id) { lock->lock("FrameCache::get_frame_ptr"); - FrameCacheItem *result = 0; - if(frame_exists(position, - layer, - frame_rate, - color_model, - w, - h, - &result, - source_id)) - { - result->age = get_age(); - return result->data; - } - - + VFrame *vframe = get_vframe(position, w, h, color_model, + layer, frame_rate, source_id); + if( vframe ) return vframe; // not unlocked lock->unlock(); return 0; } -// Puts frame in cache if enough space exists and the frame doesn't already -// exist. -void FrameCache::put_frame(VFrame *frame, int64_t position, - int layer, double frame_rate, int use_copy, Indexable *indexable) +VFrame *FrameCache::get_vframe(int64_t position, int w, int h, + int color_model, int layer, double frame_rate, + int source_id) { - lock->lock("FrameCache::put_frame"); FrameCacheItem *item = 0; - int source_id = -1; - if(indexable) source_id = indexable->id; - -//printf("FrameCache::put_frame %d position=%jd\n", __LINE__, position); - - if(frame_exists(frame, position, layer, frame_rate, &item, source_id)) { + int ret = frame_exists(position, layer, frame_rate, + w, h, color_model, &item, source_id); + if( ret && position >= 0 && item ) item->age = get_age(); - lock->unlock(); - return; - } + return ret && item ? item->data : 0; +} +VFrame *FrameCache::get_frame(int64_t position, int w, int h, + int color_model, int layer, double frame_rate, + int source_id) +{ + lock->lock("FrameCache::get_frame"); + VFrame *frame = get_vframe(position, w, h, + color_model, layer, frame_rate, source_id); + lock->unlock(); + return frame; +} - item = new FrameCacheItem; +// Returns 1 if frame exists in cache and copies it to the frame argument. +int FrameCache::get_frame(VFrame *frame, int64_t position, + int layer, double frame_rate, int source_id) +{ + lock->lock("FrameCache::get_frame"); + VFrame *vframe = get_vframe(position, + frame->get_w(), frame->get_h(), frame->get_color_model(), + layer, frame_rate, source_id); + if( vframe ) + frame->copy_from(vframe); + lock->unlock(); + return vframe ? 1 : 0; +} - item->data = use_copy ? new VFrame(*frame) : frame; -// Copy metadata +void FrameCache::put_vframe(VFrame *frame, int64_t position, + int layer, double frame_rate, int source_id) +{ + FrameCacheItem *item = new FrameCacheItem; + item->data = frame; item->position = position; item->layer = layer; item->frame_rate = frame_rate; item->source_id = source_id; - if(indexable) - item->path = cstrdup(indexable->path); - item->age = position < 0 ? INT_MAX : get_age(); - -//printf("FrameCache::put_frame %d position=%jd\n", __LINE__, position); put_item(item); - lock->unlock(); } -VFrame *FrameCache::new_cache_frame(int64_t position, int w, int h, - int color_model, int layer, double frame_rate, int first_frame) +// Puts frame in cache if the frame doesn't already exist. +void FrameCache::put_frame(VFrame *frame, int64_t position, + int layer, double frame_rate, int use_copy, Indexable *idxbl) { - FrameCacheItem *item = 0; - lock->lock("FrameCache::put_vframe"); - if( frame_exists(position, layer, frame_rate, color_model, w, h, &item, -1) ) { - lock->unlock(); - return 0; - } - if( first_frame ) { - while( last ) delete last; - total_items = 0; - current_item = 0; + int source_id = idxbl ? idxbl->id : -1; + lock->lock("FrameCache::put_frame"); + VFrame *vframe = get_vframe(position, + frame->get_w(), frame->get_h(), frame->get_color_model(), + layer, frame_rate, source_id); + if( !vframe ) { + if( use_copy ) frame = new VFrame(*frame); + put_vframe(frame, position, layer, frame_rate, source_id); } - item = new FrameCacheItem; - item->data = new VFrame(w, h, color_model); - item->position = position; - item->layer = layer; - item->frame_rate = frame_rate; - item->source_id = -1; - item->age = position < 0 ? INT_MAX : get_age(); - put_item(item); - return item->data; + lock->unlock(); } -void FrameCache::put_cache_frame() + +// get vframe for keys, overwrite frame if found +int FrameCache::get_cache_frame(VFrame *frame, int64_t position, + int layer, double frame_rate) { + lock->lock("FrameCache::get_cache_frame"); + VFrame *vframe = get_vframe(position, + frame->get_w(), frame->get_h(), frame->get_color_model(), + layer, frame_rate, -1); + if( vframe ) + frame->copy_from(vframe); lock->unlock(); + return vframe ? 1 : 0; } +// adds or replaces vframe, consumes frame if not use_copy +void FrameCache::put_cache_frame(VFrame *frame, int64_t position, + int layer, double frame_rate, int use_copy) +{ + lock->lock("FrameCache::put_cache_frame"); + FrameCacheItem *item = 0; + int w = frame->get_w(), h = frame->get_h(); + int color_model = frame->get_color_model(); + int ret = frame_exists(position, layer, frame_rate, + w, h, color_model, &item, -1); + if( use_copy ) frame = new VFrame(*frame); + if( ret ) { + delete item->data; + item->data = frame; + } + else + put_vframe(frame, position, layer, frame_rate, -1); + lock->unlock(); +} + + int FrameCache::frame_exists(VFrame *format, int64_t position, int layer, double frame_rate, FrameCacheItem **item_return, int source_id) { @@ -251,7 +210,7 @@ int FrameCache::frame_exists(VFrame *format, int64_t position, } int FrameCache::frame_exists(int64_t position, int layer, double frame_rate, - int color_model, int w, int h, FrameCacheItem **item_return, int source_id) + int w, int h, int color_model, FrameCacheItem **item_return, int source_id) { FrameCacheItem *item = (FrameCacheItem*)get_item(position); for( ; item && item->position == position ; item = (FrameCacheItem*)item->next ) { diff --git a/cinelerra-5.1/cinelerra/framecache.h b/cinelerra-5.1/cinelerra/framecache.h index 429c5bba..5708e006 100644 --- a/cinelerra-5.1/cinelerra/framecache.h +++ b/cinelerra-5.1/cinelerra/framecache.h @@ -57,67 +57,49 @@ public: FrameCache(); ~FrameCache(); -// Returns 1 if frame exists in cache and copies it to the frame argument. - int get_frame(VFrame *frame, - int64_t position, - int layer, - double frame_rate, - int source_id = -1); // Returns pointer to cache entry if frame exists or 0. // If a frame is found, the frame cache is left in the locked state until // unlock is called. If nothing is found, the frame cache is unlocked before // returning. This keeps the item from being deleted. // asset - supplied by user if the cache is not part of a file. - VFrame* get_frame_ptr(int64_t position, - int layer, - double frame_rate, - int color_model, - int w, - int h, - int source_id = -1); + VFrame* get_frame_ptr(int64_t position, int layer, double frame_rate, + int color_model, int w, int h, int source_id); +// lock and call get_vframe + VFrame *get_vframe(int64_t position, int w, int h, + int color_model, int layer, double frame_rate, + int source_id); +// caller holds lock + VFrame *get_frame(int64_t position, int w, int h, + int color_model, int layer, double frame_rate, + int source_id); +// Returns 1 if frame exists in cache and copies it to the frame argument. + int get_frame(VFrame *frame, int64_t position, + int layer, double frame_rate, int source_id); // Puts the frame in cache. // use_copy - if 1 a copy of the frame is made. if 0 the argument is stored. // The copy of the frame is deleted by FrameCache in a future delete_oldest. // asset - supplied by user if the cache is not part of a file. - void put_frame(VFrame *frame, - int64_t position, - int layer, - double frame_rate, - int use_copy, - Indexable *indexable); -// create new cache vframe at position, return 0 if it already exists -// if first_frame set, clear cache before new vframe created -// if new vframe created, leave cache locked for frame load - VFrame *new_cache_frame(int64_t position, int w, int h, - int color_model, int layer, double frame_rate, - int first_frame); - void put_cache_frame(); - +// caller holds lock + void put_vframe(VFrame *frame, int64_t position, + int layer, double frame_rate, int source_id); +// lock, call get_vframe, if exists: ret = 0; else add frame, ret = 1; unlock + void put_frame(VFrame *frame, int64_t position, + int layer, double frame_rate, int use_copy, Indexable *idxbl); + int get_cache_frame(VFrame *frame, int64_t position, + int layer, double frame_rate); + void put_cache_frame(VFrame *frame, int64_t position, + int layer, double frame_rate, int use_copy); void dump(); - - - - private: // Return 1 if matching frame exists. // Return 0 if not. int frame_exists(VFrame *format, - int64_t position, - int layer, - double frame_rate, - FrameCacheItem **item_return, - int source_id); - int frame_exists(int64_t position, - int layer, - double frame_rate, - int color_model, - int w, - int h, - FrameCacheItem **item_return, - int source_id); + int64_t position, int layer, double frame_rate, + FrameCacheItem **item_return, int source_id); + int frame_exists(int64_t position, int layer, double frame_rate, + int w, int h, int color_model, + FrameCacheItem **item_return, int source_id); }; - - #endif diff --git a/cinelerra-5.1/cinelerra/vmodule.C b/cinelerra-5.1/cinelerra/vmodule.C index f3cc19c6..a9bb93df 100644 --- a/cinelerra-5.1/cinelerra/vmodule.C +++ b/cinelerra-5.1/cinelerra/vmodule.C @@ -259,9 +259,8 @@ int VModule::import_frame(VFrame *output, VEdit *current_edit, input_temp ; // Menu effect VFrame::get_temp(input, asset_w, asset_h, get_edl()->session->color_model); - int use_cache = renderengine && - ( renderengine->command->single_frame() || - renderengine->command->get_direction() == PLAY_REVERSE ); + int use_cache = renderengine->command->single_frame() ? 1 : + renderengine->command->get_direction() == PLAY_REVERSE ? -1 : 0; // int use_asynchronous = !use_cache && // renderengine && @@ -277,13 +276,12 @@ int VModule::import_frame(VFrame *output, VEdit *current_edit, // else file->stop_video_thread(); -// cache transitions VEdit *vnext = (VEdit *)current_edit->next; pos = Units::to_int64((double)input_position / frame_rate * edl_rate); - if( renderengine && renderengine->preferences->cache_transitions && - renderengine->command->get_direction() == PLAY_FORWARD && - current_edit->next && current_edit->next->transition && - file->get_video_length() >= 0 && pos >= vnext->startproject && + if( renderengine->preferences->cache_transitions && !use_cache && +// cache transitions not using cache and inside transition + vnext && vnext->transition && file->get_video_length() >= 0 && + pos >= vnext->startproject && pos < vnext->startproject + vnext->transition->length ) { file->set_cache_frames(0); file->set_layer(current_edit->channel); @@ -303,15 +301,15 @@ int VModule::import_frame(VFrame *output, VEdit *current_edit, curr_pos += current_edit->startsource; int64_t norm_pos = Units::to_int64((double)curr_pos * current_edit->asset->frame_rate / edl_rate); - VFrame *cache_frame = file->new_cache_frame(input, norm_pos, first_frame); - if( cache_frame ) { - file->set_video_position(norm_pos, 0); - result = file->read_frame(cache_frame); - file->put_cache_frame(); + if( first_frame ) { + if( file->get_cache_frame(input, norm_pos) ) + break; // if inside a cache run + first_frame = 0; + file->purge_cache(); // start new run } - else if( first_frame ) // already loaded - break; - first_frame = 0; + file->set_cache_frames(1); + file->set_video_position(norm_pos, 0); + result = file->read_frame(input); ++pos; --count; } use_cache = 1; @@ -396,9 +394,11 @@ int VModule::import_frame(VFrame *output, VEdit *current_edit, __LINE__, this, current_edit->asset->path); - if( use_cache ) file->set_cache_frames(1); + if( use_cache ) + file->set_cache_frames(use_cache); result = file->read_frame((*input)); - if( use_cache ) file->set_cache_frames(0); + if( use_cache ) + file->set_cache_frames(0); (*input)->set_opengl_state(VFrame::RAM); } else @@ -613,9 +613,11 @@ if( debug ) printf("VModule::import_frame %d %d %d %d %d %d %d\n", else if( file ) { // Cache single frames //memset(output->get_rows()[0], 0xff, 1024); - if( use_cache ) file->set_cache_frames(1); + if( use_cache ) + file->set_cache_frames(use_cache); result = file->read_frame(output); - if( use_cache ) file->set_cache_frames(0); + if( use_cache ) + file->set_cache_frames(0); output->set_opengl_state(VFrame::RAM); } } diff --git a/cinelerra-5.1/cinelerra/vrender.C b/cinelerra-5.1/cinelerra/vrender.C index bcb87a4e..be3d0c3b 100644 --- a/cinelerra-5.1/cinelerra/vrender.C +++ b/cinelerra-5.1/cinelerra/vrender.C @@ -133,8 +133,8 @@ int VRender::process_buffer(int64_t input_position, int use_vconsole = 1; int use_brender = 0; int result = 0; - int use_cache = renderengine->command->single_frame() || - renderengine->command->get_direction() == PLAY_REVERSE; + int use_cache = renderengine->command->single_frame() ? 1 : + renderengine->command->get_direction() == PLAY_REVERSE ? -1 : 0; // int use_asynchronous = // renderengine->command->realtime && // renderengine->get_edl()->session->video_every_frame &&