LCOV - app.info - content/media/nsBuiltinDecoder.cpp

LCOV - code coverage report
| Current view: | directory - content/media - nsBuiltinDecoder.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 501 | 0 | 0.0 %
| Date: | 2012-06-02 | Functions: | 61 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
           3                 : /* ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is Mozilla code.
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is the Mozilla Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 2007
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *  Chris Double <chris.double@double.co.nz>
          24                 :  *  Chris Pearce <chris@pearce.org.nz>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
          28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include <limits>
          41                 : #include "nsNetUtil.h"
          42                 : #include "nsAudioStream.h"
          43                 : #include "nsHTMLVideoElement.h"
          44                 : #include "nsIObserver.h"
          45                 : #include "nsIObserverService.h"
          46                 : #include "nsTArray.h"
          47                 : #include "VideoUtils.h"
          48                 : #include "nsBuiltinDecoder.h"
          49                 : #include "nsBuiltinDecoderStateMachine.h"
          50                 : #include "nsTimeRanges.h"
          51                 : #include "nsContentUtils.h"
          52                 :
          53                 : using namespace mozilla;
          54                 :
          55                 : #ifdef PR_LOGGING
          56                 : PRLogModuleInfo* gBuiltinDecoderLog;
          57                 : #define LOG(type, msg) PR_LOG(gBuiltinDecoderLog, type, msg)
          58                 : #else
          59                 : #define LOG(type, msg)
          60                 : #endif
          61                 :
          62               0 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsBuiltinDecoder, nsIObserver)
          63                 :
          64               0 : void nsBuiltinDecoder::Pause()
          65                 : {
          66               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
          67               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
          68               0 :   if (mPlayState == PLAY_STATE_SEEKING || mPlayState == PLAY_STATE_ENDED) {
          69               0 :     mNextState = PLAY_STATE_PAUSED;
          70                 :     return;
          71                 :   }
          72                 :
          73               0 :   ChangeState(PLAY_STATE_PAUSED);
          74                 : }
          75                 :
          76               0 : void nsBuiltinDecoder::SetVolume(double aVolume)
          77                 : {
          78               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
          79               0 :   mInitialVolume = aVolume;
          80               0 :   if (mDecoderStateMachine) {
          81               0 :     mDecoderStateMachine->SetVolume(aVolume);
          82                 :   }
          83               0 : }
          84                 :
          85               0 : double nsBuiltinDecoder::GetDuration()
          86                 : {
          87               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
          88               0 :   if (mInfiniteStream) {
          89               0 :     return std::numeric_limits<double>::infinity();
          90                 :   }
          91               0 :   if (mDuration >= 0) {
          92               0 :      return static_cast<double>(mDuration) / static_cast<double>(USECS_PER_S);
          93                 :   }
          94               0 :   return std::numeric_limits<double>::quiet_NaN();
          95                 : }
          96                 :
          97               0 : void nsBuiltinDecoder::SetInfinite(bool aInfinite)
          98                 : {
          99               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         100               0 :   mInfiniteStream = aInfinite;
         101               0 : }
         102                 :
         103               0 : bool nsBuiltinDecoder::IsInfinite()
         104                 : {
         105               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         106               0 :   return mInfiniteStream;
         107                 : }
         108                 :
         109               0 : nsBuiltinDecoder::nsBuiltinDecoder() :
         110                 :   mDecoderPosition(0),
         111                 :   mPlaybackPosition(0),
         112                 :   mCurrentTime(0.0),
         113                 :   mInitialVolume(0.0),
         114                 :   mRequestedSeekTime(-1.0),
         115                 :   mDuration(-1),
         116                 :   mSeekable(true),
         117                 :   mReentrantMonitor("media.decoder"),
         118                 :   mPlayState(PLAY_STATE_PAUSED),
         119                 :   mNextState(PLAY_STATE_PAUSED),
         120                 :   mResourceLoaded(false),
         121                 :   mIgnoreProgressData(false),
         122               0 :   mInfiniteStream(false)
         123                 : {
         124               0 :   MOZ_COUNT_CTOR(nsBuiltinDecoder);
         125               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         126                 : #ifdef PR_LOGGING
         127               0 :   if (!gBuiltinDecoderLog) {
         128               0 :     gBuiltinDecoderLog = PR_NewLogModule("nsBuiltinDecoder");
         129                 :   }
         130                 : #endif
         131               0 : }
         132                 :
         133               0 : bool nsBuiltinDecoder::Init(nsHTMLMediaElement* aElement)
         134                 : {
         135               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         136               0 :   if (!nsMediaDecoder::Init(aElement))
         137               0 :     return false;
         138                 :
         139               0 :   nsContentUtils::RegisterShutdownObserver(this);
         140               0 :   return true;
         141                 : }
         142                 :
         143               0 : void nsBuiltinDecoder::Shutdown()
         144                 : {
         145               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         146                 :
         147               0 :   if (mShuttingDown)
         148               0 :     return;
         149                 :
         150               0 :   mShuttingDown = true;
         151                 :
         152                 :   // This changes the decoder state to SHUTDOWN and does other things
         153                 :   // necessary to unblock the state machine thread if it's blocked, so
         154                 :   // the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
         155               0 :   if (mDecoderStateMachine) {
         156               0 :     mDecoderStateMachine->Shutdown();
         157                 :   }
         158                 :
         159                 :   // Force any outstanding seek and byterange requests to complete
         160                 :   // to prevent shutdown from deadlocking.
         161               0 :   if (mResource) {
         162               0 :     mResource->Close();
         163                 :   }
         164                 :
         165               0 :   ChangeState(PLAY_STATE_SHUTDOWN);
         166               0 :   nsMediaDecoder::Shutdown();
         167                 :
         168               0 :   nsContentUtils::UnregisterShutdownObserver(this);
         169                 : }
         170                 :
         171               0 : nsBuiltinDecoder::~nsBuiltinDecoder()
         172                 : {
         173               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         174               0 :   UnpinForSeek();
         175               0 :   MOZ_COUNT_DTOR(nsBuiltinDecoder);
         176               0 : }
         177                 :
         178               0 : nsresult nsBuiltinDecoder::Load(MediaResource* aResource,
         179                 :                                 nsIStreamListener** aStreamListener,
         180                 :                                 nsMediaDecoder* aCloneDonor)
         181                 : {
         182               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         183               0 :   if (aStreamListener) {
         184               0 :     *aStreamListener = nsnull;
         185                 :   }
         186                 :
         187                 :   {
         188                 :     // Hold the lock while we do this to set proper lock ordering
         189                 :     // expectations for dynamic deadlock detectors: decoder lock(s)
         190                 :     // should be grabbed before the cache lock
         191               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         192                 :
         193               0 :     nsresult rv = aResource->Open(aStreamListener);
         194               0 :     if (NS_FAILED(rv)) {
         195               0 :       LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
         196               0 :       delete aResource;
         197               0 :       return rv;
         198                 :     }
         199                 :
         200               0 :     mResource = aResource;
         201                 :   }
         202                 :
         203               0 :   mDecoderStateMachine = CreateStateMachine();
         204               0 :   if (!mDecoderStateMachine) {
         205               0 :     LOG(PR_LOG_DEBUG, ("%p Failed to create state machine!", this));
         206               0 :     return NS_ERROR_FAILURE;
         207                 :   }
         208                 :
         209               0 :   nsBuiltinDecoder* cloneDonor = static_cast<nsBuiltinDecoder*>(aCloneDonor);
         210               0 :   if (NS_FAILED(mDecoderStateMachine->Init(cloneDonor ?
         211                 :                                            cloneDonor->mDecoderStateMachine : nsnull))) {
         212               0 :     LOG(PR_LOG_DEBUG, ("%p Failed to init state machine!", this));
         213               0 :     return NS_ERROR_FAILURE;
         214                 :   }
         215                 :   {
         216               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         217               0 :     mDecoderStateMachine->SetSeekable(mSeekable);
         218               0 :     mDecoderStateMachine->SetDuration(mDuration);
         219               0 :     mDecoderStateMachine->SetVolume(mInitialVolume);
         220                 :
         221               0 :     if (mFrameBufferLength > 0) {
         222                 :       // The valid mFrameBufferLength value was specified earlier
         223               0 :       mDecoderStateMachine->SetFrameBufferLength(mFrameBufferLength);
         224                 :     }
         225                 :   }
         226                 :
         227               0 :   ChangeState(PLAY_STATE_LOADING);
         228                 :
         229               0 :   return ScheduleStateMachineThread();
         230                 : }
         231                 :
         232               0 : nsresult nsBuiltinDecoder::RequestFrameBufferLength(PRUint32 aLength)
         233                 : {
         234               0 :   nsresult res = nsMediaDecoder::RequestFrameBufferLength(aLength);
         235               0 :   NS_ENSURE_SUCCESS(res,res);
         236                 :
         237               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         238               0 :   if (mDecoderStateMachine) {
         239               0 :       mDecoderStateMachine->SetFrameBufferLength(aLength);
         240                 :   }
         241               0 :   return res;
         242                 : }
         243                 :
         244               0 : nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
         245                 : {
         246               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         247               0 :   NS_ASSERTION(mDecoderStateMachine,
         248                 :                "Must have state machine to start state machine thread");
         249               0 :   NS_ENSURE_STATE(mDecoderStateMachine);
         250                 :
         251               0 :   if (mShuttingDown)
         252               0 :     return NS_OK;
         253               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         254                 :   nsBuiltinDecoderStateMachine* m =
         255               0 :     static_cast<nsBuiltinDecoderStateMachine*>(mDecoderStateMachine.get());
         256               0 :   return m->ScheduleStateMachine();
         257                 : }
         258                 :
         259               0 : nsresult nsBuiltinDecoder::Play()
         260                 : {
         261               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         262               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         263               0 :   NS_ASSERTION(mDecoderStateMachine != nsnull, "Should have state machine.");
         264               0 :   nsresult res = ScheduleStateMachineThread();
         265               0 :   NS_ENSURE_SUCCESS(res,res);
         266               0 :   if (mPlayState == PLAY_STATE_SEEKING) {
         267               0 :     mNextState = PLAY_STATE_PLAYING;
         268               0 :     return NS_OK;
         269                 :   }
         270               0 :   if (mPlayState == PLAY_STATE_ENDED)
         271               0 :     return Seek(0);
         272                 :
         273               0 :   ChangeState(PLAY_STATE_PLAYING);
         274               0 :   return NS_OK;
         275                 : }
         276                 :
         277                 : /**
         278                 :  * Returns true if aValue is inside a range of aRanges, and put the range
         279                 :  * index in aIntervalIndex if it is not null.
         280                 :  * If aValue is not inside a range, false is returned, and aIntervalIndex, if
         281                 :  * not null, is set to the index of the range which ends immediately before aValue
         282                 :  * (and can be -1 if aValue is before aRanges.Start(0)).
         283                 :  */
         284               0 : static bool IsInRanges(nsTimeRanges& aRanges, double aValue, PRInt32& aIntervalIndex) {
         285                 :   PRUint32 length;
         286               0 :   aRanges.GetLength(&length);
         287               0 :   for (PRUint32 i = 0; i < length; i++) {
         288                 :     double start, end;
         289               0 :     aRanges.Start(i, &start);
         290               0 :     if (start > aValue) {
         291               0 :       aIntervalIndex = i - 1;
         292               0 :       return false;
         293                 :     }
         294               0 :     aRanges.End(i, &end);
         295               0 :     if (aValue <= end) {
         296               0 :       aIntervalIndex = i;
         297               0 :       return true;
         298                 :     }
         299                 :   }
         300               0 :   aIntervalIndex = length - 1;
         301               0 :   return false;
         302                 : }
         303                 :
         304               0 : nsresult nsBuiltinDecoder::Seek(double aTime)
         305                 : {
         306               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         307               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         308                 :
         309               0 :   NS_ABORT_IF_FALSE(aTime >= 0.0, "Cannot seek to a negative value.");
         310                 :
         311               0 :   nsTimeRanges seekable;
         312                 :   nsresult res;
         313               0 :   PRUint32 length = 0;
         314               0 :   res = GetSeekable(&seekable);
         315               0 :   NS_ENSURE_SUCCESS(res, NS_OK);
         316                 :
         317               0 :   seekable.GetLength(&length);
         318               0 :   if (!length) {
         319               0 :     return NS_OK;
         320                 :   }
         321                 :
         322                 :   // If the position we want to seek to is not in a seekable range, we seek
         323                 :   // to the closest position in the seekable ranges instead. If two positions
         324                 :   // are equally close, we seek to the closest position from the currentTime.
         325                 :   // See seeking spec, point 7 :
         326                 :   // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#seeking
         327               0 :   PRInt32 range = 0;
         328               0 :   if (!IsInRanges(seekable, aTime, range)) {
         329               0 :     if (range != -1) {
         330                 :       // |range + 1| can't be negative, because the only possible negative value
         331                 :       // for |range| is -1.
         332               0 :       if (PRUint32(range + 1) < length) {
         333                 :         double leftBound, rightBound;
         334               0 :         res = seekable.End(range, &leftBound);
         335               0 :         NS_ENSURE_SUCCESS(res, NS_OK);
         336               0 :         res = seekable.Start(range + 1, &rightBound);
         337               0 :         NS_ENSURE_SUCCESS(res, NS_OK);
         338               0 :         double distanceLeft = NS_ABS(leftBound - aTime);
         339               0 :         double distanceRight = NS_ABS(rightBound - aTime);
         340               0 :         if (distanceLeft == distanceRight) {
         341               0 :           distanceLeft = NS_ABS(leftBound - mCurrentTime);
         342               0 :           distanceRight = NS_ABS(rightBound - mCurrentTime);
         343                 :         }
         344               0 :         aTime = (distanceLeft < distanceRight) ? leftBound : rightBound;
         345                 :       } else {
         346                 :         // Seek target is after the end last range in seekable data.
         347                 :         // Clamp the seek target to the end of the last seekable range.
         348               0 :         res = seekable.End(length - 1, &aTime);
         349               0 :         NS_ENSURE_SUCCESS(res, NS_OK);
         350                 :       }
         351                 :     } else {
         352                 :       // aTime is before the first range in |seekable|, the closest point we can
         353                 :       // seek to is the start of the first range.
         354               0 :       seekable.Start(0, &aTime);
         355                 :     }
         356                 :   }
         357                 :
         358               0 :   mRequestedSeekTime = aTime;
         359               0 :   mCurrentTime = aTime;
         360                 :
         361                 :   // If we are already in the seeking state, then setting mRequestedSeekTime
         362                 :   // above will result in the new seek occurring when the current seek
         363                 :   // completes.
         364               0 :   if (mPlayState != PLAY_STATE_SEEKING) {
         365               0 :     bool paused = false;
         366               0 :     if (mElement) {
         367               0 :       mElement->GetPaused(&paused);
         368                 :     }
         369               0 :     mNextState = paused ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING;
         370               0 :     PinForSeek();
         371               0 :     ChangeState(PLAY_STATE_SEEKING);
         372                 :   }
         373                 :
         374               0 :   return ScheduleStateMachineThread();
         375                 : }
         376                 :
         377               0 : nsresult nsBuiltinDecoder::PlaybackRateChanged()
         378                 : {
         379               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         380               0 :   return NS_ERROR_NOT_IMPLEMENTED;
         381                 : }
         382                 :
         383               0 : double nsBuiltinDecoder::GetCurrentTime()
         384                 : {
         385               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         386               0 :   return mCurrentTime;
         387                 : }
         388                 :
         389               0 : already_AddRefed<nsIPrincipal> nsBuiltinDecoder::GetCurrentPrincipal()
         390                 : {
         391               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         392               0 :   return mResource ? mResource->GetCurrentPrincipal() : nsnull;
         393                 : }
         394                 :
         395               0 : void nsBuiltinDecoder::AudioAvailable(float* aFrameBuffer,
         396                 :                                       PRUint32 aFrameBufferLength,
         397                 :                                       float aTime)
         398                 : {
         399                 :   // Auto manage the frame buffer's memory. If we return due to an error
         400                 :   // here, this ensures we free the memory. Otherwise, we pass off ownership
         401                 :   // to HTMLMediaElement::NotifyAudioAvailable().
         402               0 :   nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
         403               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         404               0 :   if (mShuttingDown || !mElement) {
         405                 :     return;
         406                 :   }
         407               0 :   mElement->NotifyAudioAvailable(frameBuffer.forget(), aFrameBufferLength, aTime);
         408                 : }
         409                 :
         410               0 : void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels,
         411                 :                                       PRUint32 aRate)
         412                 : {
         413               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         414               0 :   if (mShuttingDown) {
         415               0 :     return;
         416                 :   }
         417                 :
         418                 :   // Only inform the element of MetadataLoaded if not doing a load() in order
         419                 :   // to fulfill a seek, otherwise we'll get multiple metadataloaded events.
         420               0 :   bool notifyElement = true;
         421                 :   {
         422               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         423               0 :     mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
         424                 :     // Duration has changed so we should recompute playback rate
         425               0 :     UpdatePlaybackRate();
         426                 :
         427               0 :     notifyElement = mNextState != PLAY_STATE_SEEKING;
         428                 :   }
         429                 :
         430               0 :   if (mDuration == -1) {
         431               0 :     SetInfinite(true);
         432                 :   }
         433                 :
         434               0 :   if (mElement && notifyElement) {
         435                 :     // Make sure the element and the frame (if any) are told about
         436                 :     // our new size.
         437               0 :     Invalidate();
         438               0 :     mElement->MetadataLoaded(aChannels, aRate);
         439                 :   }
         440                 :
         441               0 :   if (!mResourceLoaded) {
         442               0 :     StartProgress();
         443               0 :   } else if (mElement) {
         444                 :     // Resource was loaded during metadata loading, when progress
         445                 :     // events are being ignored. Fire the final progress event.
         446               0 :     mElement->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
         447                 :   }
         448                 :
         449                 :   // Only inform the element of FirstFrameLoaded if not doing a load() in order
         450                 :   // to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
         451               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         452               0 :   bool resourceIsLoaded = !mResourceLoaded && mResource &&
         453               0 :     mResource->IsDataCachedToEndOfResource(mDecoderPosition);
         454               0 :   if (mElement && notifyElement) {
         455               0 :     mElement->FirstFrameLoaded(resourceIsLoaded);
         456                 :   }
         457                 :
         458                 :   // This can run cache callbacks.
         459               0 :   mResource->EnsureCacheUpToDate();
         460                 :
         461                 :   // The element can run javascript via events
         462                 :   // before reaching here, so only change the
         463                 :   // state if we're still set to the original
         464                 :   // loading state.
         465               0 :   if (mPlayState == PLAY_STATE_LOADING) {
         466               0 :     if (mRequestedSeekTime >= 0.0) {
         467               0 :       ChangeState(PLAY_STATE_SEEKING);
         468                 :     }
         469                 :     else {
         470               0 :       ChangeState(mNextState);
         471                 :     }
         472                 :   }
         473                 :
         474               0 :   if (resourceIsLoaded) {
         475               0 :     ResourceLoaded();
         476                 :   }
         477                 :
         478                 :   // Run NotifySuspendedStatusChanged now to give us a chance to notice
         479                 :   // that autoplay should run.
         480               0 :   NotifySuspendedStatusChanged();
         481                 : }
         482                 :
         483               0 : void nsBuiltinDecoder::ResourceLoaded()
         484                 : {
         485               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         486                 :
         487                 :   // Don't handle ResourceLoaded if we are shutting down, or if
         488                 :   // we need to ignore progress data due to seeking (in the case
         489                 :   // that the seek results in reaching end of file, we get a bogus call
         490                 :   // to ResourceLoaded).
         491               0 :   if (mShuttingDown)
         492               0 :     return;
         493                 :
         494                 :   {
         495                 :     // If we are seeking or loading then the resource loaded notification we get
         496                 :     // should be ignored, since it represents the end of the seek request.
         497               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         498               0 :     if (mIgnoreProgressData || mResourceLoaded || mPlayState == PLAY_STATE_LOADING)
         499                 :       return;
         500                 :
         501               0 :     Progress(false);
         502                 :
         503               0 :     mResourceLoaded = true;
         504               0 :     StopProgress();
         505                 :   }
         506                 :
         507                 :   // Ensure the final progress event gets fired
         508               0 :   if (mElement) {
         509               0 :     mElement->ResourceLoaded();
         510                 :   }
         511                 : }
         512                 :
         513               0 : void nsBuiltinDecoder::NetworkError()
         514                 : {
         515               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         516               0 :   if (mShuttingDown)
         517               0 :     return;
         518                 :
         519               0 :   if (mElement)
         520               0 :     mElement->NetworkError();
         521                 :
         522               0 :   Shutdown();
         523                 : }
         524                 :
         525               0 : void nsBuiltinDecoder::DecodeError()
         526                 : {
         527               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         528               0 :   if (mShuttingDown)
         529               0 :     return;
         530                 :
         531               0 :   if (mElement)
         532               0 :     mElement->DecodeError();
         533                 :
         534               0 :   Shutdown();
         535                 : }
         536                 :
         537               0 : bool nsBuiltinDecoder::IsSeeking() const
         538                 : {
         539               0 :   return mPlayState == PLAY_STATE_SEEKING || mNextState == PLAY_STATE_SEEKING;
         540                 : }
         541                 :
         542               0 : bool nsBuiltinDecoder::IsEnded() const
         543                 : {
         544               0 :   return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN;
         545                 : }
         546                 :
         547               0 : void nsBuiltinDecoder::PlaybackEnded()
         548                 : {
         549               0 :   if (mShuttingDown || mPlayState == nsBuiltinDecoder::PLAY_STATE_SEEKING)
         550               0 :     return;
         551                 :
         552               0 :   PlaybackPositionChanged();
         553               0 :   ChangeState(PLAY_STATE_ENDED);
         554                 :
         555               0 :   if (mElement)  {
         556               0 :     UpdateReadyStateForData();
         557               0 :     mElement->PlaybackEnded();
         558                 :   }
         559                 :
         560                 :   // This must be called after |mElement->PlaybackEnded()| call above, in order
         561                 :   // to fire the required durationchange.
         562               0 :   if (IsInfinite()) {
         563               0 :     SetInfinite(false);
         564                 :   }
         565                 : }
         566                 :
         567               0 : NS_IMETHODIMP nsBuiltinDecoder::Observe(nsISupports *aSubjet,
         568                 :                                         const char *aTopic,
         569                 :                                         const PRUnichar *someData)
         570                 : {
         571               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         572               0 :   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
         573               0 :     Shutdown();
         574                 :   }
         575                 :
         576               0 :   return NS_OK;
         577                 : }
         578                 :
         579                 : nsMediaDecoder::Statistics
         580               0 : nsBuiltinDecoder::GetStatistics()
         581                 : {
         582               0 :   NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
         583                 :                "Should be on main or state machine thread.");
         584                 :   Statistics result;
         585                 :
         586               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         587               0 :   if (mResource) {
         588                 :     result.mDownloadRate =
         589               0 :       mResource->GetDownloadRate(&result.mDownloadRateReliable);
         590                 :     result.mDownloadPosition =
         591               0 :       mResource->GetCachedDataEnd(mDecoderPosition);
         592               0 :     result.mTotalBytes = mResource->GetLength();
         593               0 :     result.mPlaybackRate = ComputePlaybackRate(&result.mPlaybackRateReliable);
         594               0 :     result.mDecoderPosition = mDecoderPosition;
         595               0 :     result.mPlaybackPosition = mPlaybackPosition;
         596                 :   }
         597                 :   else {
         598               0 :     result.mDownloadRate = 0;
         599               0 :     result.mDownloadRateReliable = true;
         600               0 :     result.mPlaybackRate = 0;
         601               0 :     result.mPlaybackRateReliable = true;
         602               0 :     result.mDecoderPosition = 0;
         603               0 :     result.mPlaybackPosition = 0;
         604               0 :     result.mDownloadPosition = 0;
         605               0 :     result.mTotalBytes = 0;
         606                 :   }
         607                 :
         608                 :   return result;
         609                 : }
         610                 :
         611               0 : double nsBuiltinDecoder::ComputePlaybackRate(bool* aReliable)
         612                 : {
         613               0 :   GetReentrantMonitor().AssertCurrentThreadIn();
         614               0 :   NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
         615                 :                "Should be on main or state machine thread.");
         616                 :
         617               0 :   PRInt64 length = mResource ? mResource->GetLength() : -1;
         618               0 :   if (mDuration >= 0 && length >= 0) {
         619               0 :     *aReliable = true;
         620               0 :     return length * static_cast<double>(USECS_PER_S) / mDuration;
         621                 :   }
         622               0 :   return mPlaybackStatistics.GetRateAtLastStop(aReliable);
         623                 : }
         624                 :
         625               0 : void nsBuiltinDecoder::UpdatePlaybackRate()
         626                 : {
         627               0 :   NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
         628                 :                "Should be on main or state machine thread.");
         629               0 :   GetReentrantMonitor().AssertCurrentThreadIn();
         630               0 :   if (!mResource)
         631               0 :     return;
         632                 :   bool reliable;
         633               0 :   PRUint32 rate = PRUint32(ComputePlaybackRate(&reliable));
         634               0 :   if (reliable) {
         635                 :     // Avoid passing a zero rate
         636               0 :     rate = NS_MAX(rate, 1u);
         637                 :   }
         638                 :   else {
         639                 :     // Set a minimum rate of 10,000 bytes per second ... sometimes we just
         640                 :     // don't have good data
         641               0 :     rate = NS_MAX(rate, 10000u);
         642                 :   }
         643               0 :   mResource->SetPlaybackRate(rate);
         644                 : }
         645                 :
         646               0 : void nsBuiltinDecoder::NotifySuspendedStatusChanged()
         647                 : {
         648               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         649               0 :   if (!mResource)
         650               0 :     return;
         651                 :   MediaResource* activeStream;
         652               0 :   bool suspended = mResource->IsSuspendedByCache(&activeStream);
         653                 :
         654               0 :   if (suspended && mElement) {
         655                 :     // if this is an autoplay element, we need to kick off its autoplaying
         656                 :     // now so we consume data and hopefully free up cache space
         657               0 :     mElement->NotifyAutoplayDataReady();
         658                 :   }
         659                 : }
         660                 :
         661               0 : void nsBuiltinDecoder::NotifyBytesDownloaded()
         662                 : {
         663               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         664               0 :   UpdateReadyStateForData();
         665               0 :   Progress(false);
         666               0 : }
         667                 :
         668               0 : void nsBuiltinDecoder::NotifyDownloadEnded(nsresult aStatus)
         669                 : {
         670               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         671                 :
         672               0 :   if (aStatus == NS_BINDING_ABORTED) {
         673                 :     // Download has been cancelled by user.
         674               0 :     if (mElement) {
         675               0 :       mElement->LoadAborted();
         676                 :     }
         677               0 :     return;
         678                 :   }
         679                 :
         680                 :   {
         681               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         682               0 :     UpdatePlaybackRate();
         683                 :   }
         684                 :
         685               0 :   if (NS_SUCCEEDED(aStatus)) {
         686               0 :     ResourceLoaded();
         687                 :   }
         688               0 :   else if (aStatus != NS_BASE_STREAM_CLOSED) {
         689               0 :     NetworkError();
         690                 :   }
         691               0 :   UpdateReadyStateForData();
         692                 : }
         693                 :
         694               0 : void nsBuiltinDecoder::NotifyBytesConsumed(PRInt64 aBytes)
         695                 : {
         696               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         697               0 :   NS_ASSERTION(OnStateMachineThread() || mDecoderStateMachine->OnDecodeThread(),
         698                 :                "Should be on play state machine or decode thread.");
         699               0 :   if (!mIgnoreProgressData) {
         700               0 :     mDecoderPosition += aBytes;
         701               0 :     mPlaybackStatistics.AddBytes(aBytes);
         702                 :   }
         703               0 : }
         704                 :
         705               0 : void nsBuiltinDecoder::NextFrameUnavailableBuffering()
         706                 : {
         707               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be called on main thread");
         708               0 :   if (!mElement || mShuttingDown || !mDecoderStateMachine)
         709               0 :     return;
         710                 :
         711               0 :   mElement->UpdateReadyStateForData(nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE_BUFFERING);
         712                 : }
         713                 :
         714               0 : void nsBuiltinDecoder::NextFrameAvailable()
         715                 : {
         716               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be called on main thread");
         717               0 :   if (!mElement || mShuttingDown || !mDecoderStateMachine)
         718               0 :     return;
         719                 :
         720               0 :   mElement->UpdateReadyStateForData(nsHTMLMediaElement::NEXT_FRAME_AVAILABLE);
         721                 : }
         722                 :
         723               0 : void nsBuiltinDecoder::NextFrameUnavailable()
         724                 : {
         725               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be called on main thread");
         726               0 :   if (!mElement || mShuttingDown || !mDecoderStateMachine)
         727               0 :     return;
         728               0 :   mElement->UpdateReadyStateForData(nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE);
         729                 : }
         730                 :
         731               0 : void nsBuiltinDecoder::UpdateReadyStateForData()
         732                 : {
         733               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be called on main thread");
         734               0 :   if (!mElement || mShuttingDown || !mDecoderStateMachine)
         735               0 :     return;
         736                 :   nsHTMLMediaElement::NextFrameStatus frameStatus =
         737               0 :     mDecoderStateMachine->GetNextFrameStatus();
         738               0 :   mElement->UpdateReadyStateForData(frameStatus);
         739                 : }
         740                 :
         741               0 : void nsBuiltinDecoder::SeekingStopped()
         742                 : {
         743               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         744                 :
         745               0 :   if (mShuttingDown)
         746               0 :     return;
         747                 :
         748               0 :   bool seekWasAborted = false;
         749                 :   {
         750               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         751                 :
         752                 :     // An additional seek was requested while the current seek was
         753                 :     // in operation.
         754               0 :     if (mRequestedSeekTime >= 0.0) {
         755               0 :       ChangeState(PLAY_STATE_SEEKING);
         756               0 :       seekWasAborted = true;
         757                 :     } else {
         758               0 :       UnpinForSeek();
         759               0 :       ChangeState(mNextState);
         760                 :     }
         761                 :   }
         762                 :
         763               0 :   if (mElement) {
         764               0 :     UpdateReadyStateForData();
         765               0 :     if (!seekWasAborted) {
         766               0 :       mElement->SeekCompleted();
         767                 :     }
         768                 :   }
         769                 : }
         770                 :
         771                 : // This is called when seeking stopped *and* we're at the end of the
         772                 : // media.
         773               0 : void nsBuiltinDecoder::SeekingStoppedAtEnd()
         774                 : {
         775               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         776                 :
         777               0 :   if (mShuttingDown)
         778               0 :     return;
         779                 :
         780               0 :   bool fireEnded = false;
         781               0 :   bool seekWasAborted = false;
         782                 :   {
         783               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         784                 :
         785                 :     // An additional seek was requested while the current seek was
         786                 :     // in operation.
         787               0 :     if (mRequestedSeekTime >= 0.0) {
         788               0 :       ChangeState(PLAY_STATE_SEEKING);
         789               0 :       seekWasAborted = true;
         790                 :     } else {
         791               0 :       UnpinForSeek();
         792               0 :       fireEnded = true;
         793               0 :       ChangeState(PLAY_STATE_ENDED);
         794                 :     }
         795                 :   }
         796                 :
         797               0 :   if (mElement) {
         798               0 :     UpdateReadyStateForData();
         799               0 :     if (!seekWasAborted) {
         800               0 :       mElement->SeekCompleted();
         801               0 :       if (fireEnded) {
         802               0 :         mElement->PlaybackEnded();
         803                 :       }
         804                 :     }
         805                 :   }
         806                 : }
         807                 :
         808               0 : void nsBuiltinDecoder::SeekingStarted()
         809                 : {
         810               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         811               0 :   if (mShuttingDown)
         812               0 :     return;
         813                 :
         814               0 :   if (mElement) {
         815               0 :     UpdateReadyStateForData();
         816               0 :     mElement->SeekStarted();
         817                 :   }
         818                 : }
         819                 :
         820               0 : void nsBuiltinDecoder::ChangeState(PlayState aState)
         821                 : {
         822               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         823               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         824                 :
         825               0 :   if (mNextState == aState) {
         826               0 :     mNextState = PLAY_STATE_PAUSED;
         827                 :   }
         828                 :
         829               0 :   if (mPlayState == PLAY_STATE_SHUTDOWN) {
         830               0 :     mReentrantMonitor.NotifyAll();
         831                 :     return;
         832                 :   }
         833                 :
         834               0 :   mPlayState = aState;
         835               0 :   if (mDecoderStateMachine) {
         836               0 :     switch (aState) {
         837                 :     case PLAY_STATE_PLAYING:
         838               0 :       mDecoderStateMachine->Play();
         839               0 :       break;
         840                 :     case PLAY_STATE_SEEKING:
         841               0 :       mDecoderStateMachine->Seek(mRequestedSeekTime);
         842               0 :       mRequestedSeekTime = -1.0;
         843               0 :       break;
         844                 :     default:
         845                 :       /* No action needed */
         846               0 :       break;
         847                 :     }
         848                 :   }
         849               0 :   mReentrantMonitor.NotifyAll();
         850                 : }
         851                 :
         852               0 : void nsBuiltinDecoder::PlaybackPositionChanged()
         853                 : {
         854               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         855               0 :   if (mShuttingDown)
         856               0 :     return;
         857                 :
         858               0 :   double lastTime = mCurrentTime;
         859                 :
         860                 :   // Control the scope of the monitor so it is not
         861                 :   // held while the timeupdate and the invalidate is run.
         862                 :   {
         863               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         864               0 :     if (mDecoderStateMachine) {
         865               0 :       if (!IsSeeking()) {
         866                 :         // Only update the current playback position if we're not seeking.
         867                 :         // If we are seeking, the update could have been scheduled on the
         868                 :         // state machine thread while we were playing but after the seek
         869                 :         // algorithm set the current playback position on the main thread,
         870                 :         // and we don't want to override the seek algorithm and change the
         871                 :         // current time after the seek has started but before it has
         872                 :         // completed.
         873               0 :         mCurrentTime = mDecoderStateMachine->GetCurrentTime();
         874                 :       }
         875               0 :       mDecoderStateMachine->ClearPositionChangeFlag();
         876                 :     }
         877                 :   }
         878                 :
         879                 :   // Invalidate the frame so any video data is displayed.
         880                 :   // Do this before the timeupdate event so that if that
         881                 :   // event runs JavaScript that queries the media size, the
         882                 :   // frame has reflowed and the size updated beforehand.
         883               0 :   Invalidate();
         884                 :
         885               0 :   if (mElement && lastTime != mCurrentTime) {
         886               0 :     FireTimeUpdate();
         887                 :   }
         888                 : }
         889                 :
         890               0 : void nsBuiltinDecoder::DurationChanged()
         891                 : {
         892               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         893               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         894               0 :   PRInt64 oldDuration = mDuration;
         895               0 :   mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
         896                 :   // Duration has changed so we should recompute playback rate
         897               0 :   UpdatePlaybackRate();
         898                 :
         899               0 :   if (mElement && oldDuration != mDuration && !IsInfinite()) {
         900               0 :     LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration));
         901               0 :     mElement->DispatchEvent(NS_LITERAL_STRING("durationchange"));
         902                 :   }
         903               0 : }
         904                 :
         905               0 : void nsBuiltinDecoder::SetDuration(double aDuration)
         906                 : {
         907               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         908               0 :   mDuration = static_cast<PRInt64>(NS_round(aDuration * static_cast<double>(USECS_PER_S)));
         909                 :
         910               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         911               0 :   if (mDecoderStateMachine) {
         912               0 :     mDecoderStateMachine->SetDuration(mDuration);
         913                 :   }
         914                 :
         915                 :   // Duration has changed so we should recompute playback rate
         916               0 :   UpdatePlaybackRate();
         917               0 : }
         918                 :
         919               0 : void nsBuiltinDecoder::SetSeekable(bool aSeekable)
         920                 : {
         921               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         922               0 :   mSeekable = aSeekable;
         923               0 :   if (mDecoderStateMachine) {
         924               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         925               0 :     mDecoderStateMachine->SetSeekable(aSeekable);
         926                 :   }
         927               0 : }
         928                 :
         929               0 : bool nsBuiltinDecoder::IsSeekable()
         930                 : {
         931               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         932               0 :   return mSeekable;
         933                 : }
         934                 :
         935               0 : nsresult nsBuiltinDecoder::GetSeekable(nsTimeRanges* aSeekable)
         936                 : {
         937                 :   //TODO : change 0.0 to GetInitialTime() when available
         938               0 :   double initialTime = 0.0;
         939                 :
         940               0 :   if (IsSeekable()) {
         941               0 :     double end = IsInfinite() ? std::numeric_limits<double>::infinity()
         942               0 :                               : initialTime + GetDuration();
         943               0 :     aSeekable->Add(initialTime, end);
         944               0 :     return NS_OK;
         945                 :   }
         946                 :
         947               0 :   return GetBuffered(aSeekable);
         948                 : }
         949                 :
         950               0 : void nsBuiltinDecoder::SetEndTime(double aTime)
         951                 : {
         952               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         953               0 :   if (mDecoderStateMachine) {
         954               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         955               0 :     mDecoderStateMachine->SetFragmentEndTime(static_cast<PRInt64>(aTime * USECS_PER_S));
         956                 :   }
         957               0 : }
         958                 :
         959               0 : void nsBuiltinDecoder::Suspend()
         960                 : {
         961               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         962               0 :   if (mResource) {
         963               0 :     mResource->Suspend(true);
         964                 :   }
         965               0 : }
         966                 :
         967               0 : void nsBuiltinDecoder::Resume(bool aForceBuffering)
         968                 : {
         969               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
         970               0 :   if (mResource) {
         971               0 :     mResource->Resume();
         972                 :   }
         973               0 :   if (aForceBuffering) {
         974               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
         975               0 :     if (mDecoderStateMachine) {
         976               0 :       mDecoderStateMachine->StartBuffering();
         977                 :     }
         978                 :   }
         979               0 : }
         980                 :
         981               0 : void nsBuiltinDecoder::StopProgressUpdates()
         982                 : {
         983               0 :   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
         984                 :                "Should be on state machine or decode thread.");
         985               0 :   GetReentrantMonitor().AssertCurrentThreadIn();
         986               0 :   mIgnoreProgressData = true;
         987               0 :   if (mResource) {
         988               0 :     mResource->SetReadMode(nsMediaCacheStream::MODE_METADATA);
         989                 :   }
         990               0 : }
         991                 :
         992               0 : void nsBuiltinDecoder::StartProgressUpdates()
         993                 : {
         994               0 :   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
         995                 :                "Should be on state machine or decode thread.");
         996               0 :   GetReentrantMonitor().AssertCurrentThreadIn();
         997               0 :   mIgnoreProgressData = false;
         998               0 :   if (mResource) {
         999               0 :     mResource->SetReadMode(nsMediaCacheStream::MODE_PLAYBACK);
        1000               0 :     mDecoderPosition = mPlaybackPosition = mResource->Tell();
        1001                 :   }
        1002               0 : }
        1003                 :
        1004               0 : void nsBuiltinDecoder::MoveLoadsToBackground()
        1005                 : {
        1006               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
        1007               0 :   if (mResource) {
        1008               0 :     mResource->MoveLoadsToBackground();
        1009                 :   }
        1010               0 : }
        1011                 :
        1012               0 : void nsBuiltinDecoder::UpdatePlaybackOffset(PRInt64 aOffset)
        1013                 : {
        1014               0 :   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
        1015               0 :   mPlaybackPosition = NS_MAX(aOffset, mPlaybackPosition);
        1016               0 : }
        1017                 :
        1018               0 : bool nsBuiltinDecoder::OnStateMachineThread() const
        1019                 : {
        1020               0 :   return IsCurrentThread(nsBuiltinDecoderStateMachine::GetStateMachineThread());
        1021                 : }
        1022                 :
        1023               0 : void nsBuiltinDecoder::NotifyAudioAvailableListener()
        1024                 : {
        1025               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
        1026               0 :   if (mDecoderStateMachine) {
        1027               0 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
        1028               0 :     mDecoderStateMachine->NotifyAudioAvailableListener();
        1029                 :   }
        1030               0 : }

Generated by: LCOV version 1.7