Refactoring MediaCodec decoder

This commit is contained in:
2025-09-30 19:54:29 +09:00
parent 25bbd6901e
commit f507b31b7f
65 changed files with 7822 additions and 2222 deletions

View File

@@ -0,0 +1,251 @@
#include <gtest/gtest.h>
#include <android/log.h>
#include "Decoder/MediaCodecAV1Decoder.h"
#include "Decoder/VideoDecoderFactory.h"
#include "Common/VideoTypes.h"
#define LOG_TAG "MediaCodecAV1DecoderTest"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
using namespace VavCore;
class MediaCodecAV1DecoderTest : public ::testing::Test {
protected:
void SetUp() override {
LOGI("Setting up MediaCodecAV1DecoderTest");
decoder = std::make_unique<MediaCodecAV1Decoder>();
}
void TearDown() override {
LOGI("Tearing down MediaCodecAV1DecoderTest");
// NOTE: MediaCodecAV1Decoder destructor will call Cleanup() automatically
// Calling Cleanup() here would cause double-cleanup and potential crashes
if (decoder) {
decoder.reset();
}
}
std::unique_ptr<MediaCodecAV1Decoder> decoder;
};
// Test 1: Basic initialization and cleanup
TEST_F(MediaCodecAV1DecoderTest, InitializationAndCleanup) {
LOGI("Test: InitializationAndCleanup");
ASSERT_NE(decoder, nullptr) << "Decoder should be created";
// Cleanup should not crash
decoder->Cleanup();
SUCCEED() << "Decoder initialization and cleanup successful";
}
// Test 2: Get available codecs
TEST_F(MediaCodecAV1DecoderTest, GetAvailableCodecs) {
LOGI("Test: GetAvailableCodecs");
std::vector<std::string> codecs = decoder->GetAvailableCodecs();
LOGI("Found %zu MediaCodec AV1 codecs", codecs.size());
for (const auto& codec : codecs) {
LOGI(" - %s", codec.c_str());
}
// On most Android devices, there should be at least one AV1 codec
// But we allow 0 for older devices
EXPECT_GE(codecs.size(), 0) << "Should have 0 or more codecs available";
if (codecs.size() > 0) {
SUCCEED() << "Found " << codecs.size() << " AV1 codec(s)";
} else {
GTEST_SKIP() << "No AV1 codecs available on this device (API < 29 or no hardware support)";
}
}
// Test 3: Initialize with valid metadata
TEST_F(MediaCodecAV1DecoderTest, InitializeWithValidMetadata) {
LOGI("Test: InitializeWithValidMetadata");
// Check if any codecs are available
auto codecs = decoder->GetAvailableCodecs();
if (codecs.empty()) {
GTEST_SKIP() << "No AV1 codecs available for initialization test";
}
VideoMetadata metadata;
metadata.width = 1920;
metadata.height = 1080;
metadata.frame_rate = 30.0;
metadata.codec_name = "av01";
bool success = decoder->Initialize(metadata);
if (success) {
SUCCEED() << "Decoder initialized successfully with 1920x1080@30fps";
} else {
// Initialization might fail on emulators or devices without proper support
LOGI("Decoder initialization failed (may be expected on emulator)");
}
}
// Test 4: Initialize with invalid dimensions (should fail gracefully)
TEST_F(MediaCodecAV1DecoderTest, InitializeWithInvalidDimensions) {
LOGI("Test: InitializeWithInvalidDimensions");
VideoMetadata metadata;
metadata.width = 0; // Invalid width
metadata.height = 0; // Invalid height
metadata.frame_rate = 30.0;
metadata.codec_name = "av01";
bool success = decoder->Initialize(metadata);
EXPECT_FALSE(success) << "Initialization should fail with invalid dimensions";
if (!success) {
SUCCEED() << "Correctly rejected invalid dimensions";
}
}
// Test 5: Decode frame without initialization (should fail)
TEST_F(MediaCodecAV1DecoderTest, DecodeFrameWithoutInitialization) {
LOGI("Test: DecodeFrameWithoutInitialization");
// Try to decode without initializing
std::vector<uint8_t> dummyData(100, 0);
VideoFrame frame;
bool success = decoder->DecodeFrame(dummyData.data(), dummyData.size(), frame);
EXPECT_FALSE(success) << "DecodeFrame should fail without initialization";
if (!success) {
SUCCEED() << "Correctly rejected decode attempt without initialization";
}
}
// Test 6: Test reset functionality
TEST_F(MediaCodecAV1DecoderTest, ResetFunctionality) {
LOGI("Test: ResetFunctionality");
// Initialize decoder
auto codecs = decoder->GetAvailableCodecs();
if (codecs.empty()) {
GTEST_SKIP() << "No AV1 codecs available for reset test";
}
VideoMetadata metadata;
metadata.width = 1280;
metadata.height = 720;
metadata.frame_rate = 30.0;
metadata.codec_name = "av01";
bool initSuccess = decoder->Initialize(metadata);
if (!initSuccess) {
GTEST_SKIP() << "Cannot test reset without successful initialization";
}
// Reset should not crash
decoder->Reset();
SUCCEED() << "Decoder reset successful";
}
// Test 7: Test flush functionality
TEST_F(MediaCodecAV1DecoderTest, FlushFunctionality) {
LOGI("Test: FlushFunctionality");
// Initialize decoder
auto codecs = decoder->GetAvailableCodecs();
if (codecs.empty()) {
GTEST_SKIP() << "No AV1 codecs available for flush test";
}
VideoMetadata metadata;
metadata.width = 1280;
metadata.height = 720;
metadata.frame_rate = 30.0;
metadata.codec_name = "av01";
bool initSuccess = decoder->Initialize(metadata);
if (!initSuccess) {
GTEST_SKIP() << "Cannot test flush without successful initialization";
}
// Flush should not crash
decoder->Flush();
SUCCEED() << "Decoder flush successful";
}
// Test 8: Test decoder statistics (skipped - GetStatistics not implemented)
TEST_F(MediaCodecAV1DecoderTest, DecoderStatistics) {
LOGI("Test: DecoderStatistics");
// Note: GetStatistics() method not yet implemented in MediaCodecAV1Decoder
GTEST_SKIP() << "GetStatistics() method not yet implemented";
}
// Test 9: Get decoder name (skipped - GetName not in interface)
TEST_F(MediaCodecAV1DecoderTest, GetDecoderName) {
LOGI("Test: GetDecoderName");
// Note: GetName() is not part of IVideoDecoder interface
GTEST_SKIP() << "GetName() method not in IVideoDecoder interface";
}
// Test 10: Multiple initialize/cleanup cycles
TEST_F(MediaCodecAV1DecoderTest, MultipleInitializeCleanupCycles) {
LOGI("Test: MultipleInitializeCleanupCycles");
auto codecs = decoder->GetAvailableCodecs();
if (codecs.empty()) {
GTEST_SKIP() << "No AV1 codecs available for cycle test";
}
VideoMetadata metadata;
metadata.width = 1280;
metadata.height = 720;
metadata.frame_rate = 30.0;
metadata.codec_name = "av01";
// Perform 3 cycles
for (int i = 0; i < 3; i++) {
LOGI("Cycle %d: Initializing...", i + 1);
bool initSuccess = decoder->Initialize(metadata);
if (initSuccess) {
LOGI("Cycle %d: Cleaning up...", i + 1);
decoder->Cleanup();
} else {
LOGI("Cycle %d: Initialization failed (may be expected)", i + 1);
}
}
SUCCEED() << "Multiple initialize/cleanup cycles completed";
}
// Test 11: Supports codec type (skipped - SupportsCodec not in interface)
TEST_F(MediaCodecAV1DecoderTest, SupportsCodecType) {
LOGI("Test: SupportsCodecType");
// Note: SupportsCodec() is not part of MediaCodecAV1Decoder interface
GTEST_SKIP() << "SupportsCodec() method not in MediaCodecAV1Decoder interface";
}
// Test 12: Hardware acceleration detection
TEST_F(MediaCodecAV1DecoderTest, HardwareAccelerationDetection) {
LOGI("Test: HardwareAccelerationDetection");
bool isHardwareAccelerated = decoder->IsHardwareAccelerated();
LOGI("Hardware acceleration: %s", isHardwareAccelerated ? "YES" : "NO");
// This is informational, not an assertion
if (isHardwareAccelerated) {
SUCCEED() << "Decoder reports hardware acceleration available";
} else {
SUCCEED() << "Decoder reports software decoding (may be emulator)";
}
}