2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
28 #include "DeCSSInputPin.h"
29 #include "..\DSUtil\DSUtil.h"
31 #include "CSSscramble.h"
34 #include "..\..\include\moreuuids.h"
40 CDeCSSInputPin::CDeCSSInputPin(TCHAR
* pObjectName
, CTransformFilter
* pFilter
, HRESULT
* phr
, LPWSTR pName
)
41 : CTransformInputPin(pObjectName
, pFilter
, phr
, pName
)
44 memset(m_Challenge
, 0, sizeof(m_Challenge
));
45 memset(m_KeyCheck
, 0, sizeof(m_KeyCheck
));
46 memset(m_DiscKey
, 0, sizeof(m_DiscKey
));
47 memset(m_TitleKey
, 0, sizeof(m_TitleKey
));
50 STDMETHODIMP
CDeCSSInputPin::NonDelegatingQueryInterface(REFIID riid
, void** ppv
)
52 CheckPointer(ppv
, E_POINTER
);
56 __super::NonDelegatingQueryInterface(riid
, ppv
);
61 STDMETHODIMP
CDeCSSInputPin::Receive(IMediaSample
* pSample
)
63 long len
= pSample
->GetActualDataLength();
66 if(SUCCEEDED(pSample
->GetPointer(&p
)) && len
> 0)
70 if(m_mt
.majortype
== MEDIATYPE_DVD_ENCRYPTED_PACK
&& len
== 2048 && (p
[0x14]&0x30))
72 CSSdescramble(p
, m_TitleKey
);
75 if(CComQIPtr
<IMediaSample2
> pMS2
= pSample
)
77 AM_SAMPLE2_PROPERTIES props
;
78 memset(&props
, 0, sizeof(props
));
79 if(SUCCEEDED(pMS2
->GetProperties(sizeof(props
), (BYTE
*)&props
))
80 && (props
.dwTypeSpecificFlags
& AM_UseNewCSSKey
))
82 props
.dwTypeSpecificFlags
&= ~AM_UseNewCSSKey
;
83 pMS2
->SetProperties(sizeof(props
), (BYTE
*)&props
);
89 HRESULT hr
= Transform(pSample
);
91 return hr
== S_OK
? __super::Receive(pSample
) :
92 hr
== S_FALSE
? S_OK
: hr
;
95 void CDeCSSInputPin::StripPacket(BYTE
*& p
, long& len
)
97 GUID majortype
= m_mt
.majortype
;
99 if(majortype
== MEDIATYPE_MPEG2_PACK
|| majortype
== MEDIATYPE_DVD_ENCRYPTED_PACK
)
100 if(len
> 0 && *(DWORD
*)p
== 0xba010000) // MEDIATYPE_*_PACK
103 if(int stuffing
= (p
[-1]&7)) {len
-= stuffing
; p
+= stuffing
;}
104 majortype
= MEDIATYPE_MPEG2_PES
;
107 if(majortype
== MEDIATYPE_MPEG2_PES
)
108 if(len
> 0 && *(DWORD
*)p
== 0xbb010000)
111 int hdrlen
= ((p
[0]<<8)|p
[1]) + 2;
112 len
-= hdrlen
; p
+= hdrlen
;
115 if(majortype
== MEDIATYPE_MPEG2_PES
)
117 && ((*(DWORD
*)p
&0xf0ffffff) == 0xe0010000
118 || (*(DWORD
*)p
&0xe0ffffff) == 0xc0010000
119 || (*(DWORD
*)p
&0xbdffffff) == 0xbd010000)) // PES
121 bool ps1
= (*(DWORD
*)p
&0xbdffffff) == 0xbd010000;
124 int expected
= ((p
[0]<<8)|p
[1]);
128 for(int i
= 0; i
< 16 && *p
== 0xff; i
++, len
--, p
++);
130 if((*p
&0xc0) == 0x80) // mpeg2
133 len
-= *p
+1; p
+= *p
+1;
137 if((*p
&0xc0) == 0x40)
142 if((*p
&0x30) == 0x30 || (*p
&0x30) == 0x20)
144 bool pts
= !!(*p
&0x20), dts
= !!(*p
&0x10);
145 if(pts
) len
-= 5; p
+= 5;
146 if(dts
) {ASSERT((*p
&0xf0) == 0x10); len
-= 5; p
+= 5;}
157 if(m_mt
.subtype
== MEDIASUBTYPE_DVD_LPCM_AUDIO
) {len
-= 6; p
+= 6;}
158 else if(m_mt
.subtype
== MEDIASUBTYPE_DOLBY_AC3
|| m_mt
.subtype
== MEDIASUBTYPE_WAVE_DOLBY_AC3
159 || m_mt
.subtype
== MEDIASUBTYPE_DTS
|| m_mt
.subtype
== MEDIASUBTYPE_WAVE_DTS
) {len
-= 3; p
+= 3;}
164 expected
-= (p
- p0
);
165 len
= min(expected
, len
);
169 if(len
< 0) {ASSERT(0); len
= 0;}
174 STDMETHODIMP
CDeCSSInputPin::Set(REFGUID PropSet
, ULONG Id
, LPVOID pInstanceData
, ULONG InstanceLength
, LPVOID pPropertyData
, ULONG DataLength
)
176 if(PropSet
!= AM_KSPROPSETID_CopyProt
)
181 case AM_PROPERTY_COPY_MACROVISION
:
183 case AM_PROPERTY_DVDCOPY_CHLG_KEY
: // 3. auth: receive drive nonce word, also store and encrypt the buskey made up of the two nonce words
185 AM_DVDCOPY_CHLGKEY
* pChlgKey
= (AM_DVDCOPY_CHLGKEY
*)pPropertyData
;
186 for(int i
= 0; i
< 10; i
++)
187 m_Challenge
[i
] = pChlgKey
->ChlgKey
[9-i
];
189 CSSkey2(m_varient
, m_Challenge
, &m_Key
[5]);
191 CSSbuskey(m_varient
, m_Key
, m_KeyCheck
);
194 case AM_PROPERTY_DVDCOPY_DISC_KEY
: // 5. receive the disckey
196 AM_DVDCOPY_DISCKEY
* pDiscKey
= (AM_DVDCOPY_DISCKEY
*)pPropertyData
; // pDiscKey->DiscKey holds the disckey encrypted with itself and the 408 disckeys encrypted with the playerkeys
198 bool fSuccess
= false;
200 for(int j
= 0; j
< g_nPlayerKeys
; j
++)
202 for(int k
= 1; k
< 409; k
++)
205 for(int i
= 0; i
< 5; i
++)
206 DiscKey
[i
] = pDiscKey
->DiscKey
[k
*5+i
] ^ m_KeyCheck
[4-i
];
209 CSSdisckey(DiscKey
, g_PlayerKeys
[j
]);
212 for(int i
= 0; i
< 5; i
++)
213 Hash
[i
] = pDiscKey
->DiscKey
[i
] ^ m_KeyCheck
[4-i
];
216 CSSdisckey(Hash
, DiscKey
);
218 if(!memcmp(Hash
, DiscKey
, 6))
220 memcpy(m_DiscKey
, DiscKey
, 6);
232 case AM_PROPERTY_DVDCOPY_DVD_KEY1
: // 2. auth: receive our drive-encrypted nonce word and decrypt it for verification
234 AM_DVDCOPY_BUSKEY
* pKey1
= (AM_DVDCOPY_BUSKEY
*)pPropertyData
;
235 for(int i
= 0; i
< 5; i
++)
236 m_Key
[i
] = pKey1
->BusKey
[4-i
];
240 for(int i
= 31; i
>= 0; i
--)
242 CSSkey1(i
, m_Challenge
, m_KeyCheck
);
244 if(memcmp(m_KeyCheck
, &m_Key
[0], 5) == 0)
249 case AM_PROPERTY_DVDCOPY_REGION
:
251 case AM_PROPERTY_DVDCOPY_SET_COPY_STATE
:
253 case AM_PROPERTY_DVDCOPY_TITLE_KEY
: // 6. receive the title key and decrypt it with the disc key
255 AM_DVDCOPY_TITLEKEY
* pTitleKey
= (AM_DVDCOPY_TITLEKEY
*)pPropertyData
;
256 for(int i
= 0; i
< 5; i
++)
257 m_TitleKey
[i
] = pTitleKey
->TitleKey
[i
] ^ m_KeyCheck
[4-i
];
259 CSStitlekey(m_TitleKey
, m_DiscKey
);
263 return E_PROP_ID_UNSUPPORTED
;
269 STDMETHODIMP
CDeCSSInputPin::Get(REFGUID PropSet
, ULONG Id
, LPVOID pInstanceData
, ULONG InstanceLength
, LPVOID pPropertyData
, ULONG DataLength
, ULONG
* pBytesReturned
)
271 if(PropSet
!= AM_KSPROPSETID_CopyProt
)
276 case AM_PROPERTY_DVDCOPY_CHLG_KEY
: // 1. auth: send our nonce word
278 AM_DVDCOPY_CHLGKEY
* pChlgKey
= (AM_DVDCOPY_CHLGKEY
*)pPropertyData
;
279 for(int i
= 0; i
< 10; i
++)
280 pChlgKey
->ChlgKey
[i
] = 9 - (m_Challenge
[i
] = i
);
281 *pBytesReturned
= sizeof(AM_DVDCOPY_CHLGKEY
);
284 case AM_PROPERTY_DVDCOPY_DEC_KEY2
: // 4. auth: send back the encrypted drive nonce word to finish the authentication
286 AM_DVDCOPY_BUSKEY
* pKey2
= (AM_DVDCOPY_BUSKEY
*)pPropertyData
;
287 for(int i
= 0; i
< 5; i
++)
288 pKey2
->BusKey
[4-i
] = m_Key
[5+i
];
289 *pBytesReturned
= sizeof(AM_DVDCOPY_BUSKEY
);
292 case AM_PROPERTY_DVDCOPY_REGION
:
294 DVD_REGION
* pRegion
= (DVD_REGION
*)pPropertyData
;
295 pRegion
->RegionData
= 0;
296 pRegion
->SystemRegion
= 0;
297 *pBytesReturned
= sizeof(DVD_REGION
);
300 case AM_PROPERTY_DVDCOPY_SET_COPY_STATE
:
302 AM_DVDCOPY_SET_COPY_STATE
* pState
= (AM_DVDCOPY_SET_COPY_STATE
*)pPropertyData
;
303 pState
->DVDCopyState
= AM_DVDCOPYSTATE_AUTHENTICATION_REQUIRED
;
304 *pBytesReturned
= sizeof(AM_DVDCOPY_SET_COPY_STATE
);
308 return E_PROP_ID_UNSUPPORTED
;
314 STDMETHODIMP
CDeCSSInputPin::QuerySupported(REFGUID PropSet
, ULONG Id
, ULONG
* pTypeSupport
)
316 if(PropSet
!= AM_KSPROPSETID_CopyProt
)
321 case AM_PROPERTY_COPY_MACROVISION
:
322 *pTypeSupport
= KSPROPERTY_SUPPORT_SET
;
324 case AM_PROPERTY_DVDCOPY_CHLG_KEY
:
325 *pTypeSupport
= KSPROPERTY_SUPPORT_GET
| KSPROPERTY_SUPPORT_SET
;
327 case AM_PROPERTY_DVDCOPY_DEC_KEY2
:
328 *pTypeSupport
= KSPROPERTY_SUPPORT_GET
;
330 case AM_PROPERTY_DVDCOPY_DISC_KEY
:
331 *pTypeSupport
= KSPROPERTY_SUPPORT_SET
;
333 case AM_PROPERTY_DVDCOPY_DVD_KEY1
:
334 *pTypeSupport
= KSPROPERTY_SUPPORT_SET
;
336 case AM_PROPERTY_DVDCOPY_REGION
:
337 *pTypeSupport
= KSPROPERTY_SUPPORT_GET
| KSPROPERTY_SUPPORT_SET
;
339 case AM_PROPERTY_DVDCOPY_SET_COPY_STATE
:
340 *pTypeSupport
= KSPROPERTY_SUPPORT_GET
| KSPROPERTY_SUPPORT_SET
;
342 case AM_PROPERTY_DVDCOPY_TITLE_KEY
:
343 *pTypeSupport
= KSPROPERTY_SUPPORT_SET
;
346 return E_PROP_ID_UNSUPPORTED
;