LCOV - code coverage report
Current view: directory - content/media - nsMediaDecoder.h (source / functions) Found Hit Coverage
Test: app.info Lines: 42 0 0.0 %
Date: 2012-06-02 Functions: 13 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                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : #if !defined(nsMediaDecoder_h_)
      39                 : #define nsMediaDecoder_h_
      40                 : 
      41                 : #include "ImageLayers.h"
      42                 : #include "mozilla/ReentrantMonitor.h"
      43                 : #include "VideoFrameContainer.h"
      44                 : 
      45                 : class nsHTMLMediaElement;
      46                 : class nsIStreamListener;
      47                 : class nsTimeRanges;
      48                 : class nsIMemoryReporter;
      49                 : class nsIPrincipal;
      50                 : class nsITimer;
      51                 : 
      52                 : namespace mozilla {
      53                 : class MediaResource;
      54                 : }
      55                 : 
      56                 : // The size to use for audio data frames in MozAudioAvailable events.
      57                 : // This value is per channel, and is chosen to give ~43 fps of events,
      58                 : // for example, 44100 with 2 channels, 2*1024 = 2048.
      59                 : static const PRUint32 FRAMEBUFFER_LENGTH_PER_CHANNEL = 1024;
      60                 : 
      61                 : // The total size of the framebuffer used for MozAudioAvailable events
      62                 : // has to be within the following range.
      63                 : static const PRUint32 FRAMEBUFFER_LENGTH_MIN = 512;
      64                 : static const PRUint32 FRAMEBUFFER_LENGTH_MAX = 16384;
      65                 : 
      66                 : // All methods of nsMediaDecoder must be called from the main thread only
      67                 : // with the exception of GetVideoFrameContainer and GetStatistics,
      68                 : // which can be called from any thread.
      69                 : class nsMediaDecoder : public nsIObserver
      70                 : {
      71                 : public:
      72                 :   typedef mozilla::MediaResource MediaResource;
      73                 :   typedef mozilla::ReentrantMonitor ReentrantMonitor;
      74                 :   typedef mozilla::TimeStamp TimeStamp;
      75                 :   typedef mozilla::TimeDuration TimeDuration;
      76                 :   typedef mozilla::VideoFrameContainer VideoFrameContainer;
      77                 :   typedef mozilla::layers::Image Image;
      78                 :   typedef mozilla::layers::ImageContainer ImageContainer;
      79                 : 
      80                 :   nsMediaDecoder();
      81                 :   virtual ~nsMediaDecoder();
      82                 : 
      83                 :   // Create a new decoder of the same type as this one.
      84                 :   virtual nsMediaDecoder* Clone() = 0;
      85                 : 
      86                 :   // Perform any initialization required for the decoder.
      87                 :   // Return true on successful initialisation, false
      88                 :   // on failure.
      89                 :   virtual bool Init(nsHTMLMediaElement* aElement);
      90                 : 
      91                 :   // Get the current MediaResource being used. Its URI will be returned
      92                 :   // by currentSrc. Returns what was passed to Load(), if Load() has been called.
      93                 :   virtual MediaResource* GetResource() = 0;
      94                 : 
      95                 :   // Return the principal of the current URI being played or downloaded.
      96                 :   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
      97                 : 
      98                 :   // Return the time position in the video stream being
      99                 :   // played measured in seconds.
     100                 :   virtual double GetCurrentTime() = 0;
     101                 : 
     102                 :   // Seek to the time position in (seconds) from the start of the video.
     103                 :   virtual nsresult Seek(double aTime) = 0;
     104                 : 
     105                 :   // Called by the element when the playback rate has been changed.
     106                 :   // Adjust the speed of the playback, optionally with pitch correction,
     107                 :   // when this is called.
     108                 :   virtual nsresult PlaybackRateChanged() = 0;
     109                 : 
     110                 :   // Return the duration of the video in seconds.
     111                 :   virtual double GetDuration() = 0;
     112                 : 
     113                 :   // A media stream is assumed to be infinite if the metadata doesn't
     114                 :   // contain the duration, and range requests are not supported, and
     115                 :   // no headers give a hint of a possible duration (Content-Length,
     116                 :   // Content-Duration, and variants), and we cannot seek in the media
     117                 :   // stream to determine the duration.
     118                 :   //
     119                 :   // When the media stream ends, we can know the duration, thus the stream is
     120                 :   // no longer considered to be infinite.
     121                 :   virtual void SetInfinite(bool aInfinite) = 0;
     122                 : 
     123                 :   // Return true if the stream is infinite (see SetInfinite).
     124                 :   virtual bool IsInfinite() = 0;
     125                 : 
     126                 :   // Pause video playback.
     127                 :   virtual void Pause() = 0;
     128                 : 
     129                 :   // Set the audio volume. It should be a value from 0 to 1.0.
     130                 :   virtual void SetVolume(double aVolume) = 0;
     131                 : 
     132                 :   // Start playback of a video. 'Load' must have previously been
     133                 :   // called.
     134                 :   virtual nsresult Play() = 0;
     135                 : 
     136                 :   // Start downloading the media. Decode the downloaded data up to the
     137                 :   // point of the first frame of data.
     138                 :   // aResource is the media stream to use. Ownership of aResource passes to
     139                 :   // the decoder, even if Load returns an error.
     140                 :   // This is called at most once per decoder, after Init().
     141                 :   virtual nsresult Load(MediaResource* aResource,
     142                 :                         nsIStreamListener **aListener,
     143                 :                         nsMediaDecoder* aCloneDonor) = 0;
     144                 : 
     145                 :   // Called when the video file has completed downloading.
     146                 :   virtual void ResourceLoaded() = 0;
     147                 : 
     148                 :   // Called if the media file encounters a network error.
     149                 :   virtual void NetworkError() = 0;
     150                 : 
     151                 :   // Call from any thread safely. Return true if we are currently
     152                 :   // seeking in the media resource.
     153                 :   virtual bool IsSeeking() const = 0;
     154                 : 
     155                 :   // Return true if the decoder has reached the end of playback.
     156                 :   // Call in the main thread only.
     157                 :   virtual bool IsEnded() const = 0;
     158                 : 
     159                 :   // Called when a "MozAudioAvailable" event listener is added. This enables
     160                 :   // the decoder to only dispatch "MozAudioAvailable" events when a
     161                 :   // handler exists, reducing overhead. Called on the main thread.
     162                 :   virtual void NotifyAudioAvailableListener() = 0;
     163                 : 
     164                 :   struct Statistics {
     165                 :     // Estimate of the current playback rate (bytes/second).
     166                 :     double mPlaybackRate;
     167                 :     // Estimate of the current download rate (bytes/second). This
     168                 :     // ignores time that the channel was paused by Gecko.
     169                 :     double mDownloadRate;
     170                 :     // Total length of media stream in bytes; -1 if not known
     171                 :     PRInt64 mTotalBytes;
     172                 :     // Current position of the download, in bytes. This is the offset of
     173                 :     // the first uncached byte after the decoder position.
     174                 :     PRInt64 mDownloadPosition;
     175                 :     // Current position of decoding, in bytes (how much of the stream
     176                 :     // has been consumed)
     177                 :     PRInt64 mDecoderPosition;
     178                 :     // Current position of playback, in bytes
     179                 :     PRInt64 mPlaybackPosition;
     180                 :     // If false, then mDownloadRate cannot be considered a reliable
     181                 :     // estimate (probably because the download has only been running
     182                 :     // a short time).
     183                 :     bool mDownloadRateReliable;
     184                 :     // If false, then mPlaybackRate cannot be considered a reliable
     185                 :     // estimate (probably because playback has only been running
     186                 :     // a short time).
     187                 :     bool mPlaybackRateReliable;
     188                 :   };
     189                 : 
     190                 :   // Frame decoding/painting related performance counters.
     191                 :   // Threadsafe.
     192               0 :   class FrameStatistics {
     193                 :   public:
     194                 :     
     195               0 :     FrameStatistics() :
     196                 :         mReentrantMonitor("nsMediaDecoder::FrameStats"),
     197                 :         mParsedFrames(0),
     198                 :         mDecodedFrames(0),
     199               0 :         mPresentedFrames(0) {}
     200                 : 
     201                 :     // Returns number of frames which have been parsed from the media.
     202                 :     // Can be called on any thread.
     203                 :     PRUint32 GetParsedFrames() {
     204                 :       mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     205                 :       return mParsedFrames;
     206                 :     }
     207                 : 
     208                 :     // Returns the number of parsed frames which have been decoded.
     209                 :     // Can be called on any thread.
     210                 :     PRUint32 GetDecodedFrames() {
     211                 :       mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     212                 :       return mDecodedFrames;
     213                 :     }
     214                 : 
     215                 :     // Returns the number of decoded frames which have been sent to the rendering
     216                 :     // pipeline for painting ("presented").
     217                 :     // Can be called on any thread.
     218                 :     PRUint32 GetPresentedFrames() {
     219                 :       mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     220                 :       return mPresentedFrames;
     221                 :     }
     222                 : 
     223                 :     // Increments the parsed and decoded frame counters by the passed in counts.
     224                 :     // Can be called on any thread.
     225                 :     void NotifyDecodedFrames(PRUint32 aParsed, PRUint32 aDecoded) {
     226                 :       if (aParsed == 0 && aDecoded == 0)
     227                 :         return;
     228                 :       mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     229                 :       mParsedFrames += aParsed;
     230                 :       mDecodedFrames += aDecoded;
     231                 :     }
     232                 : 
     233                 :     // Increments the presented frame counters.
     234                 :     // Can be called on any thread.
     235               0 :     void NotifyPresentedFrame() {
     236               0 :       mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     237               0 :       ++mPresentedFrames;
     238               0 :     }
     239                 : 
     240                 :   private:
     241                 : 
     242                 :     // ReentrantMonitor to protect access of playback statistics.
     243                 :     ReentrantMonitor mReentrantMonitor;
     244                 : 
     245                 :     // Number of frames parsed and demuxed from media.
     246                 :     // Access protected by mStatsReentrantMonitor.
     247                 :     PRUint32 mParsedFrames;
     248                 : 
     249                 :     // Number of parsed frames which were actually decoded.
     250                 :     // Access protected by mStatsReentrantMonitor.
     251                 :     PRUint32 mDecodedFrames;
     252                 : 
     253                 :     // Number of decoded frames which were actually sent down the rendering
     254                 :     // pipeline to be painted ("presented"). Access protected by mStatsReentrantMonitor.
     255                 :     PRUint32 mPresentedFrames;
     256                 :   };
     257                 : 
     258                 :   // Stack based class to assist in notifying the frame statistics of
     259                 :   // parsed and decoded frames. Use inside video demux & decode functions
     260                 :   // to ensure all parsed and decoded frames are reported on all return paths.
     261                 :   class AutoNotifyDecoded {
     262                 :   public:
     263                 :     AutoNotifyDecoded(nsMediaDecoder* aDecoder, PRUint32& aParsed, PRUint32& aDecoded)
     264                 :       : mDecoder(aDecoder), mParsed(aParsed), mDecoded(aDecoded) {}
     265                 :     ~AutoNotifyDecoded() {
     266                 :       mDecoder->GetFrameStatistics().NotifyDecodedFrames(mParsed, mDecoded);
     267                 :     }
     268                 :   private:
     269                 :     nsMediaDecoder* mDecoder;
     270                 :     PRUint32& mParsed;
     271                 :     PRUint32& mDecoded;
     272                 :   };
     273                 : 
     274                 :   // Return statistics. This is used for progress events and other things.
     275                 :   // This can be called from any thread. It's only a snapshot of the
     276                 :   // current state, since other threads might be changing the state
     277                 :   // at any time.
     278                 :   virtual Statistics GetStatistics() = 0;
     279                 :   
     280                 :   // Return the frame decode/paint related statistics.
     281               0 :   FrameStatistics& GetFrameStatistics() { return mFrameStats; }
     282                 : 
     283                 :   // Set the duration of the media resource in units of seconds.
     284                 :   // This is called via a channel listener if it can pick up the duration
     285                 :   // from a content header. Must be called from the main thread only.
     286                 :   virtual void SetDuration(double aDuration) = 0;
     287                 : 
     288                 :   // Set a flag indicating whether seeking is supported
     289                 :   virtual void SetSeekable(bool aSeekable) = 0;
     290                 : 
     291                 :   // Return true if seeking is supported.
     292                 :   virtual bool IsSeekable() = 0;
     293                 : 
     294                 :   // Return the time ranges that can be seeked into.
     295                 :   virtual nsresult GetSeekable(nsTimeRanges* aSeekable) = 0;
     296                 : 
     297                 :   // Set the end time of the media resource. When playback reaches
     298                 :   // this point the media pauses. aTime is in seconds.
     299                 :   virtual void SetEndTime(double aTime) = 0;
     300                 : 
     301                 :   // Invalidate the frame.
     302               0 :   void Invalidate()
     303                 :   {
     304               0 :     if (mVideoFrameContainer) {
     305               0 :       mVideoFrameContainer->Invalidate();
     306                 :     }
     307               0 :   }
     308                 : 
     309                 :   // Fire progress events if needed according to the time and byte
     310                 :   // constraints outlined in the specification. aTimer is true
     311                 :   // if the method is called as a result of the progress timer rather
     312                 :   // than the result of downloaded data.
     313                 :   virtual void Progress(bool aTimer);
     314                 : 
     315                 :   // Fire timeupdate events if needed according to the time constraints
     316                 :   // outlined in the specification.
     317                 :   virtual void FireTimeUpdate();
     318                 : 
     319                 :   // Called by MediaResource when the "cache suspended" status changes.
     320                 :   // If MediaResource::IsSuspendedByCache returns true, then the decoder
     321                 :   // should stop buffering or otherwise waiting for download progress and
     322                 :   // start consuming data, if possible, because the cache is full.
     323                 :   virtual void NotifySuspendedStatusChanged() = 0;
     324                 : 
     325                 :   // Called by MediaResource when some data has been received.
     326                 :   // Call on the main thread only.
     327                 :   virtual void NotifyBytesDownloaded() = 0;
     328                 : 
     329                 :   // Called by nsChannelToPipeListener or MediaResource when the
     330                 :   // download has ended. Called on the main thread only. aStatus is
     331                 :   // the result from OnStopRequest.
     332                 :   virtual void NotifyDownloadEnded(nsresult aStatus) = 0;
     333                 : 
     334                 :   // Called as data arrives on the stream and is read into the cache.  Called
     335                 :   // on the main thread only.
     336                 :   virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) = 0;
     337                 : 
     338                 :   // Cleanup internal data structures. Must be called on the main
     339                 :   // thread by the owning object before that object disposes of this object.
     340                 :   virtual void Shutdown();
     341                 : 
     342                 :   // Suspend any media downloads that are in progress. Called by the
     343                 :   // media element when it is sent to the bfcache, or when we need
     344                 :   // to throttle the download. Call on the main thread only. This can
     345                 :   // be called multiple times, there's an internal "suspend count".
     346                 :   virtual void Suspend() = 0;
     347                 : 
     348                 :   // Resume any media downloads that have been suspended. Called by the
     349                 :   // media element when it is restored from the bfcache, or when we need
     350                 :   // to stop throttling the download. Call on the main thread only.
     351                 :   // The download will only actually resume once as many Resume calls
     352                 :   // have been made as Suspend calls. When aForceBuffering is true,
     353                 :   // we force the decoder to go into buffering state before resuming
     354                 :   // playback.
     355                 :   virtual void Resume(bool aForceBuffering) = 0;
     356                 : 
     357                 :   // Returns a weak reference to the media element we're decoding for,
     358                 :   // if it's available.
     359                 :   nsHTMLMediaElement* GetMediaElement();
     360                 : 
     361                 :   // Returns the current size of the framebuffer used in
     362                 :   // MozAudioAvailable events.
     363               0 :   PRUint32 GetFrameBufferLength() { return mFrameBufferLength; };
     364                 : 
     365                 :   // Sets the length of the framebuffer used in MozAudioAvailable events.
     366                 :   // The new size must be between 512 and 16384.
     367                 :   virtual nsresult RequestFrameBufferLength(PRUint32 aLength);
     368                 : 
     369                 :   // Moves any existing channel loads into the background, so that they don't
     370                 :   // block the load event. This is called when we stop delaying the load
     371                 :   // event. Any new loads initiated (for example to seek) will also be in the
     372                 :   // background. Implementations of this must call MoveLoadsToBackground() on
     373                 :   // their MediaResource.
     374                 :   virtual void MoveLoadsToBackground()=0;
     375                 : 
     376                 :   // Constructs the time ranges representing what segments of the media
     377                 :   // are buffered and playable.
     378                 :   virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
     379                 : 
     380                 :   // Returns true if we can play the entire media through without stopping
     381                 :   // to buffer, given the current download and playback rates.
     382                 :   bool CanPlayThrough();
     383                 : 
     384                 :   // Returns the size, in bytes, of the heap memory used by the currently
     385                 :   // queued decoded video and audio data.
     386                 :   virtual PRInt64 VideoQueueMemoryInUse() = 0;
     387                 :   virtual PRInt64 AudioQueueMemoryInUse() = 0;
     388                 : 
     389               0 :   VideoFrameContainer* GetVideoFrameContainer() { return mVideoFrameContainer; }
     390                 :   ImageContainer* GetImageContainer()
     391                 :   {
     392                 :     return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nsnull;
     393                 :   }
     394                 : 
     395                 : protected:
     396                 : 
     397                 :   // Start timer to update download progress information.
     398                 :   nsresult StartProgress();
     399                 : 
     400                 :   // Stop progress information timer.
     401                 :   nsresult StopProgress();
     402                 : 
     403                 :   // Ensures our media stream has been pinned.
     404                 :   void PinForSeek();
     405                 : 
     406                 :   // Ensures our media stream has been unpinned.
     407                 :   void UnpinForSeek();
     408                 : 
     409                 :   // Timer used for updating progress events
     410                 :   nsCOMPtr<nsITimer> mProgressTimer;
     411                 : 
     412                 :   // This should only ever be accessed from the main thread.
     413                 :   // It is set in Init and cleared in Shutdown when the element goes away.
     414                 :   // The decoder does not add a reference the element.
     415                 :   nsHTMLMediaElement* mElement;
     416                 : 
     417                 :   // Counters related to decode and presentation of frames.
     418                 :   FrameStatistics mFrameStats;
     419                 : 
     420                 :   nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
     421                 : 
     422                 :   // Time that the last progress event was fired. Read/Write from the
     423                 :   // main thread only.
     424                 :   TimeStamp mProgressTime;
     425                 : 
     426                 :   // Time that data was last read from the media resource. Used for
     427                 :   // computing if the download has stalled and to rate limit progress events
     428                 :   // when data is arriving slower than PROGRESS_MS. A value of null indicates
     429                 :   // that a stall event has already fired and not to fire another one until
     430                 :   // more data is received. Read/Write from the main thread only.
     431                 :   TimeStamp mDataTime;
     432                 : 
     433                 :   // The framebuffer size to use for audioavailable events.
     434                 :   PRUint32 mFrameBufferLength;
     435                 : 
     436                 :   // True when our media stream has been pinned. We pin the stream
     437                 :   // while seeking.
     438                 :   bool mPinnedForSeek;
     439                 : 
     440                 :   // True if the decoder is being shutdown. At this point all events that
     441                 :   // are currently queued need to return immediately to prevent javascript
     442                 :   // being run that operates on the element and decoder during shutdown.
     443                 :   // Read/Write from the main thread only.
     444                 :   bool mShuttingDown;
     445                 : };
     446                 : 
     447                 : namespace mozilla {
     448                 : class MediaMemoryReporter
     449                 : {
     450                 :   MediaMemoryReporter();
     451                 :   ~MediaMemoryReporter();
     452                 :   static MediaMemoryReporter* sUniqueInstance;
     453                 : 
     454               0 :   static MediaMemoryReporter* UniqueInstance() {
     455               0 :     if (!sUniqueInstance) {
     456               0 :       sUniqueInstance = new MediaMemoryReporter;
     457                 :     }
     458               0 :     return sUniqueInstance;
     459                 :   }
     460                 : 
     461                 :   typedef nsTArray<nsMediaDecoder*> DecodersArray;
     462               0 :   static DecodersArray& Decoders() {
     463               0 :     return UniqueInstance()->mDecoders;
     464                 :   }
     465                 : 
     466                 :   DecodersArray mDecoders;
     467                 : 
     468                 :   nsCOMPtr<nsIMemoryReporter> mMediaDecodedVideoMemory;
     469                 :   nsCOMPtr<nsIMemoryReporter> mMediaDecodedAudioMemory;
     470                 : 
     471                 : public:
     472               0 :   static void AddMediaDecoder(nsMediaDecoder* aDecoder) {
     473               0 :     Decoders().AppendElement(aDecoder);
     474               0 :   }
     475                 : 
     476               0 :   static void RemoveMediaDecoder(nsMediaDecoder* aDecoder) {
     477               0 :     DecodersArray& decoders = Decoders();
     478               0 :     decoders.RemoveElement(aDecoder);
     479               0 :     if (decoders.IsEmpty()) {
     480               0 :       delete sUniqueInstance;
     481               0 :       sUniqueInstance = nsnull;
     482                 :     }
     483               0 :   }
     484                 : 
     485               0 :   static PRInt64 GetDecodedVideoMemory() {
     486               0 :     DecodersArray& decoders = Decoders();
     487               0 :     PRInt64 result = 0;
     488               0 :     for (size_t i = 0; i < decoders.Length(); ++i) {
     489               0 :       result += decoders[i]->VideoQueueMemoryInUse();
     490                 :     }
     491               0 :     return result;
     492                 :   }
     493                 : 
     494               0 :   static PRInt64 GetDecodedAudioMemory() {
     495               0 :     DecodersArray& decoders = Decoders();
     496               0 :     PRInt64 result = 0;
     497               0 :     for (size_t i = 0; i < decoders.Length(); ++i) {
     498               0 :       result += decoders[i]->AudioQueueMemoryInUse();
     499                 :     }
     500               0 :     return result;
     501                 :   }
     502                 : };
     503                 : 
     504                 : } //namespace mozilla
     505                 : #endif

Generated by: LCOV version 1.7