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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "AOMDecoder.h"
       8             : #include "MediaResult.h"
       9             : #include "TimeUnits.h"
      10             : #include "aom/aomdx.h"
      11             : #include "gfx2DGlue.h"
      12             : #include "mozilla/PodOperations.h"
      13             : #include "mozilla/SyncRunnable.h"
      14             : #include "nsError.h"
      15             : #include "prsystem.h"
      16             : 
      17             : #include <algorithm>
      18             : 
      19             : #undef LOG
      20             : #define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("AOMDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
      21             : #define LOG_RESULT(code, message, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("AOMDecoder::%s: %s (code %d) " message, __func__, aom_codec_err_to_string(code), (int)code, ##__VA_ARGS__))
      22             : 
      23             : namespace mozilla {
      24             : 
      25             : using namespace gfx;
      26             : using namespace layers;
      27             : 
      28             : 
      29             : static MediaResult
      30           0 : InitContext(aom_codec_ctx_t* aCtx,
      31             :             const VideoInfo& aInfo)
      32             : {
      33           0 :   aom_codec_iface_t* dx = aom_codec_av1_dx();
      34           0 :   if (!dx) {
      35             :     return MediaResult(NS_ERROR_FAILURE,
      36           0 :                        RESULT_DETAIL("Couldn't get AV1 decoder interface."));
      37             :   }
      38             : 
      39           0 :   int decode_threads = 2;
      40           0 :   if (aInfo.mDisplay.width >= 2048) {
      41           0 :     decode_threads = 8;
      42             :   }
      43           0 :   else if (aInfo.mDisplay.width >= 1024) {
      44           0 :     decode_threads = 4;
      45             :   }
      46           0 :   decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors());
      47             : 
      48             :   aom_codec_dec_cfg_t config;
      49           0 :   PodZero(&config);
      50           0 :   config.threads = decode_threads;
      51           0 :   config.w = config.h = 0; // set after decode
      52             : 
      53           0 :   aom_codec_flags_t flags = 0;
      54             : 
      55           0 :   auto res = aom_codec_dec_init(aCtx, dx, &config, flags);
      56           0 :   if (res != AOM_CODEC_OK) {
      57           0 :     LOG_RESULT(res, "Codec initialization failed!");
      58             :     return MediaResult(NS_ERROR_FAILURE,
      59           0 :                        RESULT_DETAIL("AOM error initializing AV1 decoder: %s",
      60           0 :                                      aom_codec_err_to_string(res)));
      61             :   }
      62           0 :   return NS_OK;
      63             : }
      64             : 
      65           0 : AOMDecoder::AOMDecoder(const CreateDecoderParams& aParams)
      66           0 :   : mImageContainer(aParams.mImageContainer)
      67           0 :   , mTaskQueue(aParams.mTaskQueue)
      68           0 :   , mInfo(aParams.VideoConfig())
      69             : {
      70           0 :   PodZero(&mCodec);
      71           0 : }
      72             : 
      73           0 : AOMDecoder::~AOMDecoder()
      74             : {
      75           0 : }
      76             : 
      77             : RefPtr<ShutdownPromise>
      78           0 : AOMDecoder::Shutdown()
      79             : {
      80           0 :   RefPtr<AOMDecoder> self = this;
      81           0 :   return InvokeAsync(mTaskQueue, __func__, [self, this]() {
      82           0 :     auto res = aom_codec_destroy(&mCodec);
      83           0 :     if (res != AOM_CODEC_OK) {
      84           0 :       LOG_RESULT(res, "aom_codec_destroy");
      85             :     }
      86           0 :     return ShutdownPromise::CreateAndResolve(true, __func__);
      87           0 :   });
      88             : }
      89             : 
      90             : RefPtr<MediaDataDecoder::InitPromise>
      91           0 : AOMDecoder::Init()
      92             : {
      93           0 :   if (NS_FAILED(InitContext(&mCodec, mInfo))) {
      94             :     return AOMDecoder::InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
      95           0 :                                                     __func__);
      96             :   }
      97             :   return AOMDecoder::InitPromise::CreateAndResolve(TrackInfo::kVideoTrack,
      98           0 :                                                    __func__);
      99             : }
     100             : 
     101             : RefPtr<MediaDataDecoder::FlushPromise>
     102           0 : AOMDecoder::Flush()
     103             : {
     104           0 :   return InvokeAsync(mTaskQueue, __func__, []() {
     105             :     return FlushPromise::CreateAndResolve(true, __func__);
     106           0 :   });
     107             : }
     108             : 
     109             : RefPtr<MediaDataDecoder::DecodePromise>
     110           0 : AOMDecoder::ProcessDecode(MediaRawData* aSample)
     111             : {
     112           0 :   MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     113             : 
     114             : #if defined(DEBUG)
     115           0 :   NS_ASSERTION(IsKeyframe(*aSample) == aSample->mKeyframe,
     116             :                "AOM Decode Keyframe error sample->mKeyframe and si.si_kf out of sync");
     117             : #endif
     118             : 
     119           0 :   if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr, 0)) {
     120           0 :     LOG_RESULT(r, "Decode error!");
     121             :     return DecodePromise::CreateAndReject(
     122           0 :       MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
     123           0 :                   RESULT_DETAIL("AOM error decoding AV1 sample: %s",
     124             :                                 aom_codec_err_to_string(r))),
     125           0 :       __func__);
     126             :   }
     127             : 
     128           0 :   aom_codec_iter_t iter = nullptr;
     129             :   aom_image_t *img;
     130           0 :   DecodedData results;
     131             : 
     132           0 :   while ((img = aom_codec_get_frame(&mCodec, &iter))) {
     133           0 :     NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 ||
     134             :                  img->fmt == AOM_IMG_FMT_I444,
     135             :                  "WebM image format not I420 or I444");
     136             : 
     137             :     // Chroma shifts are rounded down as per the decoding examples in the SDK
     138           0 :     VideoData::YCbCrBuffer b;
     139           0 :     b.mPlanes[0].mData = img->planes[0];
     140           0 :     b.mPlanes[0].mStride = img->stride[0];
     141           0 :     b.mPlanes[0].mHeight = img->d_h;
     142           0 :     b.mPlanes[0].mWidth = img->d_w;
     143           0 :     b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;
     144             : 
     145           0 :     b.mPlanes[1].mData = img->planes[1];
     146           0 :     b.mPlanes[1].mStride = img->stride[1];
     147           0 :     b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
     148             : 
     149           0 :     b.mPlanes[2].mData = img->planes[2];
     150           0 :     b.mPlanes[2].mStride = img->stride[2];
     151           0 :     b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
     152             : 
     153           0 :     if (img->fmt == AOM_IMG_FMT_I420) {
     154           0 :       b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
     155           0 :       b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
     156             : 
     157           0 :       b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift;
     158           0 :       b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift;
     159           0 :     } else if (img->fmt == AOM_IMG_FMT_I444) {
     160           0 :       b.mPlanes[1].mHeight = img->d_h;
     161           0 :       b.mPlanes[1].mWidth = img->d_w;
     162             : 
     163           0 :       b.mPlanes[2].mHeight = img->d_h;
     164           0 :       b.mPlanes[2].mWidth = img->d_w;
     165             :     } else {
     166           0 :       LOG("AOM Unknown image format");
     167             :       return DecodePromise::CreateAndReject(
     168           0 :         MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
     169           0 :                     RESULT_DETAIL("AOM Unknown image format")),
     170           0 :         __func__);
     171             :     }
     172             : 
     173           0 :     RefPtr<VideoData> v;
     174           0 :     v = VideoData::CreateAndCopyData(mInfo,
     175             :                                      mImageContainer,
     176             :                                      aSample->mOffset,
     177             :                                      aSample->mTime,
     178             :                                      aSample->mDuration,
     179             :                                      b,
     180           0 :                                      aSample->mKeyframe,
     181             :                                      aSample->mTimecode,
     182           0 :                                      mInfo.ScaledImageRect(img->d_w,
     183           0 :                                                            img->d_h));
     184             : 
     185           0 :     if (!v) {
     186           0 :       LOG(
     187             :         "Image allocation error source %ux%u display %ux%u picture %ux%u",
     188             :         img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height,
     189             :         mInfo.mImage.width, mInfo.mImage.height);
     190             :       return DecodePromise::CreateAndReject(
     191           0 :         MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
     192             :     }
     193           0 :     results.AppendElement(Move(v));
     194             :   }
     195           0 :   return DecodePromise::CreateAndResolve(Move(results), __func__);
     196             : }
     197             : 
     198             : RefPtr<MediaDataDecoder::DecodePromise>
     199           0 : AOMDecoder::Decode(MediaRawData* aSample)
     200             : {
     201             :   return InvokeAsync<MediaRawData*>(mTaskQueue, this, __func__,
     202           0 :                                     &AOMDecoder::ProcessDecode, aSample);
     203             : }
     204             : 
     205             : RefPtr<MediaDataDecoder::DecodePromise>
     206           0 : AOMDecoder::Drain()
     207             : {
     208           0 :   return InvokeAsync(mTaskQueue, __func__, [] {
     209           0 :     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
     210           0 :   });
     211             : }
     212             : 
     213             : 
     214             : /* static */
     215             : bool
     216           0 : AOMDecoder::IsAV1(const nsACString& aMimeType)
     217             : {
     218           0 :   return aMimeType.EqualsLiteral("video/webm; codecs=av1")
     219           0 :          || aMimeType.EqualsLiteral("video/av1");
     220             : }
     221             : 
     222             : /* static */
     223             : bool
     224           0 : AOMDecoder::IsSupportedCodec(const nsAString& aCodecType)
     225             : {
     226             :   // While AV1 is under development, we describe support
     227             :   // for a specific aom commit hash so sites can check
     228             :   // compatibility.
     229           0 :   auto version = NS_ConvertASCIItoUTF16("av1.experimental.");
     230           0 :   version.AppendLiteral("aadbb0251996c8ebb8310567bea330ab7ae9abe4");
     231           0 :   return aCodecType.EqualsLiteral("av1") ||
     232           0 :          aCodecType.Equals(version);
     233             : }
     234             : 
     235             : /* static */
     236             : bool
     237           0 : AOMDecoder::IsKeyframe(Span<const uint8_t> aBuffer) {
     238             :   aom_codec_stream_info_t info;
     239           0 :   PodZero(&info);
     240             : 
     241           0 :   auto res = aom_codec_peek_stream_info(aom_codec_av1_dx(),
     242             :                                         aBuffer.Elements(),
     243           0 :                                         aBuffer.Length(),
     244           0 :                                         &info);
     245           0 :   if (res != AOM_CODEC_OK) {
     246           0 :     LOG_RESULT(res, "couldn't get keyframe flag with aom_codec_peek_stream_info");
     247           0 :     return false;
     248             :   }
     249             : 
     250           0 :   return bool(info.is_kf);
     251             : }
     252             : 
     253             : /* static */
     254             : nsIntSize
     255           0 : AOMDecoder::GetFrameSize(Span<const uint8_t> aBuffer) {
     256             :   aom_codec_stream_info_t info;
     257           0 :   PodZero(&info);
     258             : 
     259           0 :   auto res = aom_codec_peek_stream_info(aom_codec_av1_dx(),
     260             :                                         aBuffer.Elements(),
     261           0 :                                         aBuffer.Length(),
     262           0 :                                         &info);
     263           0 :   if (res != AOM_CODEC_OK) {
     264           0 :     LOG_RESULT(res, "couldn't get frame size with aom_codec_peek_stream_info");
     265             :   }
     266             : 
     267           0 :   return nsIntSize(info.w, info.h);
     268             : }
     269             : 
     270             : } // namespace mozilla
     271             : #undef LOG

Generated by: LCOV version 1.13