HRESULT COutputPin::DeliverSample(GstBuffer *pBuffer) { HRESULT hr = S_OK; IMediaSample *pSample = NULL; REFERENCE_TIME start = -1; REFERENCE_TIME stop = -1; hr = m_pAlloc->SetGstBuffer(pBuffer); if (FAILED(hr)) return hr; hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0); if (FAILED(hr)) return hr; // Set media time pSample->SetMediaTime(NULL, NULL); // Set time if (GST_BUFFER_TIMESTAMP_IS_VALID(pBuffer)) { start = GST_BUFFER_TIMESTAMP(pBuffer) / 100; if (GST_BUFFER_DURATION_IS_VALID(pBuffer)) { stop = (GST_BUFFER_TIMESTAMP(pBuffer) + GST_BUFFER_DURATION(pBuffer)) / 100; } else { stop = start + 1; } if (stop <= start) // Sometimes it may happen stop = start + 1; pSample->SetTime(&start, &stop); } else { pSample->SetTime(NULL, NULL); } if (GST_BUFFER_IS_DISCONT(pBuffer)) pSample->SetDiscontinuity(TRUE); hr = Deliver(pSample); pSample->Release(); if (FAILED(hr)) return hr; return S_OK; }
//---------------------------------------------------------------------------- //! @brief 次のサンプルを得る //! @param pSample : サンプルを返すポインタのポインタ //! @return エラーコード //---------------------------------------------------------------------------- HRESULT CWMOutput::GetNextSample( IMediaSample **pSample ) { HRESULT hr; if( m_StreamNum == 0 || pSample == NULL ) return S_FALSE; // このストリームはない INSSBuffer *pWMSample = NULL; QWORD cnsSampleTime; QWORD cnsDuration; DWORD dwFlags; if( FAILED(hr = WMReader()->GetNextSample( m_StreamNum, &pWMSample, &cnsSampleTime, &cnsDuration, &dwFlags, NULL, NULL )) ) { if( hr == NS_E_NO_MORE_SAMPLES ) return S_FALSE; return hr; } REFERENCE_TIME startTime = (REFERENCE_TIME)cnsSampleTime; REFERENCE_TIME endTime = (REFERENCE_TIME)(cnsSampleTime + cnsDuration); IMediaSample *pOutSample = reinterpret_cast<CWMBuffer*>(pWMSample)->GetSample(); pOutSample->AddRef(); pWMSample->Release(); pOutSample->SetMediaTime(&startTime, &endTime); #if 0 if( startTime < Reader()->m_StartTime ) pOutSample->SetPreroll(TRUE); else pOutSample->SetPreroll(FALSE); #endif startTime -= Reader()->m_StartTime; endTime -= Reader()->m_StartTime; pOutSample->SetTime(&startTime, &endTime); pOutSample->SetSyncPoint(dwFlags & WM_SF_CLEANPOINT); *pSample = pOutSample; return hr; }
HRESULT CLAVAudio::DeliverBitstream(AVCodecID codec, const BYTE *buffer, DWORD dwSize, DWORD dwFrameSize, REFERENCE_TIME rtStartInput, REFERENCE_TIME rtStopInput) { HRESULT hr = S_OK; CMediaType mt = CreateBitstreamMediaType(codec, m_bsParser.m_dwSampleRate); WAVEFORMATEX* wfe = (WAVEFORMATEX*)mt.Format(); if(FAILED(hr = ReconnectOutput(dwSize, mt))) { return hr; } IMediaSample *pOut; BYTE *pDataOut = NULL; if(FAILED(GetDeliveryBuffer(&pOut, &pDataOut))) { return E_FAIL; } REFERENCE_TIME rtStart = m_rtStart, rtStop = AV_NOPTS_VALUE; // TrueHD timings // Since the SPDIF muxer takes 24 frames and puts them into one IEC61937 frame, we use the cached timestamp from before. if (codec == AV_CODEC_ID_TRUEHD) { // long-term cache is valid if (m_rtBitstreamCache != AV_NOPTS_VALUE) rtStart = m_rtBitstreamCache; // Duration - stop time of the current frame is valid if (rtStopInput != AV_NOPTS_VALUE) rtStop = rtStopInput; else // no actual time of the current frame, use typical TrueHD frame size, 24 * 0.83333ms rtStop = rtStart + (REFERENCE_TIME)(200000 / m_dRate); m_rtStart = rtStop; } else { double dDuration = DBL_SECOND_MULT * (double)m_bsParser.m_dwSamples / m_bsParser.m_dwSampleRate / m_dRate; m_dStartOffset += fmod(dDuration, 1.0); // Add rounded duration to rtStop rtStop = rtStart + (REFERENCE_TIME)(dDuration + 0.5); // and unrounded to m_rtStart.. m_rtStart += (REFERENCE_TIME)dDuration; // and accumulate error.. if (m_dStartOffset > 0.5) { m_rtStart++; m_dStartOffset -= 1.0; } } REFERENCE_TIME rtJitter = rtStart - m_rtBitstreamCache; m_faJitter.Sample(rtJitter); REFERENCE_TIME rtJitterMin = m_faJitter.AbsMinimum(); if (m_settings.AutoAVSync && abs(rtJitterMin) > m_JitterLimit && m_bHasVideo) { DbgLog((LOG_TRACE, 10, L"::Deliver(): corrected A/V sync by %I64d", rtJitterMin)); m_rtStart -= rtJitterMin; m_faJitter.OffsetValues(-rtJitterMin); m_bDiscontinuity = TRUE; } #ifdef DEBUG DbgLog((LOG_CUSTOM5, 20, L"Bitstream Delivery, rtStart(calc): %I64d, rtStart(input): %I64d, duration: %I64d, diff: %I64d", rtStart, m_rtBitstreamCache, rtStop-rtStart, rtJitter)); if (m_faJitter.CurrentSample() == 0) { DbgLog((LOG_TRACE, 20, L"Jitter Stats: min: %I64d - max: %I64d - avg: %I64d", rtJitterMin, m_faJitter.AbsMaximum(), m_faJitter.Average())); } #endif m_rtBitstreamCache = AV_NOPTS_VALUE; if(m_settings.AudioDelayEnabled) { REFERENCE_TIME rtDelay = (REFERENCE_TIME)((m_settings.AudioDelay * 10000i64) / m_dRate); rtStart += rtDelay; rtStop += rtDelay; } pOut->SetTime(&rtStart, &rtStop); pOut->SetMediaTime(NULL, NULL); pOut->SetPreroll(FALSE); pOut->SetDiscontinuity(m_bDiscontinuity); m_bDiscontinuity = FALSE; pOut->SetSyncPoint(TRUE); pOut->SetActualDataLength(dwSize); memcpy(pDataOut, buffer, dwSize); if(hr == S_OK) { hr = m_pOutput->GetConnected()->QueryAccept(&mt); if (hr == S_FALSE && m_nCodecId == AV_CODEC_ID_DTS && m_bDTSHD) { DbgLog((LOG_TRACE, 1, L"DTS-HD Media Type failed with %0#.8x, trying fallback to DTS core", hr)); m_bForceDTSCore = TRUE; UpdateBitstreamContext(); goto done; } DbgLog((LOG_TRACE, 1, L"Sending new Media Type (QueryAccept: %0#.8x)", hr)); m_pOutput->SetMediaType(&mt); pOut->SetMediaType(&mt); } hr = m_pOutput->Deliver(pOut); if (FAILED(hr)) { DbgLog((LOG_ERROR, 10, L"::DeliverBitstream failed with code: %0#.8x", hr)); } done: SafeRelease(&pOut); return hr; }
// Set up our output sample HRESULT CTransformFilter::InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample) { IMediaSample *pOutSample; // default - times are the same AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps(); DWORD dwFlags = m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0; // This will prevent the image renderer from switching us to DirectDraw // when we can't do it without skipping frames because we're not on a // keyframe. If it really has to switch us, it still will, but then we // will have to wait for the next keyframe if(!(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT)) { dwFlags |= AM_GBF_NOTASYNCPOINT; } ASSERT(m_pOutput->m_pAllocator != NULL); HRESULT hr = m_pOutput->m_pAllocator->GetBuffer(&pOutSample , pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? &pProps->tStart : NULL , pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? &pProps->tStop : NULL , dwFlags); *ppOutSample = pOutSample; if(FAILED(hr)) { return hr; } ASSERT(pOutSample); IMediaSample2 *pOutSample2; if(SUCCEEDED(pOutSample->QueryInterface(IID_IMediaSample2, (void **)&pOutSample2))) { /* Modify it */ AM_SAMPLE2_PROPERTIES OutProps; EXECUTE_ASSERT(SUCCEEDED(pOutSample2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&OutProps))); OutProps.dwTypeSpecificFlags = pProps->dwTypeSpecificFlags; OutProps.dwSampleFlags = (OutProps.dwSampleFlags & AM_SAMPLE_TYPECHANGED) | (pProps->dwSampleFlags & ~AM_SAMPLE_TYPECHANGED); OutProps.tStart = pProps->tStart; OutProps.tStop = pProps->tStop; OutProps.cbData = FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId); hr = pOutSample2->SetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, dwStreamId), (PBYTE)&OutProps); if(pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { m_bSampleSkipped = FALSE; } pOutSample2->Release(); } else { if(pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID) { pOutSample->SetTime(&pProps->tStart, &pProps->tStop); } if(pProps->dwSampleFlags & AM_SAMPLE_SPLICEPOINT) { pOutSample->SetSyncPoint(TRUE); } if(pProps->dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) { pOutSample->SetDiscontinuity(TRUE); m_bSampleSkipped = FALSE; } // Copy the media times LONGLONG MediaStart, MediaEnd; if(pSample->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { pOutSample->SetMediaTime(&MediaStart,&MediaEnd); } } return S_OK; }
// // Copy // // return a pointer to an identical copy of pSample IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource) { IMediaSample * pDest; HRESULT hr; REFERENCE_TIME tStart, tStop; const BOOL bTime = S_OK == pSource->GetTime( &tStart, &tStop); // this may block for an indeterminate amount of time hr = OutputPin()->PeekAllocator()->GetBuffer( &pDest , bTime ? &tStart : NULL , bTime ? &tStop : NULL , m_bSampleSkipped ? AM_GBF_PREVFRAMESKIPPED : 0 ); if (FAILED(hr)) { return NULL; } ASSERT(pDest); IMediaSample2 *pSample2; if (SUCCEEDED(pDest->QueryInterface(IID_IMediaSample2, (void **)&pSample2))) { HRESULT hr = pSample2->SetProperties( FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer), (PBYTE)m_pInput->SampleProps()); pSample2->Release(); if (FAILED(hr)) { pDest->Release(); return NULL; } } else { if (bTime) { pDest->SetTime(&tStart, &tStop); } if (S_OK == pSource->IsSyncPoint()) { pDest->SetSyncPoint(TRUE); } if (S_OK == pSource->IsDiscontinuity() || m_bSampleSkipped) { pDest->SetDiscontinuity(TRUE); } if (S_OK == pSource->IsPreroll()) { pDest->SetPreroll(TRUE); } // Copy the media type AM_MEDIA_TYPE *pMediaType; if (S_OK == pSource->GetMediaType(&pMediaType)) { pDest->SetMediaType(pMediaType); DeleteMediaType( pMediaType ); } } m_bSampleSkipped = FALSE; // Copy the sample media times REFERENCE_TIME TimeStart, TimeEnd; if (pSource->GetMediaTime(&TimeStart,&TimeEnd) == NOERROR) { pDest->SetMediaTime(&TimeStart,&TimeEnd); } // Copy the actual data length and the actual data. { const long lDataLength = pSource->GetActualDataLength(); pDest->SetActualDataLength(lDataLength); // Copy the sample data { BYTE *pSourceBuffer, *pDestBuffer; long lSourceSize = pSource->GetSize(); long lDestSize = pDest->GetSize(); ASSERT(lDestSize >= lSourceSize && lDestSize >= lDataLength); pSource->GetPointer(&pSourceBuffer); pDest->GetPointer(&pDestBuffer); ASSERT(lDestSize == 0 || pSourceBuffer != NULL && pDestBuffer != NULL); CopyMemory( (PVOID) pDestBuffer, (PVOID) pSourceBuffer, lDataLength ); } } return pDest; } // Copy
HRESULT CLAVOutputPin::DeliverPacket(Packet *pPacket) { HRESULT hr = S_OK; IMediaSample *pSample = NULL; long nBytes = (long)pPacket->GetDataSize(); if(nBytes == 0) { goto done; } CHECK_HR(hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0)); if (m_bPacketAllocator) { ILAVMediaSample *pLAVSample = NULL; CHECK_HR(hr = pSample->QueryInterface(&pLAVSample)); CHECK_HR(hr = pLAVSample->SetPacket(pPacket)); SafeRelease(&pLAVSample); } else { // Resize buffer if it is too small // This can cause a playback hick-up, we should avoid this if possible by setting a big enough buffer size if(nBytes > pSample->GetSize()) { SafeRelease(&pSample); ALLOCATOR_PROPERTIES props, actual; CHECK_HR(hr = m_pAllocator->GetProperties(&props)); // Give us 2 times the requested size, so we don't resize every time props.cbBuffer = nBytes*2; if(props.cBuffers > 1) { CHECK_HR(hr = __super::DeliverBeginFlush()); CHECK_HR(hr = __super::DeliverEndFlush()); } CHECK_HR(hr = m_pAllocator->Decommit()); CHECK_HR(hr = m_pAllocator->SetProperties(&props, &actual)); CHECK_HR(hr = m_pAllocator->Commit()); CHECK_HR(hr = GetDeliveryBuffer(&pSample, NULL, NULL, 0)); } // Fill the sample BYTE* pData = NULL; if(FAILED(hr = pSample->GetPointer(&pData)) || !pData) goto done; memcpy(pData, pPacket->GetData(), nBytes); } if(pPacket->pmt) { DbgLog((LOG_TRACE, 10, L"::DeliverPacket() - sending new media type to decoder")); pSample->SetMediaType(pPacket->pmt); pPacket->bDiscontinuity = true; CAutoLock cAutoLock(m_pLock); CMediaType pmt = *(pPacket->pmt); m_mts.clear(); m_mts.push_back(pmt); pPacket->pmt = NULL; SetMediaType(&pmt); } bool fTimeValid = pPacket->rtStart != Packet::INVALID_TIME; CHECK_HR(hr = pSample->SetActualDataLength(nBytes)); CHECK_HR(hr = pSample->SetTime(fTimeValid ? &pPacket->rtStart : NULL, fTimeValid ? &pPacket->rtStop : NULL)); CHECK_HR(hr = pSample->SetMediaTime(NULL, NULL)); CHECK_HR(hr = pSample->SetDiscontinuity(pPacket->bDiscontinuity)); CHECK_HR(hr = pSample->SetSyncPoint(pPacket->bSyncPoint)); CHECK_HR(hr = pSample->SetPreroll(fTimeValid && pPacket->rtStart < 0)); // Deliver CHECK_HR(hr = Deliver(pSample)); done: if (!m_bPacketAllocator) SAFE_DELETE(pPacket); SafeRelease(&pSample); return hr; }
HRESULT CLAVOutputPin::DeliverPacket(Packet *pPacket) { HRESULT hr = S_OK; IMediaSample *pSample = nullptr; long nBytes = (long)pPacket->GetDataSize(); if(nBytes == 0) { goto done; } CHECK_HR(hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0)); if (m_bPacketAllocator) { ILAVMediaSample *pLAVSample = nullptr; CHECK_HR(hr = pSample->QueryInterface(&pLAVSample)); CHECK_HR(hr = pLAVSample->SetPacket(pPacket)); SafeRelease(&pLAVSample); } else { // Resize buffer if it is too small // This can cause a playback hick-up, we should avoid this if possible by setting a big enough buffer size if(nBytes > pSample->GetSize()) { SafeRelease(&pSample); ALLOCATOR_PROPERTIES props, actual; CHECK_HR(hr = m_pAllocator->GetProperties(&props)); // Give us 2 times the requested size, so we don't resize every time props.cbBuffer = nBytes*2; if(props.cBuffers > 1) { CHECK_HR(hr = __super::DeliverBeginFlush()); CHECK_HR(hr = __super::DeliverEndFlush()); } CHECK_HR(hr = m_pAllocator->Decommit()); CHECK_HR(hr = m_pAllocator->SetProperties(&props, &actual)); CHECK_HR(hr = m_pAllocator->Commit()); CHECK_HR(hr = GetDeliveryBuffer(&pSample, nullptr, nullptr, 0)); } // Fill the sample BYTE* pData = nullptr; if(FAILED(hr = pSample->GetPointer(&pData)) || !pData) goto done; memcpy(pData, pPacket->GetData(), nBytes); } if(pPacket->pmt) { DbgLog((LOG_TRACE, 10, L"::DeliverPacket() - sending new media type to decoder")); pSample->SetMediaType(pPacket->pmt); pPacket->bDiscontinuity = true; CAutoLock cAutoLock(m_pLock); CMediaType pmt = *(pPacket->pmt); m_mts.clear(); m_mts.push_back(pmt); pPacket->pmt = nullptr; SetMediaType(&pmt); } bool fTimeValid = pPacket->rtStart != Packet::INVALID_TIME; // IBitRateInfo m_BitRate.nBytesSinceLastDeliverTime += nBytes; if (fTimeValid) { if (m_BitRate.rtLastDeliverTime == Packet::INVALID_TIME) { m_BitRate.rtLastDeliverTime = pPacket->rtStart; m_BitRate.nBytesSinceLastDeliverTime = 0; } if (m_BitRate.rtLastDeliverTime + 10000000 < pPacket->rtStart) { REFERENCE_TIME rtDiff = pPacket->rtStart - m_BitRate.rtLastDeliverTime; double dSecs, dBits; dSecs = rtDiff / 10000000.0; dBits = 8.0 * m_BitRate.nBytesSinceLastDeliverTime; m_BitRate.nCurrentBitRate = (DWORD)(dBits / dSecs); m_BitRate.rtTotalTimeDelivered += rtDiff; m_BitRate.nTotalBytesDelivered += m_BitRate.nBytesSinceLastDeliverTime; dSecs = m_BitRate.rtTotalTimeDelivered / 10000000.0; dBits = 8.0 * m_BitRate.nTotalBytesDelivered; m_BitRate.nAverageBitRate = (DWORD)(dBits / dSecs); m_BitRate.rtLastDeliverTime = pPacket->rtStart; m_BitRate.nBytesSinceLastDeliverTime = 0; } } CHECK_HR(hr = pSample->SetActualDataLength(nBytes)); CHECK_HR(hr = pSample->SetTime(fTimeValid ? &pPacket->rtStart : nullptr, fTimeValid ? &pPacket->rtStop : nullptr)); CHECK_HR(hr = pSample->SetMediaTime(nullptr, nullptr)); CHECK_HR(hr = pSample->SetDiscontinuity(pPacket->bDiscontinuity)); CHECK_HR(hr = pSample->SetSyncPoint(pPacket->bSyncPoint)); CHECK_HR(hr = pSample->SetPreroll(fTimeValid && pPacket->rtStart < 0)); // Deliver CHECK_HR(hr = Deliver(pSample)); done: if (!m_bPacketAllocator || !pSample) SAFE_DELETE(pPacket); SafeRelease(&pSample); return hr; }
IMediaSample *QMemInputPin::duplicateSampleForOutput(IMediaSample *sample, IMemAllocator *alloc) { LONG length = sample->GetActualDataLength(); HRESULT hr = alloc->Commit(); if (hr == HRESULT(VFW_E_SIZENOTSET)) { ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties(); prop.cbBuffer = qMax(prop.cbBuffer, length); ALLOCATOR_PROPERTIES actual; //we just try to set the properties... alloc->SetProperties(&prop, &actual); hr = alloc->Commit(); } Q_ASSERT(SUCCEEDED(hr)); IMediaSample *out; hr = alloc->GetBuffer(&out, 0, 0, AM_GBF_NOTASYNCPOINT); Q_ASSERT(SUCCEEDED(hr)); //let's copy the sample { REFERENCE_TIME start, end; sample->GetTime(&start, &end); out->SetTime(&start, &end); } hr = out->SetActualDataLength(length); Q_ASSERT(SUCCEEDED(hr)); hr = out->SetDiscontinuity(sample->IsDiscontinuity()); Q_ASSERT(SUCCEEDED(hr)); { LONGLONG start, end; hr = sample->GetMediaTime(&start, &end); if (hr != HRESULT(VFW_E_MEDIA_TIME_NOT_SET)) { hr = out->SetMediaTime(&start, &end); Q_ASSERT(SUCCEEDED(hr)); } } AM_MEDIA_TYPE *type = 0; hr = sample->GetMediaType(&type); Q_ASSERT(SUCCEEDED(hr)); hr = out->SetMediaType(type); Q_ASSERT(SUCCEEDED(hr)); hr = out->SetPreroll(sample->IsPreroll()); Q_ASSERT(SUCCEEDED(hr)); hr = out->SetSyncPoint(sample->IsSyncPoint()); Q_ASSERT(SUCCEEDED(hr)); BYTE *dest = 0, *src = 0; hr = out->GetPointer(&dest); Q_ASSERT(SUCCEEDED(hr)); hr = sample->GetPointer(&src); Q_ASSERT(SUCCEEDED(hr)); qMemCopy(dest, src, sample->GetActualDataLength()); return out; }
HRESULT CAudioDecFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) { // 入力データポインタを取得する const DWORD InSize = pIn->GetActualDataLength(); BYTE *pInData = NULL; HRESULT hr = pIn->GetPointer(&pInData); if (FAILED(hr)) return hr; { CAutoLock Lock(&m_cPropLock); /* 複数の音声フォーマットに対応する場合、この辺りでフォーマットの判定をする */ if (!m_pDecoder) { m_pDecoder = new CAacDecoder(); m_pDecoder->Open(); } REFERENCE_TIME rtStart, rtEnd; hr = pIn->GetTime(&rtStart, &rtEnd); if (FAILED(hr)) rtStart = -1; if (pIn->IsDiscontinuity() == S_OK) { m_bDiscontinuity = true; m_bInputDiscontinuity = true; } else if (hr == S_OK || hr == VFW_S_NO_STOP_TIME) { if (!m_bJitterCorrection) { m_StartTime = rtStart; } else if (m_StartTime >= 0 && _abs64(rtStart - m_StartTime) > MAX_JITTER) { TRACE(TEXT("Resync audio stream time (%lld -> %lld [%f])\n"), m_StartTime, rtStart, (double)(rtStart - m_StartTime) / (double)REFERENCE_TIME_SECOND); m_StartTime = rtStart; } } if (m_StartTime < 0 || m_bDiscontinuity) { TRACE(TEXT("Initialize audio stream time (%lld)\n"), rtStart); m_StartTime = rtStart; } m_BitRateCalculator.Update(InSize); } DWORD InDataPos = 0; FrameSampleInfo SampleInfo; SampleInfo.pData = &m_OutData; hr = S_OK; while (InDataPos < InSize) { { CAutoLock Lock(&m_cPropLock); CAudioDecoder::DecodeFrameInfo FrameInfo; const DWORD DataSize = InSize - InDataPos; DWORD DecodeSize = DataSize; if (!m_pDecoder->Decode(&pInData[InDataPos], &DecodeSize, &FrameInfo)) { if (DecodeSize < DataSize) { InDataPos += DecodeSize; continue; } break; } InDataPos += DecodeSize; if (FrameInfo.bDiscontinuity) m_bDiscontinuity = true; SampleInfo.bMediaTypeChanged = false; hr = OnFrame(FrameInfo.pData, FrameInfo.Samples, FrameInfo.Info, &SampleInfo); } if (SUCCEEDED(hr)) { if (SampleInfo.bMediaTypeChanged) { hr = ReconnectOutput(SampleInfo.MediaBufferSize, SampleInfo.MediaType); if (FAILED(hr)) break; OutputLog(TEXT("出力メディアタイプを更新します。\r\n")); hr = m_pOutput->SetMediaType(&SampleInfo.MediaType); if (FAILED(hr)) { OutputLog(TEXT("出力メディアタイプを設定できません。(%08x)\r\n"), hr); break; } m_MediaType = SampleInfo.MediaType; m_bDiscontinuity = true; m_bInputDiscontinuity = true; } IMediaSample *pOutSample = NULL; hr = m_pOutput->GetDeliveryBuffer(&pOutSample, NULL, NULL, 0); if (FAILED(hr)) { OutputLog(TEXT("出力メディアサンプルを取得できません。(%08x)\r\n"), hr); break; } if (SampleInfo.bMediaTypeChanged) pOutSample->SetMediaType(&m_MediaType); // 出力ポインタ取得 BYTE *pOutBuff = NULL; hr = pOutSample->GetPointer(&pOutBuff); if (FAILED(hr)) { OutputLog(TEXT("出力サンプルのバッファを取得できません。(%08x)\r\n"), hr); pOutSample->Release(); break; } ::CopyMemory(pOutBuff, m_OutData.GetData(), m_OutData.GetSize()); pOutSample->SetActualDataLength(m_OutData.GetSize()); if (m_StartTime >= 0) { REFERENCE_TIME rtDuration, rtStart, rtEnd; rtDuration = REFERENCE_TIME_SECOND * (LONGLONG)SampleInfo.Samples / FREQUENCY; rtStart = m_StartTime; m_StartTime += rtDuration; // 音ずれ補正用時間シフト if (m_DelayAdjustment > 0) { // 最大2倍まで時間を遅らせる if (rtDuration >= m_DelayAdjustment) { rtDuration += m_DelayAdjustment; m_DelayAdjustment = 0; } else { m_DelayAdjustment -= rtDuration; rtDuration *= 2; } } else if (m_DelayAdjustment < 0) { // 最短1/2まで時間を早める if (rtDuration >= -m_DelayAdjustment * 2) { rtDuration += m_DelayAdjustment; m_DelayAdjustment = 0; } else { m_DelayAdjustment += rtDuration; rtDuration /= 2; } } else { rtStart += m_Delay; } rtEnd = rtStart + rtDuration; pOutSample->SetTime(&rtStart, &rtEnd); } pOutSample->SetMediaTime(NULL, NULL); pOutSample->SetPreroll(FALSE); #if 0 // Discontinuityを設定すると倍速再生がおかしくなる模様 pOutSample->SetDiscontinuity(m_bDiscontinuity); #else pOutSample->SetDiscontinuity(m_bInputDiscontinuity); #endif m_bDiscontinuity = false; m_bInputDiscontinuity = false; pOutSample->SetSyncPoint(TRUE); hr = m_pOutput->Deliver(pOutSample); #ifdef _DEBUG if (FAILED(hr)) { OutputLog(TEXT("サンプルを送信できません。(%08x)\r\n"), hr); if (m_bPassthrough && !m_bPassthroughError) { m_bPassthroughError = true; if (m_pEventHandler) m_pEventHandler->OnSpdifPassthroughError(hr); } } #endif pOutSample->Release(); if (FAILED(hr)) break; } } return hr; }