| 1195 | } |
| 1196 | |
| 1197 | std::shared_ptr<Frame> FFmpegReader::GetFrame(int64_t requested_frame) { |
| 1198 | last_seek_max_frame = -1; |
| 1199 | seek_stagnant_count = 0; |
| 1200 | // Check for open reader (or throw exception) |
| 1201 | if (!is_open) |
| 1202 | throw ReaderClosed("The FFmpegReader is closed. Call Open() before calling this method.", path); |
| 1203 | |
| 1204 | // Adjust for a requested frame that is too small or too large |
| 1205 | if (requested_frame < 1) |
| 1206 | requested_frame = 1; |
| 1207 | if (requested_frame > info.video_length && is_duration_known) |
| 1208 | requested_frame = info.video_length; |
| 1209 | if (info.has_video && info.video_length == 0) |
| 1210 | // Invalid duration of video file |
| 1211 | throw InvalidFile("Could not detect the duration of the video or audio stream.", path); |
| 1212 | |
| 1213 | // Debug output |
| 1214 | ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "requested_frame", requested_frame, "last_frame", last_frame); |
| 1215 | |
| 1216 | // Check the cache for this frame |
| 1217 | std::shared_ptr<Frame> frame = final_cache.GetFrame(requested_frame); |
| 1218 | if (frame) { |
| 1219 | // Debug output |
| 1220 | ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame", requested_frame); |
| 1221 | // Return the cached frame |
| 1222 | return frame; |
| 1223 | } else { |
| 1224 | |
| 1225 | // Prevent async calls to the remainder of this code |
| 1226 | const std::lock_guard<std::recursive_mutex> lock(getFrameMutex); |
| 1227 | |
| 1228 | // Check the cache a 2nd time (due to the potential previous lock) |
| 1229 | frame = final_cache.GetFrame(requested_frame); |
| 1230 | if (frame) { |
| 1231 | // Debug output |
| 1232 | ZmqLogger::Instance()->AppendDebugMethod("FFmpegReader::GetFrame", "returned cached frame on 2nd look", requested_frame); |
| 1233 | } else { |
| 1234 | // Frame is not in cache |
| 1235 | // Reset seek count |
| 1236 | seek_count = 0; |
| 1237 | |
| 1238 | // Are we within X frames of the requested frame? |
| 1239 | int64_t diff = requested_frame - last_frame; |
| 1240 | if (diff >= 1 && diff <= 20) { |
| 1241 | // Continue walking the stream |
| 1242 | frame = ReadStream(requested_frame); |
| 1243 | } else { |
| 1244 | // Greater than 30 frames away, or backwards, we need to seek to the nearest key frame |
| 1245 | if (enable_seek) { |
| 1246 | // Only seek if enabled |
| 1247 | Seek(requested_frame); |
| 1248 | |
| 1249 | } else if (!enable_seek && diff < 0) { |
| 1250 | // Start over, since we can't seek, and the requested frame is smaller than our position |
| 1251 | // Since we are seeking to frame 1, this actually just closes/re-opens the reader |
| 1252 | Seek(1); |
| 1253 | } |
| 1254 |
no test coverage detected