Bug 556821 - Use Ogg Skeleton presentation time for start of videos - r=cpearce

--HG--
extra : rebase_source : 83020ac5028e9f94cabe6a3c959cf84eeb25449f
This commit is contained in:
Chris Double 2011-03-24 14:16:30 +13:00
parent 1ba8c47fbd
commit 143856bc77
6 changed files with 37 additions and 10 deletions

View File

@ -394,6 +394,7 @@ PRInt64 nsVorbisState::Time(vorbis_info* aInfo, PRInt64 aGranulepos)
nsSkeletonState::nsSkeletonState(ogg_page* aBosPage)
: nsOggCodecState(aBosPage),
mVersion(0),
mPresentationTime(0),
mLength(0)
{
MOZ_COUNT_CTOR(nsSkeletonState);
@ -407,7 +408,8 @@ nsSkeletonState::~nsSkeletonState()
// Support for Ogg Skeleton 4.0, as per specification at:
// http://wiki.xiph.org/Ogg_Skeleton_4
// Minimum length in bytes of a Skeleton 4.0 header packet.
// Minimum length in bytes of a Skeleton header packet.
#define SKELETON_MIN_HEADER_LEN 28
#define SKELETON_4_0_MIN_HEADER_LEN 80
// Minimum length in bytes of a Skeleton 4.0 index packet.
@ -421,6 +423,10 @@ nsSkeletonState::~nsSkeletonState()
#define SKELETON_VERSION_MAJOR_OFFSET 8
#define SKELETON_VERSION_MINOR_OFFSET 10
// Byte-offsets of the presentation time numerator and denominator
#define SKELETON_PRESENTATION_TIME_NUMERATOR_OFFSET 12
#define SKELETON_PRESENTATION_TIME_DENOMINATOR_OFFSET 20
// Byte-offsets of the length of file field in the Skeleton 4.0 header packet.
#define SKELETON_FILE_LENGTH_OFFSET 64
@ -434,7 +440,7 @@ nsSkeletonState::~nsSkeletonState()
static PRBool IsSkeletonBOS(ogg_packet* aPacket)
{
return aPacket->bytes >= SKELETON_4_0_MIN_HEADER_LEN &&
return aPacket->bytes >= SKELETON_MIN_HEADER_LEN &&
memcmp(reinterpret_cast<char*>(aPacket->packet), "fishead", 8) == 0;
}
@ -699,6 +705,13 @@ PRBool nsSkeletonState::DecodeHeader(ogg_packet* aPacket)
if (IsSkeletonBOS(aPacket)) {
PRUint16 verMajor = LEUint16(aPacket->packet + SKELETON_VERSION_MAJOR_OFFSET);
PRUint16 verMinor = LEUint16(aPacket->packet + SKELETON_VERSION_MINOR_OFFSET);
// Read the presentation time. We read this before the version check as the
// presentation time exists in all versions.
PRInt64 n = LEInt64(aPacket->packet + SKELETON_PRESENTATION_TIME_NUMERATOR_OFFSET);
PRInt64 d = LEInt64(aPacket->packet + SKELETON_PRESENTATION_TIME_DENOMINATOR_OFFSET);
mPresentationTime = d == 0 ? 0 : (static_cast<float>(n) / static_cast<float>(d)) * 1000;
mVersion = SKELETON_VERSION(verMajor, verMinor);
if (mVersion < SKELETON_VERSION(4,0) ||
mVersion >= SKELETON_VERSION(5,0) ||

View File

@ -214,6 +214,9 @@ public:
virtual PRInt64 Time(PRInt64 granulepos) { return -1; }
virtual PRBool Init() { return PR_TRUE; }
// Return PR_TRUE if the given time (in milliseconds) is within
// the presentation time defined in the skeleton track.
PRBool IsPresentable(PRInt64 aTime) { return aTime >= mPresentationTime; }
// Stores the offset of the page on which a keyframe starts,
// and its presentation time.
@ -283,6 +286,9 @@ private:
// Version of the decoded skeleton track, as per the SKELETON_VERSION macro.
PRUint32 mVersion;
// Presentation time of the resource in milliseconds
PRInt64 mPresentationTime;
// Length of the resource in bytes.
PRInt64 mLength;

View File

@ -628,7 +628,7 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
// packets we read subsequently.
mTheoraGranulepos = packet.granulepos;
}
if (DecodeTheora(frames, &packet) == NS_ERROR_OUT_OF_MEMORY) {
NS_WARNING("Theora decode memory allocation failure!");
return PR_FALSE;
@ -741,6 +741,7 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
PRInt64 time = mTheoraState->StartTime(mTheoraGranulepos);
NS_ASSERTION(packet.granulepos != -1, "Must know packet granulepos");
if (!aKeyframeSkip ||
(th_packet_iskeyframe(&packet) == 1 && time >= aTimeThreshold))
{
@ -754,13 +755,17 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
// Push decoded data into the video frame queue.
for (PRUint32 i = 0; i < frames.Length(); i++) {
nsAutoPtr<VideoData> data(frames[i].forget());
if (aKeyframeSkip && data->mKeyframe) {
aKeyframeSkip = PR_FALSE;
}
if (!aKeyframeSkip && data->mEndTime >= aTimeThreshold) {
mVideoQueue.Push(data.forget());
decoded++;
// Don't use the frame if it's outside the bounds of the presentation
// start time in the skeleton track.
if (!mSkeletonState || mSkeletonState->IsPresentable(data->mTime)) {
if (aKeyframeSkip && data->mKeyframe) {
aKeyframeSkip = PR_FALSE;
}
if (!aKeyframeSkip && data->mEndTime >= aTimeThreshold) {
mVideoQueue.Push(data.forget());
decoded++;
}
}
}

View File

@ -201,6 +201,7 @@ _TEST_FILES += \
bug523816.ogv \
bug533822.ogg \
bug557094.ogv \
bug556821.ogv \
bug580982.webm \
bug603918.webm \
bug604067.webm \

Binary file not shown.

View File

@ -74,6 +74,8 @@ var gPlayTests = [
{ name:"bug504613.ogv", type:"video/ogg", duration:Number.NaN },
// Multiple audio streams.
{ name:"bug516323.ogv", type:"video/ogg", duration:4.208 },
// oggz-chop with non-keyframe as first frame
{ name:"bug556821.ogv", type:"video/ogg", duration:2.551 },
// Encoded with vorbis beta1, includes unusually sized codebooks
{ name:"beta-phrasebook.ogg", type:"audio/ogg", duration:4.01 },