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

Quelle  FuzzMedia.cpp

  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/. */


#include "ADTSDemuxer.h"
#include "BufferMediaResource.h"
#include "FlacDemuxer.h"
#include "FuzzingInterface.h"
#include "MP3Demuxer.h"
#include "MP4Demuxer.h"
#include "MediaDataDecoderProxy.h"
#include "OggDemuxer.h"
#include "PDMFactory.h"
#include "PlatformDecoderModule.h"
#include "QueueObject.h"
#include "WaveDemuxer.h"
#include "WebMDemuxer.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/gfx/gfxVars.h"
#include "systemservices/MediaUtils.h"

using namespace mozilla;

class Benchmark;

class BenchmarkPlayback : public QueueObject {
  friend class Benchmark;
  BenchmarkPlayback(Benchmark* aGlobalState, MediaDataDemuxer* aDemuxer);
  void DemuxSamples();
  void DemuxNextSample();
  void GlobalShutdown();
  void InitDecoder(UniquePtr<TrackInfo>&& aInfo);

  void Output(MediaDataDecoder::DecodedData&& aResults);
  void Error(const MediaResult& aError);
  void InputExhausted();

  // Shutdown trackdemuxer and demuxer if any and shutdown the task queues.
  void FinalizeShutdown();

  Atomic<Benchmark*> mGlobalState;

  RefPtr<TaskQueue> mDecoderTaskQueue;
  RefPtr<MediaDataDecoder> mDecoder;

  // Object only accessed on Thread()
  RefPtr<MediaDataDemuxer> mDemuxer;
  RefPtr<MediaTrackDemuxer> mTrackDemuxer;
  nsTArray<RefPtr<MediaRawData>> mSamples;
  UniquePtr<TrackInfo> mInfo;
  size_t mSampleIndex;
  Maybe<TimeStamp> mDecodeStartTime;
  uint32_t mFrameCount;
  bool mFinished;
  bool mDrained;
  // Settled by Output()/Error(); delivered to mPromise from FinalizeShutdown
  // so the consumer cannot observe completion before cleanup is done.
  Maybe<MozPromise<uint32_t, MediaResult, true>::ResolveOrRejectValue>
      mFinalResult;
};

// Init() must have been called at least once prior on the
// main thread.
class Benchmark : public QueueObject {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Benchmark)

  struct Parameters {
    Parameters()
        : mFramesToMeasure(UINT32_MAX),
          mStartupFrame(1),
          mTimeout(TimeDuration::Forever()) {}

    Parameters(uint32_t aFramesToMeasure, uint32_t aStartupFrame,
               uint32_t aStopAtFrame, const TimeDuration& aTimeout)
        : mFramesToMeasure(aFramesToMeasure),
          mStartupFrame(aStartupFrame),
          mStopAtFrame(Some(aStopAtFrame)),
          mTimeout(aTimeout) {}

    const uint32_t mFramesToMeasure;
    const uint32_t mStartupFrame;
    const Maybe<uint32_t> mStopAtFrame;
    const TimeDuration mTimeout;
  };

  typedef MozPromise<uint32_t, MediaResult, /* IsExclusive = */ true>
      BenchmarkPromise;

  explicit Benchmark(MediaDataDemuxer* aDemuxer,
                     const Parameters& aParameters = Parameters());
  RefPtr<BenchmarkPromise> Run();

  // Must be called on the main thread.
  static void Init();

 private:
  friend class BenchmarkPlayback;
  virtual ~Benchmark();
  void Dispose();
  const Parameters mParameters;
  RefPtr<Benchmark> mKeepAliveUntilComplete;
  BenchmarkPlayback mPlaybackState;
  MozPromiseHolder<BenchmarkPromise> mPromise;
};

class FuzzRunner {
 public:
  explicit FuzzRunner(Benchmark* aBenchmark) : mBenchmark(aBenchmark) {}

  void Run() {
    // Assert we're on the main thread, otherwise `done` must be synchronized.
    MOZ_ASSERT(NS_IsMainThread());
    bool done = false;

    Benchmark::Init();
    mBenchmark->Run()->Then(
        // Non DocGroup-version of AbstractThread::MainThread() is fine for
        // testing.
        AbstractThread::MainThread(), __func__,
        [&](uint32_t aDecodeFps) { done = true; }, [&]() { done = true; });

    // Wait until benchmark completes.
    SpinEventLoopUntil("FuzzRunner::Run"_ns, [&]() { return done; });
  }

 private:
  RefPtr<Benchmark> mBenchmark;
};

Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters)
    : QueueObject(
          TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
                            "Benchmark::QueueObject")),
      mParameters(aParameters),
      mPlaybackState(this, aDemuxer) {
  MOZ_COUNT_CTOR(Benchmark);
}

Benchmark::~Benchmark() { MOZ_COUNT_DTOR(Benchmark); }

RefPtr<Benchmark::BenchmarkPromise> Benchmark::Run() {
  RefPtr<Benchmark> self = this;
  mKeepAliveUntilComplete = this;
  return InvokeAsync(Thread(), __func__, [self] {
    RefPtr<BenchmarkPromise> p = self->mPromise.Ensure(__func__);
    self->mPlaybackState.Dispatch(NS_NewRunnableFunction(
        "Benchmark::Run", [self]() { self->mPlaybackState.DemuxSamples(); }));
    return p;
  });
}

void Benchmark::Dispose() {
  MOZ_ASSERT(OnThread());

  mKeepAliveUntilComplete = nullptr;
}

void Benchmark::Init() {
  MOZ_ASSERT(NS_IsMainThread());
  mozilla::gfx::gfxVars::Initialize();
}

BenchmarkPlayback::BenchmarkPlayback(Benchmark* aGlobalState,
                                     MediaDataDemuxer* aDemuxer)
    : QueueObject(
          TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
                            "BenchmarkPlayback::QueueObject")),
      mGlobalState(aGlobalState),
      mDecoderTaskQueue(TaskQueue::Create(
          GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
          "BenchmarkPlayback::mDecoderTaskQueue")),
      mDemuxer(aDemuxer),
      mSampleIndex(0),
      mFrameCount(0),
      mFinished(false),
      mDrained(false) {}

void BenchmarkPlayback::DemuxSamples() {
  MOZ_ASSERT(OnThread());

  RefPtr<Benchmark> ref(mGlobalState);
  mDemuxer->Init()->Then(
      Thread(), __func__,
      [this, ref](nsresult aResult) {
        MOZ_ASSERT(OnThread());
        if (mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack)) {
          mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
        } else if (mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack)) {
          mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
        }
        if (!mTrackDemuxer) {
          Error(MediaResult(NS_ERROR_FAILURE, "Can't create track demuxer"));
          return;
        }
        DemuxNextSample();
      },
      [this, ref](const MediaResult& aError) { Error(aError); });
}

void BenchmarkPlayback::DemuxNextSample() {
  MOZ_ASSERT(OnThread());

  RefPtr<Benchmark> ref(mGlobalState);
  RefPtr<MediaTrackDemuxer::SamplesPromise> promise =
      mTrackDemuxer->GetSamples();
  promise->Then(
      Thread(), __func__,
      [this, ref](RefPtr<MediaTrackDemuxer::SamplesHolder> aHolder) {
        mSamples.AppendElements(aHolder->GetMovableSamples());
        if (ref->mParameters.mStopAtFrame &&
            mSamples.Length() == ref->mParameters.mStopAtFrame.ref()) {
          InitDecoder(mTrackDemuxer->GetInfo());
        } else {
          Dispatch(
              NS_NewRunnableFunction("BenchmarkPlayback::DemuxNextSample",
                                     [this, ref]() { DemuxNextSample(); }));
        }
      },
      [this, ref](const MediaResult& aError) {
        switch (aError.Code()) {
          case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
            InitDecoder(mTrackDemuxer->GetInfo());
            break;
          default:
            Error(aError);
            break;
        }
      });
}

void BenchmarkPlayback::InitDecoder(UniquePtr<TrackInfo>&& aInfo) {
  MOZ_ASSERT(OnThread());

  if (!aInfo) {
    Error(MediaResult(NS_ERROR_FAILURE, "Invalid TrackInfo"));
    return;
  }

  RefPtr<PDMFactory> platform = new PDMFactory();
  mInfo = std::move(aInfo);
  RefPtr<Benchmark> ref(mGlobalState);
  platform->CreateDecoder(CreateDecoderParams{*mInfo})
      ->Then(
          Thread(), __func__,
          [this, ref](RefPtr<MediaDataDecoder>&& aDecoder) {
            mDecoder = new MediaDataDecoderProxy(
                aDecoder.forget(), do_AddRef(mDecoderTaskQueue.get()));
            mDecoder->Init()->Then(
                Thread(), __func__,
                [this, ref](TrackInfo::TrackType aTrackType) {
                  InputExhausted();
                },
                [this, ref](const MediaResult& aError) { Error(aError); });
          },
          [this, ref](const MediaResult& aError) { Error(aError); });
}

void BenchmarkPlayback::FinalizeShutdown() {
  MOZ_ASSERT(OnThread());

  MOZ_ASSERT(mFinished, "GlobalShutdown must have been run");
  MOZ_ASSERT(!mDecoder, "mDecoder must have been shutdown already");
  MOZ_ASSERT(!mDemuxer, "mDemuxer must have been shutdown already");
  MOZ_DIAGNOSTIC_ASSERT(mDecoderTaskQueue->IsEmpty());
  mDecoderTaskQueue = nullptr;

  RefPtr<Benchmark> ref(mGlobalState);
  auto result = mFinalResult.extract();
  ref->Thread()->Dispatch(NS_NewRunnableFunction(
      "BenchmarkPlayback::FinalizeShutdown", [ref, r = std::move(result)]() {
        ref->mPromise.ResolveOrRejectIfExists(r, __func__);
        ref->Dispose();
      }));
}

void BenchmarkPlayback::GlobalShutdown() {
  MOZ_ASSERT(OnThread());

  MOZ_ASSERT(!mFinished, "We've already shutdown");

  mFinished = true;

  if (mTrackDemuxer) {
    mTrackDemuxer->Reset();
    mTrackDemuxer->BreakCycles();
    mTrackDemuxer = nullptr;
  }
  mDemuxer = nullptr;

  if (mDecoder) {
    RefPtr<Benchmark> ref(mGlobalState);
    mDecoder->Flush()->Then(
        Thread(), __func__,
        [ref, this]() {
          mDecoder->Shutdown()->Then(
              Thread(), __func__, [ref, this]() { FinalizeShutdown(); },
              []() { MOZ_CRASH("not reached"); });
          mDecoder = nullptr;
          mInfo = nullptr;
        },
        []() { MOZ_CRASH("not reached"); });
  } else {
    FinalizeShutdown();
  }
}

void BenchmarkPlayback::Output(MediaDataDecoder::DecodedData&& aResults) {
  MOZ_ASSERT(OnThread());
  MOZ_ASSERT(!mFinished);

  RefPtr<Benchmark> ref(mGlobalState);
  mFrameCount += aResults.Length();
  if (!mDecodeStartTime && mFrameCount >= ref->mParameters.mStartupFrame) {
    mDecodeStartTime = Some(TimeStamp::Now());
  }
  TimeStamp now = TimeStamp::Now();
  uint32_t frames = mFrameCount - ref->mParameters.mStartupFrame;
  TimeDuration elapsedTime = now - mDecodeStartTime.refOr(now);
  if (((frames == ref->mParameters.mFramesToMeasure) &&
       mFrameCount > ref->mParameters.mStartupFrame && frames > 0) ||
      elapsedTime >= ref->mParameters.mTimeout || mDrained) {
    uint32_t decodeFps = frames / elapsedTime.ToSeconds();
    mFinalResult.emplace(
        MozPromise<uint32_t, MediaResult,
                   true>::ResolveOrRejectValue::MakeResolve(decodeFps));
    GlobalShutdown();
  }
}

void BenchmarkPlayback::Error(const MediaResult& aError) {
  MOZ_ASSERT(OnThread());

  mFinalResult.emplace(
      MozPromise<uint32_t, MediaResult, true>::ResolveOrRejectValue::MakeReject(
          aError));
  GlobalShutdown();
}

void BenchmarkPlayback::InputExhausted() {
  MOZ_ASSERT(OnThread());
  MOZ_ASSERT(!mFinished);

  if (mSampleIndex >= mSamples.Length()) {
    Error(MediaResult(NS_ERROR_FAILURE, "Nothing left to decode"));
    return;
  }

  RefPtr<MediaRawData> sample = mSamples[mSampleIndex];
  RefPtr<Benchmark> ref(mGlobalState);
  RefPtr<MediaDataDecoder::DecodePromise> p = mDecoder->Decode(sample);

  mSampleIndex++;
  if (mSampleIndex == mSamples.Length() && !ref->mParameters.mStopAtFrame) {
    // Complete current frame decode then drain if still necessary.
    p->Then(
        Thread(), __func__,
        [ref, this](MediaDataDecoder::DecodedData&& aResults) {
          Output(std::move(aResults));
          if (!mFinished) {
            mDecoder->Drain()->Then(
                Thread(), __func__,
                [ref, this](MediaDataDecoder::DecodedData&& aResults) {
                  mDrained = true;
                  Output(std::move(aResults));
                  MOZ_ASSERT(mFinished, "We must be done now");
                },
                [ref, this](const MediaResult& aError) { Error(aError); });
          }
        },
        [ref, this](const MediaResult& aError) { Error(aError); });
  } else {
    if (mSampleIndex == mSamples.Length() && ref->mParameters.mStopAtFrame) {
      mSampleIndex = 0;
    }
    // Continue decoding
    p->Then(
        Thread(), __func__,
        [ref, this](MediaDataDecoder::DecodedData&& aResults) {
          Output(std::move(aResults));
          if (!mFinished) {
            InputExhausted();
          }
        },
        [ref, this](const MediaResult& aError) { Error(aError); });
  }
}

#define MOZ_MEDIA_FUZZER(_name)                                         \
  static int FuzzingRunMedia##_name(const uint8_t* data, size_t size) { \
    if (!size) {                                                        \
      return 0;                                                         \
    }                                                                   \
    RefPtr<BufferMediaResource> resource =                              \
        new BufferMediaResource(data, size);                            \
    FuzzRunner runner(new Benchmark(new _name##Demuxer(resource)));     \
    runner.Run();                                                       \
    return 0;                                                           \
  }                                                                     \
  MOZ_FUZZING_INTERFACE_RAW(nullptr, FuzzingRunMedia##_name, Media##_name);

MOZ_MEDIA_FUZZER(ADTS);
MOZ_MEDIA_FUZZER(Flac);
MOZ_MEDIA_FUZZER(MP3);
MOZ_MEDIA_FUZZER(MP4);
MOZ_MEDIA_FUZZER(Ogg);
MOZ_MEDIA_FUZZER(WAV);
MOZ_MEDIA_FUZZER(WebM);

Messung V0.5 in Prozent
C=90 H=95 G=92

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© 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.