Increase ParseScript cache from 30 to 90 seconds
[xy_vsfilter.git] / src / dsutil / HdmvClipInfo.cpp
blob1432eccd2a0c09d0226c3dc44edd27b5c5eeeda0
1 /*
2 * (C) 2006-2012 see Authors.txt
4 * This file is part of MPC-HC.
6 * MPC-HC is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * MPC-HC is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdafx.h"
22 #include "HdmvClipInfo.h"
23 #include "DSUtil.h"
25 extern LCID ISO6392ToLcid(LPCSTR code);
27 CHdmvClipInfo::CHdmvClipInfo(void) :
28 SequenceInfo_start_address(0),
29 ProgramInfo_start_address(0)
31 m_hFile = INVALID_HANDLE_VALUE;
32 m_bIsHdmv = false;
35 CHdmvClipInfo::~CHdmvClipInfo()
37 CloseFile(S_OK);
40 HRESULT CHdmvClipInfo::CloseFile(HRESULT hr)
42 if (m_hFile != INVALID_HANDLE_VALUE) {
43 CloseHandle(m_hFile);
44 m_hFile = INVALID_HANDLE_VALUE;
46 return hr;
49 DWORD CHdmvClipInfo::ReadDword()
51 return ReadByte() << 24 | ReadByte() << 16 | ReadByte() << 8 | ReadByte();
54 short CHdmvClipInfo::ReadShort()
56 return ReadByte() << 8 | ReadByte();
59 BYTE CHdmvClipInfo::ReadByte()
61 BYTE bVal;
62 DWORD dwRead;
63 ReadFile(m_hFile, &bVal, sizeof(bVal), &dwRead, NULL);
65 return bVal;
68 void CHdmvClipInfo::ReadBuffer(BYTE* pBuff, DWORD nLen)
70 DWORD dwRead;
71 ReadFile(m_hFile, pBuff, nLen, &dwRead, NULL);
74 HRESULT CHdmvClipInfo::ReadProgramInfo()
76 BYTE number_of_program_sequences;
77 BYTE number_of_streams_in_ps;
78 LARGE_INTEGER Pos;
80 m_Streams.RemoveAll();
81 Pos.QuadPart = ProgramInfo_start_address;
82 SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN);
84 ReadDword(); //length
85 ReadByte(); //reserved_for_word_align
86 number_of_program_sequences = (BYTE)ReadByte();
87 int iStream = 0;
88 for (size_t i = 0; i < number_of_program_sequences; i++) {
89 ReadDword(); //SPN_program_sequence_start
90 ReadShort(); //program_map_PID
91 number_of_streams_in_ps = (BYTE)ReadByte(); //number_of_streams_in_ps
92 ReadByte(); //reserved_for_future_use
94 for (size_t stream_index = 0; stream_index < number_of_streams_in_ps; stream_index++) {
95 m_Streams.SetCount(iStream + 1);
96 m_Streams[iStream].m_PID = ReadShort(); // stream_PID
98 // == StreamCodingInfo
99 Pos.QuadPart = 0;
100 SetFilePointerEx(m_hFile, Pos, &Pos, FILE_CURRENT);
101 Pos.QuadPart += ReadByte() + 1; // length
102 m_Streams[iStream].m_Type = (PES_STREAM_TYPE)ReadByte();
104 switch (m_Streams[iStream].m_Type) {
105 case VIDEO_STREAM_MPEG1:
106 case VIDEO_STREAM_MPEG2:
107 case VIDEO_STREAM_H264:
108 case VIDEO_STREAM_VC1: {
109 UINT8 Temp = ReadByte();
110 BDVM_VideoFormat VideoFormat = (BDVM_VideoFormat)(Temp >> 4);
111 BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf);
112 Temp = ReadByte();
113 BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4);
115 m_Streams[iStream].m_VideoFormat = VideoFormat;
116 m_Streams[iStream].m_FrameRate = FrameRate;
117 m_Streams[iStream].m_AspectRatio = AspectRatio;
119 break;
120 case AUDIO_STREAM_MPEG1:
121 case AUDIO_STREAM_MPEG2:
122 case AUDIO_STREAM_LPCM:
123 case AUDIO_STREAM_AC3:
124 case AUDIO_STREAM_DTS:
125 case AUDIO_STREAM_AC3_TRUE_HD:
126 case AUDIO_STREAM_AC3_PLUS:
127 case AUDIO_STREAM_DTS_HD:
128 case AUDIO_STREAM_DTS_HD_MASTER_AUDIO:
129 case SECONDARY_AUDIO_AC3_PLUS:
130 case SECONDARY_AUDIO_DTS_HD: {
131 UINT8 Temp = ReadByte();
132 BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4);
133 BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF);
135 ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3);
136 m_Streams[iStream].m_LCID = ISO6392ToLcid(m_Streams[iStream].m_LanguageCode);
137 m_Streams[iStream].m_ChannelLayout = ChannelLayout;
138 m_Streams[iStream].m_SampleRate = SampleRate;
140 break;
141 case PRESENTATION_GRAPHICS_STREAM:
142 case INTERACTIVE_GRAPHICS_STREAM: {
143 ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3);
144 m_Streams[iStream].m_LCID = ISO6392ToLcid(m_Streams[iStream].m_LanguageCode);
146 break;
147 case SUBTITLE_STREAM: {
148 ReadByte(); // Should this really be here?
149 ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3);
150 m_Streams[iStream].m_LCID = ISO6392ToLcid(m_Streams[iStream].m_LanguageCode);
152 break;
153 default:
154 break;
157 iStream++;
158 SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN);
161 return S_OK;
164 HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile)
166 m_bIsHdmv = false;
167 m_hFile = CreateFile(strFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
168 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
170 if (m_hFile != INVALID_HANDLE_VALUE) {
171 BYTE Buff[100];
172 ReadBuffer(Buff, 4);
173 if (memcmp(Buff, "HDMV", 4)) {
174 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
177 ReadBuffer(Buff, 4);
178 if ((memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) {
179 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
182 SequenceInfo_start_address = ReadDword();
183 ProgramInfo_start_address = ReadDword();
185 ReadProgramInfo();
187 m_bIsHdmv = true;
189 return CloseFile(S_OK);
192 return AmHresultFromWin32(GetLastError());
195 CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(short wPID)
197 size_t nStreams = m_Streams.GetCount();
198 for (size_t i = 0; i < nStreams; i++) {
199 if (m_Streams[i].m_PID == wPID) {
200 return &m_Streams[i];
204 return NULL;
207 LPCTSTR CHdmvClipInfo::Stream::Format()
209 switch (m_Type) {
210 case VIDEO_STREAM_MPEG1:
211 return _T("Mpeg1");
212 case VIDEO_STREAM_MPEG2:
213 return _T("Mpeg2");
214 case VIDEO_STREAM_H264:
215 return _T("H264");
216 case VIDEO_STREAM_VC1:
217 return _T("VC1");
218 case AUDIO_STREAM_MPEG1:
219 return _T("MPEG1");
220 case AUDIO_STREAM_MPEG2:
221 return _T("MPEG2");
222 case AUDIO_STREAM_LPCM:
223 return _T("LPCM");
224 case AUDIO_STREAM_AC3:
225 return _T("AC3");
226 case AUDIO_STREAM_DTS:
227 return _T("DTS");
228 case AUDIO_STREAM_AC3_TRUE_HD:
229 return _T("MLP");
230 case AUDIO_STREAM_AC3_PLUS:
231 return _T("DD+");
232 case AUDIO_STREAM_DTS_HD:
233 return _T("DTS-HD");
234 case AUDIO_STREAM_DTS_HD_MASTER_AUDIO:
235 return _T("DTS-HD XLL");
236 case SECONDARY_AUDIO_AC3_PLUS:
237 return _T("Sec DD+");
238 case SECONDARY_AUDIO_DTS_HD:
239 return _T("Sec DTS-HD");
240 case PRESENTATION_GRAPHICS_STREAM:
241 return _T("PG");
242 case INTERACTIVE_GRAPHICS_STREAM:
243 return _T("IG");
244 case SUBTITLE_STREAM:
245 return _T("Text");
246 default:
247 return _T("Unknown");
251 HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, CAtlList<PlaylistItem>& Playlist)
253 CPath Path(strPlaylistFile);
254 rtDuration = 0;
256 // Get BDMV folder
257 Path.RemoveFileSpec();
258 Path.RemoveFileSpec();
260 m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
261 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
263 if (m_hFile != INVALID_HANDLE_VALUE) {
264 BYTE Buff[100];
265 bool bDuplicate = false;
266 ReadBuffer(Buff, 4);
267 if (memcmp(Buff, "MPLS", 4)) {
268 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
271 ReadBuffer(Buff, 4);
272 if ((memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) {
273 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
276 LARGE_INTEGER Pos;
277 DWORD dwTemp;
278 unsigned short nPlaylistItems;
280 Pos.QuadPart = ReadDword(); // PlayList_start_address
281 ReadDword(); // PlayListMark_start_address
283 // PlayList()
284 SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN);
285 ReadDword(); // length
286 ReadShort(); // reserved_for_future_use
287 nPlaylistItems = ReadShort(); // number_of_PlayItems
288 ReadShort(); // number_of_SubPaths
290 Pos.QuadPart += 10;
291 for (size_t i = 0; i < nPlaylistItems; i++) {
292 PlaylistItem Item;
293 SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN);
294 Pos.QuadPart += ReadShort() + 2;
295 ReadBuffer(Buff, 5);
296 Item.m_strFileName.Format(_T("%s\\STREAM\\%c%c%c%c%c.M2TS"), Path, Buff[0], Buff[1], Buff[2], Buff[3], Buff[4]);
298 ReadBuffer(Buff, 4);
299 if (memcmp(Buff, "M2TS", 4)) {
300 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
302 ReadBuffer(Buff, 3);
304 dwTemp = ReadDword();
305 Item.m_rtIn = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits!
307 dwTemp = ReadDword();
308 Item.m_rtOut = 20000i64 * dwTemp / 90; // Carefull : 32->33 bits!
310 rtDuration += (Item.m_rtOut - Item.m_rtIn);
312 if (Playlist.Find(Item) != NULL) {
313 bDuplicate = true;
315 Playlist.AddTail(Item);
317 //TRACE(_T("File : %S, Duration : %S, Total duration : %S\n"), strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration));
320 CloseFile(S_OK);
321 return bDuplicate ? S_FALSE : S_OK;
324 return AmHresultFromWin32(GetLastError());
327 HRESULT CHdmvClipInfo::ReadChapters(CString strPlaylistFile, CAtlList<CHdmvClipInfo::PlaylistItem>& PlaylistItems, CAtlList<PlaylistChapter>& Chapters)
329 CPath Path(strPlaylistFile);
331 // Get BDMV folder
332 Path.RemoveFileSpec();
333 Path.RemoveFileSpec();
335 m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
336 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
338 if (m_hFile != INVALID_HANDLE_VALUE) {
339 REFERENCE_TIME* rtOffset = DEBUG_NEW REFERENCE_TIME[PlaylistItems.GetCount()];
340 REFERENCE_TIME rtSum = 0;
341 int nIndex = 0;
342 BYTE Buff[100];
343 bool bDuplicate = false;
345 POSITION pos = PlaylistItems.GetHeadPosition();
346 while (pos) {
347 CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos);
349 rtOffset[nIndex] = rtSum - PI.m_rtIn;
350 rtSum = rtSum + PI.Duration();
351 nIndex++;
354 ReadBuffer(Buff, 4);
355 if (memcmp(Buff, "MPLS", 4)) {
356 SAFE_DELETE_ARRAY(rtOffset);
357 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
360 ReadBuffer(Buff, 4);
361 if ((memcmp(Buff, "0200", 4) != 0) && (memcmp(Buff, "0100", 4) != 0)) {
362 SAFE_DELETE_ARRAY(rtOffset);
363 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
366 LARGE_INTEGER Pos;
367 unsigned short nMarkCount;
369 ReadDword(); // PlayList_start_address
370 Pos.QuadPart = ReadDword(); // PlayListMark_start_address
372 // PlayListMark()
373 SetFilePointerEx(m_hFile, Pos, NULL, FILE_BEGIN);
374 ReadDword(); // length
375 nMarkCount = ReadShort(); // number_of_PlayList_marks
376 for (size_t i = 0; i < nMarkCount; i++) {
377 PlaylistChapter Chapter;
379 ReadByte(); // reserved_for_future_use
380 Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type
381 Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id
382 Chapter.m_rtTimestamp = 20000i64 * ReadDword() / 90 + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp
383 Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID
384 Chapter.m_rtDuration = 20000i64 * ReadDword() / 90; // duration
386 Chapters.AddTail(Chapter);
388 //TRACE(_T("Chapter %d : %S\n"), i, ReftimeToString(Chapter.m_rtTimestamp));
391 CloseFile(S_OK);
392 SAFE_DELETE_ARRAY(rtOffset);
393 return bDuplicate ? S_FALSE : S_OK;
396 return AmHresultFromWin32(GetLastError());
399 #define MIN_LIMIT 3
401 HRESULT CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, CAtlList<PlaylistItem>& MainPlaylist, CAtlList<PlaylistItem>& MPLSPlaylists)
403 HRESULT hr = E_FAIL;
405 CString strPath(strFolder);
406 CString strFilter;
408 MPLSPlaylists.RemoveAll();
410 CAtlList<PlaylistItem> Playlist;
411 WIN32_FIND_DATA fd = {0};
413 strPath.Replace(_T("\\PLAYLIST\\"), _T("\\"));
414 strPath.Replace(_T("\\STREAM\\"), _T("\\"));
415 strPath += _T("\\BDMV\\");
416 strFilter.Format(_T("%sPLAYLIST\\*.mpls"), strPath);
418 HANDLE hFind = FindFirstFile(strFilter, &fd);
419 if (hFind != INVALID_HANDLE_VALUE) {
420 REFERENCE_TIME rtMax = 0;
421 REFERENCE_TIME rtCurrent;
422 CString strCurrentPlaylist;
423 do {
424 strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath, fd.cFileName);
425 Playlist.RemoveAll();
427 // Main movie shouldn't have duplicate M2TS filename...
428 if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) {
429 if (rtCurrent > rtMax) {
430 rtMax = rtCurrent;
431 strPlaylistFile = strCurrentPlaylist;
432 MainPlaylist.RemoveAll();
433 POSITION pos = Playlist.GetHeadPosition();
434 while (pos) {
435 MainPlaylist.AddTail(Playlist.GetNext(pos));
437 hr = S_OK;
439 if (rtCurrent >= (REFERENCE_TIME)MIN_LIMIT * 600000000) {
440 PlaylistItem Item;
441 Item.m_strFileName = strCurrentPlaylist;
442 Item.m_rtIn = 0;
443 Item.m_rtOut = rtCurrent;
444 MPLSPlaylists.AddTail(Item);
448 } while (FindNextFile(hFind, &fd));
450 FindClose(hFind);
453 if (MPLSPlaylists.GetCount() > 1) {
454 // bubble sort
455 for (size_t j = 0; j < MPLSPlaylists.GetCount(); j++) {
456 for (size_t i = 0; i < MPLSPlaylists.GetCount() - 1; i++) {
457 if (MPLSPlaylists.GetAt(MPLSPlaylists.FindIndex(i)).Duration() < MPLSPlaylists.GetAt(MPLSPlaylists.FindIndex(i + 1)).Duration()) {
458 MPLSPlaylists.SwapElements(MPLSPlaylists.FindIndex(i), MPLSPlaylists.FindIndex(i + 1));
464 return hr;