30namespace WindowsMediaCodec
33class JuceIStream :
public ComBaseClassHelper<IStream>
36 JuceIStream (InputStream& in) noexcept
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)
65 newPos += source.getPosition();
67 else if (origin == STREAM_SEEK_END)
69 auto len = source.getTotalLength();
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;
89 while (numBytes > 0 && ! source.isExhausted())
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 };
131class WMAudioReader :
public AudioFormatReader
134 WMAudioReader (InputStream*
const input_)
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());
148 hr = wmSyncReader->OpenStream (
new JuceIStream (*
input));
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);
207 bufferedRange.setStart ((int64) ((sampleTime * (int64)
sampleRate) / 10000000));
209 bufferedRange.setStart (bufferedRange.getEnd());
211 bufferedRange.setLength ((int64) (dataLength / stride));
213 buffer.ensureSize ((
int) dataLength);
214 memcpy (buffer.getData(), rawData, (
size_t) dataLength);
216 else if (hr == NS_E_NO_MORE_SAMPLES)
218 bufferedRange.setStart (startSampleInFile);
219 bufferedRange.setLength (256);
220 buffer.ensureSize (256 * stride);
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;
257 DynamicLibrary wmvCoreLib;
258 ComSmartPtr<IWMSyncReader> wmSyncReader;
260 Range<int64> bufferedRange;
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);
299 HeapBlock<WM_MEDIA_TYPE> mediaType;
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() {}
332Array<int> WindowsMediaAudioFormat::getPossibleSampleRates() {
return {}; }
333Array<int> WindowsMediaAudioFormat::getPossibleBitDepths() {
return {}; }
335bool WindowsMediaAudioFormat::canDoStereo() {
return true; }
336bool WindowsMediaAudioFormat::canDoMono() {
return true; }
337bool WindowsMediaAudioFormat::isCompressed() {
return true; }
340AudioFormatReader* WindowsMediaAudioFormat::createReaderFor (InputStream* sourceStream,
bool deleteStreamIfOpeningFails)
342 std::unique_ptr<WindowsMediaCodec::WMAudioReader> r (
new WindowsMediaCodec::WMAudioReader (sourceStream));
344 if (r->sampleRate > 0)
347 if (! deleteStreamIfOpeningFails)
353AudioFormatWriter* WindowsMediaAudioFormat::createWriterFor (OutputStream* ,
double ,
355 const StringPairArray& ,
int )