chromium/media/filters/android/video_frame_extractor_unittest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/android/video_frame_extractor.h"

#include <memory>

#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/test/test_file_util.h"
#include "base/test/test_mock_time_task_runner.h"
#include "media/base/test_data_util.h"
#include "media/filters/file_data_source.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {
namespace {

struct ExtractVideoFrameResult {
  bool success = false;
  std::vector<uint8_t> encoded_frame;
  VideoDecoderConfig decoder_config;
};

void OnFrameExtracted(ExtractVideoFrameResult* result,
                      base::RepeatingClosure quit_closure,
                      bool success,
                      std::vector<uint8_t> encoded_frame,
                      const VideoDecoderConfig& decoder_config) {
  result->success = success;
  result->encoded_frame = std::move(encoded_frame);
  result->decoder_config = decoder_config;

  quit_closure.Run();
}

class VideoFrameExtractorTest : public testing::Test {
 public:
  VideoFrameExtractorTest() {}

  VideoFrameExtractorTest(const VideoFrameExtractorTest&) = delete;
  VideoFrameExtractorTest& operator=(const VideoFrameExtractorTest&) = delete;

  ~VideoFrameExtractorTest() override {}

 protected:

  ExtractVideoFrameResult ExtractFrame(const base::FilePath& file_path) {
    base::File file(
        file_path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
    DCHECK(file.IsValid());
    data_source_ = std::make_unique<FileDataSource>();
    CHECK(data_source_->Initialize(file_path));
    extractor_ = std::make_unique<VideoFrameExtractor>(data_source_.get());

    ExtractVideoFrameResult result;
    base::RunLoop loop;
    extractor_->Start(
        base::BindOnce(&OnFrameExtracted, &result, loop.QuitClosure()));
    loop.Run();
    return result;
  }

 private:
  base::test::TaskEnvironment task_environment_;
  std::unique_ptr<FileDataSource> data_source_;
  std::unique_ptr<VideoFrameExtractor> extractor_;
};

// Verifies the encoded video frame can be extracted correctly.
TEST_F(VideoFrameExtractorTest, ExtractVideoFrame) {
  auto result = ExtractFrame(GetTestDataFilePath("bear.mp4"));
  EXPECT_TRUE(result.success);
  EXPECT_GT(result.encoded_frame.size(), 0u);
  EXPECT_EQ(result.decoder_config.codec(), VideoCodec::kH264);
}

TEST_F(VideoFrameExtractorTest, ExtractVideoFrameHEVC) {
  auto result = ExtractFrame(GetTestDataFilePath("bear-hevc-frag.mp4"));
  EXPECT_TRUE(result.success);
  EXPECT_GT(result.encoded_frame.size(), 0u);
  EXPECT_EQ(result.decoder_config.codec(), VideoCodec::kHEVC);
}

TEST_F(VideoFrameExtractorTest, ExtractVideoFrameAV1) {
  auto result = ExtractFrame(GetTestDataFilePath("bear-av1.mp4"));
  EXPECT_TRUE(result.success);
  EXPECT_GT(result.encoded_frame.size(), 0u);
  EXPECT_EQ(result.decoder_config.codec(), VideoCodec::kAV1);
}

TEST_F(VideoFrameExtractorTest, ExtractVideoFrameVP8) {
  auto result = ExtractFrame(GetTestDataFilePath("bear-vp8-webvtt.webm"));
  EXPECT_TRUE(result.success);
  EXPECT_GT(result.encoded_frame.size(), 0u);
  EXPECT_EQ(result.decoder_config.codec(), VideoCodec::kVP8);
}

TEST_F(VideoFrameExtractorTest, ExtractVideoFrameVP9) {
  auto result = ExtractFrame(GetTestDataFilePath("bear-vp9.webm"));
  EXPECT_TRUE(result.success);
  EXPECT_GT(result.encoded_frame.size(), 0u);
  EXPECT_EQ(result.decoder_config.codec(), VideoCodec::kVP9);
}

// Verifies graceful failure when trying to extract frame from an invalid video
// file.
TEST_F(VideoFrameExtractorTest, ExtractInvalidVideoFile) {
  // Creates a dummy video file, frame extraction should fail.
  base::FilePath file =
      base::CreateUniqueTempDirectoryScopedToTest().AppendASCII("test.txt");
  EXPECT_TRUE(base::WriteFile(file, "123"));

  auto result = ExtractFrame(file);
  EXPECT_FALSE(result.success);
  EXPECT_EQ(result.encoded_frame.size(), 0u);
  EXPECT_FALSE(result.decoder_config.IsValidConfig());
}

}  // namespace
}  // namespace media