bool DirectShowReader::DecodeAudioData() { MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); HRESULT hr; SampleSink* sink = mAudioSinkFilter->GetSampleSink(); if (sink->AtEOS()) { // End of stream. return Finish(S_OK); } // Get the next chunk of audio samples. This blocks until the sample // arrives, or an error occurs (like the stream is shutdown). RefPtr<IMediaSample> sample; hr = sink->Extract(sample); if (FAILED(hr) || hr == S_FALSE) { return Finish(hr); } int64_t start = 0, end = 0; sample->GetMediaTime(&start, &end); LOG("DirectShowReader::DecodeAudioData [%4.2lf-%4.2lf]", RefTimeToSeconds(start), RefTimeToSeconds(end)); LONG length = sample->GetActualDataLength(); LONG numSamples = length / mBytesPerSample; LONG numFrames = length / mBytesPerSample / mNumChannels; BYTE* data = nullptr; hr = sample->GetPointer(&data); NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr)); nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[numSamples]); AudioDataValue* dst = buffer.get(); if (mBytesPerSample == 1) { uint8_t* src = reinterpret_cast<uint8_t*>(data); for (int32_t i = 0; i < numSamples; ++i) { dst[i] = UnsignedByteToAudioSample(src[i]); } } else if (mBytesPerSample == 2) { int16_t* src = reinterpret_cast<int16_t*>(data); for (int32_t i = 0; i < numSamples; ++i) { dst[i] = AudioSampleToFloat(src[i]); } } mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(), RefTimeToUsecs(start), RefTimeToUsecs(end - start), numFrames, buffer.forget(), mNumChannels)); return true; }
bool DirectShowReader::DecodeAudioData() { MOZ_ASSERT(OnTaskQueue()); HRESULT hr; SampleSink* sink = mAudioSinkFilter->GetSampleSink(); if (sink->AtEOS()) { // End of stream. return Finish(S_OK); } // Get the next chunk of audio samples. This blocks until the sample // arrives, or an error occurs (like the stream is shutdown). RefPtr<IMediaSample> sample; hr = sink->Extract(sample); if (FAILED(hr) || hr == S_FALSE) { return Finish(hr); } int64_t start = 0, end = 0; sample->GetMediaTime(&start, &end); LOG("DirectShowReader::DecodeAudioData [%4.2lf-%4.2lf]", RefTimeToSeconds(start), RefTimeToSeconds(end)); LONG length = sample->GetActualDataLength(); LONG numSamples = length / mBytesPerSample; LONG numFrames = length / mBytesPerSample / mNumChannels; BYTE* data = nullptr; hr = sample->GetPointer(&data); NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr)); mAudioCompactor.Push(mDecoder->GetResource()->Tell(), RefTimeToUsecs(start), mInfo.mAudio.mRate, numFrames, mNumChannels, DirectShowCopy(reinterpret_cast<uint8_t *>(data), mBytesPerSample, numSamples, mNumChannels)); return true; }
nsresult DirectShowReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { MOZ_ASSERT(OnTaskQueue()); HRESULT hr; nsresult rv; // Create the filter graph, reference it by the GraphBuilder interface, // to make graph building more convenient. hr = CoCreateInstance(CLSID_FilterGraph, nullptr, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, reinterpret_cast<void**>(static_cast<IGraphBuilder**>(byRef(mGraph)))); NS_ENSURE_TRUE(SUCCEEDED(hr) && mGraph, NS_ERROR_FAILURE); rv = ParseMP3Headers(&mMP3FrameParser, mDecoder->GetResource()); NS_ENSURE_SUCCESS(rv, rv); #ifdef DEBUG // Add the graph to the Running Object Table so that we can connect // to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must // also regsvr32 proppage.dll from the Windows SDK. // See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); #endif // Extract the interface pointers we'll need from the filter graph. hr = mGraph->QueryInterface(static_cast<IMediaControl**>(byRef(mControl))); NS_ENSURE_TRUE(SUCCEEDED(hr) && mControl, NS_ERROR_FAILURE); hr = mGraph->QueryInterface(static_cast<IMediaSeeking**>(byRef(mMediaSeeking))); NS_ENSURE_TRUE(SUCCEEDED(hr) && mMediaSeeking, NS_ERROR_FAILURE); // Build the graph. Create the filters we need, and connect them. We // build the entire graph ourselves to prevent other decoders installed // on the system being created and used. // Our source filters, wraps the MediaResource. mSourceFilter = new SourceFilter(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); NS_ENSURE_TRUE(mSourceFilter, NS_ERROR_FAILURE); rv = mSourceFilter->Init(mDecoder->GetResource(), mMP3FrameParser.GetMP3Offset()); NS_ENSURE_SUCCESS(rv, rv); hr = mGraph->AddFilter(mSourceFilter, L"MozillaDirectShowSource"); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); // The MPEG demuxer. RefPtr<IBaseFilter> demuxer; hr = CreateAndAddFilter(mGraph, CLSID_MPEG1Splitter, L"MPEG1Splitter", byRef(demuxer)); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); // Platform MP3 decoder. RefPtr<IBaseFilter> decoder; // Firstly try to create the MP3 decoder filter that ships with WinXP // directly. This filter doesn't normally exist on later versions of // Windows. hr = CreateAndAddFilter(mGraph, CLSID_MPEG_LAYER_3_DECODER_FILTER, L"MPEG Layer 3 Decoder", byRef(decoder)); if (FAILED(hr)) { // Failed to create MP3 decoder filter. Try to instantiate // the MP3 decoder DMO. hr = AddMP3DMOWrapperFilter(mGraph, byRef(decoder)); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); } // Sink, captures audio samples and inserts them into our pipeline. static const wchar_t* AudioSinkFilterName = L"MozAudioSinkFilter"; mAudioSinkFilter = new AudioSinkFilter(AudioSinkFilterName, &hr); NS_ENSURE_TRUE(mAudioSinkFilter && SUCCEEDED(hr), NS_ERROR_FAILURE); hr = mGraph->AddFilter(mAudioSinkFilter, AudioSinkFilterName); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); // Join the filters. hr = ConnectFilters(mGraph, mSourceFilter, demuxer); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = ConnectFilters(mGraph, demuxer, decoder); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = ConnectFilters(mGraph, decoder, mAudioSinkFilter); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); WAVEFORMATEX format; mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format); NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE); mInfo.mAudio.mChannels = mNumChannels = format.nChannels; mInfo.mAudio.mRate = mAudioRate = format.nSamplesPerSec; mInfo.mAudio.mBitDepth = format.wBitsPerSample; mBytesPerSample = format.wBitsPerSample / 8; // Begin decoding! hr = mControl->Run(); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); DWORD seekCaps = 0; hr = mMediaSeeking->GetCapabilities(&seekCaps); int64_t duration = mMP3FrameParser.GetDuration(); if (SUCCEEDED(hr)) { mInfo.mMetadataDuration.emplace(TimeUnit::FromMicroseconds(duration)); } LOG("Successfully initialized DirectShow MP3 decoder."); LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d", mInfo.mAudio.mChannels, mInfo.mAudio.mRate, RefTimeToUsecs(duration), mBytesPerSample); *aInfo = mInfo; // Note: The SourceFilter strips ID3v2 tags out of the stream. *aTags = nullptr; return NS_OK; }