Attachment #468617: Implements playback statistics on video and media elements for bug #580531

View | Details | Raw Unified | Return to bug 580531
Collapse All | Expand All

(-)a/content/html/content/src/nsHTMLMediaElement.cpp (+20 lines)
Line     Link Here 
 Lines 395-410   NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsHTMLMediaElement) Link Here 
395
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
395
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
396
396
397
// nsIDOMHTMLMediaElement
397
// nsIDOMHTMLMediaElement
398
NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
398
NS_IMPL_URI_ATTR(nsHTMLMediaElement, Src, src)
399
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
399
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Controls, controls)
400
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Autoplay, autoplay)
400
NS_IMPL_BOOL_ATTR(nsHTMLMediaElement, Autoplay, autoplay)
401
NS_IMPL_STRING_ATTR(nsHTMLMediaElement, Preload, preload)
401
NS_IMPL_STRING_ATTR(nsHTMLMediaElement, Preload, preload)
402
402
403
/* readonly attribute float mozDownloadRate; */
404
NS_IMETHODIMP nsHTMLMediaElement::GetMozDownloadRate(float *aMozDownloadRate)
405
{
406
  nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
407
  *aMozDownloadRate = stats.mDownloadRateReliable ? 
408
                        stats.mDownloadRate :
409
                        std::numeric_limits<float>::quiet_NaN();
410
  return NS_OK;
411
}
412
413
/* readonly attribute float mozDecodeRate; */
414
NS_IMETHODIMP nsHTMLMediaElement::GetMozDecodeRate(float *aMozDecodeRate)
415
{
416
  nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
417
  *aMozDecodeRate = stats.mPlaybackRateReliable ? 
418
                      stats.mPlaybackRate :
419
                      std::numeric_limits<float>::quiet_NaN();
420
  return NS_OK;
421
}
422
403
/* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
423
/* readonly attribute nsIDOMHTMLMediaElement mozAutoplayEnabled; */
404
NS_IMETHODIMP nsHTMLMediaElement::GetMozAutoplayEnabled(PRBool *aAutoplayEnabled)
424
NS_IMETHODIMP nsHTMLMediaElement::GetMozAutoplayEnabled(PRBool *aAutoplayEnabled)
405
{
425
{
406
  *aAutoplayEnabled = mAutoplayEnabled;
426
  *aAutoplayEnabled = mAutoplayEnabled;
407
427
408
  return NS_OK;
428
  return NS_OK;
409
}
429
}
410
430
(-)a/content/html/content/src/nsHTMLVideoElement.cpp (+14 lines)
Line     Link Here 
 Lines 95-110   NS_IMETHODIMP nsHTMLVideoElement::GetVideoWidth(PRUint32 *aVideoWidth) Link Here 
95
95
96
/* readonly attribute unsigned long videoHeight; */
96
/* readonly attribute unsigned long videoHeight; */
97
NS_IMETHODIMP nsHTMLVideoElement::GetVideoHeight(PRUint32 *aVideoHeight)
97
NS_IMETHODIMP nsHTMLVideoElement::GetVideoHeight(PRUint32 *aVideoHeight)
98
{
98
{
99
  *aVideoHeight = mMediaSize.height == -1 ? 0 : mMediaSize.height;
99
  *aVideoHeight = mMediaSize.height == -1 ? 0 : mMediaSize.height;
100
  return NS_OK;
100
  return NS_OK;
101
}
101
}
102
102
103
/* readonly attribute unsigned long mozDecodedFrames; */
104
NS_IMETHODIMP nsHTMLVideoElement::GetMozDecodedFrames(PRUint32 *aMozDecodedFrames)
105
{
106
  *aMozDecodedFrames = mDecoder ? mDecoder->GetDecodedFrames() : 0;
107
  return NS_OK;
108
}
109
110
/* readonly attribute unsigned long mozDroppedFrames; */
111
NS_IMETHODIMP nsHTMLVideoElement::GetMozDroppedFrames(PRUint32 *aMozDroppedFrames)
112
{
113
  *aMozDroppedFrames = mDecoder ? mDecoder->GetDroppedFrames() : 0;
114
  return NS_OK;
115
}
116
103
nsHTMLVideoElement::nsHTMLVideoElement(already_AddRefed<nsINodeInfo> aNodeInfo,
117
nsHTMLVideoElement::nsHTMLVideoElement(already_AddRefed<nsINodeInfo> aNodeInfo,
104
                                       PRUint32 aFromParser)
118
                                       PRUint32 aFromParser)
105
  : nsHTMLMediaElement(aNodeInfo, aFromParser)
119
  : nsHTMLMediaElement(aNodeInfo, aFromParser)
106
{
120
{
107
}
121
}
108
122
109
nsHTMLVideoElement::~nsHTMLVideoElement()
123
nsHTMLVideoElement::~nsHTMLVideoElement()
110
{
124
{
(-)a/content/media/nsBuiltinDecoderReader.cpp (-1 / +2 lines)
Line     Link Here 
 Lines 320-336   nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget) Link Here 
320
{
320
{
321
  // Decode forward to the target frame. Start with video, if we have it.
321
  // Decode forward to the target frame. Start with video, if we have it.
322
  if (HasVideo()) {
322
  if (HasVideo()) {
323
    PRBool eof = PR_FALSE;
323
    PRBool eof = PR_FALSE;
324
    PRInt64 startTime = -1;
324
    PRInt64 startTime = -1;
325
    while (HasVideo() && !eof) {
325
    while (HasVideo() && !eof) {
326
      while (mVideoQueue.GetSize() == 0 && !eof) {
326
      while (mVideoQueue.GetSize() == 0 && !eof) {
327
        PRBool skip = PR_FALSE;
327
        PRBool skip = PR_FALSE;
328
        eof = !DecodeVideoFrame(skip, 0);
328
        PRUint32 droppedFrames = 0;
329
        eof = !DecodeVideoFrame(skip, 0, droppedFrames);
329
        {
330
        {
330
          MonitorAutoExit exitReaderMon(mMonitor);
331
          MonitorAutoExit exitReaderMon(mMonitor);
331
          MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
332
          MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
332
          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
333
          if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
333
            return NS_ERROR_FAILURE;
334
            return NS_ERROR_FAILURE;
334
          }
335
          }
335
        }
336
        }
336
      }
337
      }
(-)a/content/media/nsBuiltinDecoderReader.h (-2 / +6 lines)
Line     Link Here 
 Lines 411-428   public: Link Here 
411
  // in mAudioQueue. Returns PR_TRUE when there's more audio to decode,
411
  // in mAudioQueue. Returns PR_TRUE when there's more audio to decode,
412
  // PR_FALSE if the audio is finished, end of file has been reached,
412
  // PR_FALSE if the audio is finished, end of file has been reached,
413
  // or an un-recoverable read error has occured.
413
  // or an un-recoverable read error has occured.
414
  virtual PRBool DecodeAudioData() = 0;
414
  virtual PRBool DecodeAudioData() = 0;
415
415
416
  // Reads and decodes one video frame. Packets with a timestamp less
416
  // Reads and decodes one video frame. Packets with a timestamp less
417
  // than aTimeThreshold will be decoded (unless they're not keyframes
417
  // than aTimeThreshold will be decoded (unless they're not keyframes
418
  // and aKeyframeSkip is PR_TRUE), but will not be added to the queue.
418
  // and aKeyframeSkip is PR_TRUE), but will not be added to the queue.
419
  // 'aDroppedFrames' will be incremented everytime a video frame is
420
  // dropped.
419
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
421
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
420
                                  PRInt64 aTimeThreshold) = 0;
422
                                  PRInt64 aTimeThreshold,
423
                                  PRUint32 &aDroppedFrames) = 0;
421
424
422
  virtual PRBool HasAudio() = 0;
425
  virtual PRBool HasAudio() = 0;
423
  virtual PRBool HasVideo() = 0;
426
  virtual PRBool HasVideo() = 0;
424
427
425
  // Read header data for all bitstreams in the file. Fills mInfo with
428
  // Read header data for all bitstreams in the file. Fills mInfo with
426
  // the data required to present the media. Returns NS_OK on success,
429
  // the data required to present the media. Returns NS_OK on success,
427
  // or NS_ERROR_FAILURE on failure.
430
  // or NS_ERROR_FAILURE on failure.
428
  virtual nsresult ReadMetadata() = 0;
431
  virtual nsresult ReadMetadata() = 0;
 Lines 478-494   protected: Link Here 
478
  template<class Data>
481
  template<class Data>
479
  Data* DecodeToFirstData(DecodeFn aDecodeFn,
482
  Data* DecodeToFirstData(DecodeFn aDecodeFn,
480
                          MediaQueue<Data>& aQueue);
483
                          MediaQueue<Data>& aQueue);
481
484
482
  // Wrapper so that DecodeVideoFrame(PRBool&,PRInt64) can be called from
485
  // Wrapper so that DecodeVideoFrame(PRBool&,PRInt64) can be called from
483
  // DecodeToFirstData().
486
  // DecodeToFirstData().
484
  PRBool DecodeVideoFrame() {
487
  PRBool DecodeVideoFrame() {
485
    PRBool f = PR_FALSE;
488
    PRBool f = PR_FALSE;
486
    return DecodeVideoFrame(f, 0);
489
    PRUint32 droppedFrames = 0;
490
    return DecodeVideoFrame(f, 0, droppedFrames);
487
  }
491
  }
488
492
489
  // Fills aRanges with ByteRanges denoting the sections of the media which
493
  // Fills aRanges with ByteRanges denoting the sections of the media which
490
  // have been downloaded and are stored in the media cache. The reader
494
  // have been downloaded and are stored in the media cache. The reader
491
  // monitor must must be held with exactly one lock count. The nsMediaStream
495
  // monitor must must be held with exactly one lock count. The nsMediaStream
492
  // must be pinned while calling this.
496
  // must be pinned while calling this.
493
  nsresult GetBufferedBytes(nsTArray<ByteRange>& aRanges);
497
  nsresult GetBufferedBytes(nsTArray<ByteRange>& aRanges);
494
498
(-)a/content/media/nsBuiltinDecoderStateMachine.cpp (-1 / +3 lines)
Line     Link Here 
 Lines 249-267   void nsBuiltinDecoderStateMachine::DecodeLoop() Link Here 
249
    if (audioPump && audioDecoded > audioPumpThresholdMs) {
249
    if (audioPump && audioDecoded > audioPumpThresholdMs) {
250
      audioPump = PR_FALSE;
250
      audioPump = PR_FALSE;
251
    }
251
    }
252
    if (!audioPump && audioPlaying && audioDecoded < LOW_AUDIO_MS) {
252
    if (!audioPump && audioPlaying && audioDecoded < LOW_AUDIO_MS) {
253
      skipToNextKeyframe = PR_TRUE;
253
      skipToNextKeyframe = PR_TRUE;
254
    }
254
    }
255
255
256
    if (videoPlaying && !videoWait) {
256
    if (videoPlaying && !videoWait) {
257
      videoPlaying = mReader->DecodeVideoFrame(skipToNextKeyframe, currentTime);
257
      PRUint32 droppedFrames = 0;
258
      videoPlaying = mReader->DecodeVideoFrame(skipToNextKeyframe, currentTime, droppedFrames);
258
      {
259
      {
259
        MonitorAutoEnter mon(mDecoder->GetMonitor());
260
        MonitorAutoEnter mon(mDecoder->GetMonitor());
261
        mDecoder->NotifyDroppedFrames(droppedFrames);
260
        if (mDecoder->mDecoderPosition > initialDownloadPosition) {
262
        if (mDecoder->mDecoderPosition > initialDownloadPosition) {
261
          mBufferExhausted = PR_TRUE;
263
          mBufferExhausted = PR_TRUE;
262
        }
264
        }
263
      }
265
      }
264
    }
266
    }
265
    {
267
    {
266
      MonitorAutoEnter mon(mDecoder->GetMonitor());
268
      MonitorAutoEnter mon(mDecoder->GetMonitor());
267
      initialDownloadPosition =
269
      initialDownloadPosition =
(-)a/content/media/nsMediaDecoder.cpp (+45 lines)
Line     Link Here 
 Lines 72-87   nsMediaDecoder::nsMediaDecoder() : Link Here 
72
  mElement(0),
72
  mElement(0),
73
  mRGBWidth(-1),
73
  mRGBWidth(-1),
74
  mRGBHeight(-1),
74
  mRGBHeight(-1),
75
  mProgressTime(),
75
  mProgressTime(),
76
  mDataTime(),
76
  mDataTime(),
77
  mVideoUpdateLock(nsnull),
77
  mVideoUpdateLock(nsnull),
78
  mPixelAspectRatio(1.0),
78
  mPixelAspectRatio(1.0),
79
  mPinnedForSeek(PR_FALSE),
79
  mPinnedForSeek(PR_FALSE),
80
  mDecodeDecodedFrames(0),
81
  mDecodeDroppedFrames(0),
80
  mSizeChanged(PR_FALSE),
82
  mSizeChanged(PR_FALSE),
81
  mShuttingDown(PR_FALSE)
83
  mShuttingDown(PR_FALSE)
82
{
84
{
83
  MOZ_COUNT_CTOR(nsMediaDecoder);
85
  MOZ_COUNT_CTOR(nsMediaDecoder);
84
}
86
}
85
87
86
nsMediaDecoder::~nsMediaDecoder()
88
nsMediaDecoder::~nsMediaDecoder()
87
{
89
{
 Lines 233-248   void nsMediaDecoder::SetVideoData(const gfxIntSize& aSize, Link Here 
233
      mPixelAspectRatio != aPixelAspectRatio) {
235
      mPixelAspectRatio != aPixelAspectRatio) {
234
    mRGBWidth = aSize.width;
236
    mRGBWidth = aSize.width;
235
    mRGBHeight = aSize.height;
237
    mRGBHeight = aSize.height;
236
    mPixelAspectRatio = aPixelAspectRatio;
238
    mPixelAspectRatio = aPixelAspectRatio;
237
    mSizeChanged = PR_TRUE;
239
    mSizeChanged = PR_TRUE;
238
  }
240
  }
239
  if (mImageContainer && aImage) {
241
  if (mImageContainer && aImage) {
240
    mImageContainer->SetCurrentImage(aImage);
242
    mImageContainer->SetCurrentImage(aImage);
243
    mDecodeDecodedFrames++;
241
  }
244
  }
242
}
245
}
243
246
244
void nsMediaDecoder::PinForSeek()
247
void nsMediaDecoder::PinForSeek()
245
{
248
{
246
  nsMediaStream* stream = GetCurrentStream();
249
  nsMediaStream* stream = GetCurrentStream();
247
  if (!stream || mPinnedForSeek) {
250
  if (!stream || mPinnedForSeek) {
248
    return;
251
    return;
 Lines 274-281   PRBool nsMediaDecoder::CanPlayThrough() Link Here 
274
  }
277
  }
275
  PRInt64 bytesToDownload = stats.mTotalBytes - stats.mDownloadPosition;
278
  PRInt64 bytesToDownload = stats.mTotalBytes - stats.mDownloadPosition;
276
  PRInt64 bytesToPlayback = stats.mTotalBytes - stats.mPlaybackPosition;
279
  PRInt64 bytesToPlayback = stats.mTotalBytes - stats.mPlaybackPosition;
277
  double timeToDownload =
280
  double timeToDownload =
278
    (bytesToDownload + gDownloadSizeSafetyMargin)/stats.mDownloadRate;
281
    (bytesToDownload + gDownloadSizeSafetyMargin)/stats.mDownloadRate;
279
  double timeToPlay = bytesToPlayback/stats.mPlaybackRate;
282
  double timeToPlay = bytesToPlayback/stats.mPlaybackRate;
280
  return timeToDownload <= timeToPlay;
283
  return timeToDownload <= timeToPlay;
281
}
284
}
285
286
PRUint32 nsMediaDecoder::GetDecodedFrames()
287
{
288
  return mDecodeDecodedFrames;
289
}
290
291
PRUint32 nsMediaDecoder::GetDroppedFrames()
292
{
293
  return mDecodeDroppedFrames;
294
}
295
296
void nsMediaDecoder::IncrementDroppedFrames(PRUint32 aDroppedFrames)
297
{
298
  NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
299
300
  mDecodeDroppedFrames += aDroppedFrames;
301
}
302
303
// An event to update the dropped frames count on the main thread
304
class DroppedFrames : public nsRunnable {
305
public:
306
  DroppedFrames(nsMediaDecoder* aDecoder, PRUint32 aDroppedFrames) :
307
    mDecoder(aDecoder), mDroppedFrames(aDroppedFrames) {}
308
  NS_IMETHOD Run() {
309
    mDecoder->IncrementDroppedFrames(mDroppedFrames);
310
    return NS_OK;
311
  }
312
private:
313
  nsRefPtr<nsMediaDecoder> mDecoder;
314
  PRUint32                 mDroppedFrames;
315
};
316
317
void nsMediaDecoder::NotifyDroppedFrames(PRUint32 aDroppedFrames)
318
{
319
  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
320
321
  if (aDroppedFrames > 0) {
322
    nsCOMPtr<nsIRunnable> event = new DroppedFrames(this, aDroppedFrames);
323
    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
324
  }
325
}
326
(-)a/content/media/nsMediaDecoder.h (+24 lines)
Line     Link Here 
 Lines 240-255   public: Link Here 
240
  // Constructs the time ranges representing what segments of the media
240
  // Constructs the time ranges representing what segments of the media
241
  // are buffered and playable.
241
  // are buffered and playable.
242
  virtual nsresult GetBuffered(nsHTMLTimeRanges* aBuffered) = 0;
242
  virtual nsresult GetBuffered(nsHTMLTimeRanges* aBuffered) = 0;
243
243
244
  // Returns PR_TRUE if we can play the entire media through without stopping
244
  // Returns PR_TRUE if we can play the entire media through without stopping
245
  // to buffer, given the current download and playback rates.
245
  // to buffer, given the current download and playback rates.
246
  PRBool CanPlayThrough();
246
  PRBool CanPlayThrough();
247
247
248
  // Return the count of frames that have been decoded
249
  PRUint32 GetDecodedFrames();
250
251
  // Return the count of frames that have been dropped
252
  PRUint32 GetDroppedFrames();
253
254
  // Increment the dropped frame count by the given amount. This must
255
  // only be called on the main thread. use 'NotifyDroppedFrames' to
256
  // increment dropped frames on non-main threads.
257
  void IncrementDroppedFrames(PRUint32 aDroppedFrames);
258
259
  // Raises an event that is dispatched to the main thread to increment
260
  // the number of dropped frames. Do not call on the main thread (use
261
  // IncrementDroppedFrames instead).
262
  void NotifyDroppedFrames(PRUint32 aDroppedFrames);
263
248
protected:
264
protected:
249
265
250
  // Start timer to update download progress information.
266
  // Start timer to update download progress information.
251
  nsresult StartProgress();
267
  nsresult StartProgress();
252
268
253
  // Stop progress information timer.
269
  // Stop progress information timer.
254
  nsresult StopProgress();
270
  nsresult StopProgress();
255
271
 Lines 297-312   protected: Link Here 
297
313
298
  // Pixel aspect ratio (ratio of the pixel width to pixel height)
314
  // Pixel aspect ratio (ratio of the pixel width to pixel height)
299
  float mPixelAspectRatio;
315
  float mPixelAspectRatio;
300
316
301
  // PR_TRUE when our media stream has been pinned. We pin the stream
317
  // PR_TRUE when our media stream has been pinned. We pin the stream
302
  // while seeking.
318
  // while seeking.
303
  PRPackedBool mPinnedForSeek;
319
  PRPackedBool mPinnedForSeek;
304
320
321
  // A count of the number of frames that have been decoded and ready
322
  // to be displayed. This can be used for computing the decoding framerate
323
  PRUint32 mDecodeDecodedFrames;
324
325
  // A count of the number of frames that have been dropped for performance
326
  // reasons during playback.
327
  PRUint32 mDecodeDroppedFrames;
328
305
  // Has our size changed since the last repaint?
329
  // Has our size changed since the last repaint?
306
  PRPackedBool mSizeChanged;
330
  PRPackedBool mSizeChanged;
307
331
308
  // True if the decoder is being shutdown. At this point all events that
332
  // True if the decoder is being shutdown. At this point all events that
309
  // are currently queued need to return immediately to prevent javascript
333
  // are currently queued need to return immediately to prevent javascript
310
  // being run that operates on the element and decoder during shutdown.
334
  // being run that operates on the element and decoder during shutdown.
311
  // Read/Write from the main thread only.
335
  // Read/Write from the main thread only.
312
  PRPackedBool mShuttingDown;
336
  PRPackedBool mShuttingDown;
(-)a/content/media/ogg/nsOggReader.cpp (-2 / +8 lines)
Line     Link Here 
 Lines 565-581   nsresult nsOggReader::DecodeTheora(nsTArray<VideoData*>& aFrames, Link Here 
565
      return NS_ERROR_OUT_OF_MEMORY;
565
      return NS_ERROR_OUT_OF_MEMORY;
566
    }
566
    }
567
    aFrames.AppendElement(v);
567
    aFrames.AppendElement(v);
568
  }
568
  }
569
  return NS_OK;
569
  return NS_OK;
570
}
570
}
571
571
572
PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
572
PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
573
                                     PRInt64 aTimeThreshold)
573
                                     PRInt64 aTimeThreshold,
574
                                     PRUint32 &aDroppedFrames)
574
{
575
{
575
  MonitorAutoEnter mon(mMonitor);
576
  MonitorAutoEnter mon(mMonitor);
576
  NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
577
  NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
577
               "Should be on state machine or AV thread.");
578
               "Should be on state machine or AV thread.");
578
  // We chose to keep track of the Theora granulepos ourselves, rather than
579
  // We chose to keep track of the Theora granulepos ourselves, rather than
579
  // rely on th_decode_packetin() to do it for us. This is because
580
  // rely on th_decode_packetin() to do it for us. This is because
580
  // th_decode_packetin() simply works by incrementing a counter every time
581
  // th_decode_packetin() simply works by incrementing a counter every time
581
  // it's called, so if we drop frames and don't call it, subsequent granulepos
582
  // it's called, so if we drop frames and don't call it, subsequent granulepos
 Lines 723-751   PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip, Link Here 
723
    if (!aKeyframeSkip ||
724
    if (!aKeyframeSkip ||
724
        (th_packet_iskeyframe(&packet) == 1 && time >= aTimeThreshold))
725
        (th_packet_iskeyframe(&packet) == 1 && time >= aTimeThreshold))
725
    {
726
    {
726
      if (DecodeTheora(frames, &packet) == NS_ERROR_OUT_OF_MEMORY) {
727
      if (DecodeTheora(frames, &packet) == NS_ERROR_OUT_OF_MEMORY) {
727
        NS_WARNING("Theora decode memory allocation failure");
728
        NS_WARNING("Theora decode memory allocation failure");
728
        return PR_FALSE;
729
        return PR_FALSE;
729
      }
730
      }
730
    }
731
    }
732
    else {
733
      aDroppedFrames++;
734
    }
731
  }
735
  }
732
736
733
  // Push decoded data into the video frame queue.
737
  // Push decoded data into the video frame queue.
734
  for (PRUint32 i = 0; i < frames.Length(); i++) {
738
  for (PRUint32 i = 0; i < frames.Length(); i++) {
735
    nsAutoPtr<VideoData> data(frames[i]);
739
    nsAutoPtr<VideoData> data(frames[i]);
736
    if (!aKeyframeSkip || (aKeyframeSkip && frames[i]->mKeyframe)) {
740
    if (!aKeyframeSkip || (aKeyframeSkip && frames[i]->mKeyframe)) {
737
      mVideoQueue.Push(data.forget());
741
      mVideoQueue.Push(data.forget());
738
      if (aKeyframeSkip && frames[i]->mKeyframe) {
742
      if (aKeyframeSkip && frames[i]->mKeyframe) {
739
        aKeyframeSkip = PR_FALSE;
743
        aKeyframeSkip = PR_FALSE;
740
      }
744
      }
741
    } else {
745
    } else {
742
      frames[i] = nsnull;
746
      frames[i] = nsnull;
743
      data = nsnull;
747
      data = nsnull;
748
      aDroppedFrames++;
744
    }
749
    }
745
  }
750
  }
746
751
747
  if (endOfStream) {
752
  if (endOfStream) {
748
    // We've encountered an end of bitstream packet. Inform the queue that
753
    // We've encountered an end of bitstream packet. Inform the queue that
749
    // there will be no more frames.
754
    // there will be no more frames.
750
    mVideoQueue.Finish();
755
    mVideoQueue.Finish();
751
  }
756
  }
 Lines 1109-1125   nsresult nsOggReader::SeekInBufferedRange(PRInt64 aTarget, Link Here 
1109
    return res;
1114
    return res;
1110
  }
1115
  }
1111
1116
1112
  // We have an active Theora bitstream. Decode the next Theora frame, and
1117
  // We have an active Theora bitstream. Decode the next Theora frame, and
1113
  // extract its keyframe's time.
1118
  // extract its keyframe's time.
1114
  PRBool eof;
1119
  PRBool eof;
1115
  do {
1120
  do {
1116
    PRBool skip = PR_FALSE;
1121
    PRBool skip = PR_FALSE;
1117
    eof = !DecodeVideoFrame(skip, 0);
1122
    PRUint32 droppedFrames = 0;
1123
    eof = !DecodeVideoFrame(skip, 0, droppedFrames);
1118
    {
1124
    {
1119
      MonitorAutoExit exitReaderMon(mMonitor);
1125
      MonitorAutoExit exitReaderMon(mMonitor);
1120
      MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
1126
      MonitorAutoEnter decoderMon(mDecoder->GetMonitor());
1121
      if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
1127
      if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) {
1122
        return NS_ERROR_FAILURE;
1128
        return NS_ERROR_FAILURE;
1123
      }
1129
      }
1124
    }
1130
    }
1125
  } while (!eof &&
1131
  } while (!eof &&
(-)a/content/media/ogg/nsOggReader.h (-1 / +2 lines)
Line     Link Here 
 Lines 60-76   public: Link Here 
60
  virtual nsresult Init();
60
  virtual nsresult Init();
61
  virtual nsresult ResetDecode();
61
  virtual nsresult ResetDecode();
62
  virtual PRBool DecodeAudioData();
62
  virtual PRBool DecodeAudioData();
63
63
64
  // If the Theora granulepos has not been captured, it may read several packets
64
  // If the Theora granulepos has not been captured, it may read several packets
65
  // until one with a granulepos has been captured, to ensure that all packets
65
  // until one with a granulepos has been captured, to ensure that all packets
66
  // read have valid time info.  
66
  // read have valid time info.  
67
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
67
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
68
                                  PRInt64 aTimeThreshold);
68
                                  PRInt64 aTimeThreshold,
69
                                  PRUint32 &aDroppedFrames);
69
70
70
  virtual VideoData* FindStartTime(PRInt64 aOffset,
71
  virtual VideoData* FindStartTime(PRInt64 aOffset,
71
                                   PRInt64& aOutStartTime);
72
                                   PRInt64& aOutStartTime);
72
73
73
  // Get the end time of aEndOffset. This is the playback position we'd reach
74
  // Get the end time of aEndOffset. This is the playback position we'd reach
74
  // after playback finished at aEndOffset.
75
  // after playback finished at aEndOffset.
75
  virtual PRInt64 FindEndTime(PRInt64 aEndOffset);
76
  virtual PRInt64 FindEndTime(PRInt64 aEndOffset);
76
77
(-)a/content/media/raw/nsRawReader.cpp (-2 / +5 lines)
Line     Link Here 
 Lines 163-179   PRBool nsRawReader::ReadFromStream(nsMediaStream *aStream, PRUint8* aBuf, Link Here 
163
    aLength -= bytesRead;
163
    aLength -= bytesRead;
164
    aBuf += bytesRead;
164
    aBuf += bytesRead;
165
  }
165
  }
166
166
167
  return PR_TRUE;
167
  return PR_TRUE;
168
}
168
}
169
169
170
PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
170
PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
171
                                     PRInt64 aTimeThreshold)
171
                                     PRInt64 aTimeThreshold,
172
                                     PRUint32 &aDroppedFrames)
172
{
173
{
173
  mozilla::MonitorAutoEnter autoEnter(mMonitor);
174
  mozilla::MonitorAutoEnter autoEnter(mMonitor);
174
  NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
175
  NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
175
               "Should be on state machine thread or decode thread.");
176
               "Should be on state machine thread or decode thread.");
176
177
177
  if (!mFrameSize)
178
  if (!mFrameSize)
178
    return PR_FALSE; // Metadata read failed.  We should refuse to play.
179
    return PR_FALSE; // Metadata read failed.  We should refuse to play.
179
180
 Lines 199-214   PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, Link Here 
199
      return PR_FALSE;
200
      return PR_FALSE;
200
    }
201
    }
201
202
202
    if (currentFrameTime >= aTimeThreshold)
203
    if (currentFrameTime >= aTimeThreshold)
203
      break;
204
      break;
204
205
205
    mCurrentFrame++;
206
    mCurrentFrame++;
206
    currentFrameTime += 1000.0 / mFrameRate;
207
    currentFrameTime += 1000.0 / mFrameRate;
208
    aDroppedFrames++;
207
  }
209
  }
208
210
209
  VideoData::YCbCrBuffer b;
211
  VideoData::YCbCrBuffer b;
210
  b.mPlanes[0].mData = buffer;
212
  b.mPlanes[0].mData = buffer;
211
  b.mPlanes[0].mStride = mMetadata.frameWidth * mMetadata.lumaChannelBpp / 8.0;
213
  b.mPlanes[0].mStride = mMetadata.frameWidth * mMetadata.lumaChannelBpp / 8.0;
212
  b.mPlanes[0].mHeight = mMetadata.frameHeight;
214
  b.mPlanes[0].mHeight = mMetadata.frameHeight;
213
  b.mPlanes[0].mWidth = mMetadata.frameWidth;
215
  b.mPlanes[0].mWidth = mMetadata.frameWidth;
214
216
 Lines 264-280   nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, Link Here 
264
266
265
  nsresult rv = stream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
267
  nsresult rv = stream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
266
  NS_ENSURE_SUCCESS(rv, rv);
268
  NS_ENSURE_SUCCESS(rv, rv);
267
269
268
  mVideoQueue.Erase();
270
  mVideoQueue.Erase();
269
271
270
  while(mVideoQueue.GetSize() == 0) {
272
  while(mVideoQueue.GetSize() == 0) {
271
    PRBool keyframeSkip = PR_FALSE;
273
    PRBool keyframeSkip = PR_FALSE;
272
    if (!DecodeVideoFrame(keyframeSkip, 0)) {
274
    PRUint32 droppedFrames = 0;
275
    if (!DecodeVideoFrame(keyframeSkip, 0, droppedFrames)) {
273
      mCurrentFrame = frame;
276
      mCurrentFrame = frame;
274
      return NS_ERROR_FAILURE;
277
      return NS_ERROR_FAILURE;
275
    }
278
    }
276
279
277
    {
280
    {
278
      mozilla::MonitorAutoExit autoMonitorExit(mMonitor);
281
      mozilla::MonitorAutoExit autoMonitorExit(mMonitor);
279
      mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor());
282
      mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor());
280
      if (mDecoder->GetDecodeState() ==
283
      if (mDecoder->GetDecodeState() ==
(-)a/content/media/raw/nsRawReader.h (-1 / +2 lines)
Line     Link Here 
 Lines 93-109   public: Link Here 
93
  nsRawReader(nsBuiltinDecoder* aDecoder);
93
  nsRawReader(nsBuiltinDecoder* aDecoder);
94
  ~nsRawReader();
94
  ~nsRawReader();
95
95
96
  virtual nsresult Init();
96
  virtual nsresult Init();
97
  virtual nsresult ResetDecode();
97
  virtual nsresult ResetDecode();
98
  virtual PRBool DecodeAudioData();
98
  virtual PRBool DecodeAudioData();
99
99
100
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
100
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
101
                                  PRInt64 aTimeThreshold);
101
                                  PRInt64 aTimeThreshold,
102
                                  PRUint32 &aDroppedFrames);
102
103
103
  virtual PRBool HasAudio()
104
  virtual PRBool HasAudio()
104
  {
105
  {
105
    return PR_FALSE;
106
    return PR_FALSE;
106
  }
107
  }
107
108
108
  virtual PRBool HasVideo()
109
  virtual PRBool HasVideo()
109
  {
110
  {
(-)a/content/media/webm/nsWebMReader.cpp (-1 / +4 lines)
Line     Link Here 
 Lines 534-550   PRBool nsWebMReader::DecodeAudioData() Link Here 
534
    mAudioQueue.Finish();
534
    mAudioQueue.Finish();
535
    return PR_FALSE;
535
    return PR_FALSE;
536
  }
536
  }
537
537
538
  return DecodeAudioPacket(packet);
538
  return DecodeAudioPacket(packet);
539
}
539
}
540
540
541
PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
541
PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip,
542
                                      PRInt64 aTimeThreshold)
542
                                      PRInt64 aTimeThreshold,
543
                                      PRUint32 &aDroppedFrames)
543
{
544
{
544
  MonitorAutoEnter mon(mMonitor);
545
  MonitorAutoEnter mon(mMonitor);
545
  NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
546
  NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(),
546
               "Should be on state machine or decode thread.");
547
               "Should be on state machine or decode thread.");
547
  int r = 0;
548
  int r = 0;
548
  nestegg_packet* packet = NextPacket(VIDEO);
549
  nestegg_packet* packet = NextPacket(VIDEO);
549
550
550
  if (!packet) {
551
  if (!packet) {
 Lines 606-637   PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip, Link Here 
606
    }
607
    }
607
608
608
    vpx_codec_stream_info_t si;
609
    vpx_codec_stream_info_t si;
609
    memset(&si, 0, sizeof(si));
610
    memset(&si, 0, sizeof(si));
610
    si.sz = sizeof(si);
611
    si.sz = sizeof(si);
611
    vpx_codec_peek_stream_info(&vpx_codec_vp8_dx_algo, data, length, &si);
612
    vpx_codec_peek_stream_info(&vpx_codec_vp8_dx_algo, data, length, &si);
612
    if ((aKeyframeSkip && !si.is_kf) || (aKeyframeSkip && si.is_kf && tstamp_ms < aTimeThreshold)) {
613
    if ((aKeyframeSkip && !si.is_kf) || (aKeyframeSkip && si.is_kf && tstamp_ms < aTimeThreshold)) {
613
      aKeyframeSkip = PR_TRUE;
614
      aKeyframeSkip = PR_TRUE;
615
      aDroppedFrames++;
614
      break;
616
      break;
615
    }
617
    }
616
618
617
    if (aKeyframeSkip && si.is_kf) {
619
    if (aKeyframeSkip && si.is_kf) {
618
      aKeyframeSkip = PR_FALSE;
620
      aKeyframeSkip = PR_FALSE;
619
    }
621
    }
620
622
621
    if(vpx_codec_decode(&mVP8, data, length, NULL, 0)) {
623
    if(vpx_codec_decode(&mVP8, data, length, NULL, 0)) {
622
      nestegg_free_packet(packet);
624
      nestegg_free_packet(packet);
623
      return PR_FALSE;
625
      return PR_FALSE;
624
    }
626
    }
625
627
626
    // If the timestamp of the video frame is less than
628
    // If the timestamp of the video frame is less than
627
    // the time threshold required then it is not added
629
    // the time threshold required then it is not added
628
    // to the video queue and won't be displayed.
630
    // to the video queue and won't be displayed.
629
    if (tstamp_ms < aTimeThreshold) {
631
    if (tstamp_ms < aTimeThreshold) {
632
      aDroppedFrames++;
630
      continue;
633
      continue;
631
    }
634
    }
632
635
633
    vpx_codec_iter_t  iter = NULL;
636
    vpx_codec_iter_t  iter = NULL;
634
    vpx_image_t      *img;
637
    vpx_image_t      *img;
635
638
636
    while((img = vpx_codec_get_frame(&mVP8, &iter))) {
639
    while((img = vpx_codec_get_frame(&mVP8, &iter))) {
637
      NS_ASSERTION(mInfo.mPicture.width == static_cast<PRInt32>(img->d_w), 
640
      NS_ASSERTION(mInfo.mPicture.width == static_cast<PRInt32>(img->d_w), 
(-)a/content/media/webm/nsWebMReader.h (-1 / +2 lines)
Line     Link Here 
 Lines 104-120   public: Link Here 
104
  virtual nsresult Init();
104
  virtual nsresult Init();
105
  virtual nsresult ResetDecode();
105
  virtual nsresult ResetDecode();
106
  virtual PRBool DecodeAudioData();
106
  virtual PRBool DecodeAudioData();
107
107
108
  // If the Theora granulepos has not been captured, it may read several packets
108
  // If the Theora granulepos has not been captured, it may read several packets
109
  // until one with a granulepos has been captured, to ensure that all packets
109
  // until one with a granulepos has been captured, to ensure that all packets
110
  // read have valid time info.  
110
  // read have valid time info.  
111
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
111
  virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip,
112
                                  PRInt64 aTimeThreshold);
112
                                  PRInt64 aTimeThreshold,
113
                                  PRUint32 &aDroppedFrames);
113
114
114
  virtual PRBool HasAudio()
115
  virtual PRBool HasAudio()
115
  {
116
  {
116
    mozilla::MonitorAutoEnter mon(mMonitor);
117
    mozilla::MonitorAutoEnter mon(mMonitor);
117
    return mHasAudio;
118
    return mHasAudio;
118
  }
119
  }
119
120
120
  virtual PRBool HasVideo()
121
  virtual PRBool HasVideo()
(-)a/dom/interfaces/html/nsIDOMHTMLMediaElement.idl (-1 / +12 lines)
Line     Link Here 
 Lines 52-68    Link Here 
52
52
53
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
53
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
54
%{C++
54
%{C++
55
#ifdef GetCurrentTime
55
#ifdef GetCurrentTime
56
#undef GetCurrentTime
56
#undef GetCurrentTime
57
#endif
57
#endif
58
%}
58
%}
59
59
60
[scriptable, uuid(f748b7db-4ab9-4370-835d-59f30c8de57c)]
60
[scriptable, uuid(92999d57-ab9f-47f2-9567-723f409dc312)]
61
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
61
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
62
{
62
{
63
  // error state
63
  // error state
64
  readonly attribute nsIDOMHTMLMediaError error;
64
  readonly attribute nsIDOMHTMLMediaError error;
65
65
66
  // network state
66
  // network state
67
           attribute DOMString src;
67
           attribute DOMString src;
68
  readonly attribute DOMString currentSrc;
68
  readonly attribute DOMString currentSrc;
 Lines 103-111   interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement Link Here 
103
103
104
  // Mozilla extension: load data from another media element. This is like
104
  // Mozilla extension: load data from another media element. This is like
105
  // load() but we don't run the resource selection algorithm; instead
105
  // load() but we don't run the resource selection algorithm; instead
106
  // we just set our source to other's currentSrc. This is optimized
106
  // we just set our source to other's currentSrc. This is optimized
107
  // so that this element will get access to all of other's cached/
107
  // so that this element will get access to all of other's cached/
108
  // buffered data. In fact any future data downloaded by this element or
108
  // buffered data. In fact any future data downloaded by this element or
109
  // other will be sharable by both elements.
109
  // other will be sharable by both elements.
110
  void mozLoadFrom(in nsIDOMHTMLMediaElement other);
110
  void mozLoadFrom(in nsIDOMHTMLMediaElement other);
111
112
  // The approximate rate at which the media resource is being downloaded in
113
  // bytes per second. If the rate is not available (possibly due
114
  // to not having downloaded enough data to compute a consistent value)
115
  // this will be NaN.
116
  readonly attribute float mozDownloadRate;
117
118
  // The approximate rate at which the media resource is being decoded in
119
  // bytes per second. If the rate is not available this will be
120
  // NaN.
121
  readonly attribute float mozDecodeRate;
111
};
122
};
(-)a/dom/interfaces/html/nsIDOMHTMLVideoElement.idl (-1 / +9 lines)
Line     Link Here 
 Lines 43-60    Link Here 
43
 * <video> element.
43
 * <video> element.
44
 *
44
 *
45
 * For more information on this interface, please see
45
 * For more information on this interface, please see
46
 * http://www.whatwg.org/specs/web-apps/current-work/#video
46
 * http://www.whatwg.org/specs/web-apps/current-work/#video
47
 *
47
 *
48
 * @status UNDER_DEVELOPMENT
48
 * @status UNDER_DEVELOPMENT
49
 */
49
 */
50
50
51
[scriptable, uuid(edf468dc-42eb-4494-920b-56a315172640)]
51
[scriptable, uuid(32234b6b-e0c5-4539-8b17-cf44035b457a)]
52
interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
52
interface nsIDOMHTMLVideoElement : nsIDOMHTMLMediaElement
53
{
53
{
54
           attribute long width; 
54
           attribute long width; 
55
           attribute long height;
55
           attribute long height;
56
  readonly attribute unsigned long videoWidth;
56
  readonly attribute unsigned long videoWidth;
57
  readonly attribute unsigned long videoHeight;
57
  readonly attribute unsigned long videoHeight;
58
           attribute DOMString poster;
58
           attribute DOMString poster;
59
60
  // A count of the number of frames that have been decoded and ready
61
  // to be displayed. This can be used for computing the decoding framerate
62
  readonly attribute unsigned long mozDecodedFrames;
63
64
  // A count of the number of frames that have been dropped for performance
65
  // reasons during playback.
66
  readonly attribute unsigned long mozDroppedFrames;
59
};
67
};
60
68

Return to bug 580531