Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/media/gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 12 kB image not shown  

Quelle  TestWebMWriter.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "gtest/gtest.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/MathAlgorithms.h"
#include "nestegg/nestegg.h"
#include "DriftCompensation.h"
#include "OpusTrackEncoder.h"
#include "VP8TrackEncoder.h"
#include "WebMWriter.h"

using namespace mozilla;

class WebMOpusTrackEncoder : public OpusTrackEncoder {
 public:
  explicit WebMOpusTrackEncoder(TrackRate aTrackRate)
      : OpusTrackEncoder(aTrackRate, mEncodedAudioQueue) {}
  bool TestOpusCreation(int aChannels) {
    if (NS_SUCCEEDED(Init(aChannels))) {
      return true;
    }
    return false;
  }
  MediaQueue<EncodedFrame> mEncodedAudioQueue;
};

class WebMVP8TrackEncoder : public VP8TrackEncoder {
 public:
  explicit WebMVP8TrackEncoder(TrackRate aTrackRate = 90000)
      : VP8TrackEncoder(nullptr, aTrackRate, mEncodedVideoQueue,
                        FrameDroppingMode::DISALLOW) {}

  bool TestVP8Creation(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth,
                       int32_t aDisplayHeight) {
    if (NS_SUCCEEDED(
            Init(aWidth, aHeight, aDisplayWidth, aDisplayHeight, 30))) {
      return true;
    }
    return false;
  }
  MediaQueue<EncodedFrame> mEncodedVideoQueue;
};

static void GetOpusMetadata(int aChannels, TrackRate aTrackRate,
                            nsTArray<RefPtr<TrackMetadataBase>>& aMeta) {
  WebMOpusTrackEncoder opusEncoder(aTrackRate);
  EXPECT_TRUE(opusEncoder.TestOpusCreation(aChannels));
  aMeta.AppendElement(opusEncoder.GetMetadata());
}

static void GetVP8Metadata(int32_t aWidth, int32_t aHeight,
                           int32_t aDisplayWidth, int32_t aDisplayHeight,
                           TrackRate aTrackRate,
                           nsTArray<RefPtr<TrackMetadataBase>>& aMeta) {
  WebMVP8TrackEncoder vp8Encoder;
  EXPECT_TRUE(vp8Encoder.TestVP8Creation(aWidth, aHeight, aDisplayWidth,
                                         aDisplayHeight));
  aMeta.AppendElement(vp8Encoder.GetMetadata());
}

const uint64_t FIXED_DURATION = 1000000;
const uint32_t FIXED_FRAMESIZE = 500;

class TestWebMWriter : public WebMWriter {
 public:
  TestWebMWriter() = default;

  // When we append an I-Frame into WebM muxer, the muxer will treat previous
  // data as "a cluster".
  // In these test cases, we will call the function many times to enclose the
  // previous cluster so that we can retrieve data by |GetContainerData|.
  void AppendDummyFrame(EncodedFrame::FrameType aFrameType,
                        uint64_t aDuration) {
    nsTArray<RefPtr<EncodedFrame>> encodedVideoData;
    auto frameData = MakeRefPtr<EncodedFrame::FrameData>();
    // Create dummy frame data.
    frameData->SetLength(FIXED_FRAMESIZE);
    encodedVideoData.AppendElement(
        MakeRefPtr<EncodedFrame>(mTimestamp, aDuration, PR_USEC_PER_SEC,
                                 aFrameType, std::move(frameData)));
    WriteEncodedTrack(encodedVideoData, 0);
    mTimestamp += media::TimeUnit::FromMicroseconds(aDuration);
  }

  bool HaveValidCluster() {
    nsTArray<nsTArray<uint8_t>> encodedBuf;
    GetContainerData(&encodedBuf, 0);
    return !encodedBuf.IsEmpty();
  }

  // Timestamp accumulator that increased by AppendDummyFrame.
  // Keep it public that we can do some testcases about it.
  media::TimeUnit mTimestamp;
};

TEST(WebMWriter, Metadata)
{
  TestWebMWriter writer;

  // The output should be empty since we didn't set any metadata in writer.
  nsTArray<nsTArray<uint8_t>> encodedBuf;
  writer.GetContainerData(&encodedBuf, ContainerWriter::GET_HEADER);
  EXPECT_TRUE(encodedBuf.Length() == 0);
  writer.GetContainerData(&encodedBuf, ContainerWriter::FLUSH_NEEDED);
  EXPECT_TRUE(encodedBuf.Length() == 0);

  nsTArray<RefPtr<TrackMetadataBase>> meta;

  TrackRate trackRate = 44100;

  // Get opus metadata.
  int channel = 1;
  GetOpusMetadata(channel, trackRate, meta);

  // Get vp8 metadata
  int32_t width = 640;
  int32_t height = 480;
  int32_t displayWidth = 640;
  int32_t displayHeight = 480;
  GetVP8Metadata(width, height, displayWidth, displayHeight, trackRate, meta);

  // Set metadata
  writer.SetMetadata(meta);

  writer.GetContainerData(&encodedBuf, ContainerWriter::GET_HEADER);
  EXPECT_TRUE(encodedBuf.Length() > 0);
}

TEST(WebMWriter, Cluster)
{
  TestWebMWriter writer;
  nsTArray<RefPtr<TrackMetadataBase>> meta;
  TrackRate trackRate = 48000;
  // Get opus metadata.
  int channel = 1;
  GetOpusMetadata(channel, trackRate, meta);
  // Get vp8 metadata
  int32_t width = 320;
  int32_t height = 240;
  int32_t displayWidth = 320;
  int32_t displayHeight = 240;
  GetVP8Metadata(width, height, displayWidth, displayHeight, trackRate, meta);
  writer.SetMetadata(meta);

  nsTArray<nsTArray<uint8_t>> encodedBuf;
  writer.GetContainerData(&encodedBuf, ContainerWriter::GET_HEADER);
  EXPECT_TRUE(encodedBuf.Length() > 0);
  encodedBuf.Clear();

  // write the first I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);
  EXPECT_TRUE(writer.HaveValidCluster());

  // The second I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);
  EXPECT_TRUE(writer.HaveValidCluster());

  // P-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_P_FRAME, FIXED_DURATION);
  EXPECT_TRUE(writer.HaveValidCluster());

  // The third I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);
  EXPECT_TRUE(writer.HaveValidCluster());
}

TEST(WebMWriter, FLUSH_NEEDED)
{
  TestWebMWriter writer;
  nsTArray<RefPtr<TrackMetadataBase>> meta;
  TrackRate trackRate = 44100;
  // Get opus metadata.
  int channel = 2;
  GetOpusMetadata(channel, trackRate, meta);
  // Get vp8 metadata
  int32_t width = 176;
  int32_t height = 352;
  int32_t displayWidth = 176;
  int32_t displayHeight = 352;
  GetVP8Metadata(width, height, displayWidth, displayHeight, trackRate, meta);
  writer.SetMetadata(meta);
  // Have data because the metadata is finished.
  EXPECT_TRUE(writer.HaveValidCluster());

  // write the first I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);

  // P-Frame
  writer.AppendDummyFrame(EncodedFrame::VP8_P_FRAME, FIXED_DURATION);
  // Have data because frames were written.
  EXPECT_TRUE(writer.HaveValidCluster());
  // No data because the previous check emptied it.
  EXPECT_FALSE(writer.HaveValidCluster());

  nsTArray<nsTArray<uint8_t>> encodedBuf;
  // No data because the flag ContainerWriter::FLUSH_NEEDED does nothing.
  writer.GetContainerData(&encodedBuf, ContainerWriter::FLUSH_NEEDED);
  EXPECT_TRUE(encodedBuf.IsEmpty());
  encodedBuf.Clear();

  // P-Frame
  writer.AppendDummyFrame(EncodedFrame::VP8_P_FRAME, FIXED_DURATION);
  // Have data because we continue the previous cluster.
  EXPECT_TRUE(writer.HaveValidCluster());

  // I-Frame
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);
  // Have data with a new cluster.
  EXPECT_TRUE(writer.HaveValidCluster());

  // I-Frame
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);
  // Have data with a new cluster.
  EXPECT_TRUE(writer.HaveValidCluster());
}

struct WebMioData {
  nsTArray<uint8_t> data;
  CheckedInt<size_t> offset;
};

static int webm_read(void* aBuffer, size_t aLength, void* aUserData) {
  MOZ_RELEASE_ASSERT(aUserData, "aUserData must point to a valid WebMioData");
  WebMioData* ioData = static_cast<WebMioData*>(aUserData);

  // Check the read length.
  if (aLength > ioData->data.Length()) {
    return 0;
  }

  // Check eos.
  if (ioData->offset.value() >= ioData->data.Length()) {
    return 0;
  }

  size_t oldOffset = ioData->offset.value();
  ioData->offset += aLength;
  if (!ioData->offset.isValid() ||
      (ioData->offset.value() > ioData->data.Length())) {
    return -1;
  }
  memcpy(aBuffer, ioData->data.Elements() + oldOffset, aLength);
  return 1;
}

static int webm_seek(int64_t aOffset, int aWhence, void* aUserData) {
  MOZ_RELEASE_ASSERT(aUserData, "aUserData must point to a valid WebMioData");
  WebMioData* ioData = static_cast<WebMioData*>(aUserData);

  if (Abs(aOffset) > ioData->data.Length()) {
    NS_ERROR("Invalid aOffset");
    return -1;
  }

  switch (aWhence) {
    case NESTEGG_SEEK_END: {
      CheckedInt<size_t> tempOffset = ioData->data.Length();
      ioData->offset = tempOffset + aOffset;
      break;
    }
    case NESTEGG_SEEK_CUR:
      ioData->offset += aOffset;
      break;
    case NESTEGG_SEEK_SET:
      ioData->offset = aOffset;
      break;
    default:
      NS_ERROR("Unknown whence");
      return -1;
  }

  if (!ioData->offset.isValid()) {
    NS_ERROR("Invalid offset");
    return -1;
  }

  return 0;
}

static int64_t webm_tell(void* aUserData) {
  MOZ_RELEASE_ASSERT(aUserData, "aUserData must point to a valid WebMioData");
  WebMioData* ioData = static_cast<WebMioData*>(aUserData);
  return ioData->offset.isValid() ? ioData->offset.value() : -1;
}

TEST(WebMWriter, bug970774_aspect_ratio)
{
  TestWebMWriter writer;
  nsTArray<RefPtr<TrackMetadataBase>> meta;
  TrackRate trackRate = 44100;
  // Get opus metadata.
  int channel = 1;
  GetOpusMetadata(channel, trackRate, meta);
  // Set vp8 metadata
  int32_t width = 640;
  int32_t height = 480;
  int32_t displayWidth = 1280;
  int32_t displayHeight = 960;
  GetVP8Metadata(width, height, displayWidth, displayHeight, trackRate, meta);
  writer.SetMetadata(meta);

  // write the first I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);

  // write the second I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME, FIXED_DURATION);

  // Get the metadata and the first cluster.
  nsTArray<nsTArray<uint8_t>> encodedBuf;
  writer.GetContainerData(&encodedBuf, 0);
  // Flatten the encodedBuf.
  WebMioData ioData;
  ioData.offset = 0;
  for (uint32_t i = 0; i < encodedBuf.Length(); ++i) {
    ioData.data.AppendElements(encodedBuf[i]);
  }

  // Use nestegg to verify the information in metadata.
  nestegg* context = nullptr;
  nestegg_io io;
  io.read = webm_read;
  io.seek = webm_seek;
  io.tell = webm_tell;
  io.userdata = static_cast<void*>(&ioData);
  int rv = nestegg_init(&context, io, nullptr, -1);
  EXPECT_EQ(rv, 0);
  unsigned int ntracks = 0;
  rv = nestegg_track_count(context, &ntracks);
  EXPECT_EQ(rv, 0);
  EXPECT_EQ(ntracks, (unsigned int)2);
  for (unsigned int track = 0; track < ntracks; ++track) {
    int id = nestegg_track_codec_id(context, track);
    EXPECT_NE(id, -1);
    int type = nestegg_track_type(context, track);
    if (type == NESTEGG_TRACK_VIDEO) {
      nestegg_video_params params;
      rv = nestegg_track_video_params(context, track, ¶ms);
      EXPECT_EQ(rv, 0);
      EXPECT_EQ(width, static_cast<int32_t>(params.width));
      EXPECT_EQ(height, static_cast<int32_t>(params.height));
      EXPECT_EQ(displayWidth, static_cast<int32_t>(params.display_width));
      EXPECT_EQ(displayHeight, static_cast<int32_t>(params.display_height));
    } else if (type == NESTEGG_TRACK_AUDIO) {
      nestegg_audio_params params;
      rv = nestegg_track_audio_params(context, track, ¶ms);
      EXPECT_EQ(rv, 0);
      EXPECT_EQ(channel, static_cast<int>(params.channels));
      EXPECT_EQ(static_cast<double>(trackRate), params.rate);
    }
  }
  if (context) {
    nestegg_destroy(context);
  }
}

/**
 * Test that we don't crash when writing two video frames that are too far apart
 * to fit in the same cluster (>32767ms).
 */

TEST(WebMWriter, LongVideoGap)
{
  TestWebMWriter writer;
  nsTArray<RefPtr<TrackMetadataBase>> meta;
  TrackRate trackRate = 44100;
  // Set vp8 metadata
  int32_t width = 640;
  int32_t height = 480;
  int32_t displayWidth = 640;
  int32_t displayHeight = 480;
  GetVP8Metadata(width, height, displayWidth, displayHeight, trackRate, meta);
  writer.SetMetadata(meta);

  // write the first I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME,
                          media::TimeUnit::FromSeconds(33).ToMicroseconds());

  // write the second I-Frame.
  writer.AppendDummyFrame(EncodedFrame::VP8_I_FRAME,
                          media::TimeUnit::FromSeconds(0.33).ToMicroseconds());

  nsTArray<nsTArray<uint8_t>> encodedBuf;
  writer.GetContainerData(&encodedBuf, ContainerWriter::GET_HEADER);
  // metadata + 2 frames
  EXPECT_EQ(encodedBuf.Length(), 3U);
}

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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.