void D3DPresentEngine::presentSample(void *opaque, qint64) { HRESULT hr = S_OK; IMFSample *sample = reinterpret_cast<IMFSample*>(opaque); IMFMediaBuffer* buffer = NULL; IDirect3DSurface9* surface = NULL; if (m_surface && m_surface->isActive()) { if (sample) { // Get the buffer from the sample. hr = sample->GetBufferByIndex(0, &buffer); if (FAILED(hr)) goto done; // Get the surface from the buffer. hr = MFGetService(buffer, MR_BUFFER_SERVICE, IID_PPV_ARGS(&surface)); if (FAILED(hr)) goto done; } if (surface && updateTexture(surface)) { QVideoFrame frame = QVideoFrame(new TextureVideoBuffer(m_glTexture), m_surfaceFormat.frameSize(), m_surfaceFormat.pixelFormat()); // WMF uses 100-nanosecond units, Qt uses microseconds LONGLONG startTime = -1; if (SUCCEEDED(sample->GetSampleTime(&startTime))) { frame.setStartTime(startTime * 0.1); LONGLONG duration = -1; if (SUCCEEDED(sample->GetSampleDuration(&duration))) frame.setEndTime((startTime + duration) * 0.1); } m_surface->present(frame); } } done: qt_wmf_safeRelease(&surface); qt_wmf_safeRelease(&buffer); qt_wmf_safeRelease(&sample); }
SINT SoundSourceMediaFoundation::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer) { SINT numberOfFramesRemaining = numberOfFrames; CSAMPLE* pSampleBuffer = sampleBuffer; while (numberOfFramesRemaining > 0) { SampleBuffer::ReadableChunk readableChunk( m_sampleBuffer.readFromHead( frames2samples(numberOfFramesRemaining))); DEBUG_ASSERT(readableChunk.size() <= frames2samples(numberOfFramesRemaining)); if (readableChunk.size() > 0) { DEBUG_ASSERT(m_currentFrameIndex < getMaxFrameIndex()); if (sampleBuffer != nullptr) { SampleUtil::copy( pSampleBuffer, readableChunk.data(), readableChunk.size()); pSampleBuffer += readableChunk.size(); } m_currentFrameIndex += samples2frames(readableChunk.size()); numberOfFramesRemaining -= samples2frames(readableChunk.size()); } if (numberOfFramesRemaining == 0) { break; // finished reading } // No more decoded sample frames available DEBUG_ASSERT(m_sampleBuffer.isEmpty()); if (m_pSourceReader == nullptr) { break; // abort if reader is dead } DWORD dwFlags = 0; LONGLONG streamPos = 0; IMFSample* pSample = nullptr; HRESULT hrReadSample = m_pSourceReader->ReadSample( kStreamIndex, // [in] DWORD dwStreamIndex, 0, // [in] DWORD dwControlFlags, nullptr, // [out] DWORD *pdwActualStreamIndex, &dwFlags, // [out] DWORD *pdwStreamFlags, &streamPos, // [out] LONGLONG *pllTimestamp, &pSample); // [out] IMFSample **ppSample if (FAILED(hrReadSample)) { qWarning() << kLogPreamble << "IMFSourceReader::ReadSample() failed" << hrReadSample << "-> abort decoding"; DEBUG_ASSERT(pSample == nullptr); break; // abort } if (dwFlags & MF_SOURCE_READERF_ERROR) { qWarning() << kLogPreamble << "IMFSourceReader::ReadSample()" << "detected stream errors" << "(MF_SOURCE_READERF_ERROR)" << "-> abort and stop decoding"; DEBUG_ASSERT(pSample == nullptr); safeRelease(&m_pSourceReader); // kill the reader break; // abort } else if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM) { DEBUG_ASSERT(pSample == nullptr); break; // finished reading } else if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED) { qWarning() << kLogPreamble << "IMFSourceReader::ReadSample()" << "detected that the media type has changed" << "(MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)" << "-> abort decoding"; DEBUG_ASSERT(pSample == nullptr); break; // abort } DEBUG_ASSERT(pSample != nullptr); SINT readerFrameIndex = m_streamUnitConverter.toFrameIndex(streamPos); DEBUG_ASSERT( (m_currentFrameIndex == getMaxFrameIndex()) || // unknown position after seeking (m_currentFrameIndex == readerFrameIndex)); m_currentFrameIndex = readerFrameIndex; DWORD dwSampleBufferCount = 0; HRESULT hrGetBufferCount = pSample->GetBufferCount(&dwSampleBufferCount); if (FAILED(hrGetBufferCount)) { qWarning() << kLogPreamble << "IMFSample::GetBufferCount() failed" << hrGetBufferCount << "-> abort decoding"; safeRelease(&pSample); break; // abort } DWORD dwSampleTotalLengthInBytes = 0; HRESULT hrGetTotalLength = pSample->GetTotalLength(&dwSampleTotalLengthInBytes); if (FAILED(hrGetTotalLength)) { qWarning() << kLogPreamble << "IMFSample::GetTotalLength() failed" << hrGetTotalLength << "-> abort decoding"; safeRelease(&pSample); break; // abort } // Enlarge temporary buffer (if necessary) DEBUG_ASSERT((dwSampleTotalLengthInBytes % kBytesPerSample) == 0); SINT numberOfSamplesToBuffer = dwSampleTotalLengthInBytes / kBytesPerSample; SINT sampleBufferCapacity = m_sampleBuffer.getCapacity(); DEBUG_ASSERT(sampleBufferCapacity > 0); while (sampleBufferCapacity < numberOfSamplesToBuffer) { sampleBufferCapacity *= 2; } if (m_sampleBuffer.getCapacity() < sampleBufferCapacity) { qDebug() << kLogPreamble << "Enlarging sample buffer capacity" << m_sampleBuffer.getCapacity() << "->" << sampleBufferCapacity; m_sampleBuffer.resetCapacity(sampleBufferCapacity); } DWORD dwSampleBufferIndex = 0; while (dwSampleBufferIndex < dwSampleBufferCount) { IMFMediaBuffer* pMediaBuffer = nullptr; HRESULT hrGetBufferByIndex = pSample->GetBufferByIndex(dwSampleBufferIndex, &pMediaBuffer); if (FAILED(hrGetBufferByIndex)) { qWarning() << kLogPreamble << "IMFSample::GetBufferByIndex() failed" << hrGetBufferByIndex << "-> abort decoding"; DEBUG_ASSERT(pMediaBuffer == nullptr); break; // prematurely exit buffer loop } CSAMPLE* pLockedSampleBuffer = nullptr; DWORD lockedSampleBufferLengthInBytes = 0; HRESULT hrLock = pMediaBuffer->Lock( reinterpret_cast<quint8**>(&pLockedSampleBuffer), nullptr, &lockedSampleBufferLengthInBytes); if (FAILED(hrLock)) { qWarning() << kLogPreamble << "IMFMediaBuffer::Lock() failed" << hrLock << "-> abort decoding"; safeRelease(&pMediaBuffer); break; // prematurely exit buffer loop } DEBUG_ASSERT((lockedSampleBufferLengthInBytes % sizeof(pLockedSampleBuffer[0])) == 0); SINT lockedSampleBufferCount = lockedSampleBufferLengthInBytes / sizeof(pLockedSampleBuffer[0]); SINT copySamplesCount = std::min( frames2samples(numberOfFramesRemaining), lockedSampleBufferCount); if (copySamplesCount > 0) { // Copy samples directly into output buffer if possible if (pSampleBuffer != nullptr) { SampleUtil::copy( pSampleBuffer, pLockedSampleBuffer, copySamplesCount); pSampleBuffer += copySamplesCount; } pLockedSampleBuffer += copySamplesCount; lockedSampleBufferCount -= copySamplesCount; m_currentFrameIndex += samples2frames(copySamplesCount); numberOfFramesRemaining -= samples2frames(copySamplesCount); } // Buffer the remaining samples SampleBuffer::WritableChunk writableChunk( m_sampleBuffer.writeToTail(lockedSampleBufferCount)); // The required capacity has been calculated in advance (see above) DEBUG_ASSERT(writableChunk.size() == lockedSampleBufferCount); SampleUtil::copy( writableChunk.data(), pLockedSampleBuffer, writableChunk.size()); HRESULT hrUnlock = pMediaBuffer->Unlock(); VERIFY_OR_DEBUG_ASSERT(SUCCEEDED(hrUnlock)) { qWarning() << kLogPreamble << "IMFMediaBuffer::Unlock() failed" << hrUnlock; // ignore and continue } safeRelease(&pMediaBuffer); ++dwSampleBufferIndex; } safeRelease(&pSample); if (dwSampleBufferIndex < dwSampleBufferCount) { // Failed to read data from all buffers -> kill the reader qWarning() << kLogPreamble << "Failed to read all buffered samples" << "-> abort and stop decoding"; safeRelease(&m_pSourceReader); break; // abort } } return numberOfFrames - numberOfFramesRemaining; }