LCOV - code coverage report
Current view: top level - dom/media - VideoUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 257 0.8 %
Date: 2017-07-14 16:53:18 Functions: 0 38 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "VideoUtils.h"
       6             : 
       7             : #include "ImageContainer.h"
       8             : #include "MediaContainerType.h"
       9             : #include "MediaPrefs.h"
      10             : #include "MediaResource.h"
      11             : #include "TimeUnits.h"
      12             : #include "VorbisUtils.h"
      13             : #include "mozilla/Base64.h"
      14             : #include "mozilla/SharedThreadPool.h"
      15             : #include "mozilla/TaskQueue.h"
      16             : #include "mozilla/Telemetry.h"
      17             : #include "nsCharSeparatedTokenizer.h"
      18             : #include "nsContentTypeParser.h"
      19             : #include "nsIConsoleService.h"
      20             : #include "nsIRandomGenerator.h"
      21             : #include "nsIServiceManager.h"
      22             : #include "nsMathUtils.h"
      23             : #include "nsServiceManagerUtils.h"
      24             : #include "nsSize.h"
      25             : #include "nsThreadUtils.h"
      26             : 
      27             : #include <functional>
      28             : #include <stdint.h>
      29             : 
      30             : namespace mozilla {
      31             : 
      32           3 : NS_NAMED_LITERAL_CSTRING(kEMEKeySystemClearkey, "org.w3.clearkey");
      33           3 : NS_NAMED_LITERAL_CSTRING(kEMEKeySystemWidevine, "com.widevine.alpha");
      34             : 
      35             : using layers::PlanarYCbCrImage;
      36             : using media::TimeUnit;
      37             : 
      38           0 : CheckedInt64 SaferMultDiv(int64_t aValue, uint32_t aMul, uint32_t aDiv) {
      39           0 :   int64_t major = aValue / aDiv;
      40           0 :   int64_t remainder = aValue % aDiv;
      41           0 :   return CheckedInt64(remainder) * aMul / aDiv + CheckedInt64(major) * aMul;
      42             : }
      43             : 
      44             : // Converts from number of audio frames to microseconds, given the specified
      45             : // audio rate.
      46           0 : CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) {
      47           0 :   return SaferMultDiv(aFrames, USECS_PER_S, aRate);
      48             : }
      49             : 
      50           0 : TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate) {
      51           0 :   int64_t major = aFrames / aRate;
      52           0 :   int64_t remainder = aFrames % aRate;
      53           0 :   return TimeUnit::FromMicroseconds(major) * USECS_PER_S +
      54           0 :     (TimeUnit::FromMicroseconds(remainder) * USECS_PER_S) / aRate;
      55             : }
      56             : 
      57             : // Converts from microseconds to number of audio frames, given the specified
      58             : // audio rate.
      59           0 : CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {
      60           0 :   return SaferMultDiv(aUsecs, aRate, USECS_PER_S);
      61             : }
      62             : 
      63             : // Format TimeUnit as number of frames at given rate.
      64           0 : CheckedInt64 TimeUnitToFrames(const TimeUnit& aTime, uint32_t aRate) {
      65           0 :   return UsecsToFrames(aTime.ToMicroseconds(), aRate);
      66             : }
      67             : 
      68           0 : nsresult SecondsToUsecs(double aSeconds, int64_t& aOutUsecs) {
      69           0 :   if (aSeconds * double(USECS_PER_S) > INT64_MAX) {
      70           0 :     return NS_ERROR_FAILURE;
      71             :   }
      72           0 :   aOutUsecs = int64_t(aSeconds * double(USECS_PER_S));
      73           0 :   return NS_OK;
      74             : }
      75             : 
      76           0 : static int32_t ConditionDimension(float aValue)
      77             : {
      78             :   // This will exclude NaNs and too-big values.
      79           0 :   if (aValue > 1.0 && aValue <= INT32_MAX)
      80           0 :     return int32_t(NS_round(aValue));
      81           0 :   return 0;
      82             : }
      83             : 
      84           0 : void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio)
      85             : {
      86           0 :   if (aAspectRatio > 1.0) {
      87             :     // Increase the intrinsic width
      88           0 :     aDisplay.width = ConditionDimension(aAspectRatio * aDisplay.width);
      89             :   } else {
      90             :     // Increase the intrinsic height
      91           0 :     aDisplay.height = ConditionDimension(aDisplay.height / aAspectRatio);
      92             :   }
      93           0 : }
      94             : 
      95           0 : static int64_t BytesToTime(int64_t offset, int64_t length, int64_t durationUs) {
      96           0 :   NS_ASSERTION(length > 0, "Must have positive length");
      97           0 :   double r = double(offset) / double(length);
      98           0 :   if (r > 1.0)
      99           0 :     r = 1.0;
     100           0 :   return int64_t(double(durationUs) * r);
     101             : }
     102             : 
     103           0 : media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
     104             :                                                     int64_t aDurationUsecs)
     105             : {
     106           0 :   media::TimeIntervals buffered;
     107             :   // Nothing to cache if the media takes 0us to play.
     108           0 :   if (aDurationUsecs <= 0 || !aStream)
     109           0 :     return buffered;
     110             : 
     111             :   // Special case completely cached files.  This also handles local files.
     112           0 :   if (aStream->IsDataCachedToEndOfResource(0)) {
     113             :     buffered +=
     114           0 :       media::TimeInterval(TimeUnit::Zero(),
     115           0 :                           TimeUnit::FromMicroseconds(aDurationUsecs));
     116           0 :     return buffered;
     117             :   }
     118             : 
     119           0 :   int64_t totalBytes = aStream->GetLength();
     120             : 
     121             :   // If we can't determine the total size, pretend that we have nothing
     122             :   // buffered. This will put us in a state of eternally-low-on-undecoded-data
     123             :   // which is not great, but about the best we can do.
     124           0 :   if (totalBytes <= 0)
     125           0 :     return buffered;
     126             : 
     127           0 :   int64_t startOffset = aStream->GetNextCachedData(0);
     128           0 :   while (startOffset >= 0) {
     129           0 :     int64_t endOffset = aStream->GetCachedDataEnd(startOffset);
     130             :     // Bytes [startOffset..endOffset] are cached.
     131           0 :     NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered");
     132           0 :     NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered");
     133             : 
     134           0 :     int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs);
     135           0 :     int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs);
     136           0 :     if (startUs != endUs) {
     137             :       buffered +=
     138           0 :         media::TimeInterval(TimeUnit::FromMicroseconds(startUs),
     139           0 :                             TimeUnit::FromMicroseconds(endUs));
     140             :     }
     141           0 :     startOffset = aStream->GetNextCachedData(endOffset);
     142             :   }
     143           0 :   return buffered;
     144             : }
     145             : 
     146           0 : void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer,
     147             :                          uint32_t aFrames)
     148             : {
     149           0 :   MOZ_ASSERT(aBuffer);
     150           0 :   const int channels = 2;
     151           0 :   for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
     152             : #ifdef MOZ_SAMPLE_TYPE_FLOAT32
     153           0 :     float sample = 0.0;
     154             : #else
     155             :     int sample = 0;
     156             : #endif
     157             :     // The sample of the buffer would be interleaved.
     158           0 :     sample = (aBuffer[fIdx*channels] + aBuffer[fIdx*channels + 1]) * 0.5;
     159           0 :     aBuffer[fIdx*channels] = aBuffer[fIdx*channels + 1] = sample;
     160             :   }
     161           0 : }
     162             : 
     163             : bool
     164           0 : IsVideoContentType(const nsCString& aContentType)
     165             : {
     166           0 :   NS_NAMED_LITERAL_CSTRING(video, "video");
     167           0 :   if (FindInReadable(video, aContentType)) {
     168           0 :     return true;
     169             :   }
     170           0 :   return false;
     171             : }
     172             : 
     173             : bool
     174           0 : IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
     175             :                    const nsIntSize& aDisplay)
     176             : {
     177             :   return
     178           0 :     aFrame.width <= PlanarYCbCrImage::MAX_DIMENSION &&
     179           0 :     aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION &&
     180           0 :     aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
     181           0 :     aFrame.width * aFrame.height != 0 &&
     182           0 :     aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION &&
     183           0 :     aPicture.x < PlanarYCbCrImage::MAX_DIMENSION &&
     184           0 :     aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION &&
     185           0 :     aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION &&
     186           0 :     aPicture.y < PlanarYCbCrImage::MAX_DIMENSION &&
     187           0 :     aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION &&
     188           0 :     aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
     189           0 :     aPicture.width * aPicture.height != 0 &&
     190           0 :     aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION &&
     191           0 :     aDisplay.height <= PlanarYCbCrImage::MAX_DIMENSION &&
     192           0 :     aDisplay.width * aDisplay.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
     193           0 :     aDisplay.width * aDisplay.height != 0;
     194             : }
     195             : 
     196           0 : already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType)
     197             : {
     198             :   const char *name;
     199           0 :   switch (aType) {
     200             :     case MediaThreadType::PLATFORM_DECODER:
     201           0 :       name = "MediaPDecoder";
     202           0 :       break;
     203             :     default:
     204           0 :       MOZ_FALLTHROUGH_ASSERT("Unexpected MediaThreadType");
     205             :     case MediaThreadType::PLAYBACK:
     206           0 :       name = "MediaPlayback";
     207           0 :       break;
     208             :   }
     209             :   return SharedThreadPool::
     210           0 :     Get(nsDependentCString(name), MediaPrefs::MediaThreadPoolDefaultCount());
     211             : }
     212             : 
     213             : bool
     214           0 : ExtractH264CodecDetails(const nsAString& aCodec,
     215             :                         int16_t& aProfile,
     216             :                         int16_t& aLevel)
     217             : {
     218             :   // H.264 codecs parameters have a type defined as avcN.PPCCLL, where
     219             :   // N = avc type. avc3 is avcc with SPS & PPS implicit (within stream)
     220             :   // PP = profile_idc, CC = constraint_set flags, LL = level_idc.
     221             :   // We ignore the constraint_set flags, as it's not clear from any
     222             :   // documentation what constraints the platform decoders support.
     223             :   // See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
     224             :   // for more details.
     225           0 :   if (aCodec.Length() != strlen("avc1.PPCCLL")) {
     226           0 :     return false;
     227             :   }
     228             : 
     229             :   // Verify the codec starts with "avc1." or "avc3.".
     230           0 :   const nsAString& sample = Substring(aCodec, 0, 5);
     231           0 :   if (!sample.EqualsASCII("avc1.") && !sample.EqualsASCII("avc3.")) {
     232           0 :     return false;
     233             :   }
     234             : 
     235             :   // Extract the profile_idc and level_idc.
     236           0 :   nsresult rv = NS_OK;
     237           0 :   aProfile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16);
     238           0 :   NS_ENSURE_SUCCESS(rv, false);
     239             : 
     240           0 :   aLevel = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
     241           0 :   NS_ENSURE_SUCCESS(rv, false);
     242             : 
     243           0 :   if (aLevel == 9) {
     244           0 :     aLevel = H264_LEVEL_1_b;
     245           0 :   } else if (aLevel <= 5) {
     246           0 :     aLevel *= 10;
     247             :   }
     248             : 
     249             :   // Capture the constraint_set flag value for the purpose of Telemetry.
     250             :   // We don't NS_ENSURE_SUCCESS here because ExtractH264CodecDetails doesn't
     251             :   // care about this, but we make sure constraints is above 4 (constraint_set5_flag)
     252             :   // otherwise collect 0 for unknown.
     253           0 :   uint8_t constraints = PromiseFlatString(Substring(aCodec, 7, 2)).ToInteger(&rv, 16);
     254           0 :   Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG,
     255           0 :                         constraints >= 4 ? constraints : 0);
     256             : 
     257             :   // 244 is the highest meaningful profile value (High 4:4:4 Intra Profile)
     258             :   // that can be represented as single hex byte, otherwise collect 0 for unknown.
     259           0 :   Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_PROFILE,
     260           0 :                         aProfile <= 244 ? aProfile : 0);
     261             : 
     262             :   // Make sure aLevel represents a value between levels 1 and 5.2,
     263             :   // otherwise collect 0 for unknown.
     264           0 :   Telemetry::Accumulate(Telemetry::VIDEO_CANPLAYTYPE_H264_LEVEL,
     265           0 :                         (aLevel >= 10 && aLevel <= 52) ? aLevel : 0);
     266             : 
     267           0 :   return true;
     268             : }
     269             : 
     270             : nsresult
     271           0 : GenerateRandomName(nsCString& aOutSalt, uint32_t aLength)
     272             : {
     273             :   nsresult rv;
     274             :   nsCOMPtr<nsIRandomGenerator> rg =
     275           0 :     do_GetService("@mozilla.org/security/random-generator;1", &rv);
     276           0 :   if (NS_FAILED(rv)) return rv;
     277             : 
     278             :   // For each three bytes of random data we will get four bytes of ASCII.
     279             :   const uint32_t requiredBytesLength =
     280           0 :     static_cast<uint32_t>((aLength + 3) / 4 * 3);
     281             : 
     282             :   uint8_t* buffer;
     283           0 :   rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
     284           0 :   if (NS_FAILED(rv)) return rv;
     285             : 
     286           0 :   nsAutoCString temp;
     287             :   nsDependentCSubstring randomData(reinterpret_cast<const char*>(buffer),
     288           0 :                                    requiredBytesLength);
     289           0 :   rv = Base64Encode(randomData, temp);
     290           0 :   free(buffer);
     291           0 :   buffer = nullptr;
     292           0 :   if (NS_FAILED (rv)) return rv;
     293             : 
     294           0 :   aOutSalt = temp;
     295           0 :   return NS_OK;
     296             : }
     297             : 
     298             : nsresult
     299           0 : GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
     300             : {
     301           0 :   nsresult rv = GenerateRandomName(aOutSalt, aLength);
     302           0 :   if (NS_FAILED(rv)) return rv;
     303             : 
     304             :   // Base64 characters are alphanumeric (a-zA-Z0-9) and '+' and '/', so we need
     305             :   // to replace illegal characters -- notably '/'
     306           0 :   aOutSalt.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
     307           0 :   return NS_OK;
     308             : }
     309             : 
     310             : already_AddRefed<TaskQueue>
     311           0 : CreateMediaDecodeTaskQueue(const char* aName)
     312             : {
     313             :   RefPtr<TaskQueue> queue = new TaskQueue(
     314           0 :     GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER), aName);
     315           0 :   return queue.forget();
     316             : }
     317             : 
     318             : void
     319           0 : SimpleTimer::Cancel() {
     320           0 :   if (mTimer) {
     321             : #ifdef DEBUG
     322           0 :     nsCOMPtr<nsIEventTarget> target;
     323           0 :     mTimer->GetTarget(getter_AddRefs(target));
     324             :     bool onCurrent;
     325           0 :     nsresult rv = target->IsOnCurrentThread(&onCurrent);
     326           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv) && onCurrent);
     327             : #endif
     328           0 :     mTimer->Cancel();
     329           0 :     mTimer = nullptr;
     330             :   }
     331           0 :   mTask = nullptr;
     332           0 : }
     333             : 
     334             : NS_IMETHODIMP
     335           0 : SimpleTimer::Notify(nsITimer *timer) {
     336           0 :   RefPtr<SimpleTimer> deathGrip(this);
     337           0 :   if (mTask) {
     338           0 :     mTask->Run();
     339           0 :     mTask = nullptr;
     340             :   }
     341           0 :   return NS_OK;
     342             : }
     343             : 
     344             : nsresult
     345           0 : SimpleTimer::Init(nsIRunnable* aTask, uint32_t aTimeoutMs, nsIEventTarget* aTarget)
     346             : {
     347             :   nsresult rv;
     348             : 
     349             :   // Get target thread first, so we don't have to cancel the timer if it fails.
     350           0 :   nsCOMPtr<nsIEventTarget> target;
     351           0 :   if (aTarget) {
     352           0 :     target = aTarget;
     353             :   } else {
     354           0 :     target = GetMainThreadEventTarget();
     355           0 :     if (!target) {
     356           0 :       return NS_ERROR_NOT_AVAILABLE;
     357             :     }
     358             :   }
     359             : 
     360           0 :   nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
     361           0 :   if (NS_FAILED(rv)) {
     362           0 :     return rv;
     363             :   }
     364             :   // Note: set target before InitWithCallback in case the timer fires before
     365             :   // we change the event target.
     366           0 :   rv = timer->SetTarget(target);
     367           0 :   if (NS_FAILED(rv)) {
     368           0 :     timer->Cancel();
     369           0 :     return rv;
     370             :   }
     371           0 :   rv = timer->InitWithCallback(this, aTimeoutMs, nsITimer::TYPE_ONE_SHOT);
     372           0 :   if (NS_FAILED(rv)) {
     373           0 :     return rv;
     374             :   }
     375             : 
     376           0 :   mTimer = timer.forget();
     377           0 :   mTask = aTask;
     378           0 :   return NS_OK;
     379             : }
     380             : 
     381           0 : NS_IMPL_ISUPPORTS(SimpleTimer, nsITimerCallback)
     382             : 
     383             : already_AddRefed<SimpleTimer>
     384           0 : SimpleTimer::Create(nsIRunnable* aTask, uint32_t aTimeoutMs, nsIEventTarget* aTarget)
     385             : {
     386           0 :   RefPtr<SimpleTimer> t(new SimpleTimer());
     387           0 :   if (NS_FAILED(t->Init(aTask, aTimeoutMs, aTarget))) {
     388           0 :     return nullptr;
     389             :   }
     390           0 :   return t.forget();
     391             : }
     392             : 
     393             : void
     394           0 : LogToBrowserConsole(const nsAString& aMsg)
     395             : {
     396           0 :   if (!NS_IsMainThread()) {
     397           0 :     nsString msg(aMsg);
     398           0 :     nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
     399           0 :       "LogToBrowserConsole", [msg]() { LogToBrowserConsole(msg); });
     400           0 :     SystemGroup::Dispatch("LogToBrowserConsole", TaskCategory::Other, task.forget());
     401           0 :     return;
     402             :   }
     403             :   nsCOMPtr<nsIConsoleService> console(
     404           0 :     do_GetService("@mozilla.org/consoleservice;1"));
     405           0 :   if (!console) {
     406           0 :     NS_WARNING("Failed to log message to console.");
     407           0 :     return;
     408             :   }
     409           0 :   nsAutoString msg(aMsg);
     410           0 :   console->LogStringMessage(msg.get());
     411             : }
     412             : 
     413             : bool
     414           0 : ParseCodecsString(const nsAString& aCodecs, nsTArray<nsString>& aOutCodecs)
     415             : {
     416           0 :   aOutCodecs.Clear();
     417           0 :   bool expectMoreTokens = false;
     418           0 :   nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
     419           0 :   while (tokenizer.hasMoreTokens()) {
     420           0 :     const nsAString& token = tokenizer.nextToken();
     421           0 :     expectMoreTokens = tokenizer.separatorAfterCurrentToken();
     422           0 :     aOutCodecs.AppendElement(token);
     423             :   }
     424           0 :   if (expectMoreTokens) {
     425             :     // Last codec name was empty
     426           0 :     return false;
     427             :   }
     428           0 :   return true;
     429             : }
     430             : 
     431             : bool
     432           0 : ParseMIMETypeString(const nsAString& aMIMEType,
     433             :                     nsString& aOutContainerType,
     434             :                     nsTArray<nsString>& aOutCodecs)
     435             : {
     436           0 :   nsContentTypeParser parser(aMIMEType);
     437           0 :   nsresult rv = parser.GetType(aOutContainerType);
     438           0 :   if (NS_FAILED(rv)) {
     439           0 :     return false;
     440             :   }
     441             : 
     442           0 :   nsString codecsStr;
     443           0 :   parser.GetParameter("codecs", codecsStr);
     444           0 :   return ParseCodecsString(codecsStr, aOutCodecs);
     445             : }
     446             : 
     447             : bool
     448           0 : IsH264CodecString(const nsAString& aCodec)
     449             : {
     450           0 :   int16_t profile = 0;
     451           0 :   int16_t level = 0;
     452           0 :   return ExtractH264CodecDetails(aCodec, profile, level);
     453             : }
     454             : 
     455             : bool
     456           0 : IsAACCodecString(const nsAString& aCodec)
     457             : {
     458             :   return
     459           0 :     aCodec.EqualsLiteral("mp4a.40.2") || // MPEG4 AAC-LC
     460           0 :     aCodec.EqualsLiteral("mp4a.40.5") || // MPEG4 HE-AAC
     461           0 :     aCodec.EqualsLiteral("mp4a.67") || // MPEG2 AAC-LC
     462           0 :     aCodec.EqualsLiteral("mp4a.40.29");  // MPEG4 HE-AACv2
     463             : }
     464             : 
     465             : bool
     466           0 : IsVP8CodecString(const nsAString& aCodec)
     467             : {
     468           0 :   return aCodec.EqualsLiteral("vp8") ||
     469           0 :          aCodec.EqualsLiteral("vp8.0");
     470             : }
     471             : 
     472             : bool
     473           0 : IsVP9CodecString(const nsAString& aCodec)
     474             : {
     475           0 :   return aCodec.EqualsLiteral("vp9") ||
     476           0 :          aCodec.EqualsLiteral("vp9.0");
     477             : }
     478             : 
     479             : template <int N>
     480             : static bool
     481           0 : StartsWith(const nsACString& string, const char (&prefix)[N])
     482             : {
     483           0 :     if (N - 1 > string.Length()) {
     484           0 :       return false;
     485             :     }
     486           0 :     return memcmp(string.Data(), prefix, N - 1) == 0;
     487             : }
     488             : 
     489             : UniquePtr<TrackInfo>
     490           0 : CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType)
     491             : {
     492           0 :   UniquePtr<TrackInfo> trackInfo;
     493           0 :   if (StartsWith(aCodecMIMEType, "audio/")) {
     494           0 :     trackInfo.reset(new AudioInfo());
     495           0 :     trackInfo->mMimeType = aCodecMIMEType;
     496           0 :   } else if (StartsWith(aCodecMIMEType, "video/")) {
     497           0 :     trackInfo.reset(new VideoInfo());
     498           0 :     trackInfo->mMimeType = aCodecMIMEType;
     499             :   }
     500           0 :   return trackInfo;
     501             : }
     502             : 
     503             : UniquePtr<TrackInfo>
     504           0 : CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
     505             :   const nsACString& aCodecMIMEType,
     506             :   const MediaContainerType& aContainerType)
     507             : {
     508           0 :   UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aCodecMIMEType);
     509           0 :   if (trackInfo) {
     510           0 :     VideoInfo* videoInfo = trackInfo->GetAsVideoInfo();
     511           0 :     if (videoInfo) {
     512           0 :       Maybe<int32_t> maybeWidth = aContainerType.ExtendedType().GetWidth();
     513           0 :       if (maybeWidth && *maybeWidth > 0) {
     514           0 :         videoInfo->mImage.width = *maybeWidth;
     515             :       }
     516           0 :       Maybe<int32_t> maybeHeight = aContainerType.ExtendedType().GetHeight();
     517           0 :       if (maybeHeight && *maybeHeight > 0) {
     518           0 :         videoInfo->mImage.height = *maybeHeight;
     519             :       }
     520             :     }
     521             :   }
     522           0 :   return trackInfo;
     523             : }
     524             : 
     525             : } // end namespace mozilla

Generated by: LCOV version 1.13