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/>.
24 #include "HdmvClipInfo.h"
27 extern LCID
ISO6392ToLcid(LPCSTR code
);
29 CHdmvClipInfo::CHdmvClipInfo(void)
31 m_hFile
= INVALID_HANDLE_VALUE
;
35 CHdmvClipInfo::~CHdmvClipInfo()
40 HRESULT
CHdmvClipInfo::CloseFile(HRESULT hr
)
42 if (m_hFile
!= INVALID_HANDLE_VALUE
) {
44 m_hFile
= INVALID_HANDLE_VALUE
;
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()
63 ReadFile (m_hFile
, &bVal
, sizeof(bVal
), &dwRead
, NULL
);
68 void CHdmvClipInfo::ReadBuffer(BYTE
* pBuff
, DWORD nLen
)
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
;
80 m_Streams
.RemoveAll();
81 SetFilePointer (m_hFile
, ProgramInfo_start_address
, NULL
, FILE_BEGIN
);
84 ReadByte(); //reserved_for_word_align
85 number_of_program_sequences
= (BYTE
)ReadByte();
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);
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
;
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
;
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
);
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
);
156 SetFilePointer(m_hFile
, dwPos
, NULL
, FILE_BEGIN
);
162 HRESULT
CHdmvClipInfo::ReadInfo(LPCTSTR strFile
)
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
) {
172 if (memcmp (Buff
, "HDMV", 4)) {
173 return CloseFile(VFW_E_INVALID_FILE_FORMAT
);
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();
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
];
206 LPCTSTR
CHdmvClipInfo::Stream::Format()
209 case VIDEO_STREAM_MPEG1
:
211 case VIDEO_STREAM_MPEG2
:
213 case VIDEO_STREAM_H264
:
215 case VIDEO_STREAM_VC1
:
217 case AUDIO_STREAM_MPEG1
:
219 case AUDIO_STREAM_MPEG2
:
221 case AUDIO_STREAM_LPCM
:
223 case AUDIO_STREAM_AC3
:
225 case AUDIO_STREAM_DTS
:
227 case AUDIO_STREAM_AC3_TRUE_HD
:
229 case AUDIO_STREAM_AC3_PLUS
:
231 case AUDIO_STREAM_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
:
241 case INTERACTIVE_GRAPHICS_STREAM
:
243 case SUBTITLE_STREAM
:
246 return _T("Unknown");
250 HRESULT
CHdmvClipInfo::ReadPlaylist(CString strPlaylistFile
, REFERENCE_TIME
& rtDuration
, CAtlList
<PlaylistItem
>& Playlist
)
254 CPath
Path (strPlaylistFile
);
255 bool bDuplicate
= false;
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
) {
267 if (memcmp (Buff
, "MPLS", 4)) {
268 return CloseFile(VFW_E_INVALID_FILE_FORMAT
);
272 if ((memcmp (Buff
, "0200", 4)!=0) && (memcmp (Buff
, "0100", 4)!=0)) {
273 return CloseFile(VFW_E_INVALID_FILE_FORMAT
);
278 USHORT nPlaylistItems
;
280 dwPos
= ReadDword(); // PlayList_start_address
281 ReadDword(); // PlayListMark_start_address
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
291 for (size_t i
=0; i
<nPlaylistItems
; i
++) {
293 SetFilePointer(m_hFile
, dwPos
, NULL
, FILE_BEGIN
);
294 dwPos
= dwPos
+ ReadShort() + 2;
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]);
299 if (memcmp (Buff
, "M2TS", 4)) {
300 return CloseFile(VFW_E_INVALID_FILE_FORMAT
);
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
) {
315 Playlist
.AddTail (Item
);
317 //TRACE ("File : %S, Duration : %S, Total duration : %S\n", strTemp, ReftimeToString (rtOut - rtIn), ReftimeToString (rtDuration));
321 return bDuplicate
? S_FALSE
: S_OK
;
324 return AmHresultFromWin32(GetLastError());
327 HRESULT
CHdmvClipInfo::ReadChapters(CString strPlaylistFile
, CAtlList
<CHdmvClipInfo::PlaylistItem
>& PlaylistItems
, CAtlList
<PlaylistChapter
>& Chapters
)
330 CPath
Path (strPlaylistFile
);
331 bool bDuplicate
= false;
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;
346 POSITION pos
= PlaylistItems
.GetHeadPosition();
349 CHdmvClipInfo::PlaylistItem
& PI
= PlaylistItems
.GetNext(pos
);
351 rtOffset
[nIndex
] = rtSum
- PI
.m_rtIn
;
352 rtSum
= rtSum
+ PI
.Duration();
357 if (memcmp (Buff
, "MPLS", 4)) {
358 SAFE_DELETE_ARRAY(rtOffset
);
359 return CloseFile(VFW_E_INVALID_FILE_FORMAT
);
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
);
371 ReadDword(); // PlayList_start_address
372 dwPos
= ReadDword(); // PlayListMark_start_address
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));
395 SAFE_DELETE_ARRAY(rtOffset
);
396 return bDuplicate
? S_FALSE
: S_OK
;
399 return AmHresultFromWin32(GetLastError());
404 HRESULT
CHdmvClipInfo::FindMainMovie(LPCTSTR strFolder
, CString
& strPlaylistFile
, CAtlList
<PlaylistItem
>& MainPlaylist
, CAtlList
<PlaylistItem
>& MPLSPlaylists
)
408 CString
strPath (strFolder
);
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
;
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
) {
434 strPlaylistFile
= strCurrentPlaylist
;
435 MainPlaylist
.RemoveAll();
436 POSITION pos
= Playlist
.GetHeadPosition();
438 MainPlaylist
.AddTail(Playlist
.GetNext(pos
));
442 if(rtCurrent
>= (REFERENCE_TIME
)MIN_LIMIT
*600000000) {
444 Item
.m_strFileName
= strCurrentPlaylist
;
446 Item
.m_rtOut
= rtCurrent
;
447 MPLSPlaylists
.AddTail(Item
);
451 } while(FindNextFile(hFind
, &fd
));
456 if(MPLSPlaylists
.GetCount() > 1) {
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));