|
25 | 25 | #include "indexing.h" |
26 | 26 |
|
27 | 27 | #include <algorithm> |
| 28 | +#include <array> |
28 | 29 | #include <cmath> |
29 | 30 | #include <cstdlib> |
30 | 31 |
|
@@ -157,23 +158,79 @@ static bool PTSComparison(FrameInfo FI1, FrameInfo FI2) { |
157 | 158 | return FI1.PTS < FI2.PTS; |
158 | 159 | } |
159 | 160 |
|
160 | | -int FFMS_Track::FrameFromPTS(int64_t PTS, bool AllowHidden) const { |
| 161 | +enum class AVPacketProp { |
| 162 | + TS, // can be PTS or DTS depending on UseDTS |
| 163 | + Pos, |
| 164 | + Hidden, |
| 165 | + Key, |
| 166 | +}; |
| 167 | + |
| 168 | +const std::array<std::vector<AVPacketProp>, 5> FindPacketCheckSequence = {{ |
| 169 | + {AVPacketProp::TS, AVPacketProp::Pos, AVPacketProp::Hidden, AVPacketProp::Key}, |
| 170 | + {AVPacketProp::TS, AVPacketProp::Pos, AVPacketProp::Hidden}, |
| 171 | + {AVPacketProp::TS, AVPacketProp::Pos}, |
| 172 | + {AVPacketProp::TS}, |
| 173 | + {AVPacketProp::Pos}, |
| 174 | +}}; |
| 175 | + |
| 176 | +// Attempts to find the given AVPacket in the track's list of FrameInfos, |
| 177 | +// returning the FrameInfo's index if one was found and -1 if not. |
| 178 | +// |
| 179 | +// The finding logic begins by trying to find a *unique* FrameInfo whose |
| 180 | +// PTS, Pos, and flags match the given packet. |
| 181 | +// If no such packet exists, it tries a fallback sequence of comparing fewer fields. |
| 182 | +// |
| 183 | +// The current fallback sequence is mostly chosen based on intuition - for |
| 184 | +// well-behaved files simply checking all fields should work fine. |
| 185 | +// If examples come up where this fallback sequence becomes relevant, it can |
| 186 | +// be adjusted. |
| 187 | +int FFMS_Track::FindPacket(const AVPacket &packet) const { |
161 | 188 | FrameInfo F; |
162 | | - F.PTS = PTS; |
| 189 | + F.PTS = UseDTS ? packet.dts : packet.pts; |
163 | 190 |
|
164 | | - auto Pos = std::lower_bound(begin(), end(), F, PTSComparison); |
165 | | - while (Pos != end() && (!AllowHidden && Pos->Skipped()) && Pos->PTS == PTS) |
166 | | - Pos++; |
| 191 | + auto SameTSRange = std::equal_range(begin(), end(), F, PTSComparison);; |
167 | 192 |
|
168 | | - if (Pos == end() || Pos->PTS != PTS) |
169 | | - return -1; |
170 | | - return std::distance(begin(), Pos); |
171 | | -} |
| 193 | + for (auto const& checks : FindPacketCheckSequence) { |
| 194 | + // If the check sequence includes the timestamp, we can begin with a binary search |
| 195 | + // since the FrameInfos are sorted by their timestamp, and then do a linear search in the found interval. |
| 196 | + // If the check sequence does not include the timestamp, we have to do a full linear search. |
| 197 | + auto Begin = begin(); |
| 198 | + auto End = end(); |
| 199 | + |
| 200 | + if (checks[0] == AVPacketProp::TS) { |
| 201 | + Begin = SameTSRange.first; |
| 202 | + End = SameTSRange.second; |
| 203 | + } |
| 204 | + |
| 205 | + int found = 0; |
| 206 | + int result = -1; |
| 207 | + |
| 208 | + for (auto it = Begin; it < End; it++) { |
| 209 | + bool match = std::all_of(checks.cbegin(), checks.cend(), [&](AVPacketProp check) { |
| 210 | + switch (check) { |
| 211 | + case AVPacketProp::TS: |
| 212 | + return it->PTS == F.PTS; |
| 213 | + case AVPacketProp::Pos: |
| 214 | + return it->FilePos == packet.pos; |
| 215 | + case AVPacketProp::Hidden: |
| 216 | + return it->MarkedHidden == (packet.flags & AV_PKT_FLAG_DISCARD); |
| 217 | + case AVPacketProp::Key: |
| 218 | + return it->KeyFrame == (packet.flags & AV_PKT_FLAG_KEY); |
| 219 | + } |
| 220 | + return false; |
| 221 | + }); |
| 222 | + |
| 223 | + if (match) { |
| 224 | + found++; |
| 225 | + result = std::distance(begin(), it); |
| 226 | + } |
| 227 | + } |
| 228 | + |
| 229 | + if (found == 1) { |
| 230 | + return result; |
| 231 | + } |
| 232 | + } |
172 | 233 |
|
173 | | -int FFMS_Track::FrameFromPos(int64_t Pos, bool AllowHidden) const { |
174 | | - for (size_t i = 0; i < size(); i++) |
175 | | - if (Data->Frames[i].FilePos == Pos && (AllowHidden || !Data->Frames[i].Skipped())) |
176 | | - return static_cast<int>(i); |
177 | 234 | return -1; |
178 | 235 | } |
179 | 236 |
|
|
0 commit comments