зеркало из https://github.com/mozilla/gecko-dev.git
Bug 823646 - Handle dynamic format changes and video frame display apperature attributes in WMFReader. r=padenot
This commit is contained in:
Родитель
aac86acc69
Коммит
8edb1916a3
|
@ -100,14 +100,14 @@ bool IsWindows7OrLater()
|
|||
return versionInfo.dwMajorVersion > 6 ||
|
||||
(versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1);
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WMFDecoder::IsEnabled()
|
||||
{
|
||||
// We only use WMF on Windows 7 and up, until we can properly test Vista
|
||||
// and how it responds with and without the Platform Update installed.
|
||||
return IsWindows7OrLater() &&
|
||||
// We only use WMF on Windows 7 and up, until we can properly test Vista
|
||||
// and how it responds with and without the Platform Update installed.
|
||||
return IsWindows7OrLater() &&
|
||||
Preferences::GetBool("media.windows-media-foundation.enabled");
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ WMFReader::WMFReader(MediaDecoder* aDecoder)
|
|||
mAudioChannels(0),
|
||||
mAudioBytesPerSample(0),
|
||||
mAudioRate(0),
|
||||
mVideoWidth(0),
|
||||
mVideoHeight(0),
|
||||
mVideoStride(0),
|
||||
mHasAudio(false),
|
||||
|
@ -234,6 +233,113 @@ GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
|
|||
return hr;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
MFOffsetToInt32(const MFOffset& aOffset)
|
||||
{
|
||||
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
|
||||
}
|
||||
|
||||
// Gets the sub-region of the video frame that should be displayed.
|
||||
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
|
||||
static HRESULT
|
||||
GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion)
|
||||
{
|
||||
// Determine if "pan and scan" is enabled for this media. If it is, we
|
||||
// only display a region of the video frame, not the entire frame.
|
||||
BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
|
||||
|
||||
// If pan and scan mode is enabled. Try to get the display region.
|
||||
HRESULT hr = E_FAIL;
|
||||
MFVideoArea videoArea;
|
||||
memset(&videoArea, 0, sizeof(MFVideoArea));
|
||||
if (panScan) {
|
||||
hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
NULL);
|
||||
}
|
||||
|
||||
// If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
|
||||
// check for a minimimum display aperture.
|
||||
if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
|
||||
hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (hr == MF_E_ATTRIBUTENOTFOUND) {
|
||||
// Minimum display aperture is not set, for "backward compatibility with
|
||||
// some components", check for a geometric aperture.
|
||||
hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
|
||||
(UINT8*)&videoArea,
|
||||
sizeof(MFVideoArea),
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
// The media specified a picture region, return it.
|
||||
aOutPictureRegion = nsIntRect(MFOffsetToInt32(videoArea.OffsetX),
|
||||
MFOffsetToInt32(videoArea.OffsetY),
|
||||
videoArea.Area.cx,
|
||||
videoArea.Area.cy);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// No picture region defined, fall back to using the entire video area.
|
||||
UINT32 width = 0, height = 0;
|
||||
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
aOutPictureRegion = nsIntRect(0, 0, width, height);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WMFReader::ConfigureVideoFrameGeometry(IMFMediaType* aMediaType)
|
||||
{
|
||||
NS_ENSURE_TRUE(aMediaType != nullptr, E_POINTER);
|
||||
|
||||
nsIntRect pictureRegion;
|
||||
HRESULT hr = GetPictureRegion(aMediaType, pictureRegion);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
UINT32 width = 0, height = 0;
|
||||
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
uint32_t aspectNum = 0, aspectDenom = 0;
|
||||
hr = MFGetAttributeRatio(aMediaType,
|
||||
MF_MT_PIXEL_ASPECT_RATIO,
|
||||
&aspectNum,
|
||||
&aspectDenom);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
// Calculate and validate the picture region and frame dimensions after
|
||||
// scaling by the pixel aspect ratio.
|
||||
nsIntSize frameSize = nsIntSize(width, height);
|
||||
nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
|
||||
ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
|
||||
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRegion, displaySize)) {
|
||||
// Video track's frame sizes will overflow. Ignore the video track.
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Success! Save state.
|
||||
mInfo.mDisplay = displaySize;
|
||||
GetDefaultStride(aMediaType, &mVideoStride);
|
||||
mVideoHeight = height;
|
||||
mPictureRegion = pictureRegion;
|
||||
|
||||
LOG("WMFReader frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d",
|
||||
width, height,
|
||||
mVideoStride,
|
||||
mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
|
||||
displaySize.width, displaySize.height,
|
||||
aspectNum, aspectDenom);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void
|
||||
WMFReader::ConfigureVideoDecoder()
|
||||
{
|
||||
|
@ -266,35 +372,11 @@ WMFReader::ConfigureVideoDecoder()
|
|||
return;
|
||||
}
|
||||
|
||||
if (FAILED(MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &mVideoWidth, &mVideoHeight))) {
|
||||
NS_WARNING("WMF video decoder failed to get frame dimensions!");
|
||||
if (FAILED(ConfigureVideoFrameGeometry(mediaType))) {
|
||||
NS_WARNING("Failed configured video frame dimensions");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("Video frame %u x %u", mVideoWidth, mVideoHeight);
|
||||
uint32_t aspectNum = 0, aspectDenom = 0;
|
||||
if (FAILED(MFGetAttributeRatio(mediaType,
|
||||
MF_MT_PIXEL_ASPECT_RATIO,
|
||||
&aspectNum,
|
||||
&aspectDenom))) {
|
||||
NS_WARNING("WMF video decoder failed to get pixel aspect ratio!");
|
||||
return;
|
||||
}
|
||||
LOG("Video aspect ratio %u x %u", aspectNum, aspectDenom);
|
||||
|
||||
GetDefaultStride(mediaType, &mVideoStride);
|
||||
|
||||
// Calculate and validate the frame size.
|
||||
nsIntSize frameSize = nsIntSize(mVideoWidth, mVideoHeight);
|
||||
nsIntRect pictureRegion = nsIntRect(0, 0, mVideoWidth, mVideoHeight);
|
||||
nsIntSize displaySize = frameSize;
|
||||
ScaleDisplayByAspectRatio(displaySize, float(aspectNum)/float(aspectDenom));
|
||||
if (!VideoInfo::ValidateVideoRegion(frameSize, pictureRegion, displaySize)) {
|
||||
// Video track's frame sizes will overflow. Ignore the video track.
|
||||
return;
|
||||
}
|
||||
mInfo.mDisplay = displaySize;
|
||||
|
||||
LOG("Successfully configured video stream");
|
||||
|
||||
mHasVideo = mInfo.mHasVideo = true;
|
||||
|
@ -406,7 +488,10 @@ WMFReader::DecodeAudioData()
|
|||
|
||||
if (FAILED(hr) ||
|
||||
(flags & MF_SOURCE_READERF_ERROR) ||
|
||||
(flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
|
||||
(flags & MF_SOURCE_READERF_ENDOFSTREAM) ||
|
||||
(flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
|
||||
LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x",
|
||||
hr, flags);
|
||||
// End of stream.
|
||||
mAudioQueue.Finish();
|
||||
return false;
|
||||
|
@ -491,6 +576,19 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
|||
return true;
|
||||
}
|
||||
|
||||
if ((flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
|
||||
LOG("WMFReader: Video media type changed!");
|
||||
RefPtr<IMFMediaType> mediaType;
|
||||
hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
byRef(mediaType));
|
||||
if (FAILED(hr) ||
|
||||
FAILED(ConfigureVideoFrameGeometry(mediaType))) {
|
||||
NS_WARNING("Failed to reconfigure video media type");
|
||||
mVideoQueue.Finish();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t timestamp = HNsToUsecs(timestampHns);
|
||||
if (timestamp < aTimeThreshold) {
|
||||
return true;
|
||||
|
@ -570,7 +668,7 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
|||
b,
|
||||
false,
|
||||
-1,
|
||||
nsIntRect(0, 0, mVideoWidth, mVideoHeight));
|
||||
mPictureRegion);
|
||||
if (twoDBuffer) {
|
||||
twoDBuffer->Unlock2D();
|
||||
} else {
|
||||
|
@ -586,8 +684,8 @@ WMFReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
|||
mVideoQueue.Push(v);
|
||||
|
||||
#ifdef LOG_SAMPLE_DECODE
|
||||
LOG("Decoded video sample timestamp=%lld duration=%lld stride=%d width=%u height=%u flags=%u",
|
||||
timestamp, duration, stride, mVideoWidth, mVideoHeight, flags);
|
||||
LOG("Decoded video sample timestamp=%lld duration=%lld stride=%d height=%u flags=%u",
|
||||
timestamp, duration, stride, mVideoHeight, flags);
|
||||
#endif
|
||||
|
||||
if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) {
|
||||
|
|
|
@ -49,15 +49,19 @@ private:
|
|||
|
||||
void ConfigureAudioDecoder();
|
||||
void ConfigureVideoDecoder();
|
||||
HRESULT ConfigureVideoFrameGeometry(IMFMediaType* aMediaType);
|
||||
|
||||
RefPtr<IMFSourceReader> mSourceReader;
|
||||
RefPtr<WMFByteStream> mByteStream;
|
||||
|
||||
// Region inside the video frame that makes up the picture. Pixels outside
|
||||
// of this region should not be rendered.
|
||||
nsIntRect mPictureRegion;
|
||||
|
||||
uint32_t mAudioChannels;
|
||||
uint32_t mAudioBytesPerSample;
|
||||
uint32_t mAudioRate;
|
||||
|
||||
uint32_t mVideoWidth;
|
||||
uint32_t mVideoHeight;
|
||||
uint32_t mVideoStride;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче