Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

478 lines
20 KiB

  1. //==========================================================================;
  2. // MSVidEncoder.cpp : Declaration of the CMSVidEncoder
  3. // copyright (c) Microsoft Corp. 1998-1999.
  4. /////////////////////////////////////////////////////////////////////////////
  5. #include "stdafx.h"
  6. #ifndef TUNING_MODEL_ONLY
  7. #include "msvidencoder.h"
  8. // HARD CODED pids for program stream video and audio
  9. const ULONG g_AudioID = 0xC0;
  10. const ULONG g_VideoID = 0xE0;
  11. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_MSVidEncoder, CEncoder)
  12. // "Copied" From Demux Proppage
  13. static BYTE g_Mpeg2ProgramVideo [] = {
  14. 0x00, 0x00, 0x00, 0x00, // .hdr.rcSource.left = 0x00000000
  15. 0x00, 0x00, 0x00, 0x00, // .hdr.rcSource.top = 0x00000000
  16. 0xD0, 0x02, 0x00, 0x00, // .hdr.rcSource.right = 0x000002d0
  17. 0xE0, 0x01, 0x00, 0x00, // .hdr.rcSource.bottom = 0x000001e0
  18. 0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.left = 0x00000000
  19. 0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.top = 0x00000000
  20. 0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.right = 0x00000000
  21. 0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.bottom = 0x00000000
  22. 0x00, 0x09, 0x3D, 0x00, // .hdr.dwBitRate = 0x003d0900
  23. 0x00, 0x00, 0x00, 0x00, // .hdr.dwBitErrorRate = 0x00000000
  24. 0x63, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, // .hdr.AvgTimePerFrame = 0x0000000000051763
  25. 0x00, 0x00, 0x00, 0x00, // .hdr.dwInterlaceFlags = 0x00000000
  26. 0x00, 0x00, 0x00, 0x00, // .hdr.dwCopyProtectFlags = 0x00000000
  27. 0x04, 0x00, 0x00, 0x00, // .hdr.dwPictAspectRatioX = 0x00000004
  28. 0x03, 0x00, 0x00, 0x00, // .hdr.dwPictAspectRatioY = 0x00000003
  29. 0x00, 0x00, 0x00, 0x00, // .hdr.dwReserved1 = 0x00000000
  30. 0x00, 0x00, 0x00, 0x00, // .hdr.dwReserved2 = 0x00000000
  31. 0x28, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biSize = 0x00000028
  32. 0xD0, 0x02, 0x00, 0x00, // .hdr.bmiHeader.biWidth = 0x000002d0
  33. 0xE0, 0x01, 0x00, 0x00, // .hdr.bmiHeader.biHeight = 0x00000000
  34. 0x00, 0x00, // .hdr.bmiHeader.biPlanes = 0x0000
  35. 0x00, 0x00, // .hdr.bmiHeader.biBitCount = 0x0000
  36. 0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biCompression = 0x00000000
  37. 0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biSizeImage = 0x00000000
  38. 0xD0, 0x07, 0x00, 0x00, // .hdr.bmiHeader.biXPelsPerMeter = 0x000007d0
  39. 0x27, 0xCF, 0x00, 0x00, // .hdr.bmiHeader.biYPelsPerMeter = 0x0000cf27
  40. 0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biClrUsed = 0x00000000
  41. 0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biClrImportant = 0x00000000
  42. 0x98, 0xF4, 0x06, 0x00, // .dwStartTimeCode = 0x0006f498
  43. 0x56, 0x00, 0x00, 0x00, // .cbSequenceHeader = 0x00000056
  44. 0x02, 0x00, 0x00, 0x00, // .dwProfile = 0x00000002
  45. 0x02, 0x00, 0x00, 0x00, // .dwLevel = 0x00000002
  46. 0x00, 0x00, 0x00, 0x00, // .Flags = 0x00000000
  47. // .dwSequenceHeader [1]
  48. 0x00, 0x00, 0x01, 0xB3, 0x2D, 0x01, 0xE0, 0x24,
  49. 0x09, 0xC4, 0x23, 0x81, 0x10, 0x11, 0x11, 0x12,
  50. 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14,
  51. 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15,
  52. 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
  53. 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
  54. 0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19,
  55. 0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1B, 0x1B, 0x1B,
  56. 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1E, 0x1E,
  57. 0x1E, 0x1F, 0x1F, 0x21, 0x00, 0x00, 0x01, 0xB5,
  58. 0x14, 0x82, 0x00, 0x01, 0x00, 0x00
  59. } ;
  60. // WaveFormatEx format block; generated with the following settings:
  61. //
  62. // fwHeadFlags = 0x1c;
  63. // wHeadEmphasis = 1;
  64. // fwHeadModeExt = 1;
  65. // fwHeadMode = 1;
  66. // dwHeadBitrate = 0x3e800;
  67. // fwHeadLayer = 0x2;
  68. // wfx.cbSize = 0x16;
  69. // wfx.wBitsPerSample = 0;
  70. // wfx.nBlockAlign = 0x300;
  71. // wfx.nAvgBytesPerSec = 0x7d00;
  72. // wfx.nSamplesPerSec = 0xbb80;
  73. // wfx.nChannels = 2;
  74. // wfx.wFormatTag = 0x50;
  75. // dwPTSLow = 0;
  76. // dwPTSHigh = 0;
  77. static BYTE g_MPEG1AudioFormat [] = {
  78. 0x50, 0x00, 0x02, 0x00, 0x80, 0xBB, 0x00, 0x00,
  79. 0x00, 0x7D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
  80. 0x16, 0x00, 0x02, 0x00, 0x00, 0xE8, 0x03, 0x00,
  81. 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1C, 0x00,
  82. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  83. } ;
  84. // End "Copied" From Demux Proppage
  85. STDMETHODIMP CEncoder::get_AudioEncoderInterface(/*[out, retval]*/ IUnknown **ppEncInt){
  86. if(!ppEncInt){
  87. return E_POINTER;
  88. }
  89. DSMediaType mediaAudio(MEDIATYPE_Audio);
  90. DSFilter p_filter = m_Filters[m_iEncoder];
  91. HRESULT hr = E_NOINTERFACE;
  92. // Starting at the ecoder filter find the pin/filter implimenting the endcoder api for audio
  93. // This should work because of two facts
  94. // 1. only one audio path or audio path coming into the encoder filter
  95. // 2. we only need to find one matching media type to identify the pin type
  96. do{
  97. DSFilter::iterator pins;
  98. // check the current filters pins for a audio media type
  99. for(pins = p_filter.begin(); pins != p_filter.end(); ++pins){
  100. DSPin::iterator mTypes;
  101. for(mTypes = (*pins).begin(); mTypes != (*pins).end(); ++mTypes){
  102. if((*mTypes) == mediaAudio){
  103. // see if the current pin impliments the encoder api
  104. (*pins).QueryInterface(&m_qiAudEnc) ;
  105. if(m_qiAudEnc){
  106. hr = m_qiAudEnc.QueryInterface(ppEncInt);
  107. if(SUCCEEDED(hr)){
  108. return S_OK;
  109. }
  110. else{
  111. return E_UNEXPECTED;
  112. }
  113. }
  114. break;
  115. }
  116. }
  117. // If we did not get to the end of the media types then we found a audio type and the pin did not inpliment the interface
  118. // time to track backwards
  119. if(mTypes != (*pins).end() && (*pins).GetDirection() == PINDIR_INPUT){
  120. // Following the audio path get the next filter backwards from current filter
  121. DSPin back = (*pins).GetConnection();
  122. if(back){
  123. p_filter = back.GetFilter();
  124. // Check to see if the new filter impliments the encoder api
  125. if(p_filter){
  126. p_filter.QueryInterface(&m_qiAudEnc);
  127. if(m_qiAudEnc){
  128. hr = m_qiAudEnc.QueryInterface(ppEncInt);
  129. if(SUCCEEDED(hr)){
  130. return S_OK;
  131. }
  132. else{
  133. return E_UNEXPECTED;
  134. }
  135. }
  136. }
  137. }
  138. break;
  139. }
  140. }
  141. if(pins == p_filter.end()){
  142. p_filter.Release();
  143. }
  144. } while(p_filter && FAILED(hr));
  145. return hr;
  146. }
  147. STDMETHODIMP CEncoder::get_VideoEncoderInterface(/*[out, retval]*/ IUnknown **ppEncInt){
  148. if(!ppEncInt){
  149. return E_POINTER;
  150. }
  151. DSMediaType mediaVideo(MEDIATYPE_Video);
  152. DSFilter p_filter = m_Filters[m_iEncoder];
  153. HRESULT hr = E_NOINTERFACE;
  154. if(!m_qiVidEnc){
  155. hr = p_filter.QueryInterface(&m_qiVidEnc);
  156. if(FAILED(hr)){
  157. m_qiVidEnc = static_cast<IUnknown*>(NULL);
  158. }
  159. }
  160. if(m_qiVidEnc){
  161. hr = m_qiVidEnc.QueryInterface(ppEncInt);
  162. if(SUCCEEDED(hr)){
  163. return S_OK;
  164. }
  165. else{
  166. return hr;
  167. }
  168. }
  169. // Starting at the ecoder filter find the pin/filter implimenting the endcoder api for video
  170. // This should work because of two facts
  171. // 1. only one video path or audio path coming into the encoder filter
  172. // 2. we only need to find one matching media type to identify the pin type
  173. do{
  174. DSFilter::iterator pins;
  175. // check the current filters pins for a video media type
  176. for(pins = p_filter.begin(); pins != p_filter.end(); ++pins){
  177. DSPin::iterator mTypes;
  178. for(mTypes = (*pins).begin(); mTypes != (*pins).end(); ++mTypes){
  179. if((*mTypes) == mediaVideo){
  180. // see if the current pin impliments the encoder api
  181. (*pins).QueryInterface(&m_qiVidEnc) ;
  182. if(m_qiVidEnc){
  183. hr = m_qiVidEnc.QueryInterface(ppEncInt);
  184. if(SUCCEEDED(hr)){
  185. return S_OK;
  186. }
  187. else{
  188. return hr;
  189. }
  190. }
  191. break;
  192. }
  193. }
  194. // If we did not get to the end of the media types then we found a video type and the pin did not inpliment the interface
  195. // time to track backwards
  196. if(mTypes != (*pins).end() && (*pins).GetDirection() == PINDIR_INPUT){
  197. // Following the video path get the next filter backwards from current filter
  198. DSPin back = (*pins).GetConnection();
  199. if(back){
  200. p_filter = back.GetFilter();
  201. // Check to see if the new filter impliments the encoder api
  202. if(p_filter){
  203. p_filter.QueryInterface(&m_qiVidEnc);
  204. if(m_qiVidEnc){
  205. hr = m_qiVidEnc.QueryInterface(ppEncInt);
  206. if(SUCCEEDED(hr)){
  207. return S_OK;
  208. }
  209. else{
  210. return E_UNEXPECTED;
  211. }
  212. }
  213. }
  214. }
  215. break;
  216. }
  217. }
  218. if(pins == p_filter.end()){
  219. p_filter.Release();
  220. }
  221. } while(p_filter && FAILED(hr));
  222. return hr;
  223. }
  224. HRESULT CEncoder::Unload(void) {
  225. IMSVidGraphSegmentImpl<CEncoder, MSVidSEG_XFORM, &GUID_NULL>::Unload();
  226. m_iEncoder = -1;
  227. m_qiVidEnc.Release();
  228. m_qiAudEnc.Release();
  229. return NOERROR;
  230. }
  231. // IMSVidGraphSegment
  232. STDMETHODIMP CEncoder::Build() {
  233. return NOERROR;
  234. }
  235. STDMETHODIMP CEncoder::PreRun() {
  236. return NOERROR;
  237. }
  238. STDMETHODIMP CEncoder::put_Container(IMSVidGraphSegmentContainer *pCtl){
  239. if (!m_fInit) {
  240. return CO_E_NOTINITIALIZED;
  241. }
  242. try {
  243. if (!pCtl) {
  244. return Unload();
  245. }
  246. if (m_pContainer) {
  247. if (!m_pContainer.IsEqualObject(VWSegmentContainer(pCtl))) {
  248. return Error(IDS_OBJ_ALREADY_INIT, __uuidof(IMSVidEncoder), CO_E_ALREADYINITIALIZED);
  249. } else {
  250. return NO_ERROR;
  251. }
  252. }
  253. // DON'T addref the container. we're guaranteed nested lifetimes
  254. // and an addref creates circular refcounts so we never unload.
  255. m_pContainer.p = pCtl;
  256. m_pGraph = m_pContainer.GetGraph();
  257. // Add some filters when there is an encoder api
  258. DSFilter pEncoder(m_pGraph.AddMoniker(m_pDev));
  259. if (!pEncoder) {
  260. return E_UNEXPECTED;
  261. }
  262. m_Filters.push_back(pEncoder);
  263. m_iEncoder = 0;
  264. TRACELM(TRACE_DETAIL, "CMSVidEncoder::put_Container() Encoder added");
  265. DSFilter::iterator fPin;
  266. DSMediaType mpeg2ProgramType(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG2_PROGRAM);
  267. DSMediaType streamType(MEDIATYPE_Stream);
  268. for(fPin = pEncoder.begin(); fPin != pEncoder.end(); ++fPin) {
  269. DSPin curPin(*fPin);
  270. DSPin::iterator pMedia;
  271. // Find the Mpeg2 Progam Steam Pin if there is one
  272. for(pMedia = curPin.begin(); pMedia != curPin.end(); ++pMedia){
  273. if ((*pMedia) == streamType && curPin.GetDirection() == PINDIR_OUTPUT){
  274. break;
  275. }
  276. }
  277. if(pMedia == curPin.end()){
  278. continue;
  279. }
  280. else{
  281. if((*pMedia) == mpeg2ProgramType){
  282. // Found the program stream pin get a demux and set it up
  283. CComQIPtr<IMpeg2Demultiplexer> qiDeMux;
  284. qiDeMux.CoCreateInstance(CLSID_MPEG2Demultiplexer);
  285. if(!qiDeMux){
  286. ASSERT(FALSE);
  287. return E_UNEXPECTED;
  288. }
  289. DSFilter DeMux(qiDeMux);
  290. DSFilterList intermediates;
  291. CString csName(_T("MPEG-2 Demultiplexer"));
  292. HRESULT hr = m_pGraph.AddFilter(DeMux, csName);
  293. if (FAILED(hr)) {
  294. ASSERT(FALSE);
  295. return E_UNEXPECTED;
  296. }
  297. m_Filters.push_back(DeMux);
  298. m_iDemux = m_Filters.size() - 1;
  299. for(DSFilter::iterator dPin = DeMux.begin(); dPin != DeMux.end(); ++dPin){
  300. DSPin demuxIn(*dPin);
  301. if(demuxIn.GetDirection() == PINDIR_INPUT){
  302. hr = demuxIn.Connect(curPin);
  303. if (FAILED(hr)) {
  304. ASSERT(FALSE);
  305. return E_UNEXPECTED;
  306. }
  307. }
  308. }
  309. // Sprout the audio and video pins on the demxu
  310. DSPin dspAudio, dspVideo;
  311. DSMediaType mtVideo(MEDIATYPE_Video, MEDIASUBTYPE_MPEG2_VIDEO, FORMAT_MPEG2Video);
  312. mtVideo.p->bFixedSizeSamples = TRUE;
  313. mtVideo.p->cbFormat = sizeof(g_Mpeg2ProgramVideo);
  314. mtVideo.p->pbFormat = g_Mpeg2ProgramVideo;
  315. DSMediaType mtAudio(MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1Payload, FORMAT_WaveFormatEx);
  316. mtAudio.p->bFixedSizeSamples = TRUE;
  317. mtAudio.p->cbFormat = sizeof(g_MPEG1AudioFormat);
  318. mtAudio.p->pbFormat = g_MPEG1AudioFormat;
  319. CComBSTR szAudio("Audio Pin");
  320. CComBSTR szVideo("Video Pin");
  321. hr = qiDeMux->CreateOutputPin(mtAudio, szAudio, &dspAudio);
  322. if (FAILED(hr)) {
  323. ASSERT(FALSE);
  324. return E_UNEXPECTED;
  325. }
  326. hr = qiDeMux->CreateOutputPin(mtVideo, szVideo, &dspVideo);
  327. if (FAILED(hr)) {
  328. ASSERT(FALSE);
  329. return E_UNEXPECTED;
  330. }
  331. // Map the pids correctly
  332. // TODO: use the encoder api to find the pids for audio and video
  333. CComQIPtr<IMPEG2StreamIdMap>qiMapper(dspVideo);
  334. hr = qiMapper->MapStreamId(g_VideoID, MPEG2_PROGRAM_ELEMENTARY_STREAM, 0, 0);
  335. if (FAILED(hr)) {
  336. ASSERT(FALSE);
  337. return E_UNEXPECTED;
  338. }
  339. qiMapper = dspAudio;
  340. hr = qiMapper->MapStreamId(g_AudioID, MPEG2_PROGRAM_ELEMENTARY_STREAM, 0, 0);
  341. if (FAILED(hr)) {
  342. ASSERT(FALSE);
  343. return E_UNEXPECTED;
  344. }
  345. // Clean up
  346. mtVideo.p->cbFormat = 0;
  347. mtVideo.p->pbFormat = 0;
  348. mtAudio.p->cbFormat = 0;
  349. mtAudio.p->pbFormat = 0;
  350. break;
  351. }
  352. #if 0 // code to support custom demux (e.g. asf/wmv demux by a third party)
  353. else{
  354. CRegKey c;
  355. TCHAR szCLSID[MAX_PATH + 1];
  356. szCLSID[0] = 0;
  357. CString keyname(_T("SOFTWARE\\Debug\\MSVidCtl"));
  358. DWORD rc = c.Open(HKEY_LOCAL_MACHINE, keyname, KEY_READ);
  359. if (rc == ERROR_SUCCESS) {
  360. DWORD len = sizeof(szCLSID);
  361. rc = c.QueryValue(szCLSID, _T("CustomDemuxCLSID"), &len);
  362. if (rc != ERROR_SUCCESS) {
  363. szCLSID[0] = 0;
  364. }
  365. }
  366. DSFilter DeMux;
  367. CComBSTR asfCLSID(szCLSID);
  368. GUID2 asfDemux(asfCLSID);
  369. DeMux.CoCreateInstance(asfDemux);
  370. if(!DeMux){
  371. ASSERT(FALSE);
  372. return E_UNEXPECTED;
  373. }
  374. DSFilterList intermediates;
  375. CString csName(_T("Custom Demultiplexer"));
  376. HRESULT hr = m_pGraph.AddFilter(DeMux, csName);
  377. if (FAILED(hr)) {
  378. ASSERT(FALSE);
  379. return E_UNEXPECTED;
  380. }
  381. m_Filters.push_back(DeMux);
  382. m_iDemux = m_Filters.size() - 1;
  383. for(DSFilter::iterator dPin = DeMux.begin(); dPin != DeMux.end(); ++dPin){
  384. DSPin demuxIn(*dPin);
  385. if(demuxIn.GetDirection() == PINDIR_INPUT){
  386. hr = demuxIn.Connect(curPin);
  387. if (FAILED(hr)) {
  388. ASSERT(FALSE);
  389. return E_UNEXPECTED;
  390. }
  391. }
  392. }
  393. }
  394. #endif
  395. }
  396. }
  397. // Don't fail if there is no program stream pin. could be elementry streams or non-mpeg content
  398. return NOERROR;
  399. } catch (ComException &e) {
  400. return e;
  401. } catch(...) {
  402. return E_UNEXPECTED;
  403. }
  404. return NOERROR;
  405. }
  406. // IMSVidDevice
  407. STDMETHODIMP CEncoder::get_Name(BSTR * Name){
  408. if (!m_fInit) {
  409. return CO_E_NOTINITIALIZED;
  410. }
  411. try {
  412. CComBSTR DefaultName("Encoder Segment");
  413. return GetName(((m_iEncoder > -1) ? (m_Filters[m_iEncoder]) : DSFilter()), m_pDev, DefaultName).CopyTo(Name);
  414. return NOERROR;
  415. } catch(...) {
  416. return E_POINTER;
  417. }
  418. }
  419. STDMETHODIMP CEncoder::InterfaceSupportsErrorInfo(REFIID riid){
  420. static const IID* arr[] =
  421. {
  422. &IID_IMSVidEncoder
  423. };
  424. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++){
  425. if (InlineIsEqualGUID(*arr[i],riid))
  426. return S_OK;
  427. }
  428. return S_FALSE;
  429. }
  430. #endif // TUNING_MODEL_ONLY