30namespace WindowsMediaCodec
37 : ComBaseClassHelper<IStream> (0), source (in)
41 JUCE_COMRESULT Commit (DWORD) {
return S_OK; }
42 JUCE_COMRESULT Write (
const void*, ULONG, ULONG*) {
return E_NOTIMPL; }
43 JUCE_COMRESULT Clone (IStream**) {
return E_NOTIMPL; }
44 JUCE_COMRESULT SetSize (ULARGE_INTEGER) {
return E_NOTIMPL; }
45 JUCE_COMRESULT Revert() {
return E_NOTIMPL; }
46 JUCE_COMRESULT LockRegion (ULARGE_INTEGER, ULARGE_INTEGER, DWORD) {
return E_NOTIMPL; }
47 JUCE_COMRESULT UnlockRegion (ULARGE_INTEGER, ULARGE_INTEGER, DWORD) {
return E_NOTIMPL; }
49 JUCE_COMRESULT Read (
void* dest, ULONG numBytes, ULONG* bytesRead)
51 auto numRead = source.
read (dest, (
size_t) numBytes);
53 if (bytesRead !=
nullptr)
54 *bytesRead = (ULONG) numRead;
56 return (numRead == (
int) numBytes) ? S_OK : S_FALSE;
59 JUCE_COMRESULT Seek (LARGE_INTEGER position, DWORD origin, ULARGE_INTEGER* resultPosition)
61 auto newPos = (int64) position.QuadPart;
63 if (origin == STREAM_SEEK_CUR)
67 else if (origin == STREAM_SEEK_END)
77 if (resultPosition !=
nullptr)
78 resultPosition->QuadPart = newPos;
80 return source.
setPosition (newPos) ? S_OK : E_NOTIMPL;
83 JUCE_COMRESULT CopyTo (IStream* destStream, ULARGE_INTEGER numBytesToDo,
84 ULARGE_INTEGER* bytesRead, ULARGE_INTEGER* bytesWritten)
86 uint64 totalCopied = 0;
87 int64 numBytes = numBytesToDo.QuadPart;
93 auto numToCopy = (int) jmin ((int64)
sizeof (buffer), (int64) numBytes);
94 auto numRead = source.
read (buffer, numToCopy);
99 destStream->Write (buffer, numRead,
nullptr);
100 totalCopied += numRead;
103 if (bytesRead !=
nullptr) bytesRead->QuadPart = totalCopied;
104 if (bytesWritten !=
nullptr) bytesWritten->QuadPart = totalCopied;
109 JUCE_COMRESULT Stat (STATSTG* stat, DWORD)
112 return STG_E_INVALIDPOINTER;
115 stat->type = STGTY_STREAM;
116 stat->cbSize.QuadPart = jmax ((int64) 0, source.
getTotalLength());
123 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (
JuceIStream)
127static const char* wmFormatName =
"Windows Media";
128static const char*
const extensions[] = {
".mp3",
".wmv",
".asf",
".wm",
".wma", 0 };
136 wmvCoreLib (
"Wmvcore.dll")
138 JUCE_LOAD_WINAPI_FUNCTION (wmvCoreLib, WMCreateSyncReader, wmCreateSyncReader,
139 HRESULT, (IUnknown*, DWORD, IWMSyncReader**))
141 if (wmCreateSyncReader !=
nullptr)
143 checkCoInitialiseCalled();
145 HRESULT hr = wmCreateSyncReader (
nullptr, WMT_RIGHT_PLAYBACK, wmSyncReader.resetAndGetPointerAddress());
153 hr = wmSyncReader->GetStreamNumberForOutput (0, &streamNum);
154 hr = wmSyncReader->SetReadStreamSamples (streamNum,
false);
156 scanFileForDetails();
163 if (wmSyncReader !=
nullptr)
164 wmSyncReader->Close();
167 bool readSamples (
int** destSamples,
int numDestChannels,
int startOffsetInDestBuffer,
168 int64 startSampleInFile,
int numSamples)
override
173 checkCoInitialiseCalled();
180 while (numSamples > 0)
182 if (! bufferedRange.
contains (startSampleInFile))
184 const bool hasJumped = (startSampleInFile != bufferedRange.
getEnd());
187 wmSyncReader->SetRange ((QWORD) (startSampleInFile * 10000000 / (int64)
sampleRate), 0);
189 ComSmartPtr<INSSBuffer> sampleBuffer;
190 QWORD sampleTime, duration;
191 DWORD flags, outputNum;
194 HRESULT hr = wmSyncReader->GetNextSample (1, sampleBuffer.resetAndGetPointerAddress(),
195 &sampleTime, &duration, &flags, &outputNum, &streamNum);
197 if (sampleBuffer !=
nullptr)
199 BYTE* rawData =
nullptr;
200 DWORD dataLength = 0;
201 hr = sampleBuffer->GetBufferAndLength (&rawData, &dataLength);
211 bufferedRange.
setLength ((int64) (dataLength / stride));
214 memcpy (buffer.
getData(), rawData, (
size_t) dataLength);
216 else if (hr == NS_E_NO_MORE_SAMPLES)
218 bufferedRange.
setStart (startSampleInFile);
229 auto offsetInBuffer = (int) (startSampleInFile - bufferedRange.
getStart());
230 auto* rawData =
static_cast<const int16*
> (addBytesToPointer (buffer.
getData(), offsetInBuffer * stride));
231 auto numToDo = jmin (numSamples, (
int) (bufferedRange.
getLength() - offsetInBuffer));
233 for (
int i = 0; i < numDestChannels; ++i)
235 jassert (destSamples[i] !=
nullptr);
238 const int16* src = rawData + srcChan;
239 int*
const dst = destSamples[i] + startOffsetInDestBuffer;
241 for (
int j = 0; j < numToDo; ++j)
243 dst[j] = ((uint32) *src) << 16;
248 startSampleInFile += numToDo;
249 startOffsetInDestBuffer += numToDo;
250 numSamples -= numToDo;
258 ComSmartPtr<IWMSyncReader> wmSyncReader;
262 void checkCoInitialiseCalled()
267 void scanFileForDetails()
269 ComSmartPtr<IWMHeaderInfo> wmHeaderInfo;
270 HRESULT hr = wmSyncReader.QueryInterface (wmHeaderInfo);
274 QWORD lengthInNanoseconds = 0;
275 WORD lengthOfLength =
sizeof (lengthInNanoseconds);
277 WMT_ATTR_DATATYPE wmAttrDataType;
278 hr = wmHeaderInfo->GetAttributeByName (&streamNum, L
"Duration", &wmAttrDataType,
279 (BYTE*) &lengthInNanoseconds, &lengthOfLength);
281 ComSmartPtr<IWMProfile> wmProfile;
282 hr = wmSyncReader.QueryInterface (wmProfile);
286 ComSmartPtr<IWMStreamConfig> wmStreamConfig;
287 hr = wmProfile->GetStream (0, wmStreamConfig.resetAndGetPointerAddress());
291 ComSmartPtr<IWMMediaProps> wmMediaProperties;
292 hr = wmStreamConfig.QueryInterface (wmMediaProperties);
297 hr = wmMediaProperties->GetMediaType (0, &sizeMediaType);
300 mediaType.
malloc (sizeMediaType, 1);
301 hr = wmMediaProperties->GetMediaType (mediaType, &sizeMediaType);
303 if (mediaType->majortype == WMMEDIATYPE_Audio)
305 auto* inputFormat =
reinterpret_cast<WAVEFORMATEX*
> (mediaType->pbFormat);
309 bitsPerSample = inputFormat->wBitsPerSample != 0 ? inputFormat->wBitsPerSample : 16;
318 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WMAudioReader)
324WindowsMediaAudioFormat::WindowsMediaAudioFormat()
325 : AudioFormat (TRANS (WindowsMediaCodec::wmFormatName),
326 StringArray (WindowsMediaCodec::extensions))
330WindowsMediaAudioFormat::~WindowsMediaAudioFormat() {}
344 if (r->sampleRate > 0)
347 if (! deleteStreamIfOpeningFails)
Handles the opening and closing of DLLs.
Very simple container class to hold a pointer to some data on the heap.
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory.
A class to hold a resizable block of raw data.
void ensureSize(const size_t minimumSize, bool initialiseNewSpaceToZero=false)
Increases the block's size only if it's smaller than a given size.
void * getData() noexcept
Returns a void pointer to the data.
void fillWith(uint8 valueToUse) noexcept
Fills the entire memory block with a repeated byte value.
The base class for streams that write data to some kind of destination.
JUCE_CONSTEXPR ValueType getStart() const noexcept
Returns the start of the range.
JUCE_CONSTEXPR bool contains(const ValueType position) const noexcept
Returns true if the given position lies inside this range.
JUCE_CONSTEXPR ValueType getLength() const noexcept
Returns the length of the range.
void setLength(const ValueType newLength) noexcept
Changes the length of the range.
void setStart(const ValueType newStart) noexcept
Changes the start position of the range, leaving the end position unchanged.
JUCE_CONSTEXPR ValueType getEnd() const noexcept
Returns the end of the range.
A container for holding a set of strings which are keyed by another string.