diff --git a/content/media/video/public/nsMediaDecoder.h b/content/media/video/public/nsMediaDecoder.h index 026a59cef2fa..c06dc466d722 100644 --- a/content/media/video/public/nsMediaDecoder.h +++ b/content/media/video/public/nsMediaDecoder.h @@ -244,12 +244,14 @@ protected: // Stop progress information timer. nsresult StopProgress(); - // Set the RGB width, height and framerate. Ownership of the passed RGB - // buffer is transferred to the decoder. This is the only nsMediaDecoder - // method that may be called from threads other than the main thread. + // Set the RGB width, height, pixel aspect ratio, and framerate. + // Ownership of the passed RGB buffer is transferred to the decoder. + // This is the only nsMediaDecoder method that may be called from + // threads other than the main thread. void SetRGBData(PRInt32 aWidth, PRInt32 aHeight, float aFramerate, + float aAspectRatio, unsigned char* aRGBBuffer); protected: @@ -295,6 +297,9 @@ protected: // expressed in numbers of frames per second. float mFramerate; + // Pixel aspect ratio (ratio of the pixel width to pixel height) + float mAspectRatio; + // Has our size changed since the last repaint? PRPackedBool mSizeChanged; diff --git a/content/media/video/src/nsMediaDecoder.cpp b/content/media/video/src/nsMediaDecoder.cpp index 258db168d836..97e5225ab56b 100644 --- a/content/media/video/src/nsMediaDecoder.cpp +++ b/content/media/video/src/nsMediaDecoder.cpp @@ -72,6 +72,7 @@ nsMediaDecoder::nsMediaDecoder() : mDataTime(), mVideoUpdateLock(nsnull), mFramerate(0.0), + mAspectRatio(1.0), mSizeChanged(PR_FALSE), mShuttingDown(PR_FALSE), mStopping(PR_FALSE) @@ -114,6 +115,14 @@ nsresult nsMediaDecoder::InitLogger() return NS_OK; } +static PRInt32 ConditionDimension(float aValue, PRInt32 aDefault) +{ + // This will exclude NaNs and infinities + if (aValue >= 1.0 && aValue <= 10000.0) + return PRInt32(NS_round(aValue)); + return aDefault; +} + void nsMediaDecoder::Invalidate() { if (!mElement) @@ -124,7 +133,20 @@ void nsMediaDecoder::Invalidate() { nsAutoLock lock(mVideoUpdateLock); if (mSizeChanged) { - mElement->UpdateMediaSize(nsIntSize(mRGBWidth, mRGBHeight)); + nsIntSize scaledSize(mRGBWidth, mRGBHeight); + // Apply the aspect ratio to produce the intrinsic size we report + // to the element. + if (mAspectRatio > 1.0) { + // Increase the intrinsic width + scaledSize.width = + ConditionDimension(mAspectRatio*scaledSize.width, scaledSize.width); + } else { + // Increase the intrinsic height + scaledSize.height = + ConditionDimension(scaledSize.height/mAspectRatio, scaledSize.height); + } + mElement->UpdateMediaSize(scaledSize); + mSizeChanged = PR_FALSE; if (frame) { nsPresContext* presContext = frame->PresContext(); @@ -200,13 +222,16 @@ nsresult nsMediaDecoder::StopProgress() return rv; } -void nsMediaDecoder::SetRGBData(PRInt32 aWidth, PRInt32 aHeight, float aFramerate, unsigned char* aRGBBuffer) +void nsMediaDecoder::SetRGBData(PRInt32 aWidth, PRInt32 aHeight, float aFramerate, + float aAspectRatio, unsigned char* aRGBBuffer) { nsAutoLock lock(mVideoUpdateLock); - if (mRGBWidth != aWidth || mRGBHeight != aHeight) { + if (mRGBWidth != aWidth || mRGBHeight != aHeight || + mAspectRatio != aAspectRatio) { mRGBWidth = aWidth; mRGBHeight = aHeight; + mAspectRatio = aAspectRatio; mSizeChanged = PR_TRUE; } mFramerate = aFramerate; diff --git a/content/media/video/src/nsOggDecoder.cpp b/content/media/video/src/nsOggDecoder.cpp index 2cca639eecf7..45edb99e95d5 100644 --- a/content/media/video/src/nsOggDecoder.cpp +++ b/content/media/video/src/nsOggDecoder.cpp @@ -473,6 +473,7 @@ private: // They are only accessed from the decoder thread. PRInt32 mVideoTrack; float mFramerate; + float mAspectRatio; // Audio data. These are initially set when the metadata is loaded. // They are only accessed from the decoder thread. @@ -660,6 +661,7 @@ nsOggDecodeStateMachine::nsOggDecodeStateMachine(nsOggDecoder* aDecoder) : mCallbackPeriod(1.0), mVideoTrack(-1), mFramerate(0.0), + mAspectRatio(1.0), mAudioRate(0), mAudioChannels(0), mAudioTrack(-1), @@ -933,7 +935,8 @@ void nsOggDecodeStateMachine::PlayVideo(FrameData* aFrame) oggplay_yuv2bgra(&yuv, &rgb); - mDecoder->SetRGBData(aFrame->mVideoWidth, aFrame->mVideoHeight, mFramerate, buffer.forget()); + mDecoder->SetRGBData(aFrame->mVideoWidth, aFrame->mVideoHeight, + mFramerate, mAspectRatio, buffer.forget()); } } @@ -1550,10 +1553,18 @@ void nsOggDecodeStateMachine::LoadOggHeaders(nsChannelReader* aReader) mCallbackPeriod = 1.0 / mFramerate; LOG(PR_LOG_DEBUG, ("Frame rate: %f", mFramerate)); + int aspectd, aspectn; + // this can return E_OGGPLAY_UNINITIALIZED if the video has + // no aspect ratio data. We assume 1.0 in that case. + OggPlayErrorCode r = + oggplay_get_video_aspect_ratio(mPlayer, i, &aspectd, &aspectn); + mAspectRatio = r == E_OGGPLAY_OK && aspectd > 0 ? + float(aspectn)/float(aspectd) : 1.0; + int y_width; int y_height; oggplay_get_video_y_size(mPlayer, i, &y_width, &y_height); - mDecoder->SetRGBData(y_width, y_height, mFramerate, nsnull); + mDecoder->SetRGBData(y_width, y_height, mFramerate, mAspectRatio, nsnull); } else if (mAudioTrack == -1 && oggplay_get_track_type(mPlayer, i) == OGGZ_CONTENT_VORBIS) { mAudioTrack = i;