зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1456743 - P4. Actual implementation of SourceBuffer.changeType. r=bryce
Currently, the new init segment provided following a call to changeType() must contain the same number of audio and video tracks as previously. The Chrome team has indicated concerns in regards to this restriction. TBD. MozReview-Commit-ID: 3S6YVtQILF9 --HG-- extra : rebase_source : 59574301d8d4b6f04fc40a97a0917222f1d42fe4
This commit is contained in:
Родитель
5616b876de
Коммит
97cad9b3dd
|
@ -301,6 +301,47 @@ void
|
|||
SourceBuffer::ChangeType(const nsAString& aType, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
DecoderDoctorDiagnostics diagnostics;
|
||||
nsresult rv = MediaSource::IsTypeSupported(aType, &diagnostics);
|
||||
diagnostics.StoreFormatDiagnostics(mMediaSource->GetOwner()
|
||||
? mMediaSource->GetOwner()->GetExtantDoc()
|
||||
: nullptr,
|
||||
aType, NS_SUCCEEDED(rv), __func__);
|
||||
MSE_API("ChangeType(aType=%s)%s",
|
||||
NS_ConvertUTF16toUTF8(aType).get(),
|
||||
rv == NS_OK ? "" : " [not supported]");
|
||||
if (NS_FAILED(rv)) {
|
||||
DDLOG(DDLogCategory::API, "ChangeType", rv);
|
||||
aRv.Throw(rv);
|
||||
return;
|
||||
}
|
||||
if (!mMediaSource->GetDecoder() ||
|
||||
mMediaSource->GetDecoder()->OwnerHasError()) {
|
||||
MSE_DEBUG("HTMLMediaElement.error is not null");
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
if (!IsAttached() || mUpdating) {
|
||||
DDLOG(DDLogCategory::API, "ChangeType", NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
|
||||
if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
|
||||
mMediaSource->SetReadyState(MediaSourceReadyState::Open);
|
||||
}
|
||||
if (mCurrentAttributes.GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT){
|
||||
DDLOG(DDLogCategory::API, "ChangeType", NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
Maybe<MediaContainerType> containerType = MakeMediaContainerType(aType);
|
||||
MOZ_ASSERT(containerType);
|
||||
mType = *containerType;
|
||||
ResetParserState();
|
||||
mTrackBuffersManager->ChangeType(mType);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -24,7 +24,8 @@ public:
|
|||
Reset,
|
||||
RangeRemoval,
|
||||
EvictData,
|
||||
Detach
|
||||
Detach,
|
||||
ChangeType
|
||||
};
|
||||
|
||||
typedef Pair<bool, SourceBufferAttributes> AppendBufferResult;
|
||||
|
@ -112,6 +113,20 @@ public:
|
|||
const char* GetTypeName() const override { return "Detach"; }
|
||||
};
|
||||
|
||||
class ChangeTypeTask : public SourceBufferTask {
|
||||
public:
|
||||
explicit ChangeTypeTask(const MediaContainerType& aType)
|
||||
: mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
static const Type sType = Type::ChangeType;
|
||||
Type GetType() const override { return Type::ChangeType; }
|
||||
const char* GetTypeName() const override { return "ChangeType"; }
|
||||
|
||||
const MediaContainerType mType;
|
||||
};
|
||||
|
||||
} // end mozilla namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -111,6 +111,7 @@ TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder,
|
|||
: mInputBuffer(new MediaByteBuffer)
|
||||
, mBufferFull(false)
|
||||
, mFirstInitializationSegmentReceived(false)
|
||||
, mChangeTypeReceived(false)
|
||||
, mNewMediaSegmentStarted(false)
|
||||
, mActiveTrack(false)
|
||||
, mType(aType)
|
||||
|
@ -280,6 +281,14 @@ TrackBuffersManager::ProcessTasks()
|
|||
ShutdownDemuxers();
|
||||
ResetTaskQueue();
|
||||
return;
|
||||
case Type::ChangeType:
|
||||
MOZ_RELEASE_ASSERT(!mCurrentTask);
|
||||
mType = task->As<ChangeTypeTask>()->mType;
|
||||
mChangeTypeReceived = true;
|
||||
mInitData = nullptr;
|
||||
CompleteResetParserState();
|
||||
CreateDemuxerforMIMEType();
|
||||
break;
|
||||
default:
|
||||
NS_WARNING("Invalid Task");
|
||||
}
|
||||
|
@ -385,6 +394,15 @@ TrackBuffersManager::EvictData(const TimeUnit& aPlaybackTime, int64_t aSize)
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffersManager::ChangeType(const MediaContainerType& aType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
QueueTask(new ChangeTypeTask(aType));
|
||||
}
|
||||
|
||||
|
||||
TimeIntervals
|
||||
TrackBuffersManager::Buffered() const
|
||||
{
|
||||
|
@ -475,10 +493,13 @@ TrackBuffersManager::CompleteResetParserState()
|
|||
}
|
||||
|
||||
// We could be left with a demuxer in an unusable state. It needs to be
|
||||
// recreated. We store in the InputBuffer an init segment which will be parsed
|
||||
// during the next Segment Parser Loop and a new demuxer will be created and
|
||||
// initialized.
|
||||
if (mFirstInitializationSegmentReceived) {
|
||||
// recreated. Unless we have a pending changeType operation, we store in the
|
||||
// InputBuffer an init segment which will be parsed during the next Segment
|
||||
// Parser Loop and a new demuxer will be created and initialized.
|
||||
// If we are in the middle of a changeType operation, then we do not have an
|
||||
// init segment yet. The next appendBuffer operation will need to provide such
|
||||
// init segment.
|
||||
if (mFirstInitializationSegmentReceived && !mChangeTypeReceived) {
|
||||
MOZ_ASSERT(mInitData && mInitData->Length(), "we must have an init segment");
|
||||
// The aim here is really to destroy our current demuxer.
|
||||
CreateDemuxerforMIMEType();
|
||||
|
@ -486,8 +507,10 @@ TrackBuffersManager::CompleteResetParserState()
|
|||
// to mInputBuffer as it will get modified in the Segment Parser Loop.
|
||||
mInputBuffer = new MediaByteBuffer;
|
||||
mInputBuffer->AppendElements(*mInitData);
|
||||
}
|
||||
RecreateParser(true);
|
||||
} else {
|
||||
RecreateParser(false);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
@ -721,7 +744,7 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
MediaResult haveInitSegment = mParser->IsInitSegmentPresent(mInputBuffer);
|
||||
if (NS_SUCCEEDED(haveInitSegment)) {
|
||||
SetAppendState(AppendState::PARSING_INIT_SEGMENT);
|
||||
if (mFirstInitializationSegmentReceived) {
|
||||
if (mFirstInitializationSegmentReceived && !mChangeTypeReceived) {
|
||||
// This is a new initialization segment. Obsolete the old one.
|
||||
RecreateParser(false);
|
||||
}
|
||||
|
@ -772,8 +795,12 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
return;
|
||||
}
|
||||
if (mSourceBufferAttributes->GetAppendState() == AppendState::PARSING_MEDIA_SEGMENT) {
|
||||
// 1. If the first initialization segment received flag is false, then run the append error algorithm with the decode error parameter set to true and abort this algorithm.
|
||||
if (!mFirstInitializationSegmentReceived) {
|
||||
// 1. If the first initialization segment received flag is false, then run
|
||||
// the append error algorithm with the decode error parameter set to
|
||||
// true and abort this algorithm.
|
||||
// Or we are in the process of changeType, in which case we must first
|
||||
// get an init segment before getting a media segment.
|
||||
if (!mFirstInitializationSegmentReceived || mChangeTypeReceived) {
|
||||
RejectAppend(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
|
@ -1108,13 +1135,17 @@ TrackBuffersManager::OnDemuxerInitDone(const MediaResult& aResult)
|
|||
if (mFirstInitializationSegmentReceived) {
|
||||
if (numVideos != mVideoTracks.mNumTracks ||
|
||||
numAudios != mAudioTracks.mNumTracks ||
|
||||
(numVideos && info.mVideo.mMimeType != mVideoTracks.mInfo->mMimeType) ||
|
||||
(numAudios && info.mAudio.mMimeType != mAudioTracks.mInfo->mMimeType)) {
|
||||
(!mChangeTypeReceived &&
|
||||
((numVideos &&
|
||||
info.mVideo.mMimeType != mVideoTracks.mInfo->mMimeType) ||
|
||||
(numAudios &&
|
||||
info.mAudio.mMimeType != mAudioTracks.mInfo->mMimeType)))) {
|
||||
RejectAppend(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
// 1. If more than one track for a single type are present (ie 2 audio tracks),
|
||||
// then the Track IDs match the ones in the first initialization segment.
|
||||
// 1. If more than one track for a single type are present (ie 2 audio
|
||||
// tracks), then the Track IDs match the ones in the first initialization
|
||||
// segment.
|
||||
// TODO
|
||||
// 2. Add the appropriate track descriptions from this initialization
|
||||
// segment to each of the track buffers.
|
||||
|
@ -1214,6 +1245,9 @@ TrackBuffersManager::OnDemuxerInitDone(const MediaResult& aResult)
|
|||
mVideoTracks.mLastInfo = new TrackInfoSharedPtr(info.mVideo, streamID);
|
||||
}
|
||||
|
||||
// We have now completed the changeType operation.
|
||||
mChangeTypeReceived = false;
|
||||
|
||||
UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto();
|
||||
if (crypto && crypto->IsEncrypted()) {
|
||||
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
|
||||
|
|
|
@ -115,6 +115,9 @@ public:
|
|||
// and if still more space is needed remove from the end.
|
||||
EvictDataResult EvictData(const media::TimeUnit& aPlaybackTime, int64_t aSize);
|
||||
|
||||
// Queue a task to run ChangeType
|
||||
void ChangeType(const MediaContainerType& aType);
|
||||
|
||||
// Returns the buffered range currently managed.
|
||||
// This may be called on any thread.
|
||||
// Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
|
||||
|
@ -205,10 +208,11 @@ private:
|
|||
// Accessed on both the main thread and the task queue.
|
||||
Atomic<bool> mBufferFull;
|
||||
bool mFirstInitializationSegmentReceived;
|
||||
bool mChangeTypeReceived;
|
||||
// Set to true once a new segment is started.
|
||||
bool mNewMediaSegmentStarted;
|
||||
bool mActiveTrack;
|
||||
const MediaContainerType mType;
|
||||
MediaContainerType mType;
|
||||
|
||||
// ContainerParser objects and methods.
|
||||
// Those are used to parse the incoming input buffer.
|
||||
|
|
Загрузка…
Ссылка в новой задаче