|
|
|
Lines 1018-1033
PRInt64 nsOggReader::FindEndTime(PRInt64
|
Link Here
|
|---|
|
| 1018 |
} |
1018 |
} |
| 1019 |
} |
1019 |
} |
| 1020 |
|
1020 |
|
| 1021 |
ogg_sync_reset(aState); |
1021 |
ogg_sync_reset(aState); |
| 1022 |
|
1022 |
|
| 1023 |
return endTime; |
1023 |
return endTime; |
| 1024 |
} |
1024 |
} |
| 1025 |
|
1025 |
|
|
|
1026 |
nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges) |
| 1027 |
{ |
| 1028 |
NS_ASSERTION(mDecoder->OnStateMachineThread(), |
| 1029 |
"Should be on state machine thread."); |
| 1030 |
mMonitor.AssertCurrentThreadIn(); |
| 1031 |
PRInt64 startOffset = mDataOffset; |
| 1032 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
| 1033 |
while (PR_TRUE) { |
| 1034 |
PRInt64 endOffset = stream->GetCachedDataEnd(startOffset); |
| 1035 |
if (endOffset == startOffset) { |
| 1036 |
// Uncached at startOffset. |
| 1037 |
endOffset = stream->GetNextCachedData(startOffset); |
| 1038 |
if (endOffset == -1) { |
| 1039 |
// Uncached at startOffset until endOffset of stream, or we're at |
| 1040 |
// the end of stream. |
| 1041 |
break; |
| 1042 |
} |
| 1043 |
} else { |
| 1044 |
// Bytes [startOffset..endOffset] are cached. |
| 1045 |
PRInt64 startTime = -1; |
| 1046 |
PRInt64 endTime = -1; |
| 1047 |
if (NS_FAILED(ResetDecode())) { |
| 1048 |
return NS_ERROR_FAILURE; |
| 1049 |
} |
| 1050 |
FindStartTime(startOffset, startTime); |
| 1051 |
if (startTime != -1 && |
| 1052 |
((endTime = FindEndTime(endOffset)) != -1)) |
| 1053 |
{ |
| 1054 |
NS_ASSERTION(startOffset < endOffset, |
| 1055 |
"Start offset must be before end offset"); |
| 1056 |
NS_ASSERTION(startTime < endTime, |
| 1057 |
"Start time must be before end time"); |
| 1058 |
aRanges.AppendElement(SeekRange(startOffset, |
| 1059 |
endOffset, |
| 1060 |
startTime, |
| 1061 |
endTime)); |
| 1062 |
} |
| 1063 |
} |
| 1064 |
startOffset = endOffset; |
| 1065 |
} |
| 1066 |
if (NS_FAILED(ResetDecode())) { |
| 1067 |
return NS_ERROR_FAILURE; |
| 1068 |
} |
| 1069 |
return NS_OK; |
| 1070 |
} |
| 1071 |
|
| 1072 |
nsOggReader::SeekRange |
| 1073 |
nsOggReader::SelectSeekRange(const nsTArray<SeekRange>& ranges, |
| 1074 |
PRInt64 aTarget, |
| 1075 |
PRInt64 aStartTime, |
| 1076 |
PRInt64 aEndTime, |
| 1077 |
PRBool aExact) |
| 1078 |
{ |
| 1079 |
NS_ASSERTION(mDecoder->OnStateMachineThread(), |
| 1080 |
"Should be on state machine thread."); |
| 1081 |
PRInt64 so = mDataOffset; |
| 1082 |
PRInt64 eo = mDecoder->GetCurrentStream()->GetLength(); |
| 1083 |
PRInt64 st = aStartTime; |
| 1084 |
PRInt64 et = aEndTime; |
| 1085 |
for (PRUint32 i = 0; i < ranges.Length(); i++) { |
| 1086 |
const SeekRange &r = ranges[i]; |
| 1087 |
if (r.mTimeStart < aTarget) { |
| 1088 |
so = r.mOffsetStart; |
| 1089 |
st = r.mTimeStart; |
| 1090 |
} |
| 1091 |
if (r.mTimeEnd >= aTarget && r.mTimeEnd < et) { |
| 1092 |
eo = r.mOffsetEnd; |
| 1093 |
et = r.mTimeEnd; |
| 1094 |
} |
| 1095 |
|
| 1096 |
if (r.mTimeStart < aTarget && aTarget <= r.mTimeEnd) { |
| 1097 |
// Target lies exactly in this range. |
| 1098 |
return ranges[i]; |
| 1099 |
} |
| 1100 |
} |
| 1101 |
return aExact ? SeekRange() : SeekRange(so, eo, st, et); |
| 1102 |
} |
| 1103 |
|
| 1026 |
nsOggReader::IndexedSeekResult nsOggReader::RollbackIndexedSeek(PRInt64 aOffset) |
1104 |
nsOggReader::IndexedSeekResult nsOggReader::RollbackIndexedSeek(PRInt64 aOffset) |
| 1027 |
{ |
1105 |
{ |
| 1028 |
mSkeletonState->Deactivate(); |
1106 |
mSkeletonState->Deactivate(); |
| 1029 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
1107 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
| 1030 |
NS_ENSURE_TRUE(stream != nsnull, SEEK_FATAL_ERROR); |
1108 |
NS_ENSURE_TRUE(stream != nsnull, SEEK_FATAL_ERROR); |
| 1031 |
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, aOffset); |
1109 |
nsresult res = stream->Seek(nsISeekableStream::NS_SEEK_SET, aOffset); |
| 1032 |
NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR); |
1110 |
NS_ENSURE_SUCCESS(res, SEEK_FATAL_ERROR); |
| 1033 |
return SEEK_INDEX_FAIL; |
1111 |
return SEEK_INDEX_FAIL; |
|
Lines 1113-1130
nsOggReader::IndexedSeekResult nsOggRead
|
Link Here
|
|---|
|
| 1113 |
} |
1191 |
} |
| 1114 |
mPageOffset = keyframe.mKeyPoint.mOffset + page.header_len + page.body_len; |
1192 |
mPageOffset = keyframe.mKeyPoint.mOffset + page.header_len + page.body_len; |
| 1115 |
return SEEK_OK; |
1193 |
return SEEK_OK; |
| 1116 |
} |
1194 |
} |
| 1117 |
|
1195 |
|
| 1118 |
nsresult nsOggReader::SeekInBufferedRange(PRInt64 aTarget, |
1196 |
nsresult nsOggReader::SeekInBufferedRange(PRInt64 aTarget, |
| 1119 |
PRInt64 aStartTime, |
1197 |
PRInt64 aStartTime, |
| 1120 |
PRInt64 aEndTime, |
1198 |
PRInt64 aEndTime, |
| 1121 |
const nsTArray<ByteRange>& aRanges, |
1199 |
const nsTArray<SeekRange>& aRanges, |
| 1122 |
const ByteRange& aRange) |
1200 |
const SeekRange& aRange) |
| 1123 |
{ |
1201 |
{ |
| 1124 |
LOG(PR_LOG_DEBUG, ("%p Seeking in buffered data to %lldms using bisection search", mDecoder, aTarget)); |
1202 |
LOG(PR_LOG_DEBUG, ("%p Seeking in buffered data to %lldms using bisection search", mDecoder, aTarget)); |
| 1125 |
|
1203 |
|
| 1126 |
// We know the exact byte range in which the target must lie. It must |
1204 |
// We know the exact byte range in which the target must lie. It must |
| 1127 |
// be buffered in the media cache. Seek there. |
1205 |
// be buffered in the media cache. Seek there. |
| 1128 |
nsresult res = SeekBisection(aTarget, aRange, 0); |
1206 |
nsresult res = SeekBisection(aTarget, aRange, 0); |
| 1129 |
if (NS_FAILED(res) || !HasVideo()) { |
1207 |
if (NS_FAILED(res) || !HasVideo()) { |
| 1130 |
return res; |
1208 |
return res; |
|
Lines 1151-1171
nsresult nsOggReader::SeekInBufferedRang
|
Link Here
|
|---|
|
| 1151 |
// First decoded frame isn't a keyframe, seek back to previous keyframe, |
1229 |
// First decoded frame isn't a keyframe, seek back to previous keyframe, |
| 1152 |
// otherwise we'll get visual artifacts. |
1230 |
// otherwise we'll get visual artifacts. |
| 1153 |
NS_ASSERTION(video->mTimecode != -1, "Must have a granulepos"); |
1231 |
NS_ASSERTION(video->mTimecode != -1, "Must have a granulepos"); |
| 1154 |
int shift = mTheoraState->mInfo.keyframe_granule_shift; |
1232 |
int shift = mTheoraState->mInfo.keyframe_granule_shift; |
| 1155 |
PRInt64 keyframeGranulepos = (video->mTimecode >> shift) << shift; |
1233 |
PRInt64 keyframeGranulepos = (video->mTimecode >> shift) << shift; |
| 1156 |
PRInt64 keyframeTime = mTheoraState->StartTime(keyframeGranulepos); |
1234 |
PRInt64 keyframeTime = mTheoraState->StartTime(keyframeGranulepos); |
| 1157 |
SEEK_LOG(PR_LOG_DEBUG, ("Keyframe for %lld is at %lld, seeking back to it", |
1235 |
SEEK_LOG(PR_LOG_DEBUG, ("Keyframe for %lld is at %lld, seeking back to it", |
| 1158 |
video->mTime, keyframeTime)); |
1236 |
video->mTime, keyframeTime)); |
| 1159 |
ByteRange k = GetSeekRange(aRanges, |
1237 |
SeekRange k = SelectSeekRange(aRanges, |
| 1160 |
keyframeTime, |
1238 |
keyframeTime, |
| 1161 |
aStartTime, |
1239 |
aStartTime, |
| 1162 |
aEndTime, |
1240 |
aEndTime, |
| 1163 |
PR_FALSE); |
1241 |
PR_FALSE); |
| 1164 |
res = SeekBisection(keyframeTime, k, SEEK_FUZZ_MS); |
1242 |
res = SeekBisection(keyframeTime, k, SEEK_FUZZ_MS); |
| 1165 |
NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode"); |
1243 |
NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode"); |
| 1166 |
NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode"); |
1244 |
NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode"); |
| 1167 |
} |
1245 |
} |
| 1168 |
return res; |
1246 |
return res; |
| 1169 |
} |
1247 |
} |
| 1170 |
|
1248 |
|
| 1171 |
PRBool nsOggReader::CanDecodeToTarget(PRInt64 aTarget, |
1249 |
PRBool nsOggReader::CanDecodeToTarget(PRInt64 aTarget, |
|
Lines 1177-1193
PRBool nsOggReader::CanDecodeToTarget(PR
|
Link Here
|
|---|
|
| 1177 |
PRInt64 margin = HasVideo() ? mTheoraState->MaxKeyframeOffset() : SEEK_DECODE_MARGIN; |
1255 |
PRInt64 margin = HasVideo() ? mTheoraState->MaxKeyframeOffset() : SEEK_DECODE_MARGIN; |
| 1178 |
return aTarget >= aCurrentTime && |
1256 |
return aTarget >= aCurrentTime && |
| 1179 |
aTarget - aCurrentTime < margin; |
1257 |
aTarget - aCurrentTime < margin; |
| 1180 |
} |
1258 |
} |
| 1181 |
|
1259 |
|
| 1182 |
nsresult nsOggReader::SeekInUnbuffered(PRInt64 aTarget, |
1260 |
nsresult nsOggReader::SeekInUnbuffered(PRInt64 aTarget, |
| 1183 |
PRInt64 aStartTime, |
1261 |
PRInt64 aStartTime, |
| 1184 |
PRInt64 aEndTime, |
1262 |
PRInt64 aEndTime, |
| 1185 |
const nsTArray<ByteRange>& aRanges) |
1263 |
const nsTArray<SeekRange>& aRanges) |
| 1186 |
{ |
1264 |
{ |
| 1187 |
LOG(PR_LOG_DEBUG, ("%p Seeking in unbuffered data to %lldms using bisection search", mDecoder, aTarget)); |
1265 |
LOG(PR_LOG_DEBUG, ("%p Seeking in unbuffered data to %lldms using bisection search", mDecoder, aTarget)); |
| 1188 |
|
1266 |
|
| 1189 |
// If we've got an active Theora bitstream, determine the maximum possible |
1267 |
// If we've got an active Theora bitstream, determine the maximum possible |
| 1190 |
// time in ms which a keyframe could be before a given interframe. We |
1268 |
// time in ms which a keyframe could be before a given interframe. We |
| 1191 |
// subtract this from our seek target, seek to the new target, and then |
1269 |
// subtract this from our seek target, seek to the new target, and then |
| 1192 |
// will decode forward to the original seek target. We should encounter a |
1270 |
// will decode forward to the original seek target. We should encounter a |
| 1193 |
// keyframe in that interval. This prevents us from needing to run two |
1271 |
// keyframe in that interval. This prevents us from needing to run two |
|
Lines 1200-1216
nsresult nsOggReader::SeekInUnbuffered(P
|
Link Here
|
|---|
|
| 1200 |
// keyframe). |
1278 |
// keyframe). |
| 1201 |
PRInt64 keyframeOffsetMs = 0; |
1279 |
PRInt64 keyframeOffsetMs = 0; |
| 1202 |
if (HasVideo() && mTheoraState) { |
1280 |
if (HasVideo() && mTheoraState) { |
| 1203 |
keyframeOffsetMs = mTheoraState->MaxKeyframeOffset(); |
1281 |
keyframeOffsetMs = mTheoraState->MaxKeyframeOffset(); |
| 1204 |
} |
1282 |
} |
| 1205 |
PRInt64 seekTarget = NS_MAX(aStartTime, aTarget - keyframeOffsetMs); |
1283 |
PRInt64 seekTarget = NS_MAX(aStartTime, aTarget - keyframeOffsetMs); |
| 1206 |
// Minimize the bisection search space using the known timestamps from the |
1284 |
// Minimize the bisection search space using the known timestamps from the |
| 1207 |
// buffered ranges. |
1285 |
// buffered ranges. |
| 1208 |
ByteRange k = GetSeekRange(aRanges, seekTarget, aStartTime, aEndTime, PR_FALSE); |
1286 |
SeekRange k = SelectSeekRange(aRanges, seekTarget, aStartTime, aEndTime, PR_FALSE); |
| 1209 |
nsresult res = SeekBisection(seekTarget, k, SEEK_FUZZ_MS); |
1287 |
nsresult res = SeekBisection(seekTarget, k, SEEK_FUZZ_MS); |
| 1210 |
NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode"); |
1288 |
NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode"); |
| 1211 |
NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode"); |
1289 |
NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode"); |
| 1212 |
return res; |
1290 |
return res; |
| 1213 |
} |
1291 |
} |
| 1214 |
|
1292 |
|
| 1215 |
nsresult nsOggReader::Seek(PRInt64 aTarget, |
1293 |
nsresult nsOggReader::Seek(PRInt64 aTarget, |
| 1216 |
PRInt64 aStartTime, |
1294 |
PRInt64 aStartTime, |
|
Lines 1246-1267
nsresult nsOggReader::Seek(PRInt64 aTarg
|
Link Here
|
|---|
|
| 1246 |
"will just decode to it", mDecoder, aCurrentTime, aTarget)); |
1324 |
"will just decode to it", mDecoder, aCurrentTime, aTarget)); |
| 1247 |
} else { |
1325 |
} else { |
| 1248 |
IndexedSeekResult sres = SeekToKeyframeUsingIndex(aTarget); |
1326 |
IndexedSeekResult sres = SeekToKeyframeUsingIndex(aTarget); |
| 1249 |
NS_ENSURE_TRUE(sres != SEEK_FATAL_ERROR, NS_ERROR_FAILURE); |
1327 |
NS_ENSURE_TRUE(sres != SEEK_FATAL_ERROR, NS_ERROR_FAILURE); |
| 1250 |
if (sres == SEEK_INDEX_FAIL) { |
1328 |
if (sres == SEEK_INDEX_FAIL) { |
| 1251 |
// No index or other non-fatal index-related failure. Try to seek |
1329 |
// No index or other non-fatal index-related failure. Try to seek |
| 1252 |
// using a bisection search. Determine the already downloaded data |
1330 |
// using a bisection search. Determine the already downloaded data |
| 1253 |
// in the media cache, so we can try to seek in the cached data first. |
1331 |
// in the media cache, so we can try to seek in the cached data first. |
| 1254 |
nsAutoTArray<ByteRange, 16> ranges; |
1332 |
nsAutoTArray<SeekRange, 16> ranges; |
| 1255 |
res = GetBufferedBytes(ranges); |
1333 |
res = GetSeekRanges(ranges); |
| 1256 |
NS_ENSURE_SUCCESS(res,res); |
1334 |
NS_ENSURE_SUCCESS(res,res); |
| 1257 |
|
1335 |
|
| 1258 |
// Figure out if the seek target lies in a buffered range. |
1336 |
// Figure out if the seek target lies in a buffered range. |
| 1259 |
ByteRange r = GetSeekRange(ranges, aTarget, aStartTime, aEndTime, PR_TRUE); |
1337 |
SeekRange r = SelectSeekRange(ranges, aTarget, aStartTime, aEndTime, PR_TRUE); |
| 1260 |
|
1338 |
|
| 1261 |
if (!r.IsNull()) { |
1339 |
if (!r.IsNull()) { |
| 1262 |
// We know the buffered range in which the seek target lies, do a |
1340 |
// We know the buffered range in which the seek target lies, do a |
| 1263 |
// bisection search in that buffered range. |
1341 |
// bisection search in that buffered range. |
| 1264 |
res = SeekInBufferedRange(aTarget, aStartTime, aEndTime, ranges, r); |
1342 |
res = SeekInBufferedRange(aTarget, aStartTime, aEndTime, ranges, r); |
| 1265 |
NS_ENSURE_SUCCESS(res,res); |
1343 |
NS_ENSURE_SUCCESS(res,res); |
| 1266 |
} else { |
1344 |
} else { |
| 1267 |
// The target doesn't lie in a buffered range. Perform a bisection |
1345 |
// The target doesn't lie in a buffered range. Perform a bisection |
|
Lines 1340-1356
PageSync(nsMediaStream* aStream,
|
Link Here
|
|---|
|
| 1340 |
continue; |
1418 |
continue; |
| 1341 |
} |
1419 |
} |
| 1342 |
} |
1420 |
} |
| 1343 |
|
1421 |
|
| 1344 |
return PAGE_SYNC_OK; |
1422 |
return PAGE_SYNC_OK; |
| 1345 |
} |
1423 |
} |
| 1346 |
|
1424 |
|
| 1347 |
nsresult nsOggReader::SeekBisection(PRInt64 aTarget, |
1425 |
nsresult nsOggReader::SeekBisection(PRInt64 aTarget, |
| 1348 |
const ByteRange& aRange, |
1426 |
const SeekRange& aRange, |
| 1349 |
PRUint32 aFuzz) |
1427 |
PRUint32 aFuzz) |
| 1350 |
{ |
1428 |
{ |
| 1351 |
NS_ASSERTION(mDecoder->OnStateMachineThread(), |
1429 |
NS_ASSERTION(mDecoder->OnStateMachineThread(), |
| 1352 |
"Should be on state machine thread."); |
1430 |
"Should be on state machine thread."); |
| 1353 |
nsresult res; |
1431 |
nsresult res; |
| 1354 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
1432 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
| 1355 |
|
1433 |
|
| 1356 |
if (aTarget == aRange.mTimeStart) { |
1434 |
if (aTarget == aRange.mTimeStart) { |
|
Lines 1711-1719
PRBool nsOggReader::IsKnownStream(PRUint
|
Link Here
|
|---|
|
| 1711 |
PRUint32 serial = mKnownStreams[i]; |
1789 |
PRUint32 serial = mKnownStreams[i]; |
| 1712 |
if (serial == aSerial) { |
1790 |
if (serial == aSerial) { |
| 1713 |
return PR_TRUE; |
1791 |
return PR_TRUE; |
| 1714 |
} |
1792 |
} |
| 1715 |
} |
1793 |
} |
| 1716 |
|
1794 |
|
| 1717 |
return PR_FALSE; |
1795 |
return PR_FALSE; |
| 1718 |
} |
1796 |
} |
| 1719 |
|
|
|