Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "DirectShowReader.h" |
michael@0 | 8 | #include "MediaDecoderReader.h" |
michael@0 | 9 | #include "mozilla/RefPtr.h" |
michael@0 | 10 | #include "dshow.h" |
michael@0 | 11 | #include "AudioSinkFilter.h" |
michael@0 | 12 | #include "SourceFilter.h" |
michael@0 | 13 | #include "DirectShowUtils.h" |
michael@0 | 14 | #include "SampleSink.h" |
michael@0 | 15 | #include "MediaResource.h" |
michael@0 | 16 | #include "VideoUtils.h" |
michael@0 | 17 | |
michael@0 | 18 | namespace mozilla { |
michael@0 | 19 | |
michael@0 | 20 | |
michael@0 | 21 | #ifdef PR_LOGGING |
michael@0 | 22 | |
michael@0 | 23 | PRLogModuleInfo* |
michael@0 | 24 | GetDirectShowLog() { |
michael@0 | 25 | static PRLogModuleInfo* log = nullptr; |
michael@0 | 26 | if (!log) { |
michael@0 | 27 | log = PR_NewLogModule("DirectShowDecoder"); |
michael@0 | 28 | } |
michael@0 | 29 | return log; |
michael@0 | 30 | } |
michael@0 | 31 | |
michael@0 | 32 | #define LOG(...) PR_LOG(GetDirectShowLog(), PR_LOG_DEBUG, (__VA_ARGS__)) |
michael@0 | 33 | |
michael@0 | 34 | #else |
michael@0 | 35 | #define LOG(...) |
michael@0 | 36 | #endif |
michael@0 | 37 | |
michael@0 | 38 | DirectShowReader::DirectShowReader(AbstractMediaDecoder* aDecoder) |
michael@0 | 39 | : MediaDecoderReader(aDecoder), |
michael@0 | 40 | mMP3FrameParser(aDecoder->GetResource()->GetLength()), |
michael@0 | 41 | #ifdef DEBUG |
michael@0 | 42 | mRotRegister(0), |
michael@0 | 43 | #endif |
michael@0 | 44 | mNumChannels(0), |
michael@0 | 45 | mAudioRate(0), |
michael@0 | 46 | mBytesPerSample(0), |
michael@0 | 47 | mDuration(0) |
michael@0 | 48 | { |
michael@0 | 49 | MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); |
michael@0 | 50 | MOZ_COUNT_CTOR(DirectShowReader); |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | DirectShowReader::~DirectShowReader() |
michael@0 | 54 | { |
michael@0 | 55 | MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); |
michael@0 | 56 | MOZ_COUNT_DTOR(DirectShowReader); |
michael@0 | 57 | #ifdef DEBUG |
michael@0 | 58 | if (mRotRegister) { |
michael@0 | 59 | RemoveGraphFromRunningObjectTable(mRotRegister); |
michael@0 | 60 | } |
michael@0 | 61 | #endif |
michael@0 | 62 | } |
michael@0 | 63 | |
michael@0 | 64 | nsresult |
michael@0 | 65 | DirectShowReader::Init(MediaDecoderReader* aCloneDonor) |
michael@0 | 66 | { |
michael@0 | 67 | MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); |
michael@0 | 68 | return NS_OK; |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | // Try to parse the MP3 stream to make sure this is indeed an MP3, get the |
michael@0 | 72 | // estimated duration of the stream, and find the offset of the actual MP3 |
michael@0 | 73 | // frames in the stream, as DirectShow doesn't like large ID3 sections. |
michael@0 | 74 | static nsresult |
michael@0 | 75 | ParseMP3Headers(MP3FrameParser *aParser, MediaResource *aResource) |
michael@0 | 76 | { |
michael@0 | 77 | const uint32_t MAX_READ_SIZE = 4096; |
michael@0 | 78 | |
michael@0 | 79 | uint64_t offset = 0; |
michael@0 | 80 | while (aParser->NeedsData() && !aParser->ParsedHeaders()) { |
michael@0 | 81 | uint32_t bytesRead; |
michael@0 | 82 | char buffer[MAX_READ_SIZE]; |
michael@0 | 83 | nsresult rv = aResource->ReadAt(offset, buffer, |
michael@0 | 84 | MAX_READ_SIZE, &bytesRead); |
michael@0 | 85 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 86 | |
michael@0 | 87 | if (!bytesRead) { |
michael@0 | 88 | // End of stream. |
michael@0 | 89 | return NS_ERROR_FAILURE; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | aParser->Parse(buffer, bytesRead, offset); |
michael@0 | 93 | offset += bytesRead; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | return aParser->IsMP3() ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 97 | } |
michael@0 | 98 | |
michael@0 | 99 | // Windows XP's MP3 decoder filter. This is available on XP only, on Vista |
michael@0 | 100 | // and later we can use the DMO Wrapper filter and MP3 decoder DMO. |
michael@0 | 101 | static const GUID CLSID_MPEG_LAYER_3_DECODER_FILTER = |
michael@0 | 102 | { 0x38BE3000, 0xDBF4, 0x11D0, 0x86, 0x0E, 0x00, 0xA0, 0x24, 0xCF, 0xEF, 0x6D }; |
michael@0 | 103 | |
michael@0 | 104 | nsresult |
michael@0 | 105 | DirectShowReader::ReadMetadata(MediaInfo* aInfo, |
michael@0 | 106 | MetadataTags** aTags) |
michael@0 | 107 | { |
michael@0 | 108 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
michael@0 | 109 | HRESULT hr; |
michael@0 | 110 | nsresult rv; |
michael@0 | 111 | |
michael@0 | 112 | // Create the filter graph, reference it by the GraphBuilder interface, |
michael@0 | 113 | // to make graph building more convenient. |
michael@0 | 114 | hr = CoCreateInstance(CLSID_FilterGraph, |
michael@0 | 115 | nullptr, |
michael@0 | 116 | CLSCTX_INPROC_SERVER, |
michael@0 | 117 | IID_IGraphBuilder, |
michael@0 | 118 | reinterpret_cast<void**>(static_cast<IGraphBuilder**>(byRef(mGraph)))); |
michael@0 | 119 | NS_ENSURE_TRUE(SUCCEEDED(hr) && mGraph, NS_ERROR_FAILURE); |
michael@0 | 120 | |
michael@0 | 121 | rv = ParseMP3Headers(&mMP3FrameParser, mDecoder->GetResource()); |
michael@0 | 122 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 123 | |
michael@0 | 124 | #ifdef DEBUG |
michael@0 | 125 | // Add the graph to the Running Object Table so that we can connect |
michael@0 | 126 | // to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must |
michael@0 | 127 | // also regsvr32 proppage.dll from the Windows SDK. |
michael@0 | 128 | // See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx |
michael@0 | 129 | hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister); |
michael@0 | 130 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 131 | #endif |
michael@0 | 132 | |
michael@0 | 133 | // Extract the interface pointers we'll need from the filter graph. |
michael@0 | 134 | hr = mGraph->QueryInterface(static_cast<IMediaControl**>(byRef(mControl))); |
michael@0 | 135 | NS_ENSURE_TRUE(SUCCEEDED(hr) && mControl, NS_ERROR_FAILURE); |
michael@0 | 136 | |
michael@0 | 137 | hr = mGraph->QueryInterface(static_cast<IMediaSeeking**>(byRef(mMediaSeeking))); |
michael@0 | 138 | NS_ENSURE_TRUE(SUCCEEDED(hr) && mMediaSeeking, NS_ERROR_FAILURE); |
michael@0 | 139 | |
michael@0 | 140 | // Build the graph. Create the filters we need, and connect them. We |
michael@0 | 141 | // build the entire graph ourselves to prevent other decoders installed |
michael@0 | 142 | // on the system being created and used. |
michael@0 | 143 | |
michael@0 | 144 | // Our source filters, wraps the MediaResource. |
michael@0 | 145 | mSourceFilter = new SourceFilter(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); |
michael@0 | 146 | NS_ENSURE_TRUE(mSourceFilter, NS_ERROR_FAILURE); |
michael@0 | 147 | |
michael@0 | 148 | rv = mSourceFilter->Init(mDecoder->GetResource(), mMP3FrameParser.GetMP3Offset()); |
michael@0 | 149 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 150 | |
michael@0 | 151 | hr = mGraph->AddFilter(mSourceFilter, L"MozillaDirectShowSource"); |
michael@0 | 152 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 153 | |
michael@0 | 154 | // The MPEG demuxer. |
michael@0 | 155 | RefPtr<IBaseFilter> demuxer; |
michael@0 | 156 | hr = CreateAndAddFilter(mGraph, |
michael@0 | 157 | CLSID_MPEG1Splitter, |
michael@0 | 158 | L"MPEG1Splitter", |
michael@0 | 159 | byRef(demuxer)); |
michael@0 | 160 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 161 | |
michael@0 | 162 | // Platform MP3 decoder. |
michael@0 | 163 | RefPtr<IBaseFilter> decoder; |
michael@0 | 164 | // Firstly try to create the MP3 decoder filter that ships with WinXP |
michael@0 | 165 | // directly. This filter doesn't normally exist on later versions of |
michael@0 | 166 | // Windows. |
michael@0 | 167 | hr = CreateAndAddFilter(mGraph, |
michael@0 | 168 | CLSID_MPEG_LAYER_3_DECODER_FILTER, |
michael@0 | 169 | L"MPEG Layer 3 Decoder", |
michael@0 | 170 | byRef(decoder)); |
michael@0 | 171 | if (FAILED(hr)) { |
michael@0 | 172 | // Failed to create MP3 decoder filter. Try to instantiate |
michael@0 | 173 | // the MP3 decoder DMO. |
michael@0 | 174 | hr = AddMP3DMOWrapperFilter(mGraph, byRef(decoder)); |
michael@0 | 175 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | // Sink, captures audio samples and inserts them into our pipeline. |
michael@0 | 179 | static const wchar_t* AudioSinkFilterName = L"MozAudioSinkFilter"; |
michael@0 | 180 | mAudioSinkFilter = new AudioSinkFilter(AudioSinkFilterName, &hr); |
michael@0 | 181 | NS_ENSURE_TRUE(mAudioSinkFilter && SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 182 | hr = mGraph->AddFilter(mAudioSinkFilter, AudioSinkFilterName); |
michael@0 | 183 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 184 | |
michael@0 | 185 | // Join the filters. |
michael@0 | 186 | hr = ConnectFilters(mGraph, mSourceFilter, demuxer); |
michael@0 | 187 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 188 | |
michael@0 | 189 | hr = ConnectFilters(mGraph, demuxer, decoder); |
michael@0 | 190 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 191 | |
michael@0 | 192 | hr = ConnectFilters(mGraph, decoder, mAudioSinkFilter); |
michael@0 | 193 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 194 | |
michael@0 | 195 | WAVEFORMATEX format; |
michael@0 | 196 | mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format); |
michael@0 | 197 | NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE); |
michael@0 | 198 | |
michael@0 | 199 | mInfo.mAudio.mChannels = mNumChannels = format.nChannels; |
michael@0 | 200 | mInfo.mAudio.mRate = mAudioRate = format.nSamplesPerSec; |
michael@0 | 201 | mBytesPerSample = format.wBitsPerSample / 8; |
michael@0 | 202 | mInfo.mAudio.mHasAudio = true; |
michael@0 | 203 | |
michael@0 | 204 | *aInfo = mInfo; |
michael@0 | 205 | // Note: The SourceFilter strips ID3v2 tags out of the stream. |
michael@0 | 206 | *aTags = nullptr; |
michael@0 | 207 | |
michael@0 | 208 | // Begin decoding! |
michael@0 | 209 | hr = mControl->Run(); |
michael@0 | 210 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 211 | |
michael@0 | 212 | DWORD seekCaps = 0; |
michael@0 | 213 | hr = mMediaSeeking->GetCapabilities(&seekCaps); |
michael@0 | 214 | bool canSeek = ((AM_SEEKING_CanSeekAbsolute & seekCaps) == AM_SEEKING_CanSeekAbsolute); |
michael@0 | 215 | if (!canSeek) { |
michael@0 | 216 | mDecoder->SetMediaSeekable(false); |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | int64_t duration = mMP3FrameParser.GetDuration(); |
michael@0 | 220 | if (SUCCEEDED(hr)) { |
michael@0 | 221 | ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); |
michael@0 | 222 | mDecoder->SetMediaDuration(duration); |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | LOG("Successfully initialized DirectShow MP3 decoder."); |
michael@0 | 226 | LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d", |
michael@0 | 227 | mInfo.mAudio.mChannels, |
michael@0 | 228 | mInfo.mAudio.mRate, |
michael@0 | 229 | RefTimeToUsecs(duration), |
michael@0 | 230 | mBytesPerSample); |
michael@0 | 231 | |
michael@0 | 232 | return NS_OK; |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | inline float |
michael@0 | 236 | UnsignedByteToAudioSample(uint8_t aValue) |
michael@0 | 237 | { |
michael@0 | 238 | return aValue * (2.0f / UINT8_MAX) - 1.0f; |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | bool |
michael@0 | 242 | DirectShowReader::Finish(HRESULT aStatus) |
michael@0 | 243 | { |
michael@0 | 244 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
michael@0 | 245 | |
michael@0 | 246 | LOG("DirectShowReader::Finish(0x%x)", aStatus); |
michael@0 | 247 | // Notify the filter graph of end of stream. |
michael@0 | 248 | RefPtr<IMediaEventSink> eventSink; |
michael@0 | 249 | HRESULT hr = mGraph->QueryInterface(static_cast<IMediaEventSink**>(byRef(eventSink))); |
michael@0 | 250 | if (SUCCEEDED(hr) && eventSink) { |
michael@0 | 251 | eventSink->Notify(EC_COMPLETE, aStatus, 0); |
michael@0 | 252 | } |
michael@0 | 253 | return false; |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | class DirectShowCopy |
michael@0 | 257 | { |
michael@0 | 258 | public: |
michael@0 | 259 | DirectShowCopy(uint8_t *aSource, uint32_t aBytesPerSample, |
michael@0 | 260 | uint32_t aSamples, uint32_t aChannels) |
michael@0 | 261 | : mSource(aSource) |
michael@0 | 262 | , mBytesPerSample(aBytesPerSample) |
michael@0 | 263 | , mSamples(aSamples) |
michael@0 | 264 | , mChannels(aChannels) |
michael@0 | 265 | , mNextSample(0) |
michael@0 | 266 | { } |
michael@0 | 267 | |
michael@0 | 268 | uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples) |
michael@0 | 269 | { |
michael@0 | 270 | uint32_t maxSamples = std::min(aSamples, mSamples - mNextSample); |
michael@0 | 271 | uint32_t frames = maxSamples / mChannels; |
michael@0 | 272 | size_t byteOffset = mNextSample * mBytesPerSample; |
michael@0 | 273 | if (mBytesPerSample == 1) { |
michael@0 | 274 | for (uint32_t i = 0; i < maxSamples; ++i) { |
michael@0 | 275 | uint8_t *sample = mSource + byteOffset; |
michael@0 | 276 | aBuffer[i] = UnsignedByteToAudioSample(*sample); |
michael@0 | 277 | byteOffset += mBytesPerSample; |
michael@0 | 278 | } |
michael@0 | 279 | } else if (mBytesPerSample == 2) { |
michael@0 | 280 | for (uint32_t i = 0; i < maxSamples; ++i) { |
michael@0 | 281 | int16_t *sample = reinterpret_cast<int16_t *>(mSource + byteOffset); |
michael@0 | 282 | aBuffer[i] = AudioSampleToFloat(*sample); |
michael@0 | 283 | byteOffset += mBytesPerSample; |
michael@0 | 284 | } |
michael@0 | 285 | } |
michael@0 | 286 | mNextSample += maxSamples; |
michael@0 | 287 | return frames; |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | private: |
michael@0 | 291 | uint8_t * const mSource; |
michael@0 | 292 | const uint32_t mBytesPerSample; |
michael@0 | 293 | const uint32_t mSamples; |
michael@0 | 294 | const uint32_t mChannels; |
michael@0 | 295 | uint32_t mNextSample; |
michael@0 | 296 | }; |
michael@0 | 297 | |
michael@0 | 298 | bool |
michael@0 | 299 | DirectShowReader::DecodeAudioData() |
michael@0 | 300 | { |
michael@0 | 301 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
michael@0 | 302 | HRESULT hr; |
michael@0 | 303 | |
michael@0 | 304 | SampleSink* sink = mAudioSinkFilter->GetSampleSink(); |
michael@0 | 305 | if (sink->AtEOS()) { |
michael@0 | 306 | // End of stream. |
michael@0 | 307 | return Finish(S_OK); |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | // Get the next chunk of audio samples. This blocks until the sample |
michael@0 | 311 | // arrives, or an error occurs (like the stream is shutdown). |
michael@0 | 312 | RefPtr<IMediaSample> sample; |
michael@0 | 313 | hr = sink->Extract(sample); |
michael@0 | 314 | if (FAILED(hr) || hr == S_FALSE) { |
michael@0 | 315 | return Finish(hr); |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | int64_t start = 0, end = 0; |
michael@0 | 319 | sample->GetMediaTime(&start, &end); |
michael@0 | 320 | LOG("DirectShowReader::DecodeAudioData [%4.2lf-%4.2lf]", |
michael@0 | 321 | RefTimeToSeconds(start), |
michael@0 | 322 | RefTimeToSeconds(end)); |
michael@0 | 323 | |
michael@0 | 324 | LONG length = sample->GetActualDataLength(); |
michael@0 | 325 | LONG numSamples = length / mBytesPerSample; |
michael@0 | 326 | LONG numFrames = length / mBytesPerSample / mNumChannels; |
michael@0 | 327 | |
michael@0 | 328 | BYTE* data = nullptr; |
michael@0 | 329 | hr = sample->GetPointer(&data); |
michael@0 | 330 | NS_ENSURE_TRUE(SUCCEEDED(hr), Finish(hr)); |
michael@0 | 331 | |
michael@0 | 332 | mAudioCompactor.Push(mDecoder->GetResource()->Tell(), |
michael@0 | 333 | RefTimeToUsecs(start), |
michael@0 | 334 | mInfo.mAudio.mRate, |
michael@0 | 335 | numFrames, |
michael@0 | 336 | mNumChannels, |
michael@0 | 337 | DirectShowCopy(reinterpret_cast<uint8_t *>(data), |
michael@0 | 338 | mBytesPerSample, |
michael@0 | 339 | numSamples, |
michael@0 | 340 | mNumChannels)); |
michael@0 | 341 | return true; |
michael@0 | 342 | } |
michael@0 | 343 | |
michael@0 | 344 | bool |
michael@0 | 345 | DirectShowReader::DecodeVideoFrame(bool &aKeyframeSkip, |
michael@0 | 346 | int64_t aTimeThreshold) |
michael@0 | 347 | { |
michael@0 | 348 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
michael@0 | 349 | return false; |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | bool |
michael@0 | 353 | DirectShowReader::HasAudio() |
michael@0 | 354 | { |
michael@0 | 355 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
michael@0 | 356 | return true; |
michael@0 | 357 | } |
michael@0 | 358 | |
michael@0 | 359 | bool |
michael@0 | 360 | DirectShowReader::HasVideo() |
michael@0 | 361 | { |
michael@0 | 362 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
michael@0 | 363 | return false; |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | nsresult |
michael@0 | 367 | DirectShowReader::Seek(int64_t aTargetUs, |
michael@0 | 368 | int64_t aStartTime, |
michael@0 | 369 | int64_t aEndTime, |
michael@0 | 370 | int64_t aCurrentTime) |
michael@0 | 371 | { |
michael@0 | 372 | HRESULT hr; |
michael@0 | 373 | MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");\ |
michael@0 | 374 | |
michael@0 | 375 | LOG("DirectShowReader::Seek() target=%lld", aTargetUs); |
michael@0 | 376 | |
michael@0 | 377 | hr = mControl->Pause(); |
michael@0 | 378 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 379 | |
michael@0 | 380 | nsresult rv = ResetDecode(); |
michael@0 | 381 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 382 | |
michael@0 | 383 | LONGLONG seekPosition = UsecsToRefTime(aTargetUs); |
michael@0 | 384 | hr = mMediaSeeking->SetPositions(&seekPosition, |
michael@0 | 385 | AM_SEEKING_AbsolutePositioning, |
michael@0 | 386 | nullptr, |
michael@0 | 387 | AM_SEEKING_NoPositioning); |
michael@0 | 388 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 389 | |
michael@0 | 390 | hr = mControl->Run(); |
michael@0 | 391 | NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); |
michael@0 | 392 | |
michael@0 | 393 | return NS_OK; |
michael@0 | 394 | } |
michael@0 | 395 | |
michael@0 | 396 | void |
michael@0 | 397 | DirectShowReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) |
michael@0 | 398 | { |
michael@0 | 399 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 400 | if (!mMP3FrameParser.IsMP3()) { |
michael@0 | 401 | return; |
michael@0 | 402 | } |
michael@0 | 403 | mMP3FrameParser.Parse(aBuffer, aLength, aOffset); |
michael@0 | 404 | int64_t duration = mMP3FrameParser.GetDuration(); |
michael@0 | 405 | if (duration != mDuration) { |
michael@0 | 406 | mDuration = duration; |
michael@0 | 407 | MOZ_ASSERT(mDecoder); |
michael@0 | 408 | ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); |
michael@0 | 409 | mDecoder->UpdateEstimatedMediaDuration(mDuration); |
michael@0 | 410 | } |
michael@0 | 411 | } |
michael@0 | 412 | |
michael@0 | 413 | } // namespace mozilla |