MediaStreamer.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * cocos2d-x http://www.cocos2d-x.org
  3. *
  4. * Copyright (c) 2010-2011 - cocos2d-x community
  5. *
  6. * Portions Copyright (c) Microsoft Open Technologies, Inc.
  7. * All Rights Reserved
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and limitations under the License.
  17. */
  18. #include "audio/winrt/MediaStreamer.h"
  19. #include <Mfidl.h>
  20. #include <Mfreadwrite.h>
  21. #include <Mfapi.h>
  22. #include <wrl\wrappers\corewrappers.h>
  23. #include <ppltasks.h>
  24. using namespace Microsoft::WRL;
  25. using namespace Windows::Storage;
  26. using namespace Windows::Storage::FileProperties;
  27. using namespace Windows::Storage::Streams;
  28. using namespace Windows::Foundation;
  29. using namespace Windows::ApplicationModel;
  30. using namespace Concurrency;
  31. #ifndef MAKEFOURCC
  32. #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
  33. ((uint32)(byte)(ch0) | ((uint32)(byte)(ch1) << 8) | \
  34. ((uint32)(byte)(ch2) << 16) | ((uint32)(byte)(ch3) << 24 ))
  35. #endif /* defined(MAKEFOURCC) */
  36. const int FMT_CHUNK_MAX = 256;
  37. inline void ThrowIfFailed(HRESULT hr)
  38. {
  39. if (FAILED(hr))
  40. {
  41. // Set a breakpoint on this line to catch DX API errors.
  42. throw Platform::Exception::CreateException(hr);
  43. }
  44. }
  45. MediaStreamer::MediaStreamer() :
  46. m_offset(0)
  47. , m_dataLen(0)
  48. , m_filename(nullptr)
  49. {
  50. ZeroMemory(&m_waveFormat, sizeof(m_waveFormat));
  51. m_location = Package::Current->InstalledLocation;
  52. m_locationPath = Platform::String::Concat(m_location->Path, "\\Assets\\Resources\\");
  53. }
  54. MediaStreamer::~MediaStreamer()
  55. {
  56. }
  57. Platform::Array<byte>^ MediaStreamer::ReadData(_In_ Platform::String^ filename)
  58. {
  59. return ReadData(filename, 0, 0);
  60. }
  61. Platform::Array<byte>^ MediaStreamer::ReadData(_In_ Platform::String^ filename, uint32 from, uint32 length)
  62. {
  63. CREATEFILE2_EXTENDED_PARAMETERS extendedParams = {0};
  64. extendedParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
  65. extendedParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
  66. extendedParams.dwFileFlags = from ? FILE_FLAG_RANDOM_ACCESS : FILE_FLAG_SEQUENTIAL_SCAN;
  67. extendedParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
  68. extendedParams.lpSecurityAttributes = nullptr;
  69. extendedParams.hTemplateFile = nullptr;
  70. Wrappers::FileHandle file(
  71. CreateFile2(filename->Data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extendedParams)
  72. );
  73. if (file.Get()==INVALID_HANDLE_VALUE)
  74. {
  75. throw ref new Platform::FailureException();
  76. }
  77. FILE_STANDARD_INFO fileInfo = { 0 };
  78. if (!GetFileInformationByHandleEx(file.Get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
  79. {
  80. throw ref new Platform::FailureException();
  81. }
  82. if (fileInfo.EndOfFile.HighPart != 0)
  83. {
  84. throw ref new Platform::OutOfMemoryException();
  85. }
  86. from += static_cast<unsigned int>(m_offset);
  87. length = (length == 0 || from + length > fileInfo.EndOfFile.LowPart) ? fileInfo.EndOfFile.LowPart - from : length;
  88. Platform::Array<byte>^ fileData = ref new Platform::Array<byte>(length);
  89. if (from)
  90. {
  91. LARGE_INTEGER pos = { 0 };
  92. pos.QuadPart = from;
  93. if (!SetFilePointerEx(file.Get(), pos, nullptr, FILE_BEGIN))
  94. {
  95. throw ref new Platform::FailureException();
  96. }
  97. }
  98. if (!ReadFile(file.Get(), fileData->Data, fileData->Length, nullptr, nullptr))
  99. {
  100. throw ref new Platform::FailureException();
  101. }
  102. return fileData;
  103. }
  104. void MediaStreamer::Initialize(__in const WCHAR* url, bool lazy)
  105. {
  106. m_filename = ref new Platform::String(url);
  107. WCHAR filePath[MAX_PATH] = {0};
  108. if ((wcslen(url) > 1 && url[1] == ':'))
  109. {
  110. // path start with "x:", is absolute path
  111. wcscat_s(filePath, url);
  112. }
  113. else if (wcslen(url) > 0
  114. && (L'/' == url[0] || L'\\' == url[0]))
  115. {
  116. // path start with '/' or '\', is absolute path without driver name
  117. wcscat_s(filePath, m_locationPath->Data());
  118. // remove '/' or '\\'
  119. wcscat_s(filePath, (const WCHAR*)url[1]);
  120. }else
  121. {
  122. wcscat_s(filePath, m_locationPath->Data());
  123. wcscat_s(filePath, url);
  124. }
  125. Platform::Array<byte>^ data = lazy ? ReadData(ref new Platform::String(filePath), 0, FMT_CHUNK_MAX) : ReadData(ref new Platform::String(filePath));
  126. UINT32 length = data->Length;
  127. const byte * dataPtr = data->Data;
  128. UINT32 offset = 0;
  129. DWORD riffDataSize = 0;
  130. auto ReadChunk = [&length, &offset, &dataPtr, &riffDataSize](DWORD fourcc, DWORD& outChunkSize, DWORD& outChunkPos) -> HRESULT
  131. {
  132. while (true)
  133. {
  134. if (offset + sizeof(DWORD) * 2 >= length)
  135. {
  136. return E_FAIL;
  137. }
  138. // Read two DWORDs.
  139. DWORD chunkType = *reinterpret_cast<const DWORD *>(&dataPtr[offset]);
  140. DWORD chunkSize = *reinterpret_cast<const DWORD *>(&dataPtr[offset + sizeof(DWORD)]);
  141. offset += sizeof(DWORD) * 2;
  142. if (chunkType == MAKEFOURCC('R', 'I', 'F', 'F'))
  143. {
  144. riffDataSize = chunkSize;
  145. chunkSize = sizeof(DWORD);
  146. outChunkSize = sizeof(DWORD);
  147. outChunkPos = offset;
  148. }
  149. else
  150. {
  151. outChunkSize = chunkSize;
  152. outChunkPos = offset;
  153. }
  154. offset += chunkSize;
  155. if (chunkType == fourcc)
  156. {
  157. return S_OK;
  158. }
  159. }
  160. };
  161. // Locate riff chunk, check the file type.
  162. DWORD chunkSize = 0;
  163. DWORD chunkPos = 0;
  164. ThrowIfFailed(ReadChunk(MAKEFOURCC('R', 'I', 'F', 'F'), chunkSize, chunkPos));
  165. if (*reinterpret_cast<const DWORD *>(&dataPtr[chunkPos]) != MAKEFOURCC('W', 'A', 'V', 'E')) ThrowIfFailed(E_FAIL);
  166. // Locate 'fmt ' chunk, copy to WAVEFORMATEXTENSIBLE.
  167. ThrowIfFailed(ReadChunk(MAKEFOURCC('f', 'm', 't', ' '), chunkSize, chunkPos));
  168. ThrowIfFailed((chunkSize <= sizeof(m_waveFormat)) ? S_OK : E_FAIL);
  169. CopyMemory(&m_waveFormat, &dataPtr[chunkPos], chunkSize);
  170. // Locate the 'data' chunk and copy its contents to a buffer.
  171. ThrowIfFailed(ReadChunk(MAKEFOURCC('d', 'a', 't', 'a'), chunkSize, chunkPos));
  172. m_dataLen = chunkSize;
  173. m_offset = chunkPos;
  174. if (!lazy)
  175. {
  176. m_data.resize(chunkSize);
  177. CopyMemory(m_data.data(), &dataPtr[chunkPos], chunkSize);
  178. m_offset = 0;
  179. }
  180. }
  181. void MediaStreamer::ReadAll(uint8* buffer, uint32 maxBufferSize, uint32* bufferLength)
  182. {
  183. if (!m_data.size())
  184. {
  185. ReadChunk(buffer, 0, static_cast<unsigned int>(m_dataLen), bufferLength);
  186. }
  187. else
  188. {
  189. UINT32 toCopy = static_cast<UINT32>(m_data.size() - m_offset);
  190. if (toCopy > maxBufferSize) toCopy = maxBufferSize;
  191. CopyMemory(buffer, m_data.data(), toCopy);
  192. *bufferLength = toCopy;
  193. m_offset += toCopy;
  194. if (m_offset > m_data.size()) m_offset = m_data.size();
  195. }
  196. }
  197. void MediaStreamer::ReadChunk(uint8* buffer, uint32 from, uint32 length, uint32* bytesRead)
  198. {
  199. Platform::Array<byte>^ data = ReadData(m_filename, from, length);
  200. *bytesRead = data->Length;
  201. if (*bytesRead > 0)
  202. {
  203. CopyMemory(buffer, (byte*)data->Data, data->Length);
  204. }
  205. }
  206. void MediaStreamer::Restart()
  207. {
  208. m_offset = 0;
  209. }