// Blocks until decoded sample is produced by the deoder. HRESULT WMFVideoMFTManager::Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutData) { RefPtr<IMFSample> sample; HRESULT hr; aOutData = nullptr; int typeChangeCount = 0; // Loop until we decode a sample, or an unexpected error that we can't // handle occurs. while (true) { hr = mDecoder->Output(&sample); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return MF_E_TRANSFORM_NEED_MORE_INPUT; } if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { // Video stream output type change. Probably a geometric apperature // change. Reconfigure the video geometry, so that we output the // correct size frames. MOZ_ASSERT(!sample); hr = ConfigureVideoFrameGeometry(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Catch infinite loops, but some decoders perform at least 2 stream // changes on consecutive calls, so be permissive. // 100 is arbitrarily > 2. NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE); // Loop back and try decoding again... ++typeChangeCount; continue; } if (SUCCEEDED(hr)) { break; } // Else unexpected error, assert, and bail. NS_WARNING("WMFVideoMFTManager::Output() unexpected error"); return hr; } nsRefPtr<VideoData> frame; if (mUseHwAccel) { hr = CreateD3DVideoFrame(sample, aStreamOffset, getter_AddRefs(frame)); } else { hr = CreateBasicVideoFrame(sample, aStreamOffset, getter_AddRefs(frame)); } // Frame should be non null only when we succeeded. MOZ_ASSERT((frame != nullptr) == SUCCEEDED(hr)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); NS_ENSURE_TRUE(frame, E_FAIL); aOutData = frame; return S_OK; }
// Blocks until decoded sample is produced by the deoder. HRESULT WMFVideoOutputSource::Output(int64_t aStreamOffset, nsAutoPtr<MediaData>& aOutData) { RefPtr<IMFSample> sample; HRESULT hr; aOutData = nullptr; // Loop until we decode a sample, or an unexpected error that we can't // handle occurs. while (true) { hr = mDecoder->Output(&sample); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return MF_E_TRANSFORM_NEED_MORE_INPUT; } if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { // Video stream output type change. Probably a geometric apperature // change. Reconfigure the video geometry, so that we output the // correct size frames. MOZ_ASSERT(!sample); hr = ConfigureVideoFrameGeometry(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Loop back and try decoding again... continue; } if (SUCCEEDED(hr)) { break; } // Else unexpected error, assert, and bail. NS_WARNING("WMFVideoOutputSource::Output() unexpected error"); return E_FAIL; } VideoData* frame = nullptr; if (mUseHwAccel) { hr = CreateD3DVideoFrame(sample, aStreamOffset, &frame); } else { hr = CreateBasicVideoFrame(sample, aStreamOffset, &frame); } // Frame should be non null only when we succeeded. MOZ_ASSERT((frame != nullptr) == SUCCEEDED(hr)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); NS_ENSURE_TRUE(frame, E_FAIL); aOutData = frame; return S_OK; }
bool WMFReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { MOZ_ASSERT(OnTaskQueue()); // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder); HRESULT hr; hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, // control flags 0, // read stream index nullptr, nullptr, nullptr); if (FAILED(hr)) { DECODER_LOG("WMFReader::DecodeVideoData() ReadSample failed with hr=0x%x", hr); return false; } DWORD flags = 0; LONGLONG timestampHns = 0; RefPtr<IMFSample> sample; hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample)); if (flags & MF_SOURCE_READERF_ERROR) { NS_WARNING("WMFReader: Catastrophic failure reading video sample"); // Future ReadSample() calls will fail, so give up and report end of stream. return false; } if (FAILED(hr)) { // Unknown failure, ask caller to try again? return true; } if (!sample) { if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) { DECODER_LOG("WMFReader; Null sample after video decode, at end of stream"); return false; } DECODER_LOG("WMFReader; Null sample after video decode. Maybe insufficient data..."); return true; } if ((flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) { DECODER_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"); return false; } } int64_t timestamp = HNsToUsecs(timestampHns); if (timestamp < aTimeThreshold) { return true; } int64_t offset = mDecoder->GetResource()->Tell(); int64_t duration = GetSampleDuration(sample); VideoData* v = nullptr; if (mUseHwAccel) { hr = CreateD3DVideoFrame(sample, timestamp, duration, offset, &v); } else { hr = CreateBasicVideoFrame(sample, timestamp, duration, offset, &v); } NS_ENSURE_TRUE(SUCCEEDED(hr) && v, false); a.mParsed++; a.mDecoded++; mVideoQueue.Push(v); #ifdef LOG_SAMPLE_DECODE DECODER_LOG("Decoded video sample timestamp=%lld duration=%lld stride=%d height=%u flags=%u", timestamp, duration, mVideoStride, mVideoHeight, flags); #endif if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) { // End of stream. DECODER_LOG("End of video stream"); return false; } return true; }
// Blocks until decoded sample is produced by the deoder. HRESULT WMFVideoMFTManager::Output(int64_t aStreamOffset, RefPtr<MediaData>& aOutData) { RefPtr<IMFSample> sample; HRESULT hr; aOutData = nullptr; int typeChangeCount = 0; // Loop until we decode a sample, or an unexpected error that we can't // handle occurs. while (true) { hr = mDecoder->Output(&sample); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return MF_E_TRANSFORM_NEED_MORE_INPUT; } if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { // Video stream output type change. Probably a geometric apperature // change. Reconfigure the video geometry, so that we output the // correct size frames. MOZ_ASSERT(!sample); hr = ConfigureVideoFrameGeometry(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Catch infinite loops, but some decoders perform at least 2 stream // changes on consecutive calls, so be permissive. // 100 is arbitrarily > 2. NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE); // Loop back and try decoding again... ++typeChangeCount; continue; } if (SUCCEEDED(hr)) { if (!sample) { LOG("Video MFTDecoder returned success but no output!"); // On some machines/input the MFT returns success but doesn't output // a video frame. If we detect this, try again, but only up to a // point; after 250 failures, give up. Note we count all failures // over the life of the decoder, as we may end up exiting with a // NEED_MORE_INPUT and coming back to hit the same error. So just // counting with a local variable (like typeChangeCount does) may // not work in this situation. ++mNullOutputCount; if (mNullOutputCount > 250) { LOG("Excessive Video MFTDecoder returning success but no output; giving up"); mGotExcessiveNullOutput = true; return E_FAIL; } continue; } if (mSeekTargetThreshold.isSome()) { media::TimeUnit pts = GetSampleTime(sample); if (!pts.IsValid()) { return E_FAIL; } if (pts < mSeekTargetThreshold.ref()) { LOG("Dropping video frame which pts is smaller than seek target."); // It is necessary to clear the pointer to release the previous output // buffer. sample = nullptr; continue; } mSeekTargetThreshold.reset(); } break; } // Else unexpected error, assert, and bail. NS_WARNING("WMFVideoMFTManager::Output() unexpected error"); return hr; } RefPtr<VideoData> frame; if (mUseHwAccel) { hr = CreateD3DVideoFrame(sample, aStreamOffset, getter_AddRefs(frame)); } else { hr = CreateBasicVideoFrame(sample, aStreamOffset, getter_AddRefs(frame)); } // Frame should be non null only when we succeeded. MOZ_ASSERT((frame != nullptr) == SUCCEEDED(hr)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); NS_ENSURE_TRUE(frame, E_FAIL); aOutData = frame; if (mNullOutputCount) { mGotValidOutputAfterNullOutput = true; } return S_OK; }