I still don't like the way that read_input_cache() is arranged, it doesn't strike me as a very idiomatic way to do a cache. In general I expect something like
bool get_cache_entry(...) { for (each entry in cache) { if (entry matches) return cache entry (or fill and return true) }
return false; }
read_cached_chunk(...) { if (get_cache_entry(...)) return (or fill and return)
issue_read_request(...)
insert new cache entry }
read_input_cache(...) { for (each aligned chunk) read_cached_chunk(...) }
Where the cache is filled can vary while still being idiomatic; it's often best to e.g. return a const struct input_cache_chunk pointer from "read_cached_chunk()", allowing the GstBuffer to be filled in exactly one place. (The function names in that pseudocode aren't very consistent either but should hopefully get the point across well enough.)
We could even further simplify read_input_cache() in this case, since the loop can be at most two iterations and hence doesn't really need to be a loop.