PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Video/nuiVideoDecoder_WinXX.cpp

https://github.com/meeloo/nui3
C++ | 526 lines | 405 code | 104 blank | 17 comment | 64 complexity | fb3f1a465051dafa3e9730a838edaaca MD5 | raw file
  1. #include "nui.h"
  2. #include "nuiVideoDecoder.h"
  3. #include "windows.h"
  4. // If visual studio complains about this header you need to update to the latest windows SDK
  5. // http://www.microsoft.com/downloads/details.aspx?FamilyID=4377f86d-c913-4b5c-b87e-ef72e5b4e065&displaylang=en
  6. #include "wmsdk.h"
  7. #include "objidl.h"
  8. #pragma comment (lib, "wmvcore.lib")
  9. class nglVideoWindowsMediaIStream : public IStream
  10. {
  11. public:
  12. nglVideoWindowsMediaIStream(nglIStream& rStream);
  13. virtual ~nglVideoWindowsMediaIStream();
  14. //from IUnknown
  15. virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject);
  16. virtual ULONG STDMETHODCALLTYPE AddRef();
  17. virtual ULONG STDMETHODCALLTYPE Release();
  18. //from ISequentialStream
  19. virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead);
  20. virtual HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten);
  21. //from IStream
  22. virtual /* [local] */ HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition);
  23. virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize);
  24. virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten);
  25. virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags);
  26. virtual HRESULT STDMETHODCALLTYPE Revert();
  27. virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
  28. virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
  29. virtual HRESULT STDMETHODCALLTYPE Stat(__RPC__out STATSTG *pstatstg, DWORD grfStatFlag);
  30. virtual HRESULT STDMETHODCALLTYPE Clone(__RPC__deref_out_opt IStream **ppstm);
  31. private:
  32. ULONG mRefCount;
  33. nglIStream& mrStream;
  34. };
  35. class nuiVideoDecoderPrivate
  36. {
  37. public:
  38. nglVideoWindowsMediaIStream* mpWMStream;
  39. IWMSyncReader* mpWMReader;
  40. nglIStream* mpStream;
  41. WORD mStreamNumber;
  42. QWORD mPosition;
  43. BYTE* mpBuffer;
  44. };
  45. nuiVideoDecoder::nuiVideoDecoder(const nglPath& path)
  46. : mDuration(0),
  47. mWidth(0),
  48. mHeight(0),
  49. mRate(0),
  50. mPath(path),
  51. mpImage(NULL),
  52. mpTexture(NULL)
  53. {
  54. Init();
  55. }
  56. nuiVideoDecoder::~nuiVideoDecoder()
  57. {
  58. if (mpPrivate->mpWMReader)
  59. {
  60. mpPrivate->mpWMReader->Close();
  61. mpPrivate->mpWMReader->Release();
  62. mpPrivate->mpWMReader = NULL;
  63. }
  64. if (mpPrivate->mpWMStream)
  65. {
  66. mpPrivate->mpWMStream->Release();
  67. mpPrivate->mpWMStream = NULL;
  68. }
  69. if (mpPrivate->mpStream)
  70. delete mpPrivate->mpStream;
  71. CoUninitialize();
  72. delete[] mpPrivate->mpBuffer;
  73. if (mpPrivate)
  74. delete mpPrivate;
  75. }
  76. bool nuiVideoDecoder::Init()
  77. {
  78. CoInitialize(NULL);
  79. HRESULT hr = S_OK;
  80. mpPrivate = new nuiVideoDecoderPrivate();
  81. mpPrivate->mpStream = NULL;
  82. mpPrivate->mpWMStream = NULL;
  83. mpPrivate->mpWMReader = NULL;
  84. mpPrivate->mpBuffer = NULL;
  85. mpPrivate->mpStream = mPath.OpenRead();
  86. if (!mpPrivate->mpStream)
  87. return false;
  88. mpPrivate->mpWMStream = new nglVideoWindowsMediaIStream(*(mpPrivate->mpStream));
  89. hr = WMCreateSyncReader(NULL, WMT_RIGHT_PLAYBACK, &(mpPrivate->mpWMReader));
  90. if (SUCCEEDED(hr))
  91. {
  92. hr = mpPrivate->mpWMReader->OpenStream(mpPrivate->mpWMStream);
  93. }
  94. if (FAILED(hr))
  95. {
  96. if (mpPrivate->mpWMReader)
  97. {
  98. mpPrivate->mpWMReader->Close();
  99. mpPrivate->mpWMReader->Release();
  100. mpPrivate->mpWMReader = NULL;
  101. }
  102. return false;
  103. }
  104. bool ok = false;
  105. IWMSyncReader* pReader = mpPrivate->mpWMReader;
  106. DWORD outputCount = 0;
  107. hr = pReader->GetOutputCount(&outputCount);
  108. for (uint32 output = 0; output < outputCount && !ok; output++)
  109. {
  110. DWORD formatCount = 0;
  111. hr = pReader->GetOutputFormatCount(output, &formatCount);
  112. for (uint32 format = 0; format < formatCount && !ok; format++)
  113. {
  114. IWMOutputMediaProps* pMediaProps = NULL;
  115. hr = pReader->GetOutputFormat(output, format, &pMediaProps);
  116. //
  117. DWORD AllocSize = 0;
  118. hr = pMediaProps->GetMediaType(NULL, &AllocSize);
  119. WM_MEDIA_TYPE* pType = (WM_MEDIA_TYPE*)malloc(AllocSize);
  120. hr = pMediaProps->GetMediaType(pType, &AllocSize);
  121. if ((pType->majortype != WMMEDIATYPE_Video) || (pType->formattype != WMFORMAT_VideoInfo))
  122. continue;
  123. if (pType->subtype != WMMEDIASUBTYPE_RGB24)
  124. continue;
  125. WMVIDEOINFOHEADER* pVideoInfo = (WMVIDEOINFOHEADER*)pType->pbFormat;
  126. BITMAPINFOHEADER& rBitmapInfo = pVideoInfo->bmiHeader;
  127. mWidth = rBitmapInfo.biWidth;
  128. mHeight = rBitmapInfo.biHeight;
  129. DWORD compression = rBitmapInfo.biCompression;
  130. WORD bitCount = rBitmapInfo.biBitCount;
  131. if (rBitmapInfo.biCompression != BI_RGB || rBitmapInfo.biBitCount != 24)
  132. continue;
  133. hr = pReader->SetOutputProps(output, pMediaProps);
  134. if (FAILED(hr))
  135. {
  136. printf("can't set output props\n");
  137. continue;
  138. }
  139. hr = pReader->GetStreamNumberForOutput(output, &mpPrivate->mStreamNumber);
  140. WMT_STREAM_SELECTION streamSelection= WMT_ON;
  141. hr = pReader->SetStreamsSelected(1, &mpPrivate->mStreamNumber, &streamSelection);
  142. if (FAILED(hr))
  143. {
  144. printf("can't set stream selected\n");
  145. continue;
  146. }
  147. hr = pReader->SetReadStreamSamples(mpPrivate->mStreamNumber, FALSE);
  148. if (FAILED(hr))
  149. {
  150. printf("can't set read stream samples\n");
  151. continue;
  152. }
  153. ok = true;
  154. }
  155. }
  156. mpPrivate->mpBuffer = new BYTE[mWidth * mHeight * 3];
  157. memset(mpPrivate->mpBuffer, 0, mWidth * mHeight * 3 * sizeof(BYTE));
  158. GoToNextFrame();
  159. return ok;
  160. }
  161. bool nuiVideoDecoder::IsValid() const
  162. {
  163. if (!mpPrivate->mpStream)
  164. return false;
  165. if (!mpPrivate->mpWMReader)
  166. return false;
  167. if (!mpPrivate->mpWMStream)
  168. return false;
  169. return true;
  170. }
  171. double nuiVideoDecoder::GetPosition() const
  172. {
  173. return mpPrivate->mPosition;
  174. }
  175. void nuiVideoDecoder::SetPosition(double TimePosition)
  176. {
  177. double onesecond = 10000000; // unit is 100 nanoseconds
  178. double StartTime = TimePosition * onesecond;
  179. HRESULT hr = mpPrivate->mpWMReader->SetRange(StartTime, 0/*no duration set*/);
  180. if (FAILED(hr))
  181. printf("can't set position");
  182. mpPrivate->mPosition = TimePosition;
  183. }
  184. bool nuiVideoDecoder::GoToNextFrame()
  185. {
  186. HRESULT hr = S_OK;
  187. INSSBuffer* pTempBuffer = NULL;
  188. QWORD SampleDuration = 0;
  189. DWORD flags = 0;
  190. hr = mpPrivate->mpWMReader->GetNextSample(mpPrivate->mStreamNumber, &pTempBuffer, &mpPrivate->mPosition, &SampleDuration, &flags, NULL, NULL);
  191. if (FAILED(hr))
  192. return false;
  193. BYTE* pBuffer = NULL;
  194. DWORD length = 0;
  195. pTempBuffer->GetBufferAndLength(&pBuffer, &length);
  196. NGL_ASSERT(length == (mWidth * mHeight * 3));
  197. memcpy(mpPrivate->mpBuffer, pBuffer, length);
  198. pTempBuffer->Release();
  199. return true;
  200. }
  201. nglImage* nuiVideoDecoder::UpdateImage()
  202. {
  203. if (!mpImage)
  204. {
  205. nglImageInfo info(false/*buffer not managed*/);
  206. info.mWidth = mWidth;
  207. info.mHeight = mHeight;
  208. info.mBitDepth = 24;
  209. info.mPixelFormat = eImagePixelBGR;
  210. info.mBufferFormat = eImageFormatRaw;
  211. info.mBytesPerPixel = (info.mBitDepth + 1) / 8;
  212. info.mBytesPerLine = info.mWidth * info.mBytesPerPixel;
  213. info.mpBuffer = (char*)(mpPrivate->mpBuffer);
  214. mpImage = new nglImage(info);
  215. }
  216. else
  217. {
  218. char* pImgInfoBuffer = mpImage->GetBuffer();
  219. memcpy(pImgInfoBuffer, mpPrivate->mpBuffer, mWidth * mHeight * 3 * sizeof(BYTE));
  220. }
  221. return mpImage;
  222. }
  223. nuiTexture* nuiVideoDecoder::UpdateTexture()
  224. {
  225. if (!mpTexture)
  226. {
  227. nglImageInfo info(false/*buffer not managed*/);
  228. info.mWidth = mWidth;
  229. info.mHeight = mHeight;
  230. info.mBitDepth = 24;
  231. info.mPixelFormat = eImagePixelBGR;
  232. info.mBufferFormat = eImageFormatRaw;
  233. info.mBytesPerPixel = (info.mBitDepth + 1) / 8;
  234. info.mBytesPerLine = info.mWidth * info.mBytesPerPixel;
  235. info.mpBuffer = (char*)(mpPrivate->mpBuffer);
  236. mpTexture = nuiTexture::GetTexture(info);
  237. }
  238. else
  239. {
  240. char* pImgInfoBuffer = mpTexture->GetImage()->GetBuffer();
  241. memcpy(pImgInfoBuffer, mpPrivate->mpBuffer, mWidth * mHeight * 3 * sizeof(BYTE));
  242. mpTexture->ForceReload();
  243. }
  244. return mpTexture;
  245. }
  246. //**************************************************************
  247. //**************************************************************
  248. //
  249. //nglVideoWindowsMediaIStream
  250. //
  251. //**************************************************************
  252. //**************************************************************
  253. nglVideoWindowsMediaIStream::nglVideoWindowsMediaIStream(nglIStream& rStream) :
  254. mrStream(rStream),
  255. mRefCount(1)
  256. {
  257. }
  258. nglVideoWindowsMediaIStream::~nglVideoWindowsMediaIStream(void)
  259. {
  260. }
  261. //from IUnknown
  262. HRESULT nglVideoWindowsMediaIStream::QueryInterface(REFIID iid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
  263. {
  264. if(ppvObject == NULL)
  265. {
  266. return E_INVALIDARG;
  267. }
  268. *ppvObject = NULL;
  269. GUID unknownID;
  270. CLSIDFromString(L"{94BC0598-C3D2-11D3-BEDF-00C04F612986}", &unknownID);
  271. if(iid == IID_IUnknown)
  272. {
  273. *ppvObject = this;
  274. }
  275. else if(iid == IID_ISequentialStream)
  276. {
  277. *ppvObject = (ISequentialStream*)this;
  278. }
  279. else if(iid == IID_IStream)
  280. {
  281. *ppvObject = (IStream*)this;
  282. }
  283. else if (iid == IID_IWMIStreamProps)
  284. {
  285. return E_NOTIMPL;
  286. }
  287. else if (iid == unknownID)
  288. {
  289. return E_NOTIMPL;
  290. }
  291. else
  292. {
  293. return E_NOINTERFACE;
  294. }
  295. AddRef();
  296. return S_OK;
  297. }
  298. ULONG nglVideoWindowsMediaIStream::AddRef()
  299. {
  300. mRefCount++;
  301. return mRefCount;
  302. }
  303. ULONG nglVideoWindowsMediaIStream::Release()
  304. {
  305. mRefCount--;
  306. if (mRefCount == 0)
  307. {
  308. delete this;
  309. }
  310. return mRefCount;
  311. }
  312. //from ISequentialStream
  313. HRESULT nglVideoWindowsMediaIStream::Read(void *pv, ULONG cb, ULONG *pcbRead)
  314. {
  315. int64 sizeRead = mrStream.ReadInt8((int8*)pv, cb);
  316. *pcbRead = (ULONG)sizeRead;
  317. return S_OK;
  318. }
  319. HRESULT nglVideoWindowsMediaIStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten)
  320. {
  321. return S_OK;
  322. }
  323. //from IStream
  324. HRESULT nglVideoWindowsMediaIStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  325. {
  326. nglStreamWhence fromWhere = eStreamFromStart;
  327. if (dwOrigin == STREAM_SEEK_SET)
  328. {
  329. fromWhere = eStreamFromStart;
  330. }
  331. else if (dwOrigin == STREAM_SEEK_CUR)
  332. {
  333. fromWhere = eStreamForward;
  334. }
  335. else if (dwOrigin = STREAM_SEEK_END)
  336. {
  337. fromWhere = eStreamFromEnd;
  338. }
  339. nglFileOffset move = dlibMove.QuadPart;
  340. mrStream.SetPos(move, fromWhere);
  341. nglFileOffset newPos = mrStream.GetPos();
  342. if (plibNewPosition)
  343. plibNewPosition->QuadPart = newPos;
  344. return S_OK;
  345. }
  346. HRESULT nglVideoWindowsMediaIStream::SetSize(ULARGE_INTEGER libNewSize)
  347. {
  348. return S_OK;
  349. }
  350. HRESULT nglVideoWindowsMediaIStream::CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  351. {
  352. return S_OK;
  353. }
  354. HRESULT nglVideoWindowsMediaIStream::Commit(DWORD grfCommitFlags)
  355. {
  356. return S_OK;
  357. }
  358. HRESULT nglVideoWindowsMediaIStream::Revert()
  359. {
  360. return S_OK;
  361. }
  362. HRESULT nglVideoWindowsMediaIStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  363. {
  364. return S_OK;
  365. }
  366. HRESULT nglVideoWindowsMediaIStream::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  367. {
  368. return S_OK;
  369. }
  370. HRESULT nglVideoWindowsMediaIStream::Stat(__RPC__out STATSTG *pstatstg, DWORD grfStatFlag)
  371. {
  372. if (!pstatstg)
  373. return STG_E_INVALIDPOINTER;
  374. LPOLESTR pName = NULL;
  375. if (grfStatFlag & STATFLAG_DEFAULT)
  376. {
  377. //fill the name
  378. WCHAR wname[256];
  379. swprintf(wname, L"0x%p", this);
  380. size_t length = wcslen(wname) + 1;
  381. pName = (LPOLESTR)CoTaskMemAlloc(length * sizeof(WCHAR));
  382. if (!pName)
  383. return STG_E_INSUFFICIENTMEMORY;
  384. memcpy(pName, wname, length);
  385. }
  386. else if (grfStatFlag & STATFLAG_NONAME)
  387. {
  388. pName = NULL;
  389. }
  390. else
  391. {
  392. return STG_E_INVALIDFLAG;
  393. }
  394. nglFileSize StreamSize = mrStream.Available(1);
  395. DWORD StorageType = STGTY_STORAGE;
  396. FILETIME Mtime;
  397. Mtime.dwHighDateTime = 0;
  398. Mtime.dwLowDateTime = 0;
  399. FILETIME Ctime;
  400. Ctime.dwHighDateTime = 0;
  401. Ctime.dwLowDateTime = 0;
  402. FILETIME Atime;
  403. Atime.dwHighDateTime = 0;
  404. Atime.dwLowDateTime = 0;
  405. DWORD AccessMode = 0;
  406. DWORD LockSupported = LOCK_WRITE;
  407. CLSID ClassID = CLSID_NULL;
  408. pstatstg->pwcsName = pName;
  409. pstatstg->type = StorageType;
  410. pstatstg->cbSize.QuadPart = StreamSize;
  411. pstatstg->mtime = Mtime;
  412. pstatstg->ctime = Ctime;
  413. pstatstg->atime = Atime;
  414. pstatstg->grfMode = AccessMode;
  415. pstatstg->grfLocksSupported = LockSupported;
  416. pstatstg->clsid = ClassID;
  417. return S_OK;
  418. }
  419. HRESULT nglVideoWindowsMediaIStream::Clone(__RPC__deref_out_opt IStream **ppstm)
  420. {
  421. return S_OK;
  422. }