diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index e0ae4fb2f374..92af1dadc91c 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -154,6 +154,7 @@ MOZ_MORK = @MOZ_MORK@ MOZ_MORKREADER = @MOZ_MORKREADER@ MOZ_NO_FAST_LOAD = @MOZ_NO_FAST_LOAD@ MOZ_OGG = @MOZ_OGG@ +MOZ_RAW = @MOZ_RAW@ MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@ MOZ_WAVE = @MOZ_WAVE@ MOZ_MEDIA = @MOZ_MEDIA@ diff --git a/configure.in b/configure.in index 8597bd6ee956..6d91dbb17ce8 100644 --- a/configure.in +++ b/configure.in @@ -4907,6 +4907,7 @@ MOZ_NO_ACTIVEX_SUPPORT=1 MOZ_NO_INSPECTOR_APIS= MOZ_NO_FAST_LOAD= MOZ_OGG=1 +MOZ_RAW=1 MOZ_SYDNEYAUDIO= MOZ_VORBIS= MOZ_WAVE=1 @@ -5856,6 +5857,9 @@ if test -n "$MOZ_NO_FAST_LOAD"; then AC_DEFINE(MOZ_NO_FAST_LOAD) fi +AC_SUBST(MOZ_RAW) +AC_DEFINE(MOZ_RAW) + dnl ======================================================== dnl = Disable Ogg Codecs dnl ======================================================== diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 2bb25acc4873..fff105e69ee8 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -96,6 +96,9 @@ #ifdef MOZ_WEBM #include "nsWebMDecoder.h" #endif +#ifdef MOZ_RAW +#include "nsRawDecoder.h" +#endif #ifdef PR_LOGGING static PRLogModuleInfo* gMediaElementLog; @@ -1184,7 +1187,36 @@ void nsHTMLMediaElement::UnbindFromTree(PRBool aDeep, Pause(); nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } +#ifdef MOZ_RAW +static const char gRawTypes[][16] = { + "video/x-raw", + "video/x-raw-yuv" +}; +static const char* gRawCodecs[] = { + nsnull +}; + +static const char* gRawMaybeCodecs[] = { + nsnull +}; + +static PRBool IsRawEnabled() +{ + return nsContentUtils::GetBoolPref("media.raw.enabled"); +} + +static PRBool IsRawType(const nsACString& aType) +{ + if (!IsRawEnabled()) + return PR_FALSE; + for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gRawTypes); ++i) { + if (aType.EqualsASCII(gRawTypes[i])) + return PR_TRUE; + } + return PR_FALSE; +} +#endif #ifdef MOZ_OGG // See http://www.rfc-editor.org/rfc/rfc5334.txt for the definitions // of Ogg media types and codec types @@ -1285,6 +1317,12 @@ nsHTMLMediaElement::CanPlayStatus nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType, const char*** aCodecList) { +#ifdef MOZ_RAW + if (IsRawType(nsDependentCString(aMIMEType))) { + *aCodecList = gRawCodecs; + return CANPLAY_MAYBE; + } +#endif #ifdef MOZ_OGG if (IsOggType(nsDependentCString(aMIMEType))) { *aCodecList = gOggCodecs; @@ -1309,6 +1347,10 @@ nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType, /* static */ PRBool nsHTMLMediaElement::ShouldHandleMediaType(const char* aMIMEType) { +#ifdef MOZ_RAW + if (IsRawType(nsDependentCString(aMIMEType))) + return PR_TRUE; +#endif #ifdef MOZ_OGG if (IsOggType(nsDependentCString(aMIMEType))) return PR_TRUE; @@ -1425,6 +1467,11 @@ void nsHTMLMediaElement::ShutdownMediaTypes() nsresult rv; nsCOMPtr catMan(do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { +#ifdef MOZ_RAW + for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gRawTypes); i++) { + catMan->DeleteCategoryEntry("Gecko-Content-Viewers", gRawTypes[i], PR_FALSE); + } +#endif #ifdef MOZ_OGG for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gOggTypes); i++) { catMan->DeleteCategoryEntry("Gecko-Content-Viewers", gOggTypes[i], PR_FALSE); @@ -1446,6 +1493,14 @@ void nsHTMLMediaElement::ShutdownMediaTypes() already_AddRefed nsHTMLMediaElement::CreateDecoder(const nsACString& aType) { +#ifdef MOZ_RAW + if (IsRawType(aType)) { + nsRefPtr decoder = new nsRawDecoder(); + if (decoder && decoder->Init(this)) { + return decoder.forget().get(); + } + } +#endif #ifdef MOZ_OGG if (IsOggType(aType)) { nsRefPtr decoder = new nsOggDecoder(); diff --git a/content/media/Makefile.in b/content/media/Makefile.in index 46ad2d42b9b9..23d68816c728 100644 --- a/content/media/Makefile.in +++ b/content/media/Makefile.in @@ -73,6 +73,10 @@ CPPSRCS += \ $(NULL) endif +ifdef MOZ_RAW +PARALLEL_DIRS += raw +endif + ifdef MOZ_OGG PARALLEL_DIRS += ogg endif diff --git a/content/media/VideoUtils.h b/content/media/VideoUtils.h index 03c37ffea802..60688d4e53e7 100644 --- a/content/media/VideoUtils.h +++ b/content/media/VideoUtils.h @@ -59,6 +59,18 @@ #define PR_INT64_MIN (-PR_INT64_MAX - 1) #define PR_UINT64_MAX (~(PRUint64)(0)) +static PRBool MulOverflow32(PRUint32 a, PRUint32 b, PRUint32 &aResult) +{ + PRUint64 rl = static_cast(a) * static_cast(b); + + if (rl > PR_UINT32_MAX) { + return PR_FALSE; + } + + aResult = static_cast(rl); + + return PR_TRUE; +} // This belongs in xpcom/monitor/Monitor.h, once we've made // mozilla::Monitor non-reentrant. diff --git a/content/media/ogg/nsOggCodecState.cpp b/content/media/ogg/nsOggCodecState.cpp index bc7d50ae7c2b..ab20ce0449ff 100644 --- a/content/media/ogg/nsOggCodecState.cpp +++ b/content/media/ogg/nsOggCodecState.cpp @@ -61,20 +61,6 @@ static PRBool AddOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult); // in an integer overflow. static PRBool MulOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult); -static PRBool MulOverflow32(PRUint32 a, PRUint32 b, PRUint32& aResult) -{ - // 32 bit integer multiplication with overflow checking. Returns PR_TRUE - // if the multiplication was successful, or PR_FALSE if the operation resulted - // in an integer overflow. - PRUint64 a64 = a; - PRUint64 b64 = b; - PRUint64 r64 = a64 * b64; - if (r64 > PR_UINT32_MAX) - return PR_FALSE; - aResult = static_cast(r64); - return PR_TRUE; -} - nsOggCodecState* nsOggCodecState::Create(ogg_page* aPage) { diff --git a/content/media/raw/Makefile.in b/content/media/raw/Makefile.in new file mode 100644 index 000000000000..246d0e8bb274 --- /dev/null +++ b/content/media/raw/Makefile.in @@ -0,0 +1,67 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Raw Decoder code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Brad Lassey +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = content +LIBRARY_NAME = gkconraw_s +LIBXUL_LIBRARY = 1 + +EXPORTS += \ + nsRawDecoder.h \ + nsRawReader.h \ + $(NULL) + +CPPSRCS += \ + nsRawDecoder.cpp \ + nsRawReader.cpp \ + $(NULL) + +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/config/rules.mk + +INCLUDES += \ + -I$(srcdir)/../../base/src \ + -I$(srcdir)/../../html/content/src \ + $(NULL) diff --git a/content/media/raw/nsRawDecoder.cpp b/content/media/raw/nsRawDecoder.cpp new file mode 100644 index 000000000000..fafca6f31b0d --- /dev/null +++ b/content/media/raw/nsRawDecoder.cpp @@ -0,0 +1,44 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Raw Decoder code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsBuiltinDecoderStateMachine.h" +#include "nsRawReader.h" +#include "nsRawDecoder.h" + +nsDecoderStateMachine* nsRawDecoder::CreateStateMachine() +{ + return new nsBuiltinDecoderStateMachine(this, new nsRawReader(this)); +} diff --git a/content/media/raw/nsRawDecoder.h b/content/media/raw/nsRawDecoder.h new file mode 100644 index 000000000000..029253e897a7 --- /dev/null +++ b/content/media/raw/nsRawDecoder.h @@ -0,0 +1,49 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Raw Decoder code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined(nsRawDecoder_h_) +#define nsRawDecoder_h_ + +#include "nsBuiltinDecoder.h" + +class nsRawDecoder : public nsBuiltinDecoder +{ +public: + virtual nsMediaDecoder* Clone() { return new nsRawDecoder(); } + virtual nsDecoderStateMachine* CreateStateMachine(); +}; + +#endif diff --git a/content/media/raw/nsRawReader.cpp b/content/media/raw/nsRawReader.cpp new file mode 100644 index 000000000000..d9e1243ca197 --- /dev/null +++ b/content/media/raw/nsRawReader.cpp @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brad Lassey + * Kyle Huey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsBuiltinDecoderStateMachine.h" +#include "nsBuiltinDecoder.h" +#include "nsRawReader.h" +#include "nsRawDecoder.h" +#include "VideoUtils.h" + +#define RAW_ID 0x595556 + +nsRawReader::nsRawReader(nsBuiltinDecoder* aDecoder) + : nsBuiltinDecoderReader(aDecoder), + mCurrentFrame(0) +{ + MOZ_COUNT_CTOR(nsRawReader); +} + +nsRawReader::~nsRawReader() +{ + MOZ_COUNT_DTOR(nsRawReader); +} + +nsresult nsRawReader::Init() +{ + return NS_OK; +} + +nsresult nsRawReader::ResetDecode() +{ + mCurrentFrame = 0; + return nsBuiltinDecoderReader::ResetDecode(); +} + +nsresult nsRawReader::ReadMetadata() +{ + NS_ASSERTION(mDecoder->OnStateMachineThread(), + "Should be on state machine thread."); + mozilla::MonitorAutoEnter autoEnter(mMonitor); + + nsMediaStream* stream = mDecoder->GetCurrentStream(); + NS_ASSERTION(stream, "Decoder has no media stream"); + + if (!ReadFromStream(stream, reinterpret_cast(&mMetadata), + sizeof(mMetadata))) + return NS_ERROR_FAILURE; + + // Validate the header + if (!(mMetadata.headerPacketID == 0 /* Packet ID of 0 for the header*/ && + mMetadata.codecID == RAW_ID /* "YUV" */ && + mMetadata.majorVersion == 0 && + mMetadata.minorVersion == 1)) + return NS_ERROR_FAILURE; + + PRUint32 dummy; + if (!MulOverflow32(mMetadata.frameWidth, mMetadata.frameHeight, dummy)) + return NS_ERROR_FAILURE; + + mInfo.mHasVideo = PR_TRUE; + mInfo.mPicture.x = 0; + mInfo.mPicture.y = 0; + mInfo.mPicture.width = mMetadata.frameWidth; + mInfo.mPicture.height = mMetadata.frameHeight; + mInfo.mFrame.width = mMetadata.frameWidth; + mInfo.mFrame.height = mMetadata.frameHeight; + if (mMetadata.aspectDenominator == 0 || + mMetadata.framerateDenominator == 0) + return NS_ERROR_FAILURE; // Invalid data + mInfo.mPixelAspectRatio = static_cast(mMetadata.aspectNumerator) / + mMetadata.aspectDenominator; + mInfo.mDataOffset = sizeof(nsRawVideoHeader) + 1; + mInfo.mHasAudio = PR_FALSE; + + mFrameRate = static_cast(mMetadata.framerateNumerator) / + mMetadata.framerateDenominator; + + // Make some sanity checks + if (mFrameRate > 45 || + mFrameRate == 0 || + mInfo.mPixelAspectRatio == 0 || + mMetadata.frameWidth > 2000 || + mMetadata.frameHeight > 2000 || + mMetadata.chromaChannelBpp != 4 || + mMetadata.lumaChannelBpp != 8 || + mMetadata.colorspace != 1 /* 4:2:0 */) + return NS_ERROR_FAILURE; + + mFrameSize = mMetadata.frameWidth * mMetadata.frameHeight * + (mMetadata.lumaChannelBpp + mMetadata.chromaChannelBpp) / 8.0 + + sizeof(nsRawPacketHeader); + + PRInt64 length = stream->GetLength(); + if (length != -1) { + mozilla::MonitorAutoExit autoExitMonitor(mMonitor); + mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor()); + mDecoder->GetStateMachine()->SetDuration(1000 * + (length - sizeof(nsRawVideoHeader)) / + (mFrameSize * mFrameRate)); + } + + return NS_OK; +} + + PRBool nsRawReader::DecodeAudioData() +{ + NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), + "Should be on state machine thread or decode thread."); + return PR_FALSE; +} + +// Helper method that either reads until it gets aLength bytes +// or returns PR_FALSE +PRBool nsRawReader::ReadFromStream(nsMediaStream *aStream, PRUint8* aBuf, + PRUint32 aLength) +{ + while (aLength > 0) { + PRUint32 bytesRead = 0; + nsresult rv; + + rv = aStream->Read(reinterpret_cast(aBuf), aLength, &bytesRead); + NS_ENSURE_SUCCESS(rv, PR_FALSE); + + if (bytesRead == 0) { + return PR_FALSE; + } + + aLength -= bytesRead; + aBuf += bytesRead; + } + + return PR_TRUE; +} + +PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, + PRInt64 aTimeThreshold) +{ + mozilla::MonitorAutoEnter autoEnter(mMonitor); + NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), + "Should be on state machine thread or decode thread."); + + PRInt64 currentFrameTime = 1000 * mCurrentFrame / mFrameRate; + PRUint32 length = mFrameSize - sizeof(nsRawPacketHeader); + + nsAutoPtr buffer(new PRUint8[length]); + nsMediaStream* stream = mDecoder->GetCurrentStream(); + NS_ASSERTION(stream, "Decoder has no media stream"); + + // We're always decoding one frame when called + while(true) { + nsRawPacketHeader header; + + // Read in a packet header and validate + if (!(ReadFromStream(stream, reinterpret_cast(&header), + sizeof(header))) || + !(header.packetID == 0xFF && header.codecID == RAW_ID /* "YUV" */)) { + return PR_FALSE; + } + + if (!ReadFromStream(stream, buffer, length)) { + return PR_FALSE; + } + + if (currentFrameTime >= aTimeThreshold) + break; + + mCurrentFrame++; + currentFrameTime += 1000.0 / mFrameRate; + } + + VideoData::YCbCrBuffer b; + b.mPlanes[0].mData = buffer; + b.mPlanes[0].mStride = mMetadata.frameWidth * mMetadata.lumaChannelBpp / 8.0; + b.mPlanes[0].mHeight = mMetadata.frameHeight; + b.mPlanes[0].mWidth = mMetadata.frameWidth; + + PRUint32 cbcrStride = mMetadata.frameWidth * mMetadata.chromaChannelBpp / 8.0; + + b.mPlanes[1].mData = buffer + mMetadata.frameHeight * b.mPlanes[0].mStride; + b.mPlanes[1].mStride = cbcrStride; + b.mPlanes[1].mHeight = mMetadata.frameHeight / 2; + b.mPlanes[1].mWidth = mMetadata.frameWidth / 2; + + b.mPlanes[2].mData = b.mPlanes[1].mData + mMetadata.frameHeight * cbcrStride / 2; + b.mPlanes[2].mStride = cbcrStride; + b.mPlanes[2].mHeight = mMetadata.frameHeight / 2; + b.mPlanes[2].mWidth = mMetadata.frameWidth / 2; + + VideoData *v = VideoData::Create(mInfo, + mDecoder->GetImageContainer(), + -1, + currentFrameTime, + currentFrameTime + (1000 / mFrameRate), + b, + 1, // In raw video every frame is a keyframe + -1); + if (!v) + return PR_FALSE; + + mVideoQueue.Push(v); + mCurrentFrame++; + currentFrameTime += 1000 / mFrameRate; + + return PR_TRUE; +} + +nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime) +{ + mozilla::MonitorAutoEnter autoEnter(mMonitor); + NS_ASSERTION(mDecoder->OnStateMachineThread(), + "Should be on state machine thread."); + + nsMediaStream *stream = mDecoder->GetCurrentStream(); + NS_ASSERTION(stream, "Decoder has no media stream"); + + PRUint32 frame = mCurrentFrame; + if (aTime >= UINT_MAX) + return NS_ERROR_FAILURE; + mCurrentFrame = aTime * mFrameRate / 1000; + + PRUint32 offset; + if (!MulOverflow32(mCurrentFrame, mFrameSize, offset)) + return NS_ERROR_FAILURE; + + offset += sizeof(nsRawVideoHeader); + + nsresult rv = stream->Seek(nsISeekableStream::NS_SEEK_SET, offset); + NS_ENSURE_SUCCESS(rv, rv); + + mVideoQueue.Erase(); + + while(mVideoQueue.GetSize() == 0) { + PRBool keyframeSkip = PR_FALSE; + if (!DecodeVideoFrame(keyframeSkip, 0)) { + mCurrentFrame = frame; + return NS_ERROR_FAILURE; + } + + { + mozilla::MonitorAutoExit autoMonitorExit(mMonitor); + mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor()); + if (mDecoder->GetDecodeState() == + nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) { + mCurrentFrame = frame; + return NS_ERROR_FAILURE; + } + } + + nsAutoPtr video(mVideoQueue.PeekFront()); + if (video && video->mEndTime < aTime) { + mVideoQueue.PopFront(); + video = nsnull; + } else { + video.forget(); + } + } + + return NS_OK; +} + +PRInt64 nsRawReader::FindEndTime(PRInt64 aEndTime) +{ + return -1; +} diff --git a/content/media/raw/nsRawReader.h b/content/media/raw/nsRawReader.h new file mode 100644 index 000000000000..9f1c76737fd9 --- /dev/null +++ b/content/media/raw/nsRawReader.h @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brad Lassey + * Kyle Huey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if !defined(nsRawReader_h_) +#define nsRawReader_h_ + +#include "nsBuiltinDecoderReader.h" + +struct nsRawVideo_PRUint24 { + operator PRUint32() const { return value[2] << 16 | value[1] << 8 | value[0]; } +private: + PRUint8 value[3]; +}; + +struct nsRawPacketHeader { + typedef nsRawVideo_PRUint24 PRUint24; + PRUint8 packetID; + PRUint24 codecID; +}; + +// This is Arc's draft from wiki.xiph.org/OggYUV +struct nsRawVideoHeader { + typedef nsRawVideo_PRUint24 PRUint24; + PRUint8 headerPacketID; // Header Packet ID (always 0) + PRUint24 codecID; // Codec identifier (always "YUV") + PRUint8 majorVersion; // Version Major (breaks backwards compat) + PRUint8 minorVersion; // Version Minor (preserves backwards compat) + PRUint16 options; // Bit 1: Color (false = B/W) + // Bits 2-4: Chroma Pixel Shape + // Bit 5: 50% horizontal offset for Cr samples + // Bit 6: 50% vertical ... + // Bits 7-8: Chroma Blending + // Bit 9: Packed (false = Planar) + // Bit 10: Cr Staggered Horizontally + // Bit 11: Cr Staggered Vertically + // Bit 12: Unused (format is always little endian) + // Bit 13: Interlaced (false = Progressive) + // Bits 14-16: Interlace options (undefined) + + PRUint8 alphaChannelBpp; + PRUint8 lumaChannelBpp; + PRUint8 chromaChannelBpp; + PRUint8 colorspace; + + PRUint24 frameWidth; + PRUint24 frameHeight; + PRUint24 aspectNumerator; + PRUint24 aspectDenominator; + + PRUint32 framerateNumerator; + PRUint32 framerateDenominator; +}; + +class nsRawReader : public nsBuiltinDecoderReader +{ +public: + nsRawReader(nsBuiltinDecoder* aDecoder); + ~nsRawReader(); + + virtual nsresult Init(); + virtual nsresult ResetDecode(); + virtual PRBool DecodeAudioData(); + + virtual PRBool DecodeVideoFrame(PRBool &aKeyframeSkip, + PRInt64 aTimeThreshold); + + virtual PRBool HasAudio() + { + return PR_FALSE; + } + + virtual PRBool HasVideo() + { + return PR_TRUE; + } + + virtual nsresult ReadMetadata(); + virtual nsresult Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime); + virtual PRInt64 FindEndTime(PRInt64 aEndOffset); + +private: + PRBool ReadFromStream(nsMediaStream *aStream, PRUint8 *aBuf, + PRUint32 aLength); + + nsRawVideoHeader mMetadata; + PRUint32 mCurrentFrame; + double mFrameRate; + PRUint32 mFrameSize; +}; + +#endif diff --git a/content/media/test/Makefile.in b/content/media/test/Makefile.in index f0653304b94a..ad89c97d5891 100644 --- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -194,6 +194,7 @@ _TEST_FILES += \ dirac.ogg \ seek.ogv \ seek.webm \ + seek.yuv \ short-video.ogv \ small-shot.ogg \ sound.ogg \ diff --git a/content/media/test/manifest.js b/content/media/test/manifest.js index bfc8a681fab4..55aee164582a 100644 --- a/content/media/test/manifest.js +++ b/content/media/test/manifest.js @@ -102,6 +102,9 @@ var gPlayTests = [ // Test playback of a webm file { name:"seek.webm", type:"video/webm", duration:3.966 }, + // Test playback of a raw file + { name:"seek.yuv", type:"video/x-raw-yuv", duration:1.833 }, + { name:"bogus.duh", type:"bogus/duh", duration:Number.NaN } ]; diff --git a/content/media/test/seek.yuv b/content/media/test/seek.yuv new file mode 100644 index 000000000000..69485e8e1bd1 Binary files /dev/null and b/content/media/test/seek.yuv differ diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index 10909497919a..caf6b02e4953 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -131,6 +131,12 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifdef MOZ_RAW +SHARED_LIBRARY_LIBS += \ + $(DEPTH)/content/media/raw/$(LIB_PREFIX)gkconraw_s.$(LIB_SUFFIX)\ + $(NULL) +endif + ifdef MOZ_WEBM SHARED_LIBRARY_LIBS += \ $(DEPTH)/content/media/webm/$(LIB_PREFIX)gkconwebm_s.$(LIB_SUFFIX) \ diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index b969c8477859..47dba2bff098 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -156,6 +156,9 @@ pref("media.enforce_same_site_origin", false); // Media cache size in kilobytes pref("media.cache_size", 512000); +#ifdef MOZ_RAW +pref("media.raw.enabled", true); +#endif #ifdef MOZ_OGG pref("media.ogg.enabled", true); #endif diff --git a/netwerk/mime/nsMimeTypes.h b/netwerk/mime/nsMimeTypes.h index 3a953cf559a4..8fcbd3443c59 100644 --- a/netwerk/mime/nsMimeTypes.h +++ b/netwerk/mime/nsMimeTypes.h @@ -156,6 +156,7 @@ #define TEXT_XSL "text/xsl" #define VIDEO_MPEG "video/mpeg" +#define VIDEO_RAW "video/x-raw-yuv" #define VIDEO_OGG "video/ogg" #define VIDEO_WEBM "video/webm" #define APPLICATION_OGG "application/ogg" diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 67d9780b7eb1..8ce77f5cf378 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -544,6 +544,7 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { VIDEO_WEBM, "webm", "Web Media Video" }, { AUDIO_WEBM, "webm", "Web Media Audio" }, #endif + { VIDEO_RAW, "yuv", "Raw YUV Video" }, { AUDIO_WAV, "wav", "Waveform Audio" }, };