HRESULT SeekNextFrame( IMediaSeeking * pSeeking, double FPS, long Frame ) { // try seeking by frames first // HRESULT hr = pSeeking->SetTimeFormat(&TIME_FORMAT_FRAME); REFERENCE_TIME Pos = 0; if(!FAILED(hr)) { pSeeking->GetCurrentPosition(&Pos); Pos++; } else { // couldn't seek by frames, use Frame and FPS to calculate time // Pos = REFERENCE_TIME(double( Frame * UNITS ) / FPS); // add a half-frame to seek to middle of the frame // Pos += REFERENCE_TIME(double( UNITS ) * 0.5 / FPS); } hr = pSeeking->SetPositions(&Pos, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning); return hr; }
void CPGSSubFile::ParseFile(CString fn) { CFile f; if (!f.Open(fn, CFile::modeRead | CFile::shareDenyWrite)) { return; } // Header: Sync code | start time | stop time | segment type | segment size std::array < BYTE, 2 + 2 * 4 + 1 + 2 > header; const int nExtraSize = 1 + 2; // segment type + segment size std::vector<BYTE> segBuff; while (!m_bStopParsing && f.Read(header.data(), (UINT)header.size()) == header.size()) { // Parse the header CGolombBuffer headerBuffer(header.data(), (int)header.size()); if (WORD(headerBuffer.ReadShort()) != PGS_SYNC_CODE) { break; } REFERENCE_TIME rtStart = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; REFERENCE_TIME rtStop = REFERENCE_TIME(headerBuffer.ReadDword()) * 1000 / 9; headerBuffer.ReadByte(); // segment type WORD wLenSegment = (WORD)headerBuffer.ReadShort(); // Leave some room to add the segment type and size int nLenData = nExtraSize + wLenSegment; segBuff.resize(nLenData); memcpy(segBuff.data(), &header[header.size() - nExtraSize], nExtraSize); // Read the segment if (wLenSegment && f.Read(&segBuff[nExtraSize], wLenSegment) != wLenSegment) { break; } // Parse the data (even if the segment size is 0 because the header itself is important) TRACE_PGSSUB(_T("--------- CPGSSubFile::ParseFile rtStart=%s, rtStop=%s, len=%d ---------\n"), ReftimeToString(rtStart), ReftimeToString(rtStop), nLenData); ParseSample(rtStart, rtStop, segBuff.data(), nLenData); } }
int WASAPI_Initialize(int rate,int channels,int bits) { //WAVEFORMATEX* closest_fmt = (WAVEFORMATEX*)CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); // WAVEFORMATEX** pclosest_fmt = &closest_fmt; fmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; fmt.Format.nChannels = channels; fmt.Format.nSamplesPerSec = rate; fmt.Format.wBitsPerSample = (bits+7)&~7; fmt.Format.nBlockAlign = channels * fmt.Format.wBitsPerSample>>3; fmt.Format.nAvgBytesPerSec = fmt.Format.nBlockAlign * fmt.Format.nSamplesPerSec; fmt.Format.cbSize = 22; fmt.Samples.wValidBitsPerSample = bits; fmt.dwChannelMask = channels==2 ? 3 : 4; //Select left & right (stereo) or center (mono) fmt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; //pwfx = &fmt.Format; HRESULT hr; hr = CoCreateInstance(CLSID_MMDeviceEnumerator,NULL,CLSCTX_ALL,IID_IMMDeviceEnumerator,(void**)&device_enumurator); if (FAILED(hr)) return S_FALSE; hr = device_enumurator->GetDefaultAudioEndpoint(eRender,eConsole,&device); if (FAILED(hr)) return S_FALSE; hr = device->Activate(IID_IAudioClient, CLSCTX_ALL,NULL, (void**)&audio_client); if (FAILED(hr)) return S_FALSE; hr = audio_client->GetMixFormat(&pwfx); //if (FAILED(hr)) return S_FALSE; //hr = audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,(WAVEFORMATEX*)&fmt,pclosest_fmt); //hr = audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE,(WAVEFORMATEX*)&fmt,NULL); //CoTaskMemFree(closest_fmt); hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED,0,hnsRequestedDuration,0,pwfx,NULL); if (FAILED(hr)) return S_FALSE; //hr = pMySource->SetFormat(pwfx); //if (FAILED(hr)) return S_FALSE; // Get the actual size of the allocated buffer. hr = audio_client->GetBufferSize(&bufferFrameCount); if (FAILED(hr)) return S_FALSE; hr = audio_client->GetService(IID_IAudioRenderClient,(void**)&render_client); if (FAILED(hr)) return S_FALSE; hnsActualDuration = REFERENCE_TIME((double)REFTIMES_PER_SEC * bufferFrameCount / fmt.Format.nSamplesPerSec); written_samples = 0; audio_block = new BYTE[bufferFrameCount*pwfx->nBlockAlign]; return S_OK; }
HRESULT CBaseReferenceClock::AdviseThread() { DWORD dwWait = INFINITE; // The first thing we do is wait until something interesting happens // (meaning a first advise or shutdown). This prevents us calling // GetPrivateTime immediately which is goodness as that is a virtual // routine and the derived class may not yet be constructed. (This // thread is created in the base class constructor.) while ( !m_bAbort ) { // Wait for an interesting event to happen DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait )); WaitForSingleObject(m_pSchedule->GetEvent(), dwWait); if (m_bAbort) break; // There are several reasons why we need to work from the internal // time, mainly to do with what happens when time goes backwards. // Mainly, it stop us looping madly if an event is just about to // expire when the clock goes backward (i.e. GetTime stop for a // while). const REFERENCE_TIME rtNow = GetPrivateTime(); DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"), ConvertToMilliseconds(rtNow) )); // We must add in a millisecond, since this is the resolution of our // WaitForSingleObject timer. Failure to do so will cause us to loop // franticly for (approx) 1 a millisecond. m_rtNextAdvise = m_pSchedule->Advise( 10000 + rtNow ); LONGLONG llWait = m_rtNextAdvise - rtNow; ASSERT( llWait > 0 ); llWait = ConvertToMilliseconds(llWait); // DON'T replace this with a max!! (The type's of these things is VERY important) dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait); }; return NOERROR; }
REFERENCE_TIME CSyncClock::GetPrivateTime() { UINT64 qpcNow = GetCurrentTimestamp(); UINT64 hwClock = 0; UINT64 hwQpc = 0; INT64 delta = 0; INT64 qpcDelta = 0; HRESULT hr = S_FALSE; //UINT64 start1 = GetCurrentTimestamp(); if (m_pSettings->m_bHWBasedRefClock) hr = m_pAudioRenderer->AudioClock(hwClock, hwQpc, qpcNow); //UINT64 end1 = GetCurrentTimestamp(); if (hr == S_OK) { if (m_clockSource != HW) { Log("Using HW clock"); m_clockSource = HW; } if (m_ullStartQpcHW == 0) { m_ullStartQpcHW = hwQpc; m_ullStartTimeSystem = qpcNow; } if (m_ullStartTimeHW == 0) { m_ullStartTimeHW = hwClock; m_ullPrevSystemTime = qpcNow; } qpcDelta = qpcNow - m_ullPrevSystemTime; m_llDurationHW = (hwClock - m_ullStartTimeHW); m_llDurationSystem = (qpcNow - m_ullStartTimeSystem); if (m_bDiscontinuity) { m_ullStartTimeHW = m_ullPrevTimeHW = hwClock; m_ullStartQpcHW = m_ullPrevQpcHW = hwQpc; m_ullStartTimeSystem = qpcNow; delta = qpcNow - m_ullPrevSystemTime; m_bDiscontinuity = false; } else { delta = hwClock - m_ullPrevTimeHW; m_ullPrevTimeHW = hwClock; m_ullPrevQpcHW = hwQpc; } } else { if (m_clockSource != SYSTEM) { Log("Using SYSTEM clock"); m_clockSource = SYSTEM; } if (m_ullPrevSystemTime == 0) { m_ullPrevSystemTime = qpcNow; m_ullStartTimeSystem = qpcNow; } qpcDelta = delta = qpcNow - m_ullPrevSystemTime; if (m_ullStartTimeSystem == 0) m_ullStartTimeSystem = qpcNow; if (m_ullPrevSystemTime == 0) m_ullPrevSystemTime = qpcNow; } if (qpcNow < m_ullPrevSystemTime) delta += REFERENCE_TIME(ULLONG_MAX) + 1; m_ullPrevSystemTime = qpcNow; //UINT64 start2 = GetCurrentTimestamp(); INT64 synchCorrectedDelta = m_SynchCorrection.GetCorrectedTimeDelta(delta, m_ullHWPrivateTime, m_ullPrivateTime); //UINT64 end2 = GetCurrentTimestamp(); //Log("diff %I64d delta: %I64d synchCorrectedDelta: %I64d qpc based delta: %I64d", delta - synchCorrectedDelta, delta, synchCorrectedDelta, qpcDelta); m_ullHWPrivateTime = m_ullHWPrivateTime + delta; m_ullPrivateTime = m_ullPrivateTime + synchCorrectedDelta; //UINT64 qpcEnd = GetCurrentTimestamp(); /*if (qpcEnd - qpcNow > 2000) Log("DUR: %I64d first: %I64d second: %I64d", qpcEnd - qpcNow, end1 - start1, end2 - start2); */ return m_ullPrivateTime; }
HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CPlaylist& PlaylistItems, CPlaylistChapter& Chapters) { BYTE Buff[4]; CPath Path(strPlaylistFile); // Get BDMV folder Path.RemoveFileSpec(); Path.RemoveFileSpec(); m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (m_hFile != INVALID_HANDLE_VALUE) { REFERENCE_TIME* rtOffset = DNew REFERENCE_TIME[PlaylistItems.GetCount()]; REFERENCE_TIME rtSum = 0; USHORT nIndex = 0; POSITION pos = PlaylistItems.GetHeadPosition(); while (pos) { CHdmvClipInfo::PlaylistItem* PI = PlaylistItems.GetNext(pos); rtOffset[nIndex] = rtSum - PI->m_rtIn; rtSum = rtSum + PI->Duration(); nIndex++; } ReadBuffer(Buff, 4); if (memcmp(Buff, "MPLS", 4)) { SAFE_DELETE_ARRAY(rtOffset); return CloseFile(VFW_E_INVALID_FILE_FORMAT); } ReadBuffer(Buff, 4); if ((memcmp(Buff, "0200", 4)!=0) && (memcmp(Buff, "0100", 4)!=0)) { SAFE_DELETE_ARRAY(rtOffset); return CloseFile(VFW_E_INVALID_FILE_FORMAT); } LARGE_INTEGER Pos = {0, 0}; USHORT nMarkCount; ReadDword(); // PlayList_start_address Pos.QuadPart = ReadDword(); // PlayListMark_start_address // PlayListMark() SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN); ReadDword(); // length nMarkCount = ReadShort(); // number_of_PlayList_marks for (size_t i = 0; i < nMarkCount; i++) { PlaylistChapter Chapter; ReadByte(); // reserved_for_future_use Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id Chapter.m_rtTimestamp = REFERENCE_TIME(20000.0f*ReadDword()/90) + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID Chapter.m_rtDuration = REFERENCE_TIME(20000.0f*ReadDword()/90); // duration if (Chapter.m_rtTimestamp < 0 || Chapter.m_rtTimestamp > rtSum) { continue; } Chapters.AddTail (Chapter); } CloseFile(S_OK); SAFE_DELETE_ARRAY(rtOffset); return S_OK; } return AmHresultFromWin32(GetLastError()); }
HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, CPlaylist& Playlist, BOOL bFullInfoRead) { BYTE Buff[5]; CPath Path (strPlaylistFile); bool bDuplicate = false; rtDuration = 0; // Get BDMV folder Path.RemoveFileSpec(); Path.RemoveFileSpec(); m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (m_hFile != INVALID_HANDLE_VALUE) { DbgLog((LOG_TRACE, 3, _T("CHdmvClipInfo::ReadPlaylist() : %s"), strPlaylistFile)); ReadBuffer(Buff, 4); if (memcmp(Buff, "MPLS", 4)) { return CloseFile(VFW_E_INVALID_FILE_FORMAT); } ReadBuffer(Buff, 4); if ((memcmp(Buff, "0200", 4)) && (memcmp(Buff, "0100", 4))) { return CloseFile(VFW_E_INVALID_FILE_FORMAT); } LARGE_INTEGER Pos = {0, 0}; DWORD dwTemp; USHORT nPlaylistItems; Pos.QuadPart = ReadDword(); // PlayList_start_address ReadDword(); // PlayListMark_start_address // PlayList() SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN); ReadDword(); // length ReadShort(); // reserved_for_future_use nPlaylistItems = ReadShort(); // number_of_PlayItems ReadShort(); // number_of_SubPaths Pos.QuadPart += 10; __int64 TotalSize = 0; for (size_t i = 0; i < nPlaylistItems; i++) { CAutoPtr<PlaylistItem> Item(DNew PlaylistItem); SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN); Pos.QuadPart += ReadShort() + 2; ReadBuffer(Buff, 5); Item->m_strFileName.Format(_T("%s\\STREAM\\%c%c%c%c%c.M2TS"), CString(Path), Buff[0], Buff[1], Buff[2], Buff[3], Buff[4]); ReadBuffer(Buff, 4); if (memcmp(Buff, "M2TS", 4)) { return CloseFile(VFW_E_INVALID_FILE_FORMAT); } if (!::PathFileExists(Item->m_strFileName)) { DbgLog((LOG_TRACE, 3, _T(" ==> %s is missing, skip it"), Item->m_strFileName)); continue; } ReadBuffer(Buff, 3); dwTemp = ReadDword(); Item->m_rtIn = REFERENCE_TIME(20000.0f*dwTemp/90); dwTemp = ReadDword(); Item->m_rtOut = REFERENCE_TIME(20000.0f*dwTemp/90); Item->m_rtStartTime = rtDuration; rtDuration += (Item->m_rtOut - Item->m_rtIn); if (bFullInfoRead) { LARGE_INTEGER size = {0, 0}; HANDLE hFile = CreateFile(Item->m_strFileName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hFile != INVALID_HANDLE_VALUE) { GetFileSizeEx(hFile, &size); CloseHandle(hFile); } Item->m_SizeIn = TotalSize; TotalSize += size.QuadPart; Item->m_SizeOut = TotalSize; } POSITION pos = Playlist.GetHeadPosition(); while (pos) { PlaylistItem* pItem = Playlist.GetNext(pos); if (*pItem == *Item) { bDuplicate = true; break; } } DbgLog((LOG_TRACE, 3, _T(" ==> %s, Duration : %s [%15I64d], Total duration : %s, Size : %I64d"), Item->m_strFileName, ReftimeToString(Item->Duration()), Item->Duration(), ReftimeToString(rtDuration), Item->Size())); Playlist.AddTail(Item); } CloseFile(S_OK); if (bFullInfoRead) { POSITION pos = Playlist.GetHeadPosition(); while (pos) { PlaylistItem* pItem = Playlist.GetNext(pos); CString fname = pItem->m_strFileName; fname.Replace(L"\\STREAM\\", L"\\CLIPINF\\"); fname.Replace(L".M2TS", L".CLPI"); ReadInfo(fname, &pItem->m_sps); } } return Playlist.IsEmpty() ? E_FAIL : bDuplicate ? S_FALSE : S_OK; } return AmHresultFromWin32(GetLastError()); }
HRESULT CHdmvClipInfo::ReadCpiInfo(CAtlArray<SyncPoint>* sps) { sps->RemoveAll(); CAtlArray<ClpiEpMapEntry> ClpiEpMapList; LARGE_INTEGER Pos = {0, 0}; Pos.QuadPart = Cpi_start_addrress; SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN); DWORD len = ReadDword(); if (len == 0) { return E_FAIL; } BYTE* buf = NULL; ReadByte(); BYTE Type = ReadByte() & 0xF; DWORD ep_map_pos = Cpi_start_addrress + 4 + 2; ReadByte(); BYTE num_stream_pid = ReadByte(); DWORD size = num_stream_pid * 12; buf = DNew BYTE[size]; ReadBuffer(buf, size); CGolombBuffer gb(buf, size); for (int i = 0; i < num_stream_pid; i++) { ClpiEpMapEntry em; em.pid = gb.ReadShort(); gb.BitRead(10); em.ep_stream_type = gb.BitRead(4); em.num_ep_coarse = gb.ReadShort(); em.num_ep_fine = gb.BitRead(18); em.ep_map_stream_start_addr = gb.ReadDword() + ep_map_pos; em.coarse = DNew ClpiEpCoarse[em.num_ep_coarse]; em.fine = DNew ClpiEpFine[em.num_ep_fine]; ClpiEpMapList.Add(em); } delete[] buf; for (int i = 0; i < num_stream_pid; i++) { ClpiEpMapEntry* em = &ClpiEpMapList[i]; Pos.QuadPart = em->ep_map_stream_start_addr; SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN); DWORD fine_start = ReadDword(); size = em->num_ep_coarse * 8; buf = DNew BYTE[size]; ReadBuffer(buf, size); gb.Reset(buf, size); for (int j = 0; j < em->num_ep_coarse; j++) { em->coarse[j].ref_ep_fine_id = gb.BitRead(18); em->coarse[j].pts_ep = gb.BitRead(14); em->coarse[j].spn_ep = gb.ReadDword(); } delete[] buf; Pos.QuadPart = em->ep_map_stream_start_addr+fine_start; SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN); size = em->num_ep_fine * 4; buf = DNew BYTE[size]; ReadBuffer(buf, size); gb.Reset(buf, size); for (int j = 0; j < em->num_ep_fine; j++) { em->fine[j].is_angle_change_point = gb.BitRead(1); em->fine[j].i_end_position_offset = gb.BitRead(3); em->fine[j].pts_ep = gb.BitRead(11); em->fine[j].spn_ep = gb.BitRead(17); } delete[] buf; } if (ClpiEpMapList.GetCount() > 0) { const ClpiEpMapEntry* entry = &ClpiEpMapList[0]; for (int i = 0; i < entry->num_ep_coarse; i++) { int start, end; const ClpiEpCoarse* coarse = &entry->coarse[i]; start = coarse->ref_ep_fine_id; if (i < entry->num_ep_coarse - 1) { end = entry->coarse[i+1].ref_ep_fine_id; } else { end = entry->num_ep_fine; } for (int j = start; j < end; j++) { ClpiEpFine* fine = &entry->fine[j]; uint64 pts = ((uint64)(coarse->pts_ep & ~0x01) << 18) + ((uint64)fine->pts_ep << 8); uint32 spn = (coarse->spn_ep & ~0x1FFFF) + fine->spn_ep; SyncPoint sp = {REFERENCE_TIME(20000.0f*pts/90), (__int64)spn * 192}; sps->Add(sp); } } } for (size_t ii = 0; ii < ClpiEpMapList.GetCount(); ii++) { delete[] ClpiEpMapList[ii].coarse; delete[] ClpiEpMapList[ii].fine; } ClpiEpMapList.RemoveAll(); return S_OK; }