Merge some MPC-HC Rev.3895 code to get HdmvSub and DVBSub support.
[xy_vsfilter.git] / src / dsutil / HdmvClipInfo.cpp
blob6a170cfd06945908fcaff8b30af21727eb17305e
1 /*
2 * $Id: HdmvClipInfo.cpp 3891 2011-12-12 00:10:53Z Aleksoid $
4 * (C) 2006-2011 see AUTHORS
6 * This file is part of mplayerc.
8 * Mplayerc is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * Mplayerc is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "stdafx.h"
24 #include "HdmvClipInfo.h"
25 #include "DSUtil.h"
27 extern LCID ISO6392ToLcid(LPCSTR code);
29 CHdmvClipInfo::CHdmvClipInfo(void)
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 DWORD dwPos;
80 m_Streams.RemoveAll();
81 SetFilePointer (m_hFile, ProgramInfo_start_address, NULL, FILE_BEGIN);
83 ReadDword(); //length
84 ReadByte(); //reserved_for_word_align
85 number_of_program_sequences = (BYTE)ReadByte();
86 int iStream = 0;
87 for (size_t i=0; i<number_of_program_sequences; i++) {
88 ReadDword(); //SPN_program_sequence_start
89 ReadShort(); //program_map_PID
90 number_of_streams_in_ps = (BYTE)ReadByte(); //number_of_streams_in_ps
91 ReadByte(); //reserved_for_future_use
93 for (size_t stream_index=0; stream_index<number_of_streams_in_ps; stream_index++) {
94 m_Streams.SetCount(iStream + 1);
95 m_Streams[iStream].m_PID = ReadShort(); // stream_PID
97 // == StreamCodingInfo
98 dwPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT) + 1;
99 dwPos += ReadByte(); // length
100 m_Streams[iStream].m_Type = (PES_STREAM_TYPE)ReadByte();
102 switch (m_Streams[iStream].m_Type) {
103 case VIDEO_STREAM_MPEG1:
104 case VIDEO_STREAM_MPEG2:
105 case VIDEO_STREAM_H264:
106 case VIDEO_STREAM_VC1: {
107 uint8 Temp = ReadByte();
108 BDVM_VideoFormat VideoFormat = (BDVM_VideoFormat)(Temp >> 4);
109 BDVM_FrameRate FrameRate = (BDVM_FrameRate)(Temp & 0xf);
110 Temp = ReadByte();
111 BDVM_AspectRatio AspectRatio = (BDVM_AspectRatio)(Temp >> 4);
113 m_Streams[iStream].m_VideoFormat = VideoFormat;
114 m_Streams[iStream].m_FrameRate = FrameRate;
115 m_Streams[iStream].m_AspectRatio = AspectRatio;
117 break;
118 case AUDIO_STREAM_MPEG1:
119 case AUDIO_STREAM_MPEG2:
120 case AUDIO_STREAM_LPCM:
121 case AUDIO_STREAM_AC3:
122 case AUDIO_STREAM_DTS:
123 case AUDIO_STREAM_AC3_TRUE_HD:
124 case AUDIO_STREAM_AC3_PLUS:
125 case AUDIO_STREAM_DTS_HD:
126 case AUDIO_STREAM_DTS_HD_MASTER_AUDIO:
127 case SECONDARY_AUDIO_AC3_PLUS:
128 case SECONDARY_AUDIO_DTS_HD: {
129 uint8 Temp = ReadByte();
130 BDVM_ChannelLayout ChannelLayout = (BDVM_ChannelLayout)(Temp >> 4);
131 BDVM_SampleRate SampleRate = (BDVM_SampleRate)(Temp & 0xF);
133 ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3);
134 m_Streams[iStream].m_LCID = ISO6392ToLcid (m_Streams[iStream].m_LanguageCode);
135 m_Streams[iStream].m_ChannelLayout = ChannelLayout;
136 m_Streams[iStream].m_SampleRate = SampleRate;
138 break;
139 case PRESENTATION_GRAPHICS_STREAM:
140 case INTERACTIVE_GRAPHICS_STREAM: {
141 ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3);
142 m_Streams[iStream].m_LCID = ISO6392ToLcid (m_Streams[iStream].m_LanguageCode);
144 break;
145 case SUBTITLE_STREAM: {
146 ReadByte(); // Should this really be here?
147 ReadBuffer((BYTE*)m_Streams[iStream].m_LanguageCode, 3);
148 m_Streams[iStream].m_LCID = ISO6392ToLcid (m_Streams[iStream].m_LanguageCode);
150 break;
151 default :
152 break;
155 iStream++;
156 SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN);
159 return S_OK;
162 HRESULT CHdmvClipInfo::ReadInfo(LPCTSTR strFile)
164 BYTE Buff[100];
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 ReadBuffer(Buff, 4);
172 if (memcmp (Buff, "HDMV", 4)) {
173 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
176 ReadBuffer(Buff, 4);
177 if ((memcmp (Buff, "0200", 4)!=0) && (memcmp (Buff, "0100", 4)!=0)) {
178 return CloseFile (VFW_E_INVALID_FILE_FORMAT);
181 SequenceInfo_start_address = ReadDword();
182 ProgramInfo_start_address = ReadDword();
184 ReadProgramInfo();
186 m_bIsHdmv = true;
188 return CloseFile(S_OK);
191 return AmHresultFromWin32(GetLastError());
194 CHdmvClipInfo::Stream* CHdmvClipInfo::FindStream(SHORT wPID)
196 size_t nStreams = m_Streams.GetCount();
197 for (size_t i=0; i<nStreams; i++) {
198 if (m_Streams[i].m_PID == wPID) {
199 return &m_Streams[i];
203 return NULL;
206 LPCTSTR CHdmvClipInfo::Stream::Format()
208 switch (m_Type) {
209 case VIDEO_STREAM_MPEG1:
210 return _T("Mpeg1");
211 case VIDEO_STREAM_MPEG2:
212 return _T("Mpeg2");
213 case VIDEO_STREAM_H264:
214 return _T("H264");
215 case VIDEO_STREAM_VC1:
216 return _T("VC1");
217 case AUDIO_STREAM_MPEG1:
218 return _T("MPEG1");
219 case AUDIO_STREAM_MPEG2:
220 return _T("MPEG2");
221 case AUDIO_STREAM_LPCM:
222 return _T("LPCM");
223 case AUDIO_STREAM_AC3:
224 return _T("AC3");
225 case AUDIO_STREAM_DTS:
226 return _T("DTS");
227 case AUDIO_STREAM_AC3_TRUE_HD:
228 return _T("MLP");
229 case AUDIO_STREAM_AC3_PLUS:
230 return _T("DD+");
231 case AUDIO_STREAM_DTS_HD:
232 return _T("DTS-HD");
233 case AUDIO_STREAM_DTS_HD_MASTER_AUDIO:
234 return _T("DTS-HD XLL");
235 case SECONDARY_AUDIO_AC3_PLUS:
236 return _T("Sec DD+");
237 case SECONDARY_AUDIO_DTS_HD:
238 return _T("Sec DTS-HD");
239 case PRESENTATION_GRAPHICS_STREAM :
240 return _T("PG");
241 case INTERACTIVE_GRAPHICS_STREAM :
242 return _T("IG");
243 case SUBTITLE_STREAM :
244 return _T("Text");
245 default :
246 return _T("Unknown");
250 HRESULT CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile, REFERENCE_TIME& rtDuration, CAtlList<PlaylistItem>& Playlist)
253 BYTE Buff[100];
254 CPath Path (strPlaylistFile);
255 bool bDuplicate = false;
256 rtDuration = 0;
258 // Get BDMV folder
259 Path.RemoveFileSpec();
260 Path.RemoveFileSpec();
262 m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
263 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
265 if(m_hFile != INVALID_HANDLE_VALUE) {
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 DWORD dwPos;
277 DWORD dwTemp;
278 USHORT nPlaylistItems;
280 dwPos = ReadDword(); // PlayList_start_address
281 ReadDword(); // PlayListMark_start_address
283 // PlayList()
284 SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN);
285 ReadDword(); // length
286 ReadShort(); // reserved_for_future_use
287 nPlaylistItems = ReadShort(); // number_of_PlayItems
288 ReadShort(); // number_of_SubPaths
290 dwPos += 10;
291 for (size_t i=0; i<nPlaylistItems; i++) {
292 PlaylistItem Item;
293 SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN);
294 dwPos = dwPos + 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 ("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 BYTE Buff[100];
330 CPath Path (strPlaylistFile);
331 bool bDuplicate = false;
333 // Get BDMV folder
334 Path.RemoveFileSpec();
335 Path.RemoveFileSpec();
337 m_hFile = CreateFile(strPlaylistFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
338 OPEN_EXISTING, FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
340 if(m_hFile != INVALID_HANDLE_VALUE)
342 REFERENCE_TIME* rtOffset = new REFERENCE_TIME[PlaylistItems.GetCount()];
343 REFERENCE_TIME rtSum = 0;
344 int nIndex = 0;
346 POSITION pos = PlaylistItems.GetHeadPosition();
347 while(pos)
349 CHdmvClipInfo::PlaylistItem& PI = PlaylistItems.GetNext(pos);
351 rtOffset[nIndex] = rtSum - PI.m_rtIn;
352 rtSum = rtSum + PI.Duration();
353 nIndex++;
356 ReadBuffer(Buff, 4);
357 if (memcmp (Buff, "MPLS", 4)) {
358 SAFE_DELETE_ARRAY(rtOffset);
359 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
362 ReadBuffer(Buff, 4);
363 if ((memcmp (Buff, "0200", 4)!=0) && (memcmp (Buff, "0100", 4)!=0)) {
364 SAFE_DELETE_ARRAY(rtOffset);
365 return CloseFile(VFW_E_INVALID_FILE_FORMAT);
368 DWORD dwPos;
369 USHORT nMarkCount;
371 ReadDword(); // PlayList_start_address
372 dwPos = ReadDword(); // PlayListMark_start_address
374 // PlayListMark()
375 SetFilePointer(m_hFile, dwPos, NULL, FILE_BEGIN);
376 ReadDword(); // length
377 nMarkCount = ReadShort(); // number_of_PlayList_marks
378 for (size_t i=0; i<nMarkCount; i++)
380 PlaylistChapter Chapter;
382 ReadByte(); // reserved_for_future_use
383 Chapter.m_nMarkType = (PlaylistMarkType)ReadByte(); // mark_type
384 Chapter.m_nPlayItemId = ReadShort(); // ref_to_PlayItem_id
385 Chapter.m_rtTimestamp = 20000i64*ReadDword()/90 + rtOffset[Chapter.m_nPlayItemId]; // mark_time_stamp
386 Chapter.m_nEntryPID = ReadShort(); // entry_ES_PID
387 Chapter.m_rtDuration = 20000i64*ReadDword()/90; // duration
389 Chapters.AddTail (Chapter);
391 // TRACE ("Chapter %d : %S\n", i, ReftimeToString (Chapter.m_rtTimestamp));
394 CloseFile (S_OK);
395 SAFE_DELETE_ARRAY(rtOffset);
396 return bDuplicate ? S_FALSE : S_OK;
399 return AmHresultFromWin32(GetLastError());
402 #define MIN_LIMIT 3
404 HRESULT CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder, CString& strPlaylistFile, CAtlList<PlaylistItem>& MainPlaylist, CAtlList<PlaylistItem>& MPLSPlaylists)
406 HRESULT hr = E_FAIL;
408 CString strPath (strFolder);
409 CString strFilter;
411 MPLSPlaylists.RemoveAll();
413 CAtlList<PlaylistItem> Playlist;
414 WIN32_FIND_DATA fd = {0};
416 strPath.Replace(_T("\\PLAYLIST\\"), _T("\\"));
417 strPath.Replace(_T("\\STREAM\\"), _T("\\"));
418 strPath += _T("\\BDMV\\");
419 strFilter.Format (_T("%sPLAYLIST\\*.mpls"), strPath);
421 HANDLE hFind = FindFirstFile(strFilter, &fd);
422 if(hFind != INVALID_HANDLE_VALUE) {
423 REFERENCE_TIME rtMax = 0;
424 REFERENCE_TIME rtCurrent;
425 CString strCurrentPlaylist;
426 do {
427 strCurrentPlaylist.Format(_T("%sPLAYLIST\\%s"), strPath, fd.cFileName);
428 Playlist.RemoveAll();
430 // Main movie shouldn't have duplicate M2TS filename...
431 if (ReadPlaylist(strCurrentPlaylist, rtCurrent, Playlist) == S_OK) {
432 if(rtCurrent > rtMax) {
433 rtMax = rtCurrent;
434 strPlaylistFile = strCurrentPlaylist;
435 MainPlaylist.RemoveAll();
436 POSITION pos = Playlist.GetHeadPosition();
437 while(pos) {
438 MainPlaylist.AddTail(Playlist.GetNext(pos));
440 hr = S_OK;
442 if(rtCurrent >= (REFERENCE_TIME)MIN_LIMIT*600000000) {
443 PlaylistItem Item;
444 Item.m_strFileName = strCurrentPlaylist;
445 Item.m_rtIn = 0;
446 Item.m_rtOut = rtCurrent;
447 MPLSPlaylists.AddTail(Item);
451 } while(FindNextFile(hFind, &fd));
453 FindClose(hFind);
456 if(MPLSPlaylists.GetCount() > 1) {
457 // bubble sort
458 for (size_t j=0; j<MPLSPlaylists.GetCount(); j++) {
459 for(size_t i=0; i<MPLSPlaylists.GetCount()-1; i++) {
460 if (MPLSPlaylists.GetAt(MPLSPlaylists.FindIndex(i)).Duration() < MPLSPlaylists.GetAt(MPLSPlaylists.FindIndex(i+1)).Duration()) {
461 MPLSPlaylists.SwapElements(MPLSPlaylists.FindIndex(i), MPLSPlaylists.FindIndex(i+1));
467 return hr;