|
|
|
Lines 1023-1072
PRInt64 nsOggReader::FindEndTime(PRInt64
|
Link Here
|
|---|
|
| 1023 |
return endTime; |
1023 |
return endTime; |
| 1024 |
} |
1024 |
} |
| 1025 |
|
1025 |
|
| 1026 |
nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges) |
1026 |
nsresult nsOggReader::GetSeekRanges(nsTArray<SeekRange>& aRanges) |
| 1027 |
{ |
1027 |
{ |
| 1028 |
NS_ASSERTION(mDecoder->OnStateMachineThread(), |
1028 |
NS_ASSERTION(mDecoder->OnStateMachineThread(), |
| 1029 |
"Should be on state machine thread."); |
1029 |
"Should be on state machine thread."); |
| 1030 |
mMonitor.AssertCurrentThreadIn(); |
1030 |
mMonitor.AssertCurrentThreadIn(); |
| 1031 |
PRInt64 startOffset = mDataOffset; |
1031 |
nsTArray<nsByteRange> cached; |
| 1032 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
1032 |
nsresult res = mDecoder->GetCurrentStream()->GetCachedRanges(cached); |
| 1033 |
while (PR_TRUE) { |
1033 |
NS_ENSURE_SUCCESS(res, res); |
| 1034 |
PRInt64 endOffset = stream->GetCachedDataEnd(startOffset); |
1034 |
|
| 1035 |
if (endOffset == startOffset) { |
1035 |
for (PRUint32 index = 0; index < aRanges.Length(); index++) { |
| 1036 |
// Uncached at startOffset. |
1036 |
nsByteRange& range = cached[index]; |
| 1037 |
endOffset = stream->GetNextCachedData(startOffset); |
1037 |
PRInt64 startTime = -1; |
| 1038 |
if (endOffset == -1) { |
1038 |
PRInt64 endTime = -1; |
| 1039 |
// Uncached at startOffset until endOffset of stream, or we're at |
1039 |
if (NS_FAILED(ResetDecode())) { |
| 1040 |
// the end of stream. |
1040 |
return NS_ERROR_FAILURE; |
| 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 |
} |
1041 |
} |
| 1064 |
startOffset = endOffset; |
1042 |
// Ensure the offsets are after the header pages. |
|
|
1043 |
PRInt64 startOffset = NS_MAX(cached[index].mStart, mDataOffset); |
| 1044 |
PRInt64 endOffset = NS_MAX(cached[index].mEnd, mDataOffset); |
| 1045 |
|
| 1046 |
FindStartTime(startOffset, startTime); |
| 1047 |
if (startTime != -1 && |
| 1048 |
((endTime = FindEndTime(endOffset)) != -1)) |
| 1049 |
{ |
| 1050 |
NS_ASSERTION(startTime < endTime, |
| 1051 |
"Start time must be before end time"); |
| 1052 |
aRanges.AppendElement(SeekRange(startOffset, |
| 1053 |
endOffset, |
| 1054 |
startTime, |
| 1055 |
endTime)); |
| 1056 |
} |
| 1065 |
} |
1057 |
} |
| 1066 |
if (NS_FAILED(ResetDecode())) { |
1058 |
if (NS_FAILED(ResetDecode())) { |
| 1067 |
return NS_ERROR_FAILURE; |
1059 |
return NS_ERROR_FAILURE; |
| 1068 |
} |
1060 |
} |
| 1069 |
return NS_OK; |
1061 |
return NS_OK; |
| 1070 |
} |
1062 |
} |
| 1071 |
|
1063 |
|
| 1072 |
nsOggReader::SeekRange |
1064 |
nsOggReader::SeekRange |
|
Lines 1681-1721
nsresult nsOggReader::GetBuffered(nsTime
|
Link Here
|
|---|
|
| 1681 |
// after metadata is read and GetBuffered isn't called before metadata is |
1673 |
// after metadata is read and GetBuffered isn't called before metadata is |
| 1682 |
// read. |
1674 |
// read. |
| 1683 |
if (!mInfo.mHasVideo && !mInfo.mHasAudio) { |
1675 |
if (!mInfo.mHasVideo && !mInfo.mHasAudio) { |
| 1684 |
// No need to search through the file if there are no audio or video tracks |
1676 |
// No need to search through the file if there are no audio or video tracks |
| 1685 |
return NS_OK; |
1677 |
return NS_OK; |
| 1686 |
} |
1678 |
} |
| 1687 |
|
1679 |
|
| 1688 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
1680 |
nsMediaStream* stream = mDecoder->GetCurrentStream(); |
|
|
1681 |
nsTArray<nsByteRange> ranges; |
| 1682 |
nsresult res = stream->GetCachedRanges(ranges); |
| 1683 |
NS_ENSURE_SUCCESS(res, res); |
| 1689 |
|
1684 |
|
| 1690 |
// Traverse across the buffered byte ranges, determining the time ranges |
1685 |
// Traverse across the buffered byte ranges, determining the time ranges |
| 1691 |
// they contain. nsMediaStream::GetNextCachedData(offset) returns -1 when |
1686 |
// they contain. nsMediaStream::GetNextCachedData(offset) returns -1 when |
| 1692 |
// offset is after the end of the media stream, or there's no more cached |
1687 |
// offset is after the end of the media stream, or there's no more cached |
| 1693 |
// data after the offset. This loop will run until we've checked every |
1688 |
// data after the offset. This loop will run until we've checked every |
| 1694 |
// buffered range in the media, in increasing order of offset. |
1689 |
// buffered range in the media, in increasing order of offset. |
| 1695 |
ogg_sync_state state; |
1690 |
ogg_sync_state state; |
| 1696 |
ogg_sync_init(&state); |
1691 |
ogg_sync_init(&state); |
| 1697 |
PRInt64 startOffset = stream->GetNextCachedData(mDataOffset); |
1692 |
for (PRUint32 index = 0; index < ranges.Length(); index++) { |
| 1698 |
while (startOffset >= 0) { |
1693 |
// Ensure the offsets are after the header pages. |
| 1699 |
PRInt64 endOffset = stream->GetCachedDataEnd(startOffset); |
1694 |
PRInt64 startOffset = NS_MAX(ranges[index].mStart, mDataOffset); |
| 1700 |
NS_ASSERTION(startOffset < endOffset, "Buffered range must end after its start"); |
1695 |
PRInt64 endOffset = NS_MAX(ranges[index].mEnd, mDataOffset); |
| 1701 |
// Bytes [startOffset..endOffset] are cached. |
|
|
| 1702 |
|
1696 |
|
| 1703 |
// Find the start time of the range. |
1697 |
// Because the granulepos time is actually the end time of the page, |
| 1704 |
PRInt64 startTime = -1; |
1698 |
// we special-case (startOffset == mDataOffset) so that the first |
| 1705 |
if (startOffset == mDataOffset) { |
1699 |
// buffered range always appears to be buffered from the media start |
| 1706 |
// Because the granulepos time is actually the end time of the page, |
1700 |
// time, rather than from the end-time of the first page. |
| 1707 |
// we special-case (startOffset == mDataOffset) so that the first |
1701 |
PRInt64 startTime = (startOffset == mDataOffset) ? aStartTime : -1; |
| 1708 |
// buffered range always appears to be buffered from [t=0...] rather |
1702 |
|
| 1709 |
// than from the end-time of the first page. |
1703 |
// Find the start time of the range. Read pages until we find one with a |
| 1710 |
startTime = aStartTime; |
1704 |
// granulepos which we can convert into a timestamp to use as the time of |
| 1711 |
} |
1705 |
// the start of the buffered range. |
| 1712 |
// Read pages until we find one with a granulepos which we can convert |
|
|
| 1713 |
// into a timestamp to use as the time of the start of the buffered range. |
| 1714 |
ogg_sync_reset(&state); |
1706 |
ogg_sync_reset(&state); |
| 1715 |
while (startTime == -1) { |
1707 |
while (startTime == -1) { |
| 1716 |
ogg_page page; |
1708 |
ogg_page page; |
| 1717 |
PRInt32 discard; |
1709 |
PRInt32 discard; |
| 1718 |
PageSyncResult res = PageSync(stream, |
1710 |
PageSyncResult res = PageSync(stream, |
| 1719 |
&state, |
1711 |
&state, |
| 1720 |
PR_TRUE, |
1712 |
PR_TRUE, |
| 1721 |
startOffset, |
1713 |
startOffset, |
|
Lines 1753-1785
nsresult nsOggReader::GetBuffered(nsTime
|
Link Here
|
|---|
|
| 1753 |
// Stream is not the theora or vorbis stream we're playing, |
1745 |
// Stream is not the theora or vorbis stream we're playing, |
| 1754 |
// but is one that we have header data for. |
1746 |
// but is one that we have header data for. |
| 1755 |
startOffset += page.header_len + page.body_len; |
1747 |
startOffset += page.header_len + page.body_len; |
| 1756 |
continue; |
1748 |
continue; |
| 1757 |
} |
1749 |
} |
| 1758 |
else { |
1750 |
else { |
| 1759 |
// Page is for a stream we don't know about (possibly a chained |
1751 |
// Page is for a stream we don't know about (possibly a chained |
| 1760 |
// ogg), return an error. |
1752 |
// ogg), return an error. |
|
|
1753 |
ogg_sync_clear(&state); |
| 1761 |
return PAGE_SYNC_ERROR; |
1754 |
return PAGE_SYNC_ERROR; |
| 1762 |
} |
1755 |
} |
| 1763 |
} |
1756 |
} |
| 1764 |
|
1757 |
|
| 1765 |
if (startTime != -1) { |
1758 |
if (startTime != -1) { |
| 1766 |
// We were able to find a start time for that range, see if we can |
1759 |
// We were able to find a start time for that range, see if we can |
| 1767 |
// find an end time. |
1760 |
// find an end time. |
| 1768 |
PRInt64 endTime = FindEndTime(startOffset, endOffset, PR_TRUE, &state); |
1761 |
PRInt64 endTime = FindEndTime(startOffset, endOffset, PR_TRUE, &state); |
| 1769 |
if (endTime != -1) { |
1762 |
if (endTime != -1) { |
| 1770 |
endTime -= aStartTime; |
1763 |
endTime -= aStartTime; |
| 1771 |
aBuffered->Add(static_cast<double>(startTime) / 1000.0, |
1764 |
aBuffered->Add(static_cast<double>(startTime) / 1000.0, |
| 1772 |
static_cast<double>(endTime) / 1000.0); |
1765 |
static_cast<double>(endTime) / 1000.0); |
| 1773 |
} |
1766 |
} |
| 1774 |
} |
1767 |
} |
| 1775 |
startOffset = stream->GetNextCachedData(endOffset); |
|
|
| 1776 |
NS_ASSERTION(startOffset == -1 || startOffset > endOffset, |
| 1777 |
"Must have advanced to start of next range, or hit end of stream"); |
| 1778 |
} |
1768 |
} |
| 1779 |
|
1769 |
|
| 1780 |
// If we don't clear the sync state before exit we'll leak. |
1770 |
// If we don't clear the sync state before exit we'll leak. |
| 1781 |
ogg_sync_clear(&state); |
1771 |
ogg_sync_clear(&state); |
| 1782 |
|
1772 |
|
| 1783 |
return NS_OK; |
1773 |
return NS_OK; |
| 1784 |
} |
1774 |
} |
| 1785 |
|
1775 |
|