Attachment #472321: Rolled up and rebased patch for bug #584615

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

(-)a/content/html/content/public/nsHTMLMediaElement.h (-4 / +2 lines)
Line     Link Here 
 Lines 180-199   public: Link Here 
180
  // ImageContainer containing the video data.
180
  // ImageContainer containing the video data.
181
  ImageContainer* GetImageContainer();
181
  ImageContainer* GetImageContainer();
182
182
183
  // Called by the video frame to get the print surface, if this is
183
  // Called by the video frame to get the print surface, if this is
184
  // a static document and we're not actually playing video
184
  // a static document and we're not actually playing video
185
  gfxASurface* GetPrintSurface() { return mPrintSurface; }
185
  gfxASurface* GetPrintSurface() { return mPrintSurface; }
186
186
187
  // Dispatch events
187
  // Dispatch events
188
  nsresult DispatchSimpleEvent(const nsAString& aName);
188
  nsresult DispatchEvent(const nsAString& aName);
189
  nsresult DispatchProgressEvent(const nsAString& aName);
189
  nsresult DispatchAsyncEvent(const nsAString& aName);
190
  nsresult DispatchAsyncSimpleEvent(const nsAString& aName);
191
  nsresult DispatchAsyncProgressEvent(const nsAString& aName);
192
  nsresult DispatchAudioAvailableEvent(float* aFrameBuffer,
190
  nsresult DispatchAudioAvailableEvent(float* aFrameBuffer,
193
                                       PRUint32 aFrameBufferLength,
191
                                       PRUint32 aFrameBufferLength,
194
                                       PRUint64 aTime);
192
                                       PRUint64 aTime);
195
193
196
  // Called by the decoder when some data has been downloaded or
194
  // Called by the decoder when some data has been downloaded or
197
  // buffering/seeking has ended. aNextFrameAvailable is true when
195
  // buffering/seeking has ended. aNextFrameAvailable is true when
198
  // the data for the next frame is available. This method will
196
  // the data for the next frame is available. This method will
199
  // decide whether to set the ready state to HAVE_CURRENT_DATA,
197
  // decide whether to set the ready state to HAVE_CURRENT_DATA,
(-)a/content/html/content/src/nsHTMLMediaElement.cpp (-86 / +45 lines)
Line     Link Here 
 Lines 65-81    Link Here 
65
#include "nsIXPConnect.h"
65
#include "nsIXPConnect.h"
66
#include "jsapi.h"
66
#include "jsapi.h"
67
67
68
#include "nsIRenderingContext.h"
68
#include "nsIRenderingContext.h"
69
#include "nsITimer.h"
69
#include "nsITimer.h"
70
70
71
#include "nsEventDispatcher.h"
71
#include "nsEventDispatcher.h"
72
#include "nsIDOMDocumentEvent.h"
72
#include "nsIDOMDocumentEvent.h"
73
#include "nsIDOMProgressEvent.h"
74
#include "nsMediaError.h"
73
#include "nsMediaError.h"
75
#include "nsICategoryManager.h"
74
#include "nsICategoryManager.h"
76
#include "nsCharSeparatedTokenizer.h"
75
#include "nsCharSeparatedTokenizer.h"
77
#include "nsMediaStream.h"
76
#include "nsMediaStream.h"
78
77
79
#include "nsIDOMHTMLVideoElement.h"
78
#include "nsIDOMHTMLVideoElement.h"
80
#include "nsIContentPolicy.h"
79
#include "nsIContentPolicy.h"
81
#include "nsContentPolicyUtils.h"
80
#include "nsContentPolicyUtils.h"
 Lines 187-219   protected: Link Here 
187
  nsRefPtr<nsHTMLMediaElement> mElement;
186
  nsRefPtr<nsHTMLMediaElement> mElement;
188
  PRUint32 mLoadID;
187
  PRUint32 mLoadID;
189
};
188
};
190
189
191
class nsAsyncEventRunner : public nsMediaEvent
190
class nsAsyncEventRunner : public nsMediaEvent
192
{
191
{
193
private:
192
private:
194
  nsString mName;
193
  nsString mName;
195
  PRPackedBool mProgress;
196
194
197
public:
195
public:
198
  nsAsyncEventRunner(const nsAString& aName, nsHTMLMediaElement* aElement, PRBool aProgress) :
196
  nsAsyncEventRunner(const nsAString& aName, nsHTMLMediaElement* aElement) :
199
    nsMediaEvent(aElement), mName(aName), mProgress(aProgress)
197
    nsMediaEvent(aElement), mName(aName)
200
  {
198
  {
201
  }
199
  }
202
200
203
  NS_IMETHOD Run()
201
  NS_IMETHOD Run()
204
  {
202
  {
205
    // Silently cancel if our load has been cancelled.
203
    // Silently cancel if our load has been cancelled.
206
    if (IsCancelled())
204
    if (IsCancelled())
207
      return NS_OK;
205
      return NS_OK;
208
206
209
    return mProgress ?
207
    return mElement->DispatchEvent(mName);
210
      mElement->DispatchProgressEvent(mName) :
211
      mElement->DispatchSimpleEvent(mName);
212
  }
208
  }
213
};
209
};
214
210
215
class nsSourceErrorEventRunner : public nsMediaEvent
211
class nsSourceErrorEventRunner : public nsMediaEvent
216
{
212
{
217
private:
213
private:
218
  nsCOMPtr<nsIContent> mSource;
214
  nsCOMPtr<nsIContent> mSource;
219
public:
215
public:
 Lines 485-501   void nsHTMLMediaElement::AbortExistingLoads() Link Here 
485
    fireTimeUpdate = mDecoder->GetCurrentTime() != 0.0;
481
    fireTimeUpdate = mDecoder->GetCurrentTime() != 0.0;
486
    mDecoder->Shutdown();
482
    mDecoder->Shutdown();
487
    mDecoder = nsnull;
483
    mDecoder = nsnull;
488
  }
484
  }
489
485
490
  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
486
  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
491
      mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE)
487
      mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE)
492
  {
488
  {
493
    DispatchProgressEvent(NS_LITERAL_STRING("abort"));
489
    DispatchEvent(NS_LITERAL_STRING("abort"));
494
  }
490
  }
495
491
496
  mError = nsnull;
492
  mError = nsnull;
497
  mLoadedFirstFrame = PR_FALSE;
493
  mLoadedFirstFrame = PR_FALSE;
498
  mAutoplaying = PR_TRUE;
494
  mAutoplaying = PR_TRUE;
499
  mIsLoadingFromSrcAttribute = PR_FALSE;
495
  mIsLoadingFromSrcAttribute = PR_FALSE;
500
  mSuspendedAfterFirstFrame = PR_FALSE;
496
  mSuspendedAfterFirstFrame = PR_FALSE;
501
  mAllowSuspendAfterFirstFrame = PR_TRUE;
497
  mAllowSuspendAfterFirstFrame = PR_TRUE;
 Lines 508-542   void nsHTMLMediaElement::AbortExistingLoads() Link Here 
508
    ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
504
    ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
509
    mPaused = PR_TRUE;
505
    mPaused = PR_TRUE;
510
506
511
    if (fireTimeUpdate) {
507
    if (fireTimeUpdate) {
512
      // Since we destroyed the decoder above, the current playback position
508
      // Since we destroyed the decoder above, the current playback position
513
      // will now be reported as 0. The playback position was non-zero when
509
      // will now be reported as 0. The playback position was non-zero when
514
      // we destroyed the decoder, so fire a timeupdate event so that the
510
      // we destroyed the decoder, so fire a timeupdate event so that the
515
      // change will be reflected in the controls.
511
      // change will be reflected in the controls.
516
      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("timeupdate"));
512
      DispatchAsyncEvent(NS_LITERAL_STRING("timeupdate"));
517
    }
513
    }
518
    DispatchSimpleEvent(NS_LITERAL_STRING("emptied"));
514
    DispatchEvent(NS_LITERAL_STRING("emptied"));
519
  }
515
  }
520
516
521
  // We may have changed mPaused, mAutoplaying, mNetworkState and other
517
  // We may have changed mPaused, mAutoplaying, mNetworkState and other
522
  // things which can affect AddRemoveSelfReference
518
  // things which can affect AddRemoveSelfReference
523
  AddRemoveSelfReference();
519
  AddRemoveSelfReference();
524
520
525
  mIsRunningSelectResource = PR_FALSE;
521
  mIsRunningSelectResource = PR_FALSE;
526
}
522
}
527
523
528
void nsHTMLMediaElement::NoSupportedMediaSourceError()
524
void nsHTMLMediaElement::NoSupportedMediaSourceError()
529
{
525
{
530
  NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
526
  NS_ASSERTION(mDelayingLoadEvent, "Load event not delayed during source selection?");
531
527
532
  mError = new nsMediaError(nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
528
  mError = new nsMediaError(nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
533
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
529
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE;
534
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
530
  DispatchAsyncEvent(NS_LITERAL_STRING("error"));
535
  // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
531
  // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
536
  ChangeDelayLoadStatus(PR_FALSE);
532
  ChangeDelayLoadStatus(PR_FALSE);
537
}
533
}
538
534
539
typedef void (nsHTMLMediaElement::*SyncSectionFn)();
535
typedef void (nsHTMLMediaElement::*SyncSectionFn)();
540
536
541
// Runs a "synchronous section", a function that must run once the event loop
537
// Runs a "synchronous section", a function that must run once the event loop
542
// has reached a "stable state". See:
538
// has reached a "stable state". See:
 Lines 644-660   void nsHTMLMediaElement::SelectResource() Link Here 
644
    return;
640
    return;
645
  }
641
  }
646
642
647
  ChangeDelayLoadStatus(PR_TRUE);
643
  ChangeDelayLoadStatus(PR_TRUE);
648
644
649
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
645
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
650
  // Load event was delayed, and still is, so no need to call
646
  // Load event was delayed, and still is, so no need to call
651
  // AddRemoveSelfReference, since it must still be held
647
  // AddRemoveSelfReference, since it must still be held
652
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
648
  DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
653
649
654
  nsAutoString src;
650
  nsAutoString src;
655
  nsCOMPtr<nsIURI> uri;
651
  nsCOMPtr<nsIURI> uri;
656
652
657
  // If we have a 'src' attribute, use that exclusively.
653
  // If we have a 'src' attribute, use that exclusively.
658
  if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
654
  if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
659
    nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
655
    nsresult rv = NewURIFromString(src, getter_AddRefs(uri));
660
    if (NS_SUCCEEDED(rv)) {
656
    if (NS_SUCCEEDED(rv)) {
 Lines 796-812   void nsHTMLMediaElement::LoadFromSourceChildren() Link Here 
796
  }
792
  }
797
  NS_NOTREACHED("Execution should not reach here!");
793
  NS_NOTREACHED("Execution should not reach here!");
798
}
794
}
799
795
800
void nsHTMLMediaElement::SuspendLoad(nsIURI* aURI)
796
void nsHTMLMediaElement::SuspendLoad(nsIURI* aURI)
801
{
797
{
802
  mLoadIsSuspended = PR_TRUE;
798
  mLoadIsSuspended = PR_TRUE;
803
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
799
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
804
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("suspend"));
800
  DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
805
  ChangeDelayLoadStatus(PR_FALSE);
801
  ChangeDelayLoadStatus(PR_FALSE);
806
}
802
}
807
803
808
void nsHTMLMediaElement::ResumeLoad(PreloadAction aAction)
804
void nsHTMLMediaElement::ResumeLoad(PreloadAction aAction)
809
{
805
{
810
  NS_ASSERTION(mLoadIsSuspended, "Can only resume preload if halted for one");
806
  NS_ASSERTION(mLoadIsSuspended, "Can only resume preload if halted for one");
811
  nsCOMPtr<nsIURI> uri = mLoadingSrc;
807
  nsCOMPtr<nsIURI> uri = mLoadingSrc;
812
  mLoadIsSuspended = PR_FALSE;
808
  mLoadIsSuspended = PR_FALSE;
 Lines 1032-1048   nsresult nsHTMLMediaElement::LoadWithChannel(nsIChannel *aChannel, Link Here 
1032
  ChangeDelayLoadStatus(PR_TRUE);
1028
  ChangeDelayLoadStatus(PR_TRUE);
1033
1029
1034
  nsresult rv = InitializeDecoderForChannel(aChannel, aListener);
1030
  nsresult rv = InitializeDecoderForChannel(aChannel, aListener);
1035
  if (NS_FAILED(rv)) {
1031
  if (NS_FAILED(rv)) {
1036
    ChangeDelayLoadStatus(PR_FALSE);
1032
    ChangeDelayLoadStatus(PR_FALSE);
1037
    return rv;
1033
    return rv;
1038
  }
1034
  }
1039
1035
1040
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
1036
  DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
1041
1037
1042
  return NS_OK;
1038
  return NS_OK;
1043
}
1039
}
1044
1040
1045
NS_IMETHODIMP nsHTMLMediaElement::MozLoadFrom(nsIDOMHTMLMediaElement* aOther)
1041
NS_IMETHODIMP nsHTMLMediaElement::MozLoadFrom(nsIDOMHTMLMediaElement* aOther)
1046
{
1042
{
1047
  NS_ENSURE_ARG_POINTER(aOther);
1043
  NS_ENSURE_ARG_POINTER(aOther);
1048
1044
 Lines 1056-1072   NS_IMETHODIMP nsHTMLMediaElement::MozLoadFrom(nsIDOMHTMLMediaElement* aOther) Link Here 
1056
  ChangeDelayLoadStatus(PR_TRUE);
1052
  ChangeDelayLoadStatus(PR_TRUE);
1057
1053
1058
  nsresult rv = InitializeDecoderAsClone(other->mDecoder);
1054
  nsresult rv = InitializeDecoderAsClone(other->mDecoder);
1059
  if (NS_FAILED(rv)) {
1055
  if (NS_FAILED(rv)) {
1060
    ChangeDelayLoadStatus(PR_FALSE);
1056
    ChangeDelayLoadStatus(PR_FALSE);
1061
    return rv;
1057
    return rv;
1062
  }
1058
  }
1063
1059
1064
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart"));
1060
  DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
1065
1061
1066
  return NS_OK;
1062
  return NS_OK;
1067
}
1063
}
1068
1064
1069
/* readonly attribute unsigned short readyState; */
1065
/* readonly attribute unsigned short readyState; */
1070
NS_IMETHODIMP nsHTMLMediaElement::GetReadyState(PRUint16 *aReadyState)
1066
NS_IMETHODIMP nsHTMLMediaElement::GetReadyState(PRUint16 *aReadyState)
1071
{
1067
{
1072
  *aReadyState = mReadyState;
1068
  *aReadyState = mReadyState;
 Lines 1156-1173   NS_IMETHODIMP nsHTMLMediaElement::Pause() Link Here 
1156
1152
1157
  PRBool oldPaused = mPaused;
1153
  PRBool oldPaused = mPaused;
1158
  mPaused = PR_TRUE;
1154
  mPaused = PR_TRUE;
1159
  mAutoplaying = PR_FALSE;
1155
  mAutoplaying = PR_FALSE;
1160
  // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
1156
  // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
1161
  AddRemoveSelfReference();
1157
  AddRemoveSelfReference();
1162
1158
1163
  if (!oldPaused) {
1159
  if (!oldPaused) {
1164
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("timeupdate"));
1160
    DispatchAsyncEvent(NS_LITERAL_STRING("timeupdate"));
1165
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("pause"));
1161
    DispatchAsyncEvent(NS_LITERAL_STRING("pause"));
1166
  }
1162
  }
1167
1163
1168
  return NS_OK;
1164
  return NS_OK;
1169
}
1165
}
1170
1166
1171
/* attribute float volume; */
1167
/* attribute float volume; */
1172
NS_IMETHODIMP nsHTMLMediaElement::GetVolume(float *aVolume)
1168
NS_IMETHODIMP nsHTMLMediaElement::GetVolume(float *aVolume)
1173
{
1169
{
 Lines 1187-1203   NS_IMETHODIMP nsHTMLMediaElement::SetVolume(float aVolume) Link Here 
1187
  mVolume = aVolume;
1183
  mVolume = aVolume;
1188
1184
1189
  if (mDecoder && !mMuted) {
1185
  if (mDecoder && !mMuted) {
1190
    mDecoder->SetVolume(mVolume);
1186
    mDecoder->SetVolume(mVolume);
1191
  } else if (mAudioStream && !mMuted) {
1187
  } else if (mAudioStream && !mMuted) {
1192
    mAudioStream->SetVolume(mVolume);
1188
    mAudioStream->SetVolume(mVolume);
1193
  }
1189
  }
1194
1190
1195
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("volumechange"));
1191
  DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
1196
1192
1197
  return NS_OK;
1193
  return NS_OK;
1198
}
1194
}
1199
1195
1200
NS_IMETHODIMP
1196
NS_IMETHODIMP
1201
nsHTMLMediaElement::GetMozChannels(PRUint32 *aMozChannels)
1197
nsHTMLMediaElement::GetMozChannels(PRUint32 *aMozChannels)
1202
{
1198
{
1203
  if (!mDecoder && !mAudioStream) {
1199
  if (!mDecoder && !mAudioStream) {
 Lines 1257-1273   NS_IMETHODIMP nsHTMLMediaElement::SetMuted(PRBool aMuted) Link Here 
1257
  mMuted = aMuted;
1253
  mMuted = aMuted;
1258
1254
1259
  if (mDecoder) {
1255
  if (mDecoder) {
1260
    mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
1256
    mDecoder->SetVolume(mMuted ? 0.0 : mVolume);
1261
  } else if (mAudioStream) {
1257
  } else if (mAudioStream) {
1262
    mAudioStream->SetVolume(mMuted ? 0.0 : mVolume);
1258
    mAudioStream->SetVolume(mMuted ? 0.0 : mVolume);
1263
  }
1259
  }
1264
1260
1265
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("volumechange"));
1261
  DispatchAsyncEvent(NS_LITERAL_STRING("volumechange"));
1266
1262
1267
  return NS_OK;
1263
  return NS_OK;
1268
}
1264
}
1269
1265
1270
nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo,
1266
nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo,
1271
                                       PRUint32 aFromParser)
1267
                                       PRUint32 aFromParser)
1272
  : nsGenericHTMLElement(aNodeInfo),
1268
  : nsGenericHTMLElement(aNodeInfo),
1273
    mCurrentLoadID(0),
1269
    mCurrentLoadID(0),
 Lines 1380-1404   NS_IMETHODIMP nsHTMLMediaElement::Play() Link Here 
1380
      NS_ENSURE_SUCCESS(rv, rv);
1376
      NS_ENSURE_SUCCESS(rv, rv);
1381
    }
1377
    }
1382
  }
1378
  }
1383
1379
1384
  // TODO: If the playback has ended, then the user agent must set
1380
  // TODO: If the playback has ended, then the user agent must set
1385
  // seek to the effective start.
1381
  // seek to the effective start.
1386
  // TODO: The playback rate must be set to the default playback rate.
1382
  // TODO: The playback rate must be set to the default playback rate.
1387
  if (mPaused) {
1383
  if (mPaused) {
1388
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
1384
    DispatchAsyncEvent(NS_LITERAL_STRING("play"));
1389
    switch (mReadyState) {
1385
    switch (mReadyState) {
1390
    case nsIDOMHTMLMediaElement::HAVE_METADATA:
1386
    case nsIDOMHTMLMediaElement::HAVE_METADATA:
1391
    case nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA:
1387
    case nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA:
1392
      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("waiting"));
1388
      DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
1393
      break;
1389
      break;
1394
    case nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA:
1390
    case nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA:
1395
    case nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA:
1391
    case nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA:
1396
      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("playing"));
1392
      DispatchAsyncEvent(NS_LITERAL_STRING("playing"));
1397
      break;
1393
      break;
1398
    }
1394
    }
1399
  }
1395
  }
1400
1396
1401
  mPaused = PR_FALSE;
1397
  mPaused = PR_FALSE;
1402
  mAutoplaying = PR_FALSE;
1398
  mAutoplaying = PR_FALSE;
1403
  // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
1399
  // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
1404
  AddRemoveSelfReference();
1400
  AddRemoveSelfReference();
 Lines 1944-1961   nsresult nsHTMLMediaElement::NewURIFromString(const nsAutoString& aURISpec, nsIU Link Here 
1944
  return NS_OK;
1940
  return NS_OK;
1945
}
1941
}
1946
1942
1947
void nsHTMLMediaElement::MetadataLoaded(PRUint32 aChannels, PRUint32 aRate)
1943
void nsHTMLMediaElement::MetadataLoaded(PRUint32 aChannels, PRUint32 aRate)
1948
{
1944
{
1949
  mChannels = aChannels;
1945
  mChannels = aChannels;
1950
  mRate = aRate;
1946
  mRate = aRate;
1951
  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
1947
  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
1952
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("durationchange"));
1948
  DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
1953
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("loadedmetadata"));
1949
  DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
1954
}
1950
}
1955
1951
1956
void nsHTMLMediaElement::FirstFrameLoaded(PRBool aResourceFullyLoaded)
1952
void nsHTMLMediaElement::FirstFrameLoaded(PRBool aResourceFullyLoaded)
1957
{
1953
{
1958
  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
1954
  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
1959
  ChangeDelayLoadStatus(PR_FALSE);
1955
  ChangeDelayLoadStatus(PR_FALSE);
1960
1956
1961
  NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
1957
  NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
 Lines 1971-1989   void nsHTMLMediaElement::FirstFrameLoaded(PRBool aResourceFullyLoaded) Link Here 
1971
1967
1972
void nsHTMLMediaElement::ResourceLoaded()
1968
void nsHTMLMediaElement::ResourceLoaded()
1973
{
1969
{
1974
  mBegun = PR_FALSE;
1970
  mBegun = PR_FALSE;
1975
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
1971
  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
1976
  AddRemoveSelfReference();
1972
  AddRemoveSelfReference();
1977
  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
1973
  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
1978
  // Ensure a progress event is dispatched at the end of download.
1974
  // Ensure a progress event is dispatched at the end of download.
1979
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("progress"));
1975
  DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
1980
  // The download has stopped.
1976
  // The download has stopped.
1981
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
1977
  DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
1982
}
1978
}
1983
1979
1984
void nsHTMLMediaElement::NetworkError()
1980
void nsHTMLMediaElement::NetworkError()
1985
{
1981
{
1986
  Error(nsIDOMMediaError::MEDIA_ERR_NETWORK);
1982
  Error(nsIDOMMediaError::MEDIA_ERR_NETWORK);
1987
}
1983
}
1988
1984
1989
void nsHTMLMediaElement::DecodeError()
1985
void nsHTMLMediaElement::DecodeError()
 Lines 1999-2069   void nsHTMLMediaElement::LoadAborted() Link Here 
1999
void nsHTMLMediaElement::Error(PRUint16 aErrorCode)
1995
void nsHTMLMediaElement::Error(PRUint16 aErrorCode)
2000
{
1996
{
2001
  NS_ASSERTION(aErrorCode == nsIDOMMediaError::MEDIA_ERR_DECODE ||
1997
  NS_ASSERTION(aErrorCode == nsIDOMMediaError::MEDIA_ERR_DECODE ||
2002
               aErrorCode == nsIDOMMediaError::MEDIA_ERR_NETWORK ||
1998
               aErrorCode == nsIDOMMediaError::MEDIA_ERR_NETWORK ||
2003
               aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED,
1999
               aErrorCode == nsIDOMMediaError::MEDIA_ERR_ABORTED,
2004
               "Only use nsIDOMMediaError codes!");
2000
               "Only use nsIDOMMediaError codes!");
2005
  mError = new nsMediaError(aErrorCode);
2001
  mError = new nsMediaError(aErrorCode);
2006
  mBegun = PR_FALSE;
2002
  mBegun = PR_FALSE;
2007
  DispatchAsyncProgressEvent(NS_LITERAL_STRING("error"));
2003
  DispatchAsyncEvent(NS_LITERAL_STRING("error"));
2008
  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
2004
  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
2009
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
2005
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY;
2010
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("emptied"));
2006
    DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
2011
  } else {
2007
  } else {
2012
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
2008
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
2013
  }
2009
  }
2014
  AddRemoveSelfReference();
2010
  AddRemoveSelfReference();
2015
  ChangeDelayLoadStatus(PR_FALSE);
2011
  ChangeDelayLoadStatus(PR_FALSE);
2016
}
2012
}
2017
2013
2018
void nsHTMLMediaElement::PlaybackEnded()
2014
void nsHTMLMediaElement::PlaybackEnded()
2019
{
2015
{
2020
  NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state");
2016
  NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state");
2021
  // We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
2017
  // We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
2022
  AddRemoveSelfReference();
2018
  AddRemoveSelfReference();
2023
2019
2024
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("ended"));
2020
  DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
2025
}
2021
}
2026
2022
2027
void nsHTMLMediaElement::SeekStarted()
2023
void nsHTMLMediaElement::SeekStarted()
2028
{
2024
{
2029
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeking"));
2025
  DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
2030
}
2026
}
2031
2027
2032
void nsHTMLMediaElement::SeekCompleted()
2028
void nsHTMLMediaElement::SeekCompleted()
2033
{
2029
{
2034
  mPlayingBeforeSeek = PR_FALSE;
2030
  mPlayingBeforeSeek = PR_FALSE;
2035
  SetPlayedOrSeeked(PR_TRUE);
2031
  SetPlayedOrSeeked(PR_TRUE);
2036
  DispatchAsyncSimpleEvent(NS_LITERAL_STRING("seeked"));
2032
  DispatchAsyncEvent(NS_LITERAL_STRING("seeked"));
2037
  // We changed whether we're seeking so we need to AddRemoveSelfReference
2033
  // We changed whether we're seeking so we need to AddRemoveSelfReference
2038
  AddRemoveSelfReference();
2034
  AddRemoveSelfReference();
2039
}
2035
}
2040
2036
2041
void nsHTMLMediaElement::DownloadSuspended()
2037
void nsHTMLMediaElement::DownloadSuspended()
2042
{
2038
{
2043
  if (mBegun) {
2039
  if (mBegun) {
2044
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
2040
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
2045
    AddRemoveSelfReference();
2041
    AddRemoveSelfReference();
2046
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("suspend"));
2042
    DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
2047
  }
2043
  }
2048
}
2044
}
2049
2045
2050
void nsHTMLMediaElement::DownloadResumed()
2046
void nsHTMLMediaElement::DownloadResumed()
2051
{
2047
{
2052
  if (mBegun) {
2048
  if (mBegun) {
2053
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
2049
    mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
2054
    AddRemoveSelfReference();
2050
    AddRemoveSelfReference();
2055
  }
2051
  }
2056
}
2052
}
2057
2053
2058
void nsHTMLMediaElement::DownloadStalled()
2054
void nsHTMLMediaElement::DownloadStalled()
2059
{
2055
{
2060
  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
2056
  if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
2061
    DispatchAsyncProgressEvent(NS_LITERAL_STRING("stalled"));
2057
    DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
2062
  }
2058
  }
2063
}
2059
}
2064
2060
2065
PRBool nsHTMLMediaElement::ShouldCheckAllowOrigin()
2061
PRBool nsHTMLMediaElement::ShouldCheckAllowOrigin()
2066
{
2062
{
2067
  return nsContentUtils::GetBoolPref("media.enforce_same_site_origin",
2063
  return nsContentUtils::GetBoolPref("media.enforce_same_site_origin",
2068
                                     PR_TRUE);
2064
                                     PR_TRUE);
2069
}
2065
}
 Lines 2076-2092   void nsHTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame) Link Here 
2076
    // a chance to run.
2072
    // a chance to run.
2077
    // The arrival of more data can't change us out of this readyState.
2073
    // The arrival of more data can't change us out of this readyState.
2078
    return;
2074
    return;
2079
  }
2075
  }
2080
2076
2081
  if (aNextFrame != NEXT_FRAME_AVAILABLE) {
2077
  if (aNextFrame != NEXT_FRAME_AVAILABLE) {
2082
    ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
2078
    ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
2083
    if (!mWaitingFired && aNextFrame == NEXT_FRAME_UNAVAILABLE_BUFFERING) {
2079
    if (!mWaitingFired && aNextFrame == NEXT_FRAME_UNAVAILABLE_BUFFERING) {
2084
      DispatchAsyncSimpleEvent(NS_LITERAL_STRING("waiting"));
2080
      DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
2085
      mWaitingFired = PR_TRUE;
2081
      mWaitingFired = PR_TRUE;
2086
    }
2082
    }
2087
    return;
2083
    return;
2088
  }
2084
  }
2089
2085
2090
  // Now see if we should set HAVE_ENOUGH_DATA.
2086
  // Now see if we should set HAVE_ENOUGH_DATA.
2091
  // If it's something we don't know the size of, then we can't
2087
  // If it's something we don't know the size of, then we can't
2092
  // make a real estimate, so we go straight to HAVE_ENOUGH_DATA once
2088
  // make a real estimate, so we go straight to HAVE_ENOUGH_DATA once
 Lines 2126-2174   void nsHTMLMediaElement::ChangeReadyState(nsMediaReadyState aState) Link Here 
2126
    return;
2122
    return;
2127
  }
2123
  }
2128
2124
2129
  LOG(PR_LOG_DEBUG, ("%p Ready state changed to %s", this, gReadyStateToString[aState]));
2125
  LOG(PR_LOG_DEBUG, ("%p Ready state changed to %s", this, gReadyStateToString[aState]));
2130
2126
2131
  // Handle raising of "waiting" event during seek (see 4.8.10.9)
2127
  // Handle raising of "waiting" event during seek (see 4.8.10.9)
2132
  if (mPlayingBeforeSeek &&
2128
  if (mPlayingBeforeSeek &&
2133
      oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
2129
      oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
2134
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("waiting"));
2130
    DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
2135
  }
2131
  }
2136
2132
2137
  if (oldState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
2133
  if (oldState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
2138
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
2134
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA &&
2139
      !mLoadedFirstFrame)
2135
      !mLoadedFirstFrame)
2140
  {
2136
  {
2141
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("loadeddata"));
2137
    DispatchAsyncEvent(NS_LITERAL_STRING("loadeddata"));
2142
    mLoadedFirstFrame = PR_TRUE;
2138
    mLoadedFirstFrame = PR_TRUE;
2143
  }
2139
  }
2144
2140
2145
  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
2141
  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA) {
2146
    mWaitingFired = PR_FALSE;
2142
    mWaitingFired = PR_FALSE;
2147
  }
2143
  }
2148
2144
2149
  if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
2145
  if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
2150
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
2146
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA) {
2151
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canplay"));
2147
    DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
2152
  }
2148
  }
2153
2149
2154
  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
2150
  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
2155
    NotifyAutoplayDataReady();
2151
    NotifyAutoplayDataReady();
2156
  }
2152
  }
2157
2153
2158
  if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
2154
  if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
2159
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
2155
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
2160
      IsPotentiallyPlaying()) {
2156
      IsPotentiallyPlaying()) {
2161
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("playing"));
2157
    DispatchAsyncEvent(NS_LITERAL_STRING("playing"));
2162
  }
2158
  }
2163
2159
2164
  if (oldState < nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA &&
2160
  if (oldState < nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA &&
2165
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
2161
      mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
2166
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("canplaythrough"));
2162
    DispatchAsyncEvent(NS_LITERAL_STRING("canplaythrough"));
2167
  }
2163
  }
2168
}
2164
}
2169
2165
2170
PRBool nsHTMLMediaElement::CanActivateAutoplay()
2166
PRBool nsHTMLMediaElement::CanActivateAutoplay()
2171
{
2167
{
2172
  return mAutoplaying &&
2168
  return mAutoplaying &&
2173
         mPaused &&
2169
         mPaused &&
2174
         HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
2170
         HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
 Lines 2181-2197   void nsHTMLMediaElement::NotifyAutoplayDataReady() Link Here 
2181
    mPaused = PR_FALSE;
2177
    mPaused = PR_FALSE;
2182
    // We changed mPaused which can affect AddRemoveSelfReference
2178
    // We changed mPaused which can affect AddRemoveSelfReference
2183
    AddRemoveSelfReference();
2179
    AddRemoveSelfReference();
2184
2180
2185
    if (mDecoder) {
2181
    if (mDecoder) {
2186
      SetPlayedOrSeeked(PR_TRUE);
2182
      SetPlayedOrSeeked(PR_TRUE);
2187
      mDecoder->Play();
2183
      mDecoder->Play();
2188
    }
2184
    }
2189
    DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play"));
2185
    DispatchAsyncEvent(NS_LITERAL_STRING("play"));
2190
  }
2186
  }
2191
}
2187
}
2192
2188
2193
ImageContainer* nsHTMLMediaElement::GetImageContainer()
2189
ImageContainer* nsHTMLMediaElement::GetImageContainer()
2194
{
2190
{
2195
  if (mImageContainer)
2191
  if (mImageContainer)
2196
    return mImageContainer;
2192
    return mImageContainer;
2197
2193
 Lines 2238-2314   nsresult nsHTMLMediaElement::DispatchAudioAvailableEvent(float* aFrameBuffer, Link Here 
2238
                                                    PR_TRUE, PR_TRUE, frameBuffer.forget(), aFrameBufferLength,
2234
                                                    PR_TRUE, PR_TRUE, frameBuffer.forget(), aFrameBufferLength,
2239
                                                    (float)aTime / MS_PER_SECOND, mAllowAudioData);
2235
                                                    (float)aTime / MS_PER_SECOND, mAllowAudioData);
2240
  NS_ENSURE_SUCCESS(rv, rv);
2236
  NS_ENSURE_SUCCESS(rv, rv);
2241
2237
2242
  PRBool dummy;
2238
  PRBool dummy;
2243
  return target->DispatchEvent(event, &dummy);
2239
  return target->DispatchEvent(event, &dummy);
2244
}
2240
}
2245
2241
2246
nsresult nsHTMLMediaElement::DispatchSimpleEvent(const nsAString& aName)
2242
nsresult nsHTMLMediaElement::DispatchEvent(const nsAString& aName)
2247
{
2243
{
2248
  LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching simple event %s", this,
2244
  LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching event %s", this,
2249
                          NS_ConvertUTF16toUTF8(aName).get()));
2245
                          NS_ConvertUTF16toUTF8(aName).get()));
2250
2246
2251
  return nsContentUtils::DispatchTrustedEvent(GetOwnerDoc(),
2247
  return nsContentUtils::DispatchTrustedEvent(GetOwnerDoc(),
2252
                                              static_cast<nsIContent*>(this),
2248
                                              static_cast<nsIContent*>(this),
2253
                                              aName,
2249
                                              aName,
2254
                                              PR_TRUE,
2250
                                              PR_TRUE,
2255
                                              PR_TRUE);
2251
                                              PR_TRUE);
2256
}
2252
}
2257
2253
2258
nsresult nsHTMLMediaElement::DispatchAsyncSimpleEvent(const nsAString& aName)
2254
nsresult nsHTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
2259
{
2255
{
2260
  LOG_EVENT(PR_LOG_DEBUG, ("%p Queuing simple event %s", this, NS_ConvertUTF16toUTF8(aName).get()));
2256
  LOG_EVENT(PR_LOG_DEBUG, ("%p Queuing event %s", this,
2257
            NS_ConvertUTF16toUTF8(aName).get()));
2261
2258
2262
  nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this, PR_FALSE);
2259
  nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this);
2263
  NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
2260
  NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
2264
  return NS_OK;
2261
  return NS_OK;
2265
}
2262
}
2266
2263
2267
nsresult nsHTMLMediaElement::DispatchAsyncProgressEvent(const nsAString& aName)
2268
{
2269
  LOG_EVENT(PR_LOG_DEBUG, ("%p Queuing progress event %s", this, NS_ConvertUTF16toUTF8(aName).get()));
2270
2271
  nsCOMPtr<nsIRunnable> event = new nsAsyncEventRunner(aName, this, PR_TRUE);
2272
  NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
2273
  return NS_OK;
2274
}
2275
2276
nsresult nsHTMLMediaElement::DispatchProgressEvent(const nsAString& aName)
2277
{
2278
  nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(GetOwnerDoc()));
2279
  nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(static_cast<nsIContent*>(this)));
2280
  NS_ENSURE_TRUE(docEvent && target, NS_ERROR_INVALID_ARG);
2281
2282
  nsCOMPtr<nsIDOMEvent> event;
2283
  nsresult rv = docEvent->CreateEvent(NS_LITERAL_STRING("ProgressEvent"), getter_AddRefs(event));
2284
  NS_ENSURE_SUCCESS(rv, rv);
2285
2286
  nsCOMPtr<nsIDOMProgressEvent> progressEvent(do_QueryInterface(event));
2287
  NS_ENSURE_TRUE(progressEvent, NS_ERROR_FAILURE);
2288
2289
  PRInt64 totalBytes = 0;
2290
  PRUint64 downloadPosition = 0;
2291
  if (mDecoder) {
2292
    nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
2293
    totalBytes = stats.mTotalBytes;
2294
    downloadPosition = stats.mDownloadPosition;
2295
  }
2296
  rv = progressEvent->InitProgressEvent(aName, PR_TRUE, PR_TRUE,
2297
    totalBytes >= 0, downloadPosition, totalBytes);
2298
  NS_ENSURE_SUCCESS(rv, rv);
2299
2300
  LOG_EVENT(PR_LOG_DEBUG, ("%p Dispatching progress event %s", this,
2301
                          NS_ConvertUTF16toUTF8(aName).get()));
2302
2303
  PRBool dummy;
2304
  return target->DispatchEvent(event, &dummy);
2305
}
2306
2307
PRBool nsHTMLMediaElement::IsPotentiallyPlaying() const
2264
PRBool nsHTMLMediaElement::IsPotentiallyPlaying() const
2308
{
2265
{
2309
  // TODO:
2266
  // TODO:
2310
  //   playback has not stopped due to errors,
2267
  //   playback has not stopped due to errors,
2311
  //   and the element has not paused for user interaction
2268
  //   and the element has not paused for user interaction
2312
  return
2269
  return
2313
    !mPaused &&
2270
    !mPaused &&
2314
    (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA ||
2271
    (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA ||
 Lines 2568-2579   nsHTMLMediaElement::CopyInnerTo(nsGenericElement* aDest) const Link Here 
2568
  return rv;
2525
  return rv;
2569
}
2526
}
2570
2527
2571
nsresult nsHTMLMediaElement::GetBuffered(nsIDOMTimeRanges** aBuffered)
2528
nsresult nsHTMLMediaElement::GetBuffered(nsIDOMTimeRanges** aBuffered)
2572
{
2529
{
2573
  nsTimeRanges* ranges = new nsTimeRanges();
2530
  nsTimeRanges* ranges = new nsTimeRanges();
2574
  NS_ADDREF(*aBuffered = ranges);
2531
  NS_ADDREF(*aBuffered = ranges);
2575
  if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && mDecoder) {
2532
  if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && mDecoder) {
2576
    return mDecoder->GetBuffered(ranges);
2533
    // If GetBuffered fails we ignore the error result and just return the
2534
    // time ranges we found up till the error.
2535
    mDecoder->GetBuffered(ranges);
2577
  }
2536
  }
2578
  return NS_OK;
2537
  return NS_OK;
2579
}
2538
}
(-)a/content/media/nsBuiltinDecoder.cpp (-3 / +3 lines)
Line     Link Here 
 Lines 354-370   void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels, Link Here 
354
  }
354
  }
355
355
356
  if (!mResourceLoaded) {
356
  if (!mResourceLoaded) {
357
    StartProgress();
357
    StartProgress();
358
  }
358
  }
359
  else if (mElement) {
359
  else if (mElement) {
360
    // Resource was loaded during metadata loading, when progress
360
    // Resource was loaded during metadata loading, when progress
361
    // events are being ignored. Fire the final progress event.
361
    // events are being ignored. Fire the final progress event.
362
    mElement->DispatchAsyncProgressEvent(NS_LITERAL_STRING("progress"));
362
    mElement->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
363
  }
363
  }
364
364
365
  // Only inform the element of FirstFrameLoaded if not doing a load() in order
365
  // Only inform the element of FirstFrameLoaded if not doing a load() in order
366
  // to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
366
  // to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
367
  MonitorAutoEnter mon(mMonitor);
367
  MonitorAutoEnter mon(mMonitor);
368
  PRBool resourceIsLoaded = !mResourceLoaded && mStream &&
368
  PRBool resourceIsLoaded = !mResourceLoaded && mStream &&
369
    mStream->IsDataCachedToEndOfStream(mDecoderPosition);
369
    mStream->IsDataCachedToEndOfStream(mDecoderPosition);
370
  if (mElement && notifyElement) {
370
  if (mElement && notifyElement) {
 Lines 768-799   void nsBuiltinDecoder::PlaybackPositionChanged() Link Here 
768
768
769
  // Invalidate the frame so any video data is displayed.
769
  // Invalidate the frame so any video data is displayed.
770
  // Do this before the timeupdate event so that if that
770
  // Do this before the timeupdate event so that if that
771
  // event runs JavaScript that queries the media size, the
771
  // event runs JavaScript that queries the media size, the
772
  // frame has reflowed and the size updated beforehand.
772
  // frame has reflowed and the size updated beforehand.
773
  Invalidate();
773
  Invalidate();
774
774
775
  if (mElement && lastTime != mCurrentTime) {
775
  if (mElement && lastTime != mCurrentTime) {
776
    mElement->DispatchSimpleEvent(NS_LITERAL_STRING("timeupdate"));
776
    mElement->DispatchEvent(NS_LITERAL_STRING("timeupdate"));
777
  }
777
  }
778
}
778
}
779
779
780
void nsBuiltinDecoder::DurationChanged()
780
void nsBuiltinDecoder::DurationChanged()
781
{
781
{
782
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
782
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
783
  MonitorAutoEnter mon(mMonitor);
783
  MonitorAutoEnter mon(mMonitor);
784
  PRInt64 oldDuration = mDuration;
784
  PRInt64 oldDuration = mDuration;
785
  mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
785
  mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
786
  // Duration has changed so we should recompute playback rate
786
  // Duration has changed so we should recompute playback rate
787
  UpdatePlaybackRate();
787
  UpdatePlaybackRate();
788
788
789
  if (mElement && oldDuration != mDuration) {
789
  if (mElement && oldDuration != mDuration) {
790
    LOG(PR_LOG_DEBUG, ("%p duration changed to %lldms", this, mDuration));
790
    LOG(PR_LOG_DEBUG, ("%p duration changed to %lldms", this, mDuration));
791
    mElement->DispatchSimpleEvent(NS_LITERAL_STRING("durationchange"));
791
    mElement->DispatchEvent(NS_LITERAL_STRING("durationchange"));
792
  }
792
  }
793
}
793
}
794
794
795
void nsBuiltinDecoder::SetDuration(PRInt64 aDuration)
795
void nsBuiltinDecoder::SetDuration(PRInt64 aDuration)
796
{
796
{
797
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
797
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
798
  mDuration = aDuration;
798
  mDuration = aDuration;
799
799
(-)a/content/media/nsMediaDecoder.cpp (-1 / +1 lines)
Line     Link Here 
 Lines 203-219   void nsMediaDecoder::Progress(PRBool aTimer) Link Here 
203
  }
203
  }
204
204
205
  // If PROGRESS_MS has passed since the last progress event fired and more
205
  // If PROGRESS_MS has passed since the last progress event fired and more
206
  // data has arrived since then, fire another progress event.
206
  // data has arrived since then, fire another progress event.
207
  if ((mProgressTime.IsNull() ||
207
  if ((mProgressTime.IsNull() ||
208
       now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
208
       now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
209
      !mDataTime.IsNull() &&
209
      !mDataTime.IsNull() &&
210
      now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
210
      now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
211
    mElement->DispatchAsyncProgressEvent(NS_LITERAL_STRING("progress"));
211
    mElement->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
212
    mProgressTime = now;
212
    mProgressTime = now;
213
  }
213
  }
214
214
215
  if (!mDataTime.IsNull() &&
215
  if (!mDataTime.IsNull() &&
216
      now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
216
      now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
217
    mElement->DownloadStalled();
217
    mElement->DownloadStalled();
218
    // Null it out
218
    // Null it out
219
    mDataTime = TimeStamp();
219
    mDataTime = TimeStamp();
(-)a/content/media/ogg/nsOggReader.cpp (-9 / +25 lines)
Line     Link Here 
 Lines 279-302   nsresult nsOggReader::ReadMetadata() Link Here 
279
      s->Deactivate();
279
      s->Deactivate();
280
    }
280
    }
281
  }
281
  }
282
282
283
  // Initialize the first Theora and Vorbis bitstreams. According to the
283
  // Initialize the first Theora and Vorbis bitstreams. According to the
284
  // Theora spec these can be considered the 'primary' bitstreams for playback.
284
  // Theora spec these can be considered the 'primary' bitstreams for playback.
285
  // Extract the metadata needed from these streams.
285
  // Extract the metadata needed from these streams.
286
  // Set a default callback period for if we have no video data
286
  // Set a default callback period for if we have no video data
287
  if (mTheoraState) {
287
  if (mTheoraState && mTheoraState->Init()) {
288
    if (mTheoraState->Init()) {
288
    gfxIntSize sz(mTheoraState->mInfo.pic_width,
289
      gfxIntSize sz(mTheoraState->mInfo.pic_width,
289
                  mTheoraState->mInfo.pic_height);
290
                    mTheoraState->mInfo.pic_height);
290
    mDecoder->SetVideoData(sz, mTheoraState->mPixelAspectRatio, nsnull);
291
      mDecoder->SetVideoData(sz, mTheoraState->mPixelAspectRatio, nsnull);
292
    } else {
293
      mTheoraState = nsnull;
294
    }
295
  }
291
  }
296
  if (mVorbisState) {
292
  if (mVorbisState) {
297
    mVorbisState->Init();
293
    mVorbisState->Init();
298
  }
294
  }
299
295
300
  if (!HasAudio() && !HasVideo() && mSkeletonState) {
296
  if (!HasAudio() && !HasVideo() && mSkeletonState) {
301
    // We have a skeleton track, but no audio or video, may as well disable
297
    // We have a skeleton track, but no audio or video, may as well disable
302
    // the skeleton, we can't do anything useful with this media.
298
    // the skeleton, we can't do anything useful with this media.
 Lines 905-921   PRInt64 nsOggReader::FindEndTime(PRInt64 aEndOffset, Link Here 
905
  PRBool mustBackOff = PR_FALSE;
901
  PRBool mustBackOff = PR_FALSE;
906
  while (PR_TRUE) {
902
  while (PR_TRUE) {
907
    ogg_page page;    
903
    ogg_page page;    
908
    int ret = ogg_sync_pageseek(aState, &page);
904
    int ret = ogg_sync_pageseek(aState, &page);
909
    if (ret == 0) {
905
    if (ret == 0) {
910
      // We need more data if we've not encountered a page we've seen before,
906
      // We need more data if we've not encountered a page we've seen before,
911
      // or we've read to the end of file.
907
      // or we've read to the end of file.
912
      if (mustBackOff || readHead == aEndOffset) {
908
      if (mustBackOff || readHead == aEndOffset) {
913
        if (endTime != -1) {
909
        if (endTime != -1 || readStartOffset == 0) {
914
          // We have encountered a page before, or we're at the end of file.
910
          // We have encountered a page before, or we're at the end of file.
915
          break;
911
          break;
916
        }
912
        }
917
        mustBackOff = PR_FALSE;
913
        mustBackOff = PR_FALSE;
918
        prevChecksumAfterSeek = checksumAfterSeek;
914
        prevChecksumAfterSeek = checksumAfterSeek;
919
        checksumAfterSeek = 0;
915
        checksumAfterSeek = 0;
920
        ogg_sync_reset(aState);
916
        ogg_sync_reset(aState);
921
        readStartOffset = NS_MAX(static_cast<PRInt64>(0), readStartOffset - step);
917
        readStartOffset = NS_MAX(static_cast<PRInt64>(0), readStartOffset - step);
 Lines 1537-1552   nsresult nsOggReader::SeekBisection(PRInt64 aTarget, Link Here 
1537
  SEEK_LOG(PR_LOG_DEBUG, ("Seek complete in %d bisections.", hops));
1533
  SEEK_LOG(PR_LOG_DEBUG, ("Seek complete in %d bisections.", hops));
1538
1534
1539
  return NS_OK;
1535
  return NS_OK;
1540
}
1536
}
1541
1537
1542
nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
1538
nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
1543
{
1539
{
1544
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
1540
  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
1541
1542
  // HasAudio and HasVideo are not used here as they take a lock and cause
1543
  // a deadlock. Accessing mInfo doesn't require a lock - it doesn't change
1544
  // after metadata is read and GetBuffered isn't called before metadata is
1545
  // read.
1546
  if (!mInfo.mHasVideo && !mInfo.mHasAudio) {
1547
    // No need to search through the file if there are no audio or video tracks
1548
    return NS_OK;
1549
  }
1550
1545
  nsMediaStream* stream = mDecoder->GetCurrentStream();
1551
  nsMediaStream* stream = mDecoder->GetCurrentStream();
1546
1552
1547
  // Traverse across the buffered byte ranges, determining the time ranges
1553
  // Traverse across the buffered byte ranges, determining the time ranges
1548
  // they contain. nsMediaStream::GetNextCachedData(offset) returns -1 when
1554
  // they contain. nsMediaStream::GetNextCachedData(offset) returns -1 when
1549
  // offset is after the end of the media stream, or there's no more cached
1555
  // offset is after the end of the media stream, or there's no more cached
1550
  // data after the offset. This loop will run until we've checked every
1556
  // data after the offset. This loop will run until we've checked every
1551
  // buffered range in the media, in increasing order of offset.
1557
  // buffered range in the media, in increasing order of offset.
1552
  ogg_sync_state state;
1558
  ogg_sync_state state;
 Lines 1599-1614   nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime) Link Here 
1599
1605
1600
      PRUint32 serial = ogg_page_serialno(&page);
1606
      PRUint32 serial = ogg_page_serialno(&page);
1601
      nsOggCodecState* codecState = nsnull;
1607
      nsOggCodecState* codecState = nsnull;
1602
      mCodecStates.Get(serial, &codecState);
1608
      mCodecStates.Get(serial, &codecState);
1603
      if (codecState && codecState->mActive) {
1609
      if (codecState && codecState->mActive) {
1604
        startTime = codecState->Time(granulepos) - aStartTime;
1610
        startTime = codecState->Time(granulepos) - aStartTime;
1605
        NS_ASSERTION(startTime > 0, "Must have positive start time");
1611
        NS_ASSERTION(startTime > 0, "Must have positive start time");
1606
      }
1612
      }
1613
      else if(codecState) {
1614
        // Page is for an inactive stream, skip it.
1615
        startOffset += page.header_len + page.body_len;
1616
        continue;
1617
      }
1618
      else {
1619
        // Page is for a stream we don't know about (possibly a chained
1620
        // ogg), return an error.
1621
        return PAGE_SYNC_ERROR;
1622
      }
1607
    }
1623
    }
1608
1624
1609
    if (startTime != -1) {
1625
    if (startTime != -1) {
1610
      // We were able to find a start time for that range, see if we can
1626
      // We were able to find a start time for that range, see if we can
1611
      // find an end time.
1627
      // find an end time.
1612
      PRInt64 endTime = FindEndTime(endOffset, PR_TRUE, &state);
1628
      PRInt64 endTime = FindEndTime(endOffset, PR_TRUE, &state);
1613
      if (endTime != -1) {
1629
      if (endTime != -1) {
1614
        endTime -= aStartTime;
1630
        endTime -= aStartTime;
(-)a/content/media/test/test_progress.html (-6 lines)
Line     Link Here 
 Lines 12-31    Link Here 
12
<script src="use_large_cache.js"></script>
12
<script src="use_large_cache.js"></script>
13
<script class="testbody" type="text/javascript">
13
<script class="testbody" type="text/javascript">
14
14
15
var manager = new MediaTestManager;
15
var manager = new MediaTestManager;
16
16
17
function do_progress(e) {
17
function do_progress(e) {
18
  var v = e.target;
18
  var v = e.target;
19
  ok(!v._finished, "Check no progress events after completed for " + v._name);
19
  ok(!v._finished, "Check no progress events after completed for " + v._name);
20
  ok(e.lengthComputable, "Check progress lengthComputable for " + v._name);
21
  v._last_progress_total = e.loaded;
22
  ok(e.loaded <= e.total, "Check progress in bounds: " + e.loaded + " for " + v._name);
23
  is(e.total, v._size, "Check progress total for " + v._name);
24
}
20
}
25
21
26
function do_ended(e) {
22
function do_ended(e) {
27
  var v = e.target;
23
  var v = e.target;
28
  ok(!v._finished, "Only one ended event for " + v._name);
24
  ok(!v._finished, "Only one ended event for " + v._name);
29
  v._finished = true;
25
  v._finished = true;
30
  v.parentNode.removeChild(v);
26
  v.parentNode.removeChild(v);
31
  manager.finished(v.token);
27
  manager.finished(v.token);
 Lines 34-52   function do_ended(e) { Link Here 
34
function startTest(test, token) {
30
function startTest(test, token) {
35
  var type = /^video/.test(test.type) ? "video" : "audio";
31
  var type = /^video/.test(test.type) ? "video" : "audio";
36
  var v = document.createElement(type);
32
  var v = document.createElement(type);
37
  v.token = token;
33
  v.token = token;
38
  manager.started(token);
34
  manager.started(token);
39
  v.src = test.name;
35
  v.src = test.name;
40
  v.autoplay = true;
36
  v.autoplay = true;
41
  v._name = test.name;
37
  v._name = test.name;
42
  v._size = test.size;
43
  v._finished = false;
38
  v._finished = false;
44
  v._last_progress_total = 0;
45
  v.addEventListener("ended", do_ended, false);
39
  v.addEventListener("ended", do_ended, false);
46
  v.addEventListener("progress", do_progress, false);
40
  v.addEventListener("progress", do_progress, false);
47
  document.body.appendChild(v);
41
  document.body.appendChild(v);
48
}
42
}
49
43
50
manager.runTests(gProgressTests, startTest);
44
manager.runTests(gProgressTests, startTest);
51
45
52
</script>
46
</script>
(-)a/content/media/wave/nsWaveDecoder.cpp (-1 / +1 lines)
Line     Link Here 
 Lines 1669-1685   nsWaveDecoder::PlaybackPositionChanged() Link Here 
1669
  float lastTime = mCurrentTime;
1669
  float lastTime = mCurrentTime;
1670
1670
1671
  if (mPlaybackStateMachine) {
1671
  if (mPlaybackStateMachine) {
1672
    mCurrentTime = mPlaybackStateMachine->GetTimeForPositionChange();
1672
    mCurrentTime = mPlaybackStateMachine->GetTimeForPositionChange();
1673
  }
1673
  }
1674
1674
1675
  if (mElement && lastTime != mCurrentTime) {
1675
  if (mElement && lastTime != mCurrentTime) {
1676
    UpdateReadyStateForData();
1676
    UpdateReadyStateForData();
1677
    mElement->DispatchSimpleEvent(NS_LITERAL_STRING("timeupdate"));
1677
    mElement->DispatchEvent(NS_LITERAL_STRING("timeupdate"));
1678
  }
1678
  }
1679
}
1679
}
1680
1680
1681
void
1681
void
1682
nsWaveDecoder::SetDuration(PRInt64 /* aDuration */)
1682
nsWaveDecoder::SetDuration(PRInt64 /* aDuration */)
1683
{
1683
{
1684
  // Ignored by the wave decoder since we can compute the
1684
  // Ignored by the wave decoder since we can compute the
1685
  // duration directly from the wave data itself.
1685
  // duration directly from the wave data itself.
(-)a/toolkit/content/widgets/videocontrols.xml (-11 / +59 lines)
Line     Link Here 
 Lines 363-380    Link Here 
363
                    // If the first frame hasn't loaded, kick off a throbber fade-in.
363
                    // If the first frame hasn't loaded, kick off a throbber fade-in.
364
                    if (this.video.readyState >= this.video.HAVE_CURRENT_DATA)
364
                    if (this.video.readyState >= this.video.HAVE_CURRENT_DATA)
365
                        this.firstFrameShown = true;
365
                        this.firstFrameShown = true;
366
366
367
                    // We can't determine the exact buffering status, but do know if it's
367
                    // We can't determine the exact buffering status, but do know if it's
368
                    // fully loaded. (If it's still loading, it will fire a progress event
368
                    // fully loaded. (If it's still loading, it will fire a progress event
369
                    // and we'll figure out the exact state then.)
369
                    // and we'll figure out the exact state then.)
370
                    this.bufferBar.setAttribute("max", 100);
370
                    this.bufferBar.setAttribute("max", 100);
371
                    if (this.video.networkState == this.video.NETWORK_LOADED)
371
                    if (this.video.readyState >= this.video.HAVE_METADATA)
372
                        this.bufferBar.setAttribute("value", 100);
372
                        this.showBuffered();
373
                    else
373
                    else
374
                        this.bufferBar.setAttribute("value", 0);
374
                        this.bufferBar.setAttribute("value", 0);
375
375
376
                    // Set the current status icon.
376
                    // Set the current status icon.
377
                    if (this.video.error) {
377
                    if (this.video.error) {
378
                        this.statusIcon.setAttribute("type", "error");
378
                        this.statusIcon.setAttribute("type", "error");
379
                        this.setupStatusFader(true);
379
                        this.setupStatusFader(true);
380
                    } else {
380
                    } else {
 Lines 453-477    Link Here 
453
                            this.isAudioOnly = (this.video instanceof HTMLAudioElement);
453
                            this.isAudioOnly = (this.video instanceof HTMLAudioElement);
454
                            this.setPlayButtonState(true);
454
                            this.setPlayButtonState(true);
455
                            break;
455
                            break;
456
                        case "durationchange":
456
                        case "durationchange":
457
                            var duration = Math.round(this.video.duration * 1000); // in ms
457
                            var duration = Math.round(this.video.duration * 1000); // in ms
458
                            this.durationChange(duration);
458
                            this.durationChange(duration);
459
                            break;
459
                            break;
460
                        case "progress":
460
                        case "progress":
461
                            var loaded = aEvent.loaded;
461
                            this.showBuffered();
462
                            var total = aEvent.total;
463
                            this.log("+++ load, " + loaded + " of " + total);
464
                            // When the source is streaming, the value of .total is -1. Set the
465
                            // progress bar to the maximum, since it's not useful.
466
                            if (total == -1)
467
                                total = loaded;
468
                            this.bufferBar.max = total;
469
                            this.bufferBar.value = loaded;
470
                            this.setupStatusFader();
462
                            this.setupStatusFader();
471
                            break;
463
                            break;
472
                        case "suspend":
464
                        case "suspend":
473
                            this.setupStatusFader();
465
                            this.setupStatusFader();
474
                            break;
466
                            break;
475
                        case "timeupdate":
467
                        case "timeupdate":
476
                            var currentTime = Math.round(this.video.currentTime * 1000); // in ms
468
                            var currentTime = Math.round(this.video.currentTime * 1000); // in ms
477
                            var duration = Math.round(this.video.duration * 1000); // in ms
469
                            var duration = Math.round(this.video.duration * 1000); // in ms
 Lines 503-523    Link Here 
503
                                return;
495
                                return;
504
                            this.lastTimeUpdate = currentTime;
496
                            this.lastTimeUpdate = currentTime;
505
                            this.showPosition(currentTime, duration);
497
                            this.showPosition(currentTime, duration);
506
                            break;
498
                            break;
507
                        case "emptied":
499
                        case "emptied":
508
                            this.bufferBar.value = 0;
500
                            this.bufferBar.value = 0;
509
                            break;
501
                            break;
510
                        case "seeking":
502
                        case "seeking":
503
                            this.showBuffered();
504
                            this.statusIcon.setAttribute("type", "throbber");
505
                            this.setupStatusFader();
506
                            break;
511
                        case "waiting":
507
                        case "waiting":
512
                            this.statusIcon.setAttribute("type", "throbber");
508
                            this.statusIcon.setAttribute("type", "throbber");
513
                            this.setupStatusFader();
509
                            this.setupStatusFader();
514
                            break;
510
                            break;
515
                        case "seeked":
511
                        case "seeked":
512
			    // XXX: This call to showBuffered() can be removed
513
			    // when bug 588312 is fixed.
514
                            this.showBuffered();
515
                            this.setupStatusFader();
516
                            break;
516
                        case "playing":
517
                        case "playing":
517
                        case "canplay":
518
                        case "canplay":
518
                        case "canplaythrough":
519
                        case "canplaythrough":
519
                            this.setupStatusFader();
520
                            this.setupStatusFader();
520
                            break;
521
                            break;
521
                        case "error":
522
                        case "error":
522
                            this.statusIcon.setAttribute("type", "error");
523
                            this.statusIcon.setAttribute("type", "error");
523
                            this.setupStatusFader(true);
524
                            this.setupStatusFader(true);
 Lines 594-609    Link Here 
594
                        duration = this.maxCurrentTimeSeen;
595
                        duration = this.maxCurrentTimeSeen;
595
                        this.durationChange(duration);
596
                        this.durationChange(duration);
596
                    }
597
                    }
597
598
598
                    this.log("time update @ " + currentTime + "ms of " + duration + "ms");
599
                    this.log("time update @ " + currentTime + "ms of " + duration + "ms");
599
                    this.scrubber.value = currentTime;
600
                    this.scrubber.value = currentTime;
600
                },
601
                },
601
602
603
                showBuffered : function() {
604
                    function bsearch(haystack, needle, cmp) {
605
                        var length = haystack.length;
606
                        var low = 0;
607
                        var high = length;
608
                        while (high - low > 1) {
609
                            var probe = low + ((high - low) >> 1);
610
                            var r = cmp(haystack, probe, needle);
611
                            if (r == 0) {
612
                                low = probe;
613
                                break;
614
                            } else if (r > 0) {
615
                                low = probe + 1;
616
                            } else {
617
                                high = probe;
618
                            }
619
                        }
620
                        return low < length ? low : -1;
621
                    }
622
623
                    function bufferedCompare(buffered, i, time) {
624
                        if (time > buffered.end(i)) {
625
                            return 1;
626
                        } else if (time >= buffered.start(i)) {
627
                            return 0;
628
                        }
629
                        return -1;
630
                    }
631
632
                    var duration = Math.round(this.video.duration * 1000);
633
                    if (isNaN(duration))
634
                        duration = this.maxCurrentTimeSeen;
635
636
                    // Find the range that the current play position is in and use that
637
                    // range for bufferBar.  At some point we may support multiple ranges
638
                    // displayed in the bar.
639
                    var currentTime = this.video.currentTime;
640
                    var buffered = this.video.buffered;
641
                    var index = bsearch(buffered, currentTime, bufferedCompare);
642
                    var endTime = 0;
643
                    if (index >= 0) {
644
                        endTime = Math.round(buffered.end(index) * 1000);
645
                    }
646
                    this.bufferBar.max = duration;
647
                    this.bufferBar.value = endTime;
648
                },
649
602
                onVolumeMouseInOut : function (event) {
650
                onVolumeMouseInOut : function (event) {
603
                    // Ignore events caused by transitions between mute button and volumeStack,
651
                    // Ignore events caused by transitions between mute button and volumeStack,
604
                    // or between nodes inside these two elements.
652
                    // or between nodes inside these two elements.
605
                    if (this.isEventWithin(event, this.muteButton, this.volumeStack))
653
                    if (this.isEventWithin(event, this.muteButton, this.volumeStack))
606
                        return;
654
                        return;
607
                    var isMouseOver = (event.type == "mouseover");
655
                    var isMouseOver = (event.type == "mouseover");
608
                    this.startFade(this.volumeStack, isMouseOver);
656
                    this.startFade(this.volumeStack, isMouseOver);
609
                },
657
                },

Return to bug 584615