Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/media/platforms/ffmpeg/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 16 kB image not shown  

Quelle  FFmpegVideoDecoder.h

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef FFmpegVideoDecoder_h_
#define FFmpegVideoDecoder_h_

#include <atomic>

#include "AndroidSurfaceTexture.h"
#include "FFmpegDataDecoder.h"
#include "FFmpegLibWrapper.h"
#include "ImageContainer.h"
#include "PerformanceRecorder.h"
#include "SimpleMap.h"
#include "nsTHashMap.h"
#if defined(MOZ_USE_HWDECODE) && defined(MOZ_WIDGET_GTK)
#  include "FFmpegVideoFramePool.h"
#  if LIBAVCODEC_VERSION_MAJOR >= 60 && !defined(FFVPX_VERSION)
#    include "VulkanDeviceHolder.h"
#  endif
#endif
#include "libavutil/pixfmt.h"
#if LIBAVCODEC_VERSION_MAJOR < 54
#  define AVPixelFormat PixelFormat
#endif

#ifdef MOZ_WIDGET_ANDROID
#  include "mozilla/java/GeckoSurfaceWrappers.h"
#endif

#if LIBAVCODEC_VERSION_MAJOR >= 57 && LIBAVUTIL_VERSION_MAJOR >= 56
#  define CUSTOMIZED_BUFFER_ALLOCATION 1
#  ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
#    define CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
#  endif
#endif

#ifdef CUSTOMIZED_BUFFER_ALLOCATION
#  include "mozilla/layers/TextureClient.h"
#endif

#ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
#  include "mozilla/DataMutex.h"
#  include "nsTHashSet.h"
#endif

#if LIBAVCODEC_VERSION_MAJOR < 58 || defined(MOZ_WIDGET_ANDROID)
#  define MOZ_FFMPEG_USE_INPUT_INFO_MAP
#endif

struct _VADRMPRIMESurfaceDescriptor;
typedef struct _VADRMPRIMESurfaceDescriptor VADRMPRIMESurfaceDescriptor;

struct AVHWFramesContext;
struct AVFrame;
#if LIBAVCODEC_VERSION_MAJOR >= 60 && !defined(FFVPX_VERSION)
#  include <vulkan/vulkan.h>
#endif

namespace mozilla {
namespace layers {
class BufferRecycleBin;
}

#ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
class ImageBufferTracker;
class ImageBufferWrapper;
#endif

#ifdef MOZ_ENABLE_D3D11VA
class DXVA2Manager;
#endif

template <int V>
class FFmpegVideoDecoder : public FFmpegDataDecoder<V> {};

template <>
class FFmpegVideoDecoder<LIBAV_VER>;
DDLoggedTypeNameAndBase(FFmpegVideoDecoder<LIBAV_VER>,
                        FFmpegDataDecoder<LIBAV_VER>);

template <>
class FFmpegVideoDecoder<LIBAV_VER>
    : public FFmpegDataDecoder<LIBAV_VER>,
      public DecoderDoctorLifeLogger<FFmpegVideoDecoder<LIBAV_VER>> {
  typedef mozilla::layers::Image Image;
  typedef mozilla::layers::ImageContainer ImageContainer;
  typedef mozilla::layers::KnowsCompositor KnowsCompositor;

 public:
  FFmpegVideoDecoder(const FFmpegLibWrapper* aLib, const VideoInfo& aConfig,
                     KnowsCompositor* aAllocator,
                     ImageContainer* aImageContainer, bool aLowLatency,
                     bool aDisableHardwareDecoding, bool a8BitOutput,
                     Maybe<TrackingId> aTrackingId, PRemoteCDMActor* aCDM);

  ~FFmpegVideoDecoder();

  RefPtr<InitPromise> Init() override;
  void InitCodecContext() MOZ_REQUIRES(sMutex) override;
  nsCString GetDescriptionName() const override {
#ifdef USING_MOZFFVPX
    return "ffvpx video decoder"_ns;
#else
    return "ffmpeg video decoder"_ns;
#endif
  }
  nsCString GetCodecName() const override;
  ConversionRequired NeedsConversion() const override {
#ifdef MOZ_WIDGET_ANDROID
    return mCodecID == AV_CODEC_ID_H264 || mCodecID == AV_CODEC_ID_HEVC
               ? ConversionRequired::kNeedAnnexB
               : ConversionRequired::kNeedNone;
#else
#  if LIBAVCODEC_VERSION_MAJOR >= 55
    if (mCodecID == AV_CODEC_ID_HEVC) {
      return ConversionRequired::kNeedHVCC;
    }
#  endif
    return mCodecID == AV_CODEC_ID_H264 ? ConversionRequired::kNeedAVCC
                                        : ConversionRequired::kNeedNone;
#endif
  }

#ifdef MOZ_WIDGET_ANDROID
  Maybe<MediaDataDecoder::PropertyValue> GetDecodeProperty(
      MediaDataDecoder::PropertyName aName) const override;
#endif

  static AVCodecID GetCodecId(const nsACString& aMimeType);

#ifdef CUSTOMIZED_BUFFER_ALLOCATION
  int GetVideoBuffer(struct AVCodecContext* aCodecContext, AVFrame* aFrame,
                     int aFlags);
  int GetVideoBufferDefault(struct AVCodecContext* aCodecContext,
                            AVFrame* aFrame, int aFlags) {
    mIsUsingShmemBufferForDecode = Some(false);
    return mLib->avcodec_default_get_buffer2(aCodecContext, aFrame, aFlags);
  }
#endif
  bool IsHardwareAccelerated() const {
    nsAutoCString dummy;
    return IsHardwareAccelerated(dummy);
  }

 private:
  RefPtr<FlushPromise> ProcessFlush() override;
  void ProcessShutdown() override;
  MediaResult DoDecode(MediaRawData* aSample, uint8_t* aData, int aSize,
                       bool* aGotFrame, DecodedData& aResults) override;
  void OutputDelayedFrames();
  bool NeedParser() const override {
    return
#if LIBAVCODEC_VERSION_MAJOR >= 58
        false;
#else
#  if LIBAVCODEC_VERSION_MAJOR >= 55
        mCodecID == AV_CODEC_ID_VP9 ||
#  endif
        mCodecID == AV_CODEC_ID_VP8;
#endif
  }
  gfx::ColorDepth GetColorDepth(const AVPixelFormat& aFormat) const;
  gfx::YUVColorSpace GetFrameColorSpace() const;
  gfx::ColorSpace2 GetFrameColorPrimaries() const;
  gfx::ColorRange GetFrameColorRange() const;
  gfx::SurfaceFormat GetSurfaceFormat() const;

  MediaResult CreateImage(int64_t aOffset, int64_t aPts, int64_t aDuration,
                          MediaDataDecoder::DecodedData& aResults);

  bool IsHardwareAccelerated(nsACString& aFailureReason) const override;

#ifdef CUSTOMIZED_BUFFER_ALLOCATION
  layers::TextureClient* AllocateTextureClientForImage(
      struct AVCodecContext* aCodecContext, layers::PlanarYCbCrImage* aImage);

  gfx::IntSize GetAlignmentVideoFrameSize(struct AVCodecContext* aCodecContext,
                                          int32_t aWidth,
                                          int32_t aHeight) const;
#endif

  RefPtr<KnowsCompositor> mImageAllocator;
  RefPtr<ImageContainer> mImageContainer;
  VideoInfo mInfo;

#ifdef MOZ_USE_HWDECODE
 public:
  static AVCodec* FindVideoHardwareAVCodec(
      const FFmpegLibWrapper* aLib, AVCodecID aCodec,
      AVHWDeviceType aDeviceType = AV_HWDEVICE_TYPE_NONE);

 private:
  // This will be called inside the ctor.
  void InitHWDecoderIfAllowed();

  enum class ContextType {
    D3D11VA,     // Windows
    MediaCodec,  // Android
    VAAPI,       // Linux Desktop
    V4L2,        // Linux embedded
    Vulkan,      // Linux Vulkan Video
  };
  void InitHWCodecContext(ContextType aType);

  bool ShouldDisableHWDecoding(bool aDisableHardwareDecoding) const;

  // True if hardware decoding is disabled explicitly.
  const bool mHardwareDecodingDisabled;
#endif

#ifdef MOZ_ENABLE_D3D11VA
  MediaResult InitD3D11VADecoder();

  MediaResult CreateImageD3D11(int64_t aOffset, int64_t aPts, int64_t aDuration,
                               MediaDataDecoder::DecodedData& aResults);
  bool CanUseZeroCopyVideoFrame() const;

  AVBufferRef* mD3D11VADeviceContext = nullptr;
  RefPtr<ID3D11Device> mDevice;
  UniquePtr<DXVA2Manager> mDXVA2Manager;
  // Number of HW Textures are already in use by Gecko
  std::atomic<uint8_t> mNumOfHWTexturesInUse{0};
#endif

#ifdef MOZ_WIDGET_ANDROID
#  ifdef USING_MOZFFVPX
  MediaResult AllocateExtraData();
  MediaResult AllocateH264ExtraData();
  MediaResult AllocateHEVCExtraData();
#  endif
  MediaResult InitMediaCodecDecoder();
  MediaResult CreateImageMediaCodec(int64_t aOffset, int64_t aPts,
                                    int64_t aTimecode, int64_t aDuration,
                                    MediaDataDecoder::DecodedData& aResults);
  bool ReleaseFrameMediaCodec(void* aKey, bool aRender);
  void ReleaseFramesMediaCodec();
  int32_t mTextureAlignment;
  AVBufferRef* mMediaCodecDeviceContext = nullptr;
  java::GeckoSurface::GlobalRef mSurface;
  AndroidSurfaceTextureHandle mSurfaceHandle{};
  SimpleMap<void*, AVFrame*, ThreadSafePolicy> mFrameMap;
#endif

#if defined(MOZ_USE_HWDECODE) && defined(MOZ_WIDGET_GTK)
  bool UploadSWDecodeToDMABuf() const;
  bool IsLinuxHDR() const;
  MediaResult InitVAAPIDecoder();
  MediaResult InitV4L2Decoder();
#  if LIBAVCODEC_VERSION_MAJOR >= 60 && !defined(FFVPX_VERSION)
  MediaResult InitVulkanDecoder();

#    include "FFmpegVulkanVideoDecoder.h"
#  endif
  bool CreateVAAPIDeviceContext();
#  if LIBAVCODEC_VERSION_MAJOR >= 60 && !defined(FFVPX_VERSION)
  bool CreateVulkanDeviceContext(const StaticMutexAutoLock& aProofOfLock);
  void PrepareVulkanDrmModifiersForSwFormat(int aSwFormat,
                                            VkImageUsageFlags aImageUsages);
#  endif
  bool GetVAAPISurfaceDescriptor(VADRMPRIMESurfaceDescriptor* aVaDesc);
  void AddAcceleratedFormats(nsTArray<AVCodecID>& aCodecList,
                             AVCodecID aCodecID, AVVAAPIHWConfig* hwconfig);
  nsTArray<AVCodecID> GetAcceleratedFormats();
  bool IsFormatAccelerated(AVCodecID aCodecID) const;

  MediaResult CreateImageVAAPI(int64_t aOffset, int64_t aPts, int64_t aDuration,
                               MediaDataDecoder::DecodedData& aResults);
  MediaResult CreateImageV4L2(int64_t aOffset, int64_t aPts, int64_t aDuration,
                              MediaDataDecoder::DecodedData& aResults);
#  if LIBAVCODEC_VERSION_MAJOR >= 60 && !defined(FFVPX_VERSION)
 public:
  int ChooseVulkanPixelFormatFromContext(struct AVCodecContext* aCodecContext,
                                         const int* aFormats);

 private:
  MediaResult CreateImageVulkan(int64_t aOffset, int64_t aPts,
                                int64_t aDuration,
                                MediaDataDecoder::DecodedData& aResults);
#  endif
  void AdjustHWDecodeLogging();

  AVBufferRef* mVAAPIDeviceContext = nullptr;
  AVBufferRef* mVulkanDeviceContext = nullptr;
#  if LIBAVCODEC_VERSION_MAJOR >= 60 && !defined(FFVPX_VERSION)
  RefPtr<VulkanDeviceHolder> mVulkanDeviceHolder;
  FFmpegVulkanVideoDecoder mVulkanDecoder;
  VkImageDrmFormatModifierListCreateInfoEXT mVulkanDrmModifierList = {};
  VkImageFormatListCreateInfo mVulkanImageFormatList = {};
  VkMemoryDedicatedAllocateInfo mVulkanAllocPnextDedicated[2] = {};
  bool mVulkanDecodeUsesDrmModifier = false;
  bool mVulkanTilingSettled = false;
#  endif
  bool mUsingV4L2 = false;
  // If video overlay is used we want to upload SW decoded frames to
  // DMABuf and present it as a external texture to rendering pipeline.
  bool mUploadSWDecodeToDMABuf = false;
  VADisplay mDisplay = nullptr;
  UniquePtr<VideoFramePool<LIBAV_VER>> mVideoFramePool;
  static nsTArray<AVCodecID> mAcceleratedFormats;
#endif

#if LIBAVCODEC_VERSION_MAJOR >= 58
  class DecodeStats {
   public:
    void DecodeStart();
    void UpdateDecodeTimes(int64_t aDuration);
    bool IsDecodingSlow() const;

   private:
    uint32_t mDecodedFrames = 0;

    double mAverageFrameDecodeTime = 0;
    double mAverageFrameDuration = 0;

    // Number of delayed frames until we consider decoding as slow.
    const uint32_t mMaxLateDecodedFrames = 15;
    // How many frames is decoded behind its pts time, i.e. video decode lags.
    uint32_t mDecodedFramesLate = 0;

    // Reset mDecodedFramesLate every 3 seconds of correct playback.
    const uint32_t mDelayedFrameReset = 3000;

    uint32_t mLastDelayedFrameNum = 0;

    TimeStamp mDecodeStart;
  };

  DecodeStats mDecodeStats;
#endif

#if LIBAVCODEC_VERSION_MAJOR >= 58
  bool mHasSentDrainPacket = false;
#endif

#if LIBAVCODEC_VERSION_MAJOR < 58
  class PtsCorrectionContext {
   public:
    PtsCorrectionContext();
    int64_t GuessCorrectPts(int64_t aPts, int64_t aDts);
    void Reset();
    int64_t LastDts() const { return mLastDts; }

   private:
    int64_t mNumFaultyPts;  /// Number of incorrect PTS values so far
    int64_t mNumFaultyDts;  /// Number of incorrect DTS values so far
    int64_t mLastPts;       /// PTS of the last frame
    int64_t mLastDts;       /// DTS of the last frame
  };

  PtsCorrectionContext mPtsContext;
#endif

#ifdef MOZ_FFMPEG_USE_INPUT_INFO_MAP
  struct InputInfo {
    explicit InputInfo(const MediaRawData* aSample)
        : mDuration(aSample->mDuration.ToMicroseconds())
#  ifdef MOZ_WIDGET_ANDROID
          ,
          mTimecode(aSample->mTimecode.ToMicroseconds())
#  endif
    {
    }

    int64_t mDuration;
#  ifdef MOZ_WIDGET_ANDROID
    int64_t mTimecode;
#  endif
  };

  SimpleMap<int64_t, InputInfo, ThreadSafePolicy> mInputInfo;

  static int64_t GetSampleInputKey(const MediaRawData* aSample) {
#  ifdef MOZ_WIDGET_ANDROID
    return aSample->mTime.ToMicroseconds();
#  else
    return aSample->mTimecode.ToMicroseconds();
#  endif
  }

  static int64_t GetFrameInputKey(const AVFrame* aFrame) {
#  ifdef MOZ_WIDGET_ANDROID
    return aFrame->pts;
#  else
    return aFrame->pkt_dts;
#  endif
  }

  void InsertInputInfo(const MediaRawData* aSample) {
    // LibAV provides no API to retrieve the decoded sample's duration.
    // (FFmpeg >= 1.0 provides av_frame_get_pkt_duration)
    // Additionally some platforms (e.g. Android) do not supply a valid duration
    // after decoding. As such we instead use a map using the given ts as key
    // that we will retrieve later. The map will have a typical size of 16
    // entry.
    mInputInfo.Insert(GetSampleInputKey(aSample), InputInfo(aSample));
  }

  void TakeInputInfo(const AVFrame* aFrame, InputInfo& aEntry) {
    // Retrieve duration from the given ts.
    // We use the first entry found matching this ts (this is done to
    // handle damaged file with multiple frames with the same ts)
    if (Maybe<InputInfo> v = mInputInfo.Take(GetFrameInputKey(aFrame))) {
      aEntry = v.extract();
    } else {
      NS_WARNING("Unable to retrieve input info from map");
      // dts are probably incorrectly reported ; so clear the map as we're
      // unlikely to find them in the future anyway. This also guards
      // against the map becoming extremely big.
      mInputInfo.Clear();
    }
  }
#endif

  const bool mLowLatency;
  const Maybe<TrackingId> mTrackingId;

  void RecordFrame(const MediaRawData* aSample, const MediaData* aData);

  PerformanceRecorderMulti<DecodeStage> mPerformanceRecorder;

  bool MaybeQueueDrain(const MediaDataDecoder::DecodedData& aData);
#ifdef MOZ_WIDGET_ANDROID
  void QueueResumeDrain();
  void ResumeDrain();

  Atomic<bool> mShouldResumeDrain{false};
#endif

  // True if we're allocating shmem for ffmpeg decode buffer.
  Maybe<Atomic<bool>> mIsUsingShmemBufferForDecode;

#ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
  // Used to explicitly track allocated images to ensure they are all released
  // by ffmpeg after shutdown.
  RefPtr<ImageBufferTracker> mImageTracker;
#endif

  // Convert dav1d output to 8-bit when GPU doesn't support higher bit images.
  // See bug 1970771 for details.
  Atomic<bool> m8BitOutput;
  RefPtr<layers::BufferRecycleBin> m8BitRecycleBin;
};

#ifdef CUSTOMIZED_BUFFER_ALLOCATION
#  ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
class ImageBufferTracker {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageBufferTracker)

  ImageBufferTracker() = default;

  void Insert(ImageBufferWrapper* aImage) {
    auto lock = mAllocatedImages.Lock();
    lock->Insert(aImage);
  }

  void Remove(ImageBufferWrapper* aImage) {
    auto lock = mAllocatedImages.Lock();
    lock->Remove(aImage);
  }

  bool IsEmpty() const {
    auto lock = mAllocatedImages.Lock();
    return lock->IsEmpty();
  }

 private:
  ~ImageBufferTracker() = default;

  mutable DataMutex<nsTHashSet<ImageBufferWrapper*>> mAllocatedImages{
      "ImageBufferTracker::mAllocatedImages"};
};
#  endif

class ImageBufferWrapper final {
 public:
  typedef mozilla::layers::Image Image;

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageBufferWrapper)

#  ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
  ImageBufferWrapper(RefPtr<Image>&& aImage, ImageBufferTracker* aTracker)
      : mImage(std::move(aImage)), mTracker(aTracker) {
    MOZ_ASSERT(mImage);
    MOZ_ASSERT(mTracker);
  }
#  else
  explicit ImageBufferWrapper(RefPtr<Image>&& aImage)
      : mImage(std::move(aImage)) {
    MOZ_ASSERT(mImage);
  }
#  endif

  Image* AsImage() { return mImage; }

  void StartTracking() {
#  ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
    mTracker->Insert(this);
#  endif
  }

  void StopTracking() {
#  ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
    mTracker->Remove(this);
#  endif
  }

 private:
  ~ImageBufferWrapper() = default;
  const RefPtr<Image> mImage;
#  ifdef CUSTOMIZED_BUFFER_ALLOCATION_ASSERT_ENABLED
  const RefPtr<ImageBufferTracker> mTracker;
#  endif
};
#endif

}  // namespace mozilla

#endif  // FFmpegVideoDecoder_h_

Messung V0.5 in Prozent
C=93 H=100 G=96

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-08-22) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.