static int64_t GetSampleDuration(IMFSample* aSample) { int64_t duration = 0; aSample->GetSampleDuration(&duration); return HNsToUsecs(duration); }
int64_t GetSampleDuration(IMFSample* aSample) { NS_ENSURE_TRUE(aSample, -1); int64_t duration = 0; aSample->GetSampleDuration(&duration); return HNsToUsecs(duration); }
int64_t GetSampleTime(IMFSample* aSample) { NS_ENSURE_TRUE(aSample, -1); LONGLONG timestampHns = 0; HRESULT hr = aSample->GetSampleTime(×tampHns); NS_ENSURE_TRUE(SUCCEEDED(hr), -1); return HNsToUsecs(timestampHns); }
// Returns the duration of the resource, in microseconds. HRESULT GetSourceReaderDuration(IMFSourceReader *aReader, int64_t& aOutDuration) { AutoPropVar var; HRESULT hr = aReader->GetPresentationAttribute(MF_SOURCE_READER_MEDIASOURCE, MF_PD_DURATION, &var); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // WMF stores duration in hundred nanosecond units. int64_t duration_hns = 0; hr = wmf::PropVariantToInt64(var, &duration_hns); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); aOutDuration = HNsToUsecs(duration_hns); 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; }
bool WMFReader::DecodeAudioData() { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); HRESULT hr; hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, // control flags 0, // read stream index nullptr, nullptr, nullptr); if (FAILED(hr)) { LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr); // End the stream. mAudioQueue.Finish(); return false; } DWORD flags = 0; LONGLONG timestampHns = 0; RefPtr<IMFSample> sample; hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample)); if (FAILED(hr) || (flags & MF_SOURCE_READERF_ERROR) || (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 the stream. mAudioQueue.Finish(); return false; } if (!sample) { // Not enough data? Try again... return true; } RefPtr<IMFMediaBuffer> buffer; hr = sample->ConvertToContiguousBuffer(byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), false); BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it. DWORD maxLength = 0, currentLength = 0; hr = buffer->Lock(&data, &maxLength, ¤tLength); NS_ENSURE_TRUE(SUCCEEDED(hr), false); uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels; NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong"); nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]); memcpy(pcmSamples.get(), data, currentLength); buffer->Unlock(); int64_t offset = mDecoder->GetResource()->Tell(); int64_t timestamp = HNsToUsecs(timestampHns); int64_t duration = GetSampleDuration(sample); mAudioQueue.Push(new AudioData(offset, timestamp, duration, numFrames, pcmSamples.forget(), mAudioChannels)); #ifdef LOG_SAMPLE_DECODE LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u", timestamp, duration, currentLength); #endif return true; }