tests: migrate gtest suite to the ffmpeg_bridge API and add bridge coverage

- Replace direct FFmpeg usage in the test suite (channel layout masks,
  pixel/sample format constants, AVFrame field access, sws_scale) with
  the bridge equivalents and the olive::AVFrame adapter
- Drop CoreRational.ToAVRational (API removed with core's FFmpeg
  dependency) and the GetSwsColorspaceFromAVColorSpace tests (helper
  moved inside the bridge)
- New ffmpeg_bridge_test.cpp exercises the C API directly: constants vs
  core, error strings, pixel format utilities, frames/packets, scaler,
  resampler, audio graph tempo processing, probe/decoder round-trip on
  tests/demo.mp4 (including hw-frame transfer), SRT subtitle reading,
  and encoder end-to-end tests (PNG video and PCM audio probed back)
This commit is contained in:
2026-07-15 23:00:13 +08:00
parent 3a3ead6fc0
commit e1d3019659
18 changed files with 1074 additions and 272 deletions
+1
View File
@@ -11,6 +11,7 @@ add_executable(olive-gtest
common_digit_test.cpp common_digit_test.cpp
common_jobtime_test.cpp common_jobtime_test.cpp
common_ffmpegutils_test.cpp common_ffmpegutils_test.cpp
ffmpeg_bridge_test.cpp
config_test.cpp config_test.cpp
audio_level_meter_test.cpp audio_level_meter_test.cpp
audio_synchronizer_test.cpp audio_synchronizer_test.cpp
+1 -5
View File
@@ -7,16 +7,12 @@
#include "olive/core/render/samplebuffer.h" #include "olive/core/render/samplebuffer.h"
#include "olive/core/render/sampleformat.h" #include "olive/core/render/sampleformat.h"
extern "C" {
#include <libavutil/channel_layout.h>
}
namespace namespace
{ {
olive::core::AudioParams MakeStereoParams() olive::core::AudioParams MakeStereoParams()
{ {
return olive::core::AudioParams(48000, AV_CH_LAYOUT_STEREO, return olive::core::AudioParams(48000, olive::core::kChannelLayoutStereo,
olive::core::SampleFormat::F32P); olive::core::SampleFormat::F32P);
} }
+43 -47
View File
@@ -26,10 +26,6 @@
#include "olive/core/render/audioparams.h" #include "olive/core/render/audioparams.h"
#include "olive/core/render/sampleformat.h" #include "olive/core/render/sampleformat.h"
extern "C" {
#include <libavutil/channel_layout.h>
}
using namespace olive; using namespace olive;
using namespace olive::core; using namespace olive::core;
@@ -75,7 +71,7 @@ TEST(AudioSmokeParams, DefaultConstruction)
TEST(AudioSmokeParams, ValidConstruction) TEST(AudioSmokeParams, ValidConstruction)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
EXPECT_TRUE(params.is_valid()); EXPECT_TRUE(params.is_valid());
EXPECT_EQ(params.sample_rate(), 48000); EXPECT_EQ(params.sample_rate(), 48000);
@@ -87,7 +83,7 @@ TEST(AudioSmokeParams, ValidConstruction)
TEST(AudioSmokeParams, MonoChannelLayout) TEST(AudioSmokeParams, MonoChannelLayout)
{ {
AudioParams params(44100, AV_CH_LAYOUT_MONO, SampleFormat::S16); AudioParams params(44100, kChannelLayoutMono, SampleFormat::S16);
EXPECT_TRUE(params.is_valid()); EXPECT_TRUE(params.is_valid());
EXPECT_EQ(params.sample_rate(), 44100); EXPECT_EQ(params.sample_rate(), 44100);
@@ -96,7 +92,7 @@ TEST(AudioSmokeParams, MonoChannelLayout)
TEST(AudioSmokeParams, SurroundChannelLayout) TEST(AudioSmokeParams, SurroundChannelLayout)
{ {
AudioParams params(48000, AV_CH_LAYOUT_5POINT1, SampleFormat::F32P); AudioParams params(48000, kChannelLayout5Point1, SampleFormat::F32P);
EXPECT_TRUE(params.is_valid()); EXPECT_TRUE(params.is_valid());
EXPECT_EQ(params.channel_count(), 6); EXPECT_EQ(params.channel_count(), 6);
@@ -104,7 +100,7 @@ TEST(AudioSmokeParams, SurroundChannelLayout)
TEST(AudioSmokeParams, TimeConversions) TEST(AudioSmokeParams, TimeConversions)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
// Time to samples // Time to samples
EXPECT_EQ(params.time_to_samples(1.0), 48000); EXPECT_EQ(params.time_to_samples(1.0), 48000);
@@ -121,11 +117,11 @@ TEST(AudioSmokeParams, TimeConversions)
TEST(AudioSmokeParams, EqualityOperators) TEST(AudioSmokeParams, EqualityOperators)
{ {
AudioParams params1(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params1(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams params2(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params2(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams params3(44100, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params3(44100, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams params4(48000, AV_CH_LAYOUT_MONO, SampleFormat::F32P); AudioParams params4(48000, kChannelLayoutMono, SampleFormat::F32P);
AudioParams params5(48000, AV_CH_LAYOUT_STEREO, SampleFormat::S16); AudioParams params5(48000, kChannelLayoutStereo, SampleFormat::S16);
EXPECT_TRUE(params1 == params2); EXPECT_TRUE(params1 == params2);
EXPECT_FALSE(params1 != params2); EXPECT_FALSE(params1 != params2);
@@ -137,7 +133,7 @@ TEST(AudioSmokeParams, EqualityOperators)
TEST(AudioSmokeParams, CopyConstruction) TEST(AudioSmokeParams, CopyConstruction)
{ {
AudioParams original(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams original(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams copy(original); AudioParams copy(original);
EXPECT_TRUE(copy.is_valid()); EXPECT_TRUE(copy.is_valid());
@@ -153,7 +149,7 @@ TEST(AudioSmokeParams, CopyConstruction)
TEST(AudioSmokeParams, CopyAssignment) TEST(AudioSmokeParams, CopyAssignment)
{ {
AudioParams original(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams original(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams copy; AudioParams copy;
copy = original; copy = original;
@@ -165,15 +161,15 @@ TEST(AudioSmokeParams, CopyAssignment)
TEST(AudioSmokeParams, ChannelLayoutModification) TEST(AudioSmokeParams, ChannelLayoutModification)
{ {
AudioParams params(48000, AV_CH_LAYOUT_MONO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutMono, SampleFormat::F32P);
EXPECT_EQ(params.channel_count(), 1); EXPECT_EQ(params.channel_count(), 1);
// Change to stereo // Change to stereo
params.set_channel_layout(AV_CH_LAYOUT_STEREO); params.set_channel_layout(kChannelLayoutStereo);
EXPECT_EQ(params.channel_count(), 2); EXPECT_EQ(params.channel_count(), 2);
// Change to 5.1 // Change to 5.1
params.set_channel_layout(AV_CH_LAYOUT_5POINT1); params.set_channel_layout(kChannelLayout5Point1);
EXPECT_EQ(params.channel_count(), 6); EXPECT_EQ(params.channel_count(), 6);
} }
@@ -191,7 +187,7 @@ TEST(AudioSmokeBuffer, DefaultConstruction)
TEST(AudioSmokeBuffer, Allocation) TEST(AudioSmokeBuffer, Allocation)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(48000)); // 1 second of samples SampleBuffer buffer(params, size_t(48000)); // 1 second of samples
EXPECT_TRUE(buffer.is_allocated()); EXPECT_TRUE(buffer.is_allocated());
@@ -201,7 +197,7 @@ TEST(AudioSmokeBuffer, Allocation)
TEST(AudioSmokeBuffer, DataAccess) TEST(AudioSmokeBuffer, DataAccess)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(100)); SampleBuffer buffer(params, size_t(100));
// Fill with test data // Fill with test data
@@ -218,7 +214,7 @@ TEST(AudioSmokeBuffer, DataAccess)
TEST(AudioSmokeBuffer, Silence) TEST(AudioSmokeBuffer, Silence)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(100)); SampleBuffer buffer(params, size_t(100));
// Fill with non-zero values // Fill with non-zero values
@@ -238,7 +234,7 @@ TEST(AudioSmokeBuffer, Silence)
TEST(AudioSmokeBuffer, VolumeTransform) TEST(AudioSmokeBuffer, VolumeTransform)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(100)); SampleBuffer buffer(params, size_t(100));
// Fill with 1.0 // Fill with 1.0
@@ -258,7 +254,7 @@ TEST(AudioSmokeBuffer, VolumeTransform)
TEST(AudioSmokeBuffer, Clamp) TEST(AudioSmokeBuffer, Clamp)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(100)); SampleBuffer buffer(params, size_t(100));
// Fill with values outside [-1, 1] // Fill with values outside [-1, 1]
@@ -284,7 +280,7 @@ TEST(AudioSmokeBuffer, Clamp)
TEST(AudioSmokeBuffer, FastSet) TEST(AudioSmokeBuffer, FastSet)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer source(params, size_t(100)); SampleBuffer source(params, size_t(100));
SampleBuffer dest(params, size_t(100)); SampleBuffer dest(params, size_t(100));
@@ -303,7 +299,7 @@ TEST(AudioSmokeBuffer, FastSet)
TEST(AudioSmokeBuffer, RipChannel) TEST(AudioSmokeBuffer, RipChannel)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(100)); SampleBuffer buffer(params, size_t(100));
// Fill channel 0 with 0.5, channel 1 with 0.25 // Fill channel 0 with 0.5, channel 1 with 0.25
@@ -353,7 +349,7 @@ TEST(AudioSmokeWaveform, OverwriteSamples)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Create sample buffer with sine wave-like data // Create sample buffer with sine wave-like data
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(4800)); // 0.1 seconds SampleBuffer buffer(params, size_t(4800)); // 0.1 seconds
for (int ch = 0; ch < buffer.channel_count(); ++ch) { for (int ch = 0; ch < buffer.channel_count(); ++ch) {
@@ -375,7 +371,7 @@ TEST(AudioSmokeWaveform, OverwriteSilence)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// First add some samples // First add some samples
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(4800)); SampleBuffer buffer(params, size_t(4800));
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
waveform.OverwriteSamples(buffer, 48000, rational(0)); waveform.OverwriteSamples(buffer, 48000, rational(0));
@@ -395,7 +391,7 @@ TEST(AudioSmokeWaveform, TrimIn)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Add samples // Add samples
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(48000)); // 1 second SampleBuffer buffer(params, size_t(48000)); // 1 second
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
waveform.OverwriteSamples(buffer, 48000, rational(0)); waveform.OverwriteSamples(buffer, 48000, rational(0));
@@ -414,7 +410,7 @@ TEST(AudioSmokeWaveform, Resize)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Add samples // Add samples
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(48000)); SampleBuffer buffer(params, size_t(48000));
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
waveform.OverwriteSamples(buffer, 48000, rational(0)); waveform.OverwriteSamples(buffer, 48000, rational(0));
@@ -433,7 +429,7 @@ TEST(AudioSmokeWaveform, TrimRange)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Add 2 seconds of samples // Add 2 seconds of samples
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(96000)); SampleBuffer buffer(params, size_t(96000));
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
waveform.OverwriteSamples(buffer, 48000, rational(0)); waveform.OverwriteSamples(buffer, 48000, rational(0));
@@ -452,7 +448,7 @@ TEST(AudioSmokeWaveform, Mid)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Add 2 seconds of samples // Add 2 seconds of samples
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(96000)); SampleBuffer buffer(params, size_t(96000));
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
waveform.OverwriteSamples(buffer, 48000, rational(0)); waveform.OverwriteSamples(buffer, 48000, rational(0));
@@ -470,7 +466,7 @@ TEST(AudioSmokeWaveform, GetSummaryFromTime)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Add samples with varying values // Add samples with varying values
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(4800)); SampleBuffer buffer(params, size_t(4800));
for (int ch = 0; ch < buffer.channel_count(); ++ch) { for (int ch = 0; ch < buffer.channel_count(); ++ch) {
float *data = buffer.data(ch); float *data = buffer.data(ch);
@@ -491,7 +487,7 @@ TEST(AudioSmokeWaveform, GetSummaryFromTime)
TEST(AudioSmokeWaveform, SumSamples) TEST(AudioSmokeWaveform, SumSamples)
{ {
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(100)); SampleBuffer buffer(params, size_t(100));
// Fill with known pattern // Fill with known pattern
@@ -543,8 +539,8 @@ TEST(AudioSmokeProcessor, OpenClose)
{ {
AudioProcessor processor; AudioProcessor processor;
AudioParams from(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams from(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams to(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams to(48000, kChannelLayoutStereo, SampleFormat::F32P);
EXPECT_TRUE(processor.Open(from, to, 1.0)); EXPECT_TRUE(processor.Open(from, to, 1.0));
EXPECT_TRUE(processor.IsOpen()); EXPECT_TRUE(processor.IsOpen());
@@ -557,8 +553,8 @@ TEST(AudioSmokeProcessor, SampleRateConversion)
{ {
AudioProcessor processor; AudioProcessor processor;
AudioParams from(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams from(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams to(44100, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams to(44100, kChannelLayoutStereo, SampleFormat::F32P);
EXPECT_TRUE(processor.Open(from, to, 1.0)); EXPECT_TRUE(processor.Open(from, to, 1.0));
EXPECT_TRUE(processor.IsOpen()); EXPECT_TRUE(processor.IsOpen());
@@ -570,8 +566,8 @@ TEST(AudioSmokeProcessor, ChannelLayoutConversion)
{ {
AudioProcessor processor; AudioProcessor processor;
AudioParams from(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams from(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams to(48000, AV_CH_LAYOUT_MONO, SampleFormat::F32P); AudioParams to(48000, kChannelLayoutMono, SampleFormat::F32P);
EXPECT_TRUE(processor.Open(from, to, 1.0)); EXPECT_TRUE(processor.Open(from, to, 1.0));
EXPECT_TRUE(processor.IsOpen()); EXPECT_TRUE(processor.IsOpen());
@@ -583,8 +579,8 @@ TEST(AudioSmokeProcessor, FormatConversion)
{ {
AudioProcessor processor; AudioProcessor processor;
AudioParams from(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams from(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams to(48000, AV_CH_LAYOUT_STEREO, SampleFormat::S16P); AudioParams to(48000, kChannelLayoutStereo, SampleFormat::S16P);
EXPECT_TRUE(processor.Open(from, to, 1.0)); EXPECT_TRUE(processor.Open(from, to, 1.0));
EXPECT_TRUE(processor.IsOpen()); EXPECT_TRUE(processor.IsOpen());
@@ -594,8 +590,8 @@ TEST(AudioSmokeProcessor, TempoChange)
{ {
AudioProcessor processor; AudioProcessor processor;
AudioParams from(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams from(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams to(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams to(48000, kChannelLayoutStereo, SampleFormat::F32P);
// Open with 2x tempo // Open with 2x tempo
EXPECT_TRUE(processor.Open(from, to, 2.0)); EXPECT_TRUE(processor.Open(from, to, 2.0));
@@ -607,8 +603,8 @@ TEST(AudioSmokeProcessor, InvalidOpen)
AudioProcessor processor; AudioProcessor processor;
// Open with valid params // Open with valid params
AudioParams from(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams from(48000, kChannelLayoutStereo, SampleFormat::F32P);
AudioParams to(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams to(48000, kChannelLayoutStereo, SampleFormat::F32P);
EXPECT_TRUE(processor.Open(from, to, 1.0)); EXPECT_TRUE(processor.Open(from, to, 1.0));
// Try to open again while already open (should fail) // Try to open again while already open (should fail)
@@ -756,7 +752,7 @@ TEST(AudioSmokeThread, ConcurrentWaveformAccess)
waveform.set_channel_count(2); waveform.set_channel_count(2);
// Pre-populate with data // Pre-populate with data
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(4800)); SampleBuffer buffer(params, size_t(4800));
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
waveform.OverwriteSamples(buffer, 48000, rational(0)); waveform.OverwriteSamples(buffer, 48000, rational(0));
@@ -791,7 +787,7 @@ TEST(AudioSmokeThread, ConcurrentSampleBufferOperations)
{ {
const int num_threads = 4; const int num_threads = 4;
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
SampleBuffer buffer(params, size_t(1000)); SampleBuffer buffer(params, size_t(1000));
FillSampleBuffer(buffer, 0.5f); FillSampleBuffer(buffer, 0.5f);
+1 -5
View File
@@ -5,16 +5,12 @@
#include "olive/core/render/samplebuffer.h" #include "olive/core/render/samplebuffer.h"
#include "olive/core/render/sampleformat.h" #include "olive/core/render/sampleformat.h"
extern "C" {
#include <libavutil/channel_layout.h>
}
namespace namespace
{ {
olive::core::AudioParams MakeMonoParams() olive::core::AudioParams MakeMonoParams()
{ {
return olive::core::AudioParams(48000, AV_CH_LAYOUT_MONO, return olive::core::AudioParams(48000, olive::core::kChannelLayoutMono,
olive::core::SampleFormat::F32P); olive::core::SampleFormat::F32P);
} }
+49 -72
View File
@@ -6,100 +6,78 @@ using namespace olive;
TEST(CommonFFmpegUtils, GetNativeSampleFormatMapsCorrectly) TEST(CommonFFmpegUtils, GetNativeSampleFormatMapsCorrectly)
{ {
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_U8), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_U8),
SampleFormat::U8); SampleFormat::U8);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S16), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_S16),
SampleFormat::S16); SampleFormat::S16);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S32), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_S32),
SampleFormat::S32); SampleFormat::S32);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S64), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_S64),
SampleFormat::S64); SampleFormat::S64);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_FLT), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_FLT),
SampleFormat::F32); SampleFormat::F32);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_DBL), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_DBL),
SampleFormat::F64); SampleFormat::F64);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_U8P), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_U8P),
SampleFormat::U8P); SampleFormat::U8P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S16P), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_S16P),
SampleFormat::S16P); SampleFormat::S16P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S32P), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_S32P),
SampleFormat::S32P); SampleFormat::S32P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_S64P), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_S64P),
SampleFormat::S64P); SampleFormat::S64P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_FLTP), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_FLTP),
SampleFormat::F32P); SampleFormat::F32P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_DBLP), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_DBLP),
SampleFormat::F64P); SampleFormat::F64P);
EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(AV_SAMPLE_FMT_NONE), EXPECT_EQ(FFmpegUtils::GetNativeSampleFormat(FB_SAMPLE_FMT_NONE),
SampleFormat::INVALID); SampleFormat::INVALID);
} }
TEST(CommonFFmpegUtils, GetFFmpegSampleFormatMapsCorrectly) TEST(CommonFFmpegUtils, GetFFmpegSampleFormatMapsCorrectly)
{ {
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8),
AV_SAMPLE_FMT_U8); FB_SAMPLE_FMT_U8);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16),
AV_SAMPLE_FMT_S16); FB_SAMPLE_FMT_S16);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32),
AV_SAMPLE_FMT_S32); FB_SAMPLE_FMT_S32);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64),
AV_SAMPLE_FMT_S64); FB_SAMPLE_FMT_S64);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32),
AV_SAMPLE_FMT_FLT); FB_SAMPLE_FMT_FLT);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64),
AV_SAMPLE_FMT_DBL); FB_SAMPLE_FMT_DBL);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8P), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::U8P),
AV_SAMPLE_FMT_U8P); FB_SAMPLE_FMT_U8P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16P), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S16P),
AV_SAMPLE_FMT_S16P); FB_SAMPLE_FMT_S16P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32P), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S32P),
AV_SAMPLE_FMT_S32P); FB_SAMPLE_FMT_S32P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64P), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::S64P),
AV_SAMPLE_FMT_S64P); FB_SAMPLE_FMT_S64P);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32P), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F32P),
AV_SAMPLE_FMT_FLTP); FB_SAMPLE_FMT_FLTP);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64P), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::F64P),
AV_SAMPLE_FMT_DBLP); FB_SAMPLE_FMT_DBLP);
EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::INVALID), EXPECT_EQ(FFmpegUtils::GetFFmpegSampleFormat(SampleFormat::INVALID),
AV_SAMPLE_FMT_NONE); FB_SAMPLE_FMT_NONE);
}
TEST(CommonFFmpegUtils, GetSwsColorspaceFromAVColorSpace)
{
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT709),
SWS_CS_ITU709);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_FCC),
SWS_CS_FCC);
EXPECT_EQ(FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT470BG),
SWS_CS_ITU624);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_SMPTE170M),
SWS_CS_SMPTE170M);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_SMPTE240M),
SWS_CS_SMPTE240M);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_BT2020_NCL),
SWS_CS_BT2020);
EXPECT_EQ(
FFmpegUtils::GetSwsColorspaceFromAVColorSpace(AVCOL_SPC_UNSPECIFIED),
SWS_CS_DEFAULT);
} }
TEST(CommonFFmpegUtils, ConvertJPEGSpaceToRegularSpace) TEST(CommonFFmpegUtils, ConvertJPEGSpaceToRegularSpace)
{ {
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ420P), EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(FB_PIX_FMT_YUVJ420P),
AV_PIX_FMT_YUV420P); FB_PIX_FMT_YUV420P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ422P), EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(FB_PIX_FMT_YUVJ422P),
AV_PIX_FMT_YUV422P); FB_PIX_FMT_YUV422P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ444P), EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(FB_PIX_FMT_YUVJ444P),
AV_PIX_FMT_YUV444P); FB_PIX_FMT_YUV444P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ440P), EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(FB_PIX_FMT_YUVJ440P),
AV_PIX_FMT_YUV440P); FB_PIX_FMT_YUV440P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUVJ411P), EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(FB_PIX_FMT_YUVJ411P),
AV_PIX_FMT_YUV411P); FB_PIX_FMT_YUV411P);
EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(AV_PIX_FMT_YUV420P), EXPECT_EQ(FFmpegUtils::ConvertJPEGSpaceToRegularSpace(FB_PIX_FMT_YUV420P),
AV_PIX_FMT_YUV420P); FB_PIX_FMT_YUV420P);
} }
TEST(CommonFFmpegUtils, GetCompatiblePixelFormatNative) TEST(CommonFFmpegUtils, GetCompatiblePixelFormatNative)
@@ -122,33 +100,32 @@ TEST(CommonFFmpegUtils, GetFFmpegPixelFormat)
{ {
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8, EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8,
VideoParams::kRGBChannelCount), VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGB24); FB_PIX_FMT_RGB24);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16, EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16,
VideoParams::kRGBChannelCount), VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGB48); FB_PIX_FMT_RGB48LE);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32, EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32,
VideoParams::kRGBChannelCount), VideoParams::kRGBChannelCount),
AV_PIX_FMT_RGBF32); FB_PIX_FMT_RGBF32LE);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8, EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U8,
VideoParams::kRGBAChannelCount), VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBA); FB_PIX_FMT_RGBA);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16, EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::U16,
VideoParams::kRGBAChannelCount), VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBA64); FB_PIX_FMT_RGBA64LE);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32, EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::F32,
VideoParams::kRGBAChannelCount), VideoParams::kRGBAChannelCount),
AV_PIX_FMT_RGBAF32); FB_PIX_FMT_RGBAF32LE);
EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::INVALID, 0), EXPECT_EQ(FFmpegUtils::GetFFmpegPixelFormat(PixelFormat::INVALID, 0),
AV_PIX_FMT_NONE); FB_PIX_FMT_NONE);
} }
TEST(CommonFFmpegUtils, GetCompatiblePixelFormatAV) TEST(CommonFFmpegUtils, GetCompatiblePixelFormatAV)
{ {
AVPixelFormat fmt = int fmt = FFmpegUtils::GetCompatibleBridgePixelFormat(FB_PIX_FMT_YUV420P);
FFmpegUtils::GetCompatiblePixelFormat(AV_PIX_FMT_YUV420P); EXPECT_NE(fmt, FB_PIX_FMT_NONE);
EXPECT_NE(fmt, AV_PIX_FMT_NONE);
fmt = FFmpegUtils::GetCompatiblePixelFormat(AV_PIX_FMT_YUV420P, fmt = FFmpegUtils::GetCompatibleBridgePixelFormat(FB_PIX_FMT_YUV420P,
PixelFormat::U8); PixelFormat::U8);
EXPECT_EQ(fmt, AV_PIX_FMT_RGBA); EXPECT_EQ(fmt, FB_PIX_FMT_RGBA);
} }
-7
View File
@@ -82,13 +82,6 @@ TEST(CoreRational, ToString)
EXPECT_EQ(rational(1, 2).toString(), "1/2"); EXPECT_EQ(rational(1, 2).toString(), "1/2");
} }
TEST(CoreRational, ToAVRational)
{
AVRational av = rational(3, 4).toAVRational();
EXPECT_EQ(av.num, 3);
EXPECT_EQ(av.den, 4);
}
TEST(CoreRational, Arithmetic) TEST(CoreRational, Arithmetic)
{ {
rational a(1, 2); rational a(1, 2);
+1 -1
View File
@@ -6,7 +6,7 @@ using namespace olive::core;
static AudioParams MakeParams(int channels = 2, int sample_rate = 48000) static AudioParams MakeParams(int channels = 2, int sample_rate = 48000)
{ {
AudioParams params(sample_rate, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(sample_rate, kChannelLayoutStereo, SampleFormat::F32P);
return params; return params;
} }
+855
View File
@@ -0,0 +1,855 @@
/*
* Oak Video Editor - ffmpeg_bridge C API Tests
* Copyright (C) 2025 Olive CE Team
*
* Direct tests of the pure C ffmpeg_bridge API. These tests exercise the
* bridge in isolation from the editor: handles are created, used and freed
* entirely through the fb_* functions, mirroring how the C++ adapter layer
* drives the library at runtime.
*/
#include <gtest/gtest.h>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <ffmpeg_bridge/ffmpeg_bridge.h>
#include "olive/core/render/channellayout.h"
namespace
{
QString DemoPath()
{
return QDir(QStringLiteral(OAK_TEST_SOURCE_DIR))
.filePath(QStringLiteral("tests/demo.mp4"));
}
QString TempFilePath(const QString &name)
{
return QDir::temp().filePath(name);
}
constexpr double kPi = 3.14159265358979323846;
// Finds the first stream of `type`; returns its index or -1.
int FindStream(FBProbe *probe, int type)
{
const int count = fb_probe_get_stream_count(probe);
for (int i = 0; i < count; ++i) {
FBStreamInfo info;
if (fb_probe_get_stream_info(probe, i, &info) == 0 &&
info.codec_type == type) {
return i;
}
}
return -1;
}
} // namespace
// ============================================================================
// Constants
// ============================================================================
TEST(FFmpegBridgeConstants, ChannelLayoutsMatchCore)
{
// The core library and the bridge must agree on layout masks or all
// audio plumbing between them breaks.
EXPECT_EQ(FB_CH_LAYOUT_MONO, olive::core::kChannelLayoutMono);
EXPECT_EQ(FB_CH_LAYOUT_STEREO, olive::core::kChannelLayoutStereo);
EXPECT_EQ(FB_CH_LAYOUT_2_1, olive::core::kChannelLayout2_1);
EXPECT_EQ(FB_CH_LAYOUT_5POINT1, olive::core::kChannelLayout5Point1);
EXPECT_EQ(FB_CH_LAYOUT_7POINT1, olive::core::kChannelLayout7Point1);
}
TEST(FFmpegBridgeConstants, SpecialValues)
{
EXPECT_EQ(FB_NOPTS_VALUE, INT64_MIN);
EXPECT_EQ(FB_TIME_BASE, 1000000);
EXPECT_LT(FB_ERROR_EOF, 0);
EXPECT_EQ(FB_PIX_FMT_NONE, -1);
EXPECT_EQ(FB_SAMPLE_FMT_NONE, -1);
}
// ============================================================================
// Error strings / version
// ============================================================================
TEST(FFmpegBridgeError, ErrorString)
{
char buffer[256];
fb_error_string(FB_ERROR_EOF, buffer, sizeof(buffer));
EXPECT_GT(std::strlen(buffer), 0u);
fb_error_string(0, buffer, sizeof(buffer));
EXPECT_GT(std::strlen(buffer), 0u);
}
TEST(FFmpegBridgeError, VersionString)
{
const char *version = fb_version_string();
ASSERT_NE(version, nullptr);
EXPECT_GT(std::strlen(version), 0u);
}
// ============================================================================
// Pixel/sample format utilities
// ============================================================================
TEST(FFmpegBridgePixFmt, NameRoundtrip)
{
const char *name = fb_pix_fmt_name(FB_PIX_FMT_YUV420P);
ASSERT_NE(name, nullptr);
EXPECT_STREQ(name, "yuv420p");
EXPECT_EQ(fb_pix_fmt_from_name(name), FB_PIX_FMT_YUV420P);
EXPECT_STREQ(fb_pix_fmt_name(FB_PIX_FMT_RGBA), "rgba");
EXPECT_EQ(fb_pix_fmt_from_name("rgba"), FB_PIX_FMT_RGBA);
}
TEST(FFmpegBridgePixFmt, Properties)
{
EXPECT_EQ(fb_pix_fmt_bits_per_pixel(FB_PIX_FMT_RGBA), 32);
EXPECT_EQ(fb_pix_fmt_bits_per_pixel(FB_PIX_FMT_YUV420P), 12);
EXPECT_EQ(fb_pix_fmt_bits_per_pixel(FB_PIX_FMT_RGBA64LE), 64);
EXPECT_EQ(fb_pix_fmt_has_alpha(FB_PIX_FMT_RGBA), 1);
EXPECT_EQ(fb_pix_fmt_has_alpha(FB_PIX_FMT_YUV420P), 0);
EXPECT_EQ(fb_pix_fmt_is_planar(FB_PIX_FMT_YUV420P), 1);
EXPECT_EQ(fb_pix_fmt_is_planar(FB_PIX_FMT_RGBA), 0);
EXPECT_EQ(fb_pix_fmt_component_size(FB_PIX_FMT_RGBA), 1);
EXPECT_EQ(fb_pix_fmt_component_size(FB_PIX_FMT_RGBA64LE), 2);
}
TEST(FFmpegBridgePixFmt, FindBestOfList)
{
const int list[] = { FB_PIX_FMT_YUV420P, FB_PIX_FMT_YUV444P,
FB_PIX_FMT_NONE };
EXPECT_EQ(fb_find_best_pix_fmt_of_list(list, FB_PIX_FMT_YUV420P),
FB_PIX_FMT_YUV420P);
}
TEST(FFmpegBridgeChannelLayout, ChannelCounts)
{
EXPECT_EQ(fb_channel_layout_get_channels(FB_CH_LAYOUT_MONO), 1);
EXPECT_EQ(fb_channel_layout_get_channels(FB_CH_LAYOUT_STEREO), 2);
EXPECT_EQ(fb_channel_layout_get_channels(FB_CH_LAYOUT_5POINT1), 6);
EXPECT_EQ(fb_channel_layout_get_channels(FB_CH_LAYOUT_7POINT1), 8);
}
TEST(FFmpegBridgeChannelLayout, Defaults)
{
EXPECT_EQ(fb_channel_layout_default(1), FB_CH_LAYOUT_MONO);
EXPECT_EQ(fb_channel_layout_default(2), FB_CH_LAYOUT_STEREO);
// av_channel_layout_default picks a valid layout with the right channel
// count, but not necessarily the same variant as the named constants
EXPECT_EQ(fb_channel_layout_get_channels(fb_channel_layout_default(6)), 6);
EXPECT_NE(fb_channel_layout_default(3), (uint64_t)0);
}
// ============================================================================
// Frame
// ============================================================================
TEST(FFmpegBridgeFrame, AllocAndFields)
{
FBFrame *frame = fb_frame_alloc();
ASSERT_NE(frame, nullptr);
EXPECT_EQ(fb_frame_get_width(frame), 0);
EXPECT_EQ(fb_frame_get_format(frame), FB_PIX_FMT_NONE);
fb_frame_set_width(frame, 320);
fb_frame_set_height(frame, 240);
fb_frame_set_format(frame, FB_PIX_FMT_RGBA);
fb_frame_set_pts(frame, 12345);
EXPECT_EQ(fb_frame_get_width(frame), 320);
EXPECT_EQ(fb_frame_get_height(frame), 240);
EXPECT_EQ(fb_frame_get_format(frame), FB_PIX_FMT_RGBA);
EXPECT_EQ(fb_frame_get_pts(frame), 12345);
fb_frame_free(&frame);
EXPECT_EQ(frame, nullptr);
}
TEST(FFmpegBridgeFrame, BufferAllocAndAccess)
{
FBFrame *frame = fb_frame_alloc();
ASSERT_NE(frame, nullptr);
fb_frame_set_width(frame, 64);
fb_frame_set_height(frame, 48);
fb_frame_set_format(frame, FB_PIX_FMT_RGBA);
ASSERT_EQ(fb_frame_get_buffer(frame, 0), 0);
ASSERT_EQ(fb_frame_make_writable(frame), 0);
EXPECT_NE(fb_frame_get_data(frame, 0), nullptr);
EXPECT_GE(fb_frame_get_linesize(frame, 0), 64 * 4);
EXPECT_EQ(fb_frame_is_hw(frame), 0);
// Write a pattern through the API and read it back
const int linesize = fb_frame_get_linesize(frame, 0);
for (int y = 0; y < 48; ++y) {
std::memset(fb_frame_get_data(frame, 0) + y * linesize, y & 0xFF,
linesize);
}
const uint8_t *data = fb_frame_get_data_const(frame, 0);
ASSERT_NE(data, nullptr);
EXPECT_EQ(data[0], 0);
EXPECT_EQ(data[10 * linesize], 10);
// Out-of-range plane access is safe
EXPECT_EQ(fb_frame_get_data(frame, -1), nullptr);
EXPECT_EQ(fb_frame_get_data(frame, 8), nullptr);
fb_frame_unref(frame);
EXPECT_EQ(fb_frame_get_data(frame, 0), nullptr);
fb_frame_free(&frame);
}
TEST(FFmpegBridgeFrame, AudioFields)
{
FBFrame *frame = fb_frame_alloc();
ASSERT_NE(frame, nullptr);
fb_frame_set_nb_samples(frame, 1024);
fb_frame_set_sample_rate(frame, 44100);
fb_frame_set_format(frame, FB_SAMPLE_FMT_FLTP);
fb_frame_set_channel_layout_mask(frame, FB_CH_LAYOUT_STEREO);
ASSERT_EQ(fb_frame_get_buffer(frame, 0), 0);
EXPECT_EQ(fb_frame_get_nb_samples(frame), 1024);
EXPECT_EQ(fb_frame_get_sample_rate(frame), 44100);
EXPECT_EQ(fb_frame_get_channel_layout_mask(frame), FB_CH_LAYOUT_STEREO);
// Planar stereo: two data planes
EXPECT_NE(fb_frame_get_data(frame, 0), nullptr);
EXPECT_NE(fb_frame_get_data(frame, 1), nullptr);
fb_frame_free(&frame);
}
TEST(FFmpegBridgeFrame, CopyProps)
{
FBFrame *src = fb_frame_alloc();
FBFrame *dst = fb_frame_alloc();
ASSERT_NE(src, nullptr);
ASSERT_NE(dst, nullptr);
// av_frame_copy_props copies metadata properties, not dimensions/format
fb_frame_set_pts(src, 777);
fb_frame_set_color_range(src, FB_COLOR_RANGE_JPEG);
fb_frame_set_colorspace(src, FB_COL_SPC_BT709);
ASSERT_EQ(fb_frame_copy_props(dst, src), 0);
EXPECT_EQ(fb_frame_get_pts(dst), 777);
EXPECT_EQ(fb_frame_get_color_range(dst), FB_COLOR_RANGE_JPEG);
EXPECT_EQ(fb_frame_get_colorspace(dst), FB_COL_SPC_BT709);
fb_frame_free(&src);
fb_frame_free(&dst);
}
TEST(FFmpegBridgeFrame, NullSafety)
{
EXPECT_LT(fb_frame_get_buffer(nullptr, 0), 0);
EXPECT_LT(fb_frame_make_writable(nullptr), 0);
EXPECT_EQ(fb_frame_get_width(nullptr), 0);
EXPECT_EQ(fb_frame_get_data(nullptr, 0), nullptr);
fb_frame_free(nullptr); // must not crash
}
// ============================================================================
// Packet
// ============================================================================
TEST(FFmpegBridgePacket, AllocAndDefaults)
{
FBPacket *packet = fb_packet_alloc();
ASSERT_NE(packet, nullptr);
EXPECT_EQ(fb_packet_get_pts(packet), FB_NOPTS_VALUE);
EXPECT_EQ(fb_packet_get_size(packet), 0);
EXPECT_EQ(fb_packet_get_data(packet), nullptr);
fb_packet_unref(packet);
fb_packet_free(&packet);
EXPECT_EQ(packet, nullptr);
}
// ============================================================================
// Scaler
// ============================================================================
TEST(FFmpegBridgeScaler, RgbaToYuv420P)
{
const int width = 64;
const int height = 64;
FBFrame *src = fb_frame_alloc();
fb_frame_set_width(src, width);
fb_frame_set_height(src, height);
fb_frame_set_format(src, FB_PIX_FMT_RGBA);
ASSERT_EQ(fb_frame_get_buffer(src, 0), 0);
// Solid mid-grey image
const int src_linesize = fb_frame_get_linesize(src, 0);
for (int y = 0; y < height; ++y) {
std::memset(fb_frame_get_data(src, 0) + y * src_linesize, 128,
width * 4);
}
FBFrame *dst = fb_frame_alloc();
fb_frame_set_width(dst, width);
fb_frame_set_height(dst, height);
fb_frame_set_format(dst, FB_PIX_FMT_YUV420P);
ASSERT_EQ(fb_frame_get_buffer(dst, 0), 0);
FBScaler *scaler = fb_scaler_create(width, height, FB_PIX_FMT_RGBA, width,
height, FB_PIX_FMT_YUV420P,
FB_SCALER_POINT);
ASSERT_NE(scaler, nullptr);
// sws_scale returns the output slice height on success
ASSERT_GE(fb_scaler_scale_frame(scaler, dst, src), 0);
fb_scaler_free(&scaler);
EXPECT_EQ(scaler, nullptr);
// Y plane of a mid-grey RGB source should sit near 128
const uint8_t *y_plane = fb_frame_get_data_const(dst, 0);
ASSERT_NE(y_plane, nullptr);
EXPECT_NEAR(y_plane[0], 128, 8);
// U and V planes of a grey image should sit near 128 (neutral chroma)
const uint8_t *u_plane = fb_frame_get_data_const(dst, 1);
const uint8_t *v_plane = fb_frame_get_data_const(dst, 2);
ASSERT_NE(u_plane, nullptr);
ASSERT_NE(v_plane, nullptr);
EXPECT_NEAR(u_plane[0], 128, 8);
EXPECT_NEAR(v_plane[0], 128, 8);
fb_frame_free(&src);
fb_frame_free(&dst);
}
TEST(FFmpegBridgeScaler, SetColorspace)
{
FBScaler *scaler = fb_scaler_create(64, 64, FB_PIX_FMT_YUV420P, 64, 64,
FB_PIX_FMT_RGBA, FB_SCALER_POINT);
ASSERT_NE(scaler, nullptr);
EXPECT_GE(fb_scaler_set_colorspace(scaler, FB_COL_SPC_BT709, 0), 0);
fb_scaler_free(&scaler);
}
TEST(FFmpegBridgeScaler, YuvCoefficients)
{
// Values come from swscale's coefficient tables (sws_getCoefficients /
// 65536), which include the studio-range scaling factor.
double coeffs[4] = { 0, 0, 0, 0 };
fb_get_yuv_coefficients(FB_COL_SPC_BT709, coeffs);
EXPECT_NEAR(coeffs[0], 117489 / 65536.0, 1e-6); // crv
EXPECT_NEAR(coeffs[1], 138438 / 65536.0, 1e-6); // cbu
EXPECT_GT(coeffs[2], 0.0);
EXPECT_GT(coeffs[3], 0.0);
fb_get_yuv_coefficients(FB_COL_SPC_SMPTE170M, coeffs);
EXPECT_NEAR(coeffs[0], 104597 / 65536.0, 1e-6); // crv
}
// ============================================================================
// Resampler
// ============================================================================
TEST(FFmpegBridgeResampler, ConvertFltpToS16p)
{
const int in_samples = 1024;
const double freq = 440.0;
const double rate = 44100.0;
FBResampler *resampler =
fb_resampler_create(FB_CH_LAYOUT_STEREO, FB_SAMPLE_FMT_S16P, 44100,
FB_CH_LAYOUT_STEREO, FB_SAMPLE_FMT_FLTP, 44100);
ASSERT_NE(resampler, nullptr);
const int out_capacity = fb_resampler_get_out_samples(resampler, in_samples);
ASSERT_GT(out_capacity, 0);
std::vector<float> in_left(in_samples), in_right(in_samples);
for (int i = 0; i < in_samples; ++i) {
in_left[i] = 0.5f * std::sin(2.0 * kPi * freq * i / rate);
in_right[i] = 0.5f * std::sin(2.0 * kPi * freq * i / rate);
}
const uint8_t *in_planes[2] = {
reinterpret_cast<const uint8_t *>(in_left.data()),
reinterpret_cast<const uint8_t *>(in_right.data())
};
std::vector<int16_t> out_left(out_capacity), out_right(out_capacity);
uint8_t *out_planes[2] = {
reinterpret_cast<uint8_t *>(out_left.data()),
reinterpret_cast<uint8_t *>(out_right.data())
};
const int converted = fb_resampler_convert(
resampler, out_planes, out_capacity, in_planes, in_samples);
ASSERT_GT(converted, 0);
// Output must be non-silent and bounded to full scale
bool non_silent = false;
for (int i = 0; i < converted; ++i) {
if (out_left[i] != 0) {
non_silent = true;
}
EXPECT_LE(std::abs(out_left[i]), 32767);
}
EXPECT_TRUE(non_silent);
fb_resampler_free(&resampler);
EXPECT_EQ(resampler, nullptr);
}
TEST(FFmpegBridgeResampler, ConvertFrameInput)
{
const int in_samples = 512;
FBResampler *resampler =
fb_resampler_create(FB_CH_LAYOUT_STEREO, FB_SAMPLE_FMT_S16P, 44100,
FB_CH_LAYOUT_STEREO, FB_SAMPLE_FMT_FLTP, 44100);
ASSERT_NE(resampler, nullptr);
FBFrame *frame = fb_frame_alloc();
fb_frame_set_nb_samples(frame, in_samples);
fb_frame_set_sample_rate(frame, 44100);
fb_frame_set_format(frame, FB_SAMPLE_FMT_FLTP);
fb_frame_set_channel_layout_mask(frame, FB_CH_LAYOUT_STEREO);
ASSERT_EQ(fb_frame_get_buffer(frame, 0), 0);
float *left = reinterpret_cast<float *>(fb_frame_get_data(frame, 0));
float *right = reinterpret_cast<float *>(fb_frame_get_data(frame, 1));
for (int i = 0; i < in_samples; ++i) {
left[i] = 0.25f;
right[i] = -0.25f;
}
const int out_capacity = fb_resampler_get_out_samples(resampler, in_samples);
std::vector<int16_t> out_left(out_capacity), out_right(out_capacity);
uint8_t *out_planes[2] = {
reinterpret_cast<uint8_t *>(out_left.data()),
reinterpret_cast<uint8_t *>(out_right.data())
};
const int converted =
fb_resampler_convert_frame(resampler, out_planes, out_capacity, frame);
ASSERT_GT(converted, 0);
// Constant 0.25 input should land near 0.25 * 32767
EXPECT_NEAR(out_left[converted / 2], 8192, 256);
EXPECT_NEAR(out_right[converted / 2], -8192, 256);
fb_frame_free(&frame);
fb_resampler_free(&resampler);
}
// ============================================================================
// Probe / Decoder on tests/demo.mp4
// ============================================================================
TEST(FFmpegBridgeProbe, DemoMp4Streams)
{
const QString path = DemoPath();
ASSERT_TRUE(QFileInfo::exists(path));
FBProbe *probe = fb_probe_create();
ASSERT_NE(probe, nullptr);
ASSERT_EQ(fb_probe_open(probe, path.toUtf8().constData()), 0);
EXPECT_GE(fb_probe_get_stream_count(probe), 1);
EXPECT_GT(fb_probe_get_duration(probe), 0);
const int video = FindStream(probe, FB_MEDIA_TYPE_VIDEO);
ASSERT_GE(video, 0);
FBStreamInfo info;
ASSERT_EQ(fb_probe_get_stream_info(probe, video, &info), 0);
EXPECT_EQ(info.width, 1920);
EXPECT_EQ(info.height, 1080);
EXPECT_NE(info.pixel_format, FB_PIX_FMT_NONE);
EXPECT_EQ(info.has_decoder, 1);
EXPECT_GT(info.time_base_den, 0);
// Metadata lookups must be safe whether or not the key exists
char buffer[256];
int found = fb_probe_get_metadata(probe, -1, "title", buffer, sizeof(buffer));
EXPECT_TRUE(found == 0 || found == 1);
fb_probe_close(probe);
fb_probe_free(&probe);
EXPECT_EQ(probe, nullptr);
}
TEST(FFmpegBridgeProbe, VideoStreamDetails)
{
const QString path = DemoPath();
ASSERT_TRUE(QFileInfo::exists(path));
FBVideoStreamDetails details;
ASSERT_EQ(fb_probe_video_stream_details(path.toUtf8().constData(), 0,
&details, 0, nullptr, nullptr),
0);
EXPECT_TRUE(details.field_order == FB_FIELD_ORDER_PROGRESSIVE ||
details.field_order == FB_FIELD_ORDER_UNKNOWN);
EXPECT_GT(details.frame_rate_num, 0);
EXPECT_GT(details.frame_rate_den, 0);
EXPECT_EQ(details.pixel_aspect_num, 1);
EXPECT_EQ(details.pixel_aspect_den, 1);
}
TEST(FFmpegBridgeProbe, ReadSubtitleStream)
{
// Write a small SRT file and read it back through the bridge
const QString path = TempFilePath(QStringLiteral("fb_bridge_test.srt"));
{
QFile file(path);
ASSERT_TRUE(file.open(QIODevice::WriteOnly | QIODevice::Text));
file.write("1\n00:00:01,000 --> 00:00:02,000\nHello bridge\n\n"
"2\n00:00:03,000 --> 00:00:04,500\nSecond line\n\n");
file.close();
}
struct Context {
int count = 0;
std::string first_text;
int64_t first_pts = FB_NOPTS_VALUE;
} ctx;
int result = fb_probe_read_subtitle_stream(
path.toUtf8().constData(), 0,
[](int64_t pts, int64_t, const char *text, int, void *userdata) {
auto *c = static_cast<Context *>(userdata);
if (c->count == 0) {
c->first_pts = pts;
c->first_text = text ? text : "";
}
c->count++;
},
&ctx);
EXPECT_EQ(result, 0);
EXPECT_EQ(ctx.count, 2);
EXPECT_NE(ctx.first_text.find("Hello bridge"), std::string::npos);
EXPECT_GE(ctx.first_pts, 0);
QFile::remove(path);
}
TEST(FFmpegBridgeDecoder, DecodeFirstFrame)
{
const QString path = DemoPath();
ASSERT_TRUE(QFileInfo::exists(path));
FBDecoder *decoder = fb_decoder_create();
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(fb_decoder_open(decoder, path.toUtf8().constData(), 0), 0);
FBStreamInfo info;
ASSERT_EQ(fb_decoder_get_stream_info(decoder, &info), 0);
EXPECT_EQ(info.width, 1920);
EXPECT_EQ(info.height, 1080);
EXPECT_EQ(info.codec_type, FB_MEDIA_TYPE_VIDEO);
EXPECT_GT(fb_decoder_get_format_duration(decoder), 0);
FBPacket *packet = fb_packet_alloc();
FBFrame *frame = fb_frame_alloc();
ASSERT_NE(packet, nullptr);
ASSERT_NE(frame, nullptr);
int result = -1;
for (int attempt = 0; attempt < 200 && result != 0; ++attempt) {
result = fb_decoder_get_frame(decoder, packet, frame);
}
ASSERT_EQ(result, 0);
EXPECT_EQ(fb_frame_get_width(frame), 1920);
EXPECT_EQ(fb_frame_get_height(frame), 1080);
EXPECT_NE(fb_frame_get_format(frame), FB_PIX_FMT_NONE);
EXPECT_NE(fb_frame_get_data(frame, 0), nullptr);
// Hardware frames live in device memory: transfer to a software frame
// before reading pixels
FBFrame *sw_frame = nullptr;
const FBFrame *read_frame = frame;
if (fb_frame_is_hw(frame)) {
sw_frame = fb_frame_alloc();
ASSERT_NE(sw_frame, nullptr);
ASSERT_EQ(fb_frame_hw_transfer_data(sw_frame, frame), 0);
read_frame = sw_frame;
}
// The decoded image should not be a black frame
const uint8_t *data = fb_frame_get_data_const(read_frame, 0);
ASSERT_NE(data, nullptr);
bool has_nonzero = false;
const int linesize = fb_frame_get_linesize(read_frame, 0);
for (int y = 0; y < 64 && !has_nonzero; ++y) {
for (int x = 0; x < 64; ++x) {
if (data[y * linesize + x] != 0) {
has_nonzero = true;
break;
}
}
}
EXPECT_TRUE(has_nonzero);
fb_frame_free(&sw_frame);
// Seek back to the start and decode again
fb_decoder_seek(decoder, 0);
result = -1;
for (int attempt = 0; attempt < 200 && result != 0; ++attempt) {
result = fb_decoder_get_frame(decoder, packet, frame);
}
EXPECT_EQ(result, 0);
fb_frame_free(&frame);
fb_packet_free(&packet);
fb_decoder_close(decoder);
fb_decoder_free(&decoder);
}
TEST(FFmpegBridgeDecoder, OpenFailure)
{
FBDecoder *decoder = fb_decoder_create();
ASSERT_NE(decoder, nullptr);
EXPECT_LT(fb_decoder_open(decoder, "/nonexistent/file.mp4", 0), 0);
fb_decoder_free(&decoder);
}
TEST(FFmpegBridgeDecoder, GuessRates)
{
const QString path = DemoPath();
ASSERT_TRUE(QFileInfo::exists(path));
FBDecoder *decoder = fb_decoder_create();
ASSERT_EQ(fb_decoder_open(decoder, path.toUtf8().constData(), 0), 0);
int num = 0, den = 0;
ASSERT_EQ(fb_decoder_guess_frame_rate(decoder, nullptr, &num, &den), 0);
EXPECT_GT(num, 0);
EXPECT_GT(den, 0);
ASSERT_EQ(fb_decoder_guess_sample_aspect_ratio(decoder, nullptr, &num, &den),
0);
EXPECT_EQ(num, 1);
EXPECT_EQ(den, 1);
fb_decoder_free(&decoder);
}
// ============================================================================
// Audio graph
// ============================================================================
TEST(FFmpegBridgeAudioGraph, TempoProcessing)
{
FBAudioGraphConfig config = {};
config.in_sample_rate = 44100;
config.in_channel_layout_mask = FB_CH_LAYOUT_STEREO;
config.in_sample_format = FB_SAMPLE_FMT_FLTP;
config.in_channels = 2;
config.out_sample_rate = 44100;
config.out_channel_layout_mask = FB_CH_LAYOUT_STEREO;
config.out_sample_format = FB_SAMPLE_FMT_FLTP;
config.out_channels = 2;
config.out_is_planar = 1;
config.tempo = 2.0;
FBAudioGraph *graph = fb_audio_graph_create(&config);
ASSERT_NE(graph, nullptr);
const int in_samples = 4410; // 0.1 seconds
std::vector<float> left(in_samples, 0.5f), right(in_samples, 0.5f);
const uint8_t *planes[2] = {
reinterpret_cast<const uint8_t *>(left.data()),
reinterpret_cast<const uint8_t *>(right.data())
};
ASSERT_EQ(fb_audio_graph_push(graph, planes, in_samples), 0);
// Flush
ASSERT_EQ(fb_audio_graph_push(graph, nullptr, 0), 0);
FBFrame *out = fb_frame_alloc();
int total_samples = 0;
int pull_result;
while ((pull_result = fb_audio_graph_pull(graph, out)) == 1) {
total_samples += fb_frame_get_nb_samples(out);
fb_frame_unref(out);
}
// 0 = needs more input, FB_ERROR_EOF = flushed graph is drained
EXPECT_TRUE(pull_result == 0 || pull_result == FB_ERROR_EOF);
// tempo 2.0 halves the duration; atempo has some internal padding,
// so allow generous bounds around the ideal 2205 samples
EXPECT_GT(total_samples, 1500);
EXPECT_LT(total_samples, 3000);
fb_frame_free(&out);
fb_audio_graph_free(&graph);
EXPECT_EQ(graph, nullptr);
}
// ============================================================================
// Encoder (end-to-end: encode, then probe the result back)
// ============================================================================
TEST(FFmpegBridgeEncoder, CodecFormatLists)
{
// PNG is a native FFmpeg encoder and always available
const char *names[16];
const int pix_count =
fb_encoder_codec_get_pixel_formats(FB_CODEC_PNG, names, 16);
EXPECT_GT(pix_count, 0);
int fmts[16];
const int sample_count =
fb_encoder_codec_get_sample_formats(FB_CODEC_AAC, fmts, 16);
EXPECT_GT(sample_count, 0);
}
TEST(FFmpegBridgeEncoder, WritePngVideoAndProbeBack)
{
const QString path = TempFilePath(QStringLiteral("fb_bridge_test.mkv"));
QFile::remove(path);
const int width = 64;
const int height = 64;
const int frame_count = 5;
FBEncoderConfig config = {};
config.filename = path.toUtf8().constData();
config.video_enabled = 1;
config.video_codec = FB_CODEC_PNG;
config.video_width = width;
config.video_height = height;
config.video_pixel_aspect_num = 1;
config.video_pixel_aspect_den = 1;
config.video_time_base_num = 1;
config.video_time_base_den = 30;
config.video_frame_rate_num = 30;
config.video_frame_rate_den = 1;
config.video_pix_fmt = "rgba";
config.video_src_pix_fmt = FB_PIX_FMT_RGBA;
config.video_color_range = FB_COLOR_RANGE_UNSPEC;
config.video_field_order = FB_FIELD_ORDER_PROGRESSIVE;
config.video_threads = 1;
FBEncoder *encoder = fb_encoder_create(&config);
ASSERT_NE(encoder, nullptr);
ASSERT_EQ(fb_encoder_open(encoder), 0)
<< "encoder error: " << fb_encoder_get_error(encoder);
std::vector<uint8_t> pixels(width * height * 4);
for (int f = 0; f < frame_count; ++f) {
for (int i = 0; i < width * height; ++i) {
pixels[i * 4 + 0] = static_cast<uint8_t>(f * 40); // R
pixels[i * 4 + 1] = 128; // G
pixels[i * 4 + 2] = 64; // B
pixels[i * 4 + 3] = 255; // A
}
ASSERT_EQ(fb_encoder_write_video_frame(encoder, width, height,
FB_PIX_FMT_RGBA, pixels.data(),
width * 4, f / 30.0),
0)
<< "encoder error: " << fb_encoder_get_error(encoder);
}
fb_encoder_close(encoder);
fb_encoder_free(&encoder);
// The file must exist and probe back as a 64x64 video
ASSERT_TRUE(QFileInfo::exists(path));
FBProbe *probe = fb_probe_create();
ASSERT_EQ(fb_probe_open(probe, path.toUtf8().constData()), 0);
const int video = FindStream(probe, FB_MEDIA_TYPE_VIDEO);
ASSERT_GE(video, 0);
FBStreamInfo info;
ASSERT_EQ(fb_probe_get_stream_info(probe, video, &info), 0);
EXPECT_EQ(info.width, width);
EXPECT_EQ(info.height, height);
fb_probe_close(probe);
fb_probe_free(&probe);
QFile::remove(path);
}
TEST(FFmpegBridgeEncoder, WritePcmAudioAndProbeBack)
{
const QString path = TempFilePath(QStringLiteral("fb_bridge_test.wav"));
QFile::remove(path);
FBEncoderConfig config = {};
config.filename = path.toUtf8().constData();
config.audio_enabled = 1;
config.audio_codec = FB_CODEC_PCM;
config.audio_sample_rate = 44100;
config.audio_channel_layout_mask = FB_CH_LAYOUT_STEREO;
config.audio_sample_format = FB_SAMPLE_FMT_S16;
FBEncoder *encoder = fb_encoder_create(&config);
ASSERT_NE(encoder, nullptr);
ASSERT_EQ(fb_encoder_open(encoder), 0)
<< "encoder error: " << fb_encoder_get_error(encoder);
const int sample_count = 4410;
std::vector<int16_t> left(sample_count), right(sample_count);
for (int i = 0; i < sample_count; ++i) {
left[i] = static_cast<int16_t>(
10000 * std::sin(2.0 * kPi * 440.0 * i / 44100.0));
right[i] = left[i];
}
const uint8_t *planes[2] = {
reinterpret_cast<const uint8_t *>(left.data()),
reinterpret_cast<const uint8_t *>(right.data())
};
ASSERT_EQ(fb_encoder_write_audio(encoder, planes, 2, FB_SAMPLE_FMT_S16P,
44100, FB_CH_LAYOUT_STEREO, sample_count),
0)
<< "encoder error: " << fb_encoder_get_error(encoder);
// Flush
EXPECT_EQ(fb_encoder_write_audio(encoder, nullptr, 2, FB_SAMPLE_FMT_S16P,
44100, FB_CH_LAYOUT_STEREO, 0),
0);
fb_encoder_close(encoder);
fb_encoder_free(&encoder);
ASSERT_TRUE(QFileInfo::exists(path));
FBProbe *probe = fb_probe_create();
ASSERT_EQ(fb_probe_open(probe, path.toUtf8().constData()), 0);
const int audio = FindStream(probe, FB_MEDIA_TYPE_AUDIO);
ASSERT_GE(audio, 0);
FBStreamInfo info;
ASSERT_EQ(fb_probe_get_stream_info(probe, audio, &info), 0);
EXPECT_EQ(info.sample_rate, 44100);
EXPECT_EQ(fb_channel_layout_get_channels(info.channel_layout_mask), 2);
fb_probe_close(probe);
fb_probe_free(&probe);
QFile::remove(path);
}
+2 -2
View File
@@ -49,8 +49,8 @@ TEST(ModuleSmoke, HumanStringsSampleRate)
TEST(ModuleSmoke, HumanStringsChannelLayout) TEST(ModuleSmoke, HumanStringsChannelLayout)
{ {
EXPECT_FALSE( EXPECT_FALSE(
olive::HumanStrings::ChannelLayoutToString(AV_CH_LAYOUT_MONO).isEmpty()); olive::HumanStrings::ChannelLayoutToString(olive::core::kChannelLayoutMono).isEmpty());
EXPECT_FALSE(olive::HumanStrings::ChannelLayoutToString(AV_CH_LAYOUT_STEREO) EXPECT_FALSE(olive::HumanStrings::ChannelLayoutToString(olive::core::kChannelLayoutStereo)
.isEmpty()); .isEmpty());
} }
+1 -1
View File
@@ -17,7 +17,7 @@ TEST(NodeGlobals, ConstructedWithParams)
olive::VideoParams video_params(1920, 1080, olive::PixelFormat::F32, 4); olive::VideoParams video_params(1920, 1080, olive::PixelFormat::F32, 4);
olive::AudioParams audio_params; olive::AudioParams audio_params;
audio_params.set_sample_rate(48000); audio_params.set_sample_rate(48000);
audio_params.set_channel_layout(AV_CH_LAYOUT_STEREO); audio_params.set_channel_layout(olive::core::kChannelLayoutStereo);
olive::TimeRange time(olive::core::rational(1, 24), olive::TimeRange time(olive::core::rational(1, 24),
olive::core::rational(2, 24)); olive::core::rational(2, 24));
+63 -57
View File
@@ -7,11 +7,6 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#include "common/ffmpegutils.h" #include "common/ffmpegutils.h"
#include "render/videoparams.h" #include "render/videoparams.h"
#include "render/texture.h" #include "render/texture.h"
@@ -20,19 +15,19 @@ using namespace olive;
using namespace olive::core; using namespace olive::core;
// Test helper to create AVFrame with specific format // Test helper to create AVFrame with specific format
static AVFramePtr CreateTestFrame(int width, int height, AVPixelFormat fmt, static AVFramePtr CreateTestFrame(int width, int height, int fmt,
uint32_t fill_color = 0xFF804020) uint32_t fill_color = 0xFF804020)
{ {
AVFramePtr frame = CreateAVFramePtr(); AVFramePtr frame = CreateAVFramePtr();
frame->width = width; frame->set_width(width);
frame->height = height; frame->set_height(height);
frame->format = fmt; frame->set_format(fmt);
if (av_frame_get_buffer(frame.get(), 0) < 0) { if (frame->get_buffer(0) < 0) {
return nullptr; return nullptr;
} }
if (av_frame_make_writable(frame.get()) < 0) { if (frame->make_writable() < 0) {
return nullptr; return nullptr;
} }
@@ -42,9 +37,9 @@ static AVFramePtr CreateTestFrame(int width, int height, AVPixelFormat fmt,
uint8_t b = (fill_color >> 8) & 0xFF; uint8_t b = (fill_color >> 8) & 0xFF;
uint8_t a = fill_color & 0xFF; uint8_t a = fill_color & 0xFF;
if (fmt == AV_PIX_FMT_RGBA) { if (fmt == FB_PIX_FMT_RGBA) {
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
uint8_t *row = frame->data[0] + y * frame->linesize[0]; uint8_t *row = frame->data(0) + y * frame->linesize(0);
for (int x = 0; x < width; ++x) { for (int x = 0; x < width; ++x) {
row[x * 4 + 0] = r; row[x * 4 + 0] = r;
row[x * 4 + 1] = g; row[x * 4 + 1] = g;
@@ -52,14 +47,14 @@ static AVFramePtr CreateTestFrame(int width, int height, AVPixelFormat fmt,
row[x * 4 + 3] = a; row[x * 4 + 3] = a;
} }
} }
} else if (fmt == AV_PIX_FMT_RGBA64) { } else if (fmt == FB_PIX_FMT_RGBA64LE) {
uint16_t r16 = (r << 8) | r; uint16_t r16 = (r << 8) | r;
uint16_t g16 = (g << 8) | g; uint16_t g16 = (g << 8) | g;
uint16_t b16 = (b << 8) | b; uint16_t b16 = (b << 8) | b;
uint16_t a16 = (a << 8) | a; uint16_t a16 = (a << 8) | a;
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
uint16_t *row = reinterpret_cast<uint16_t *>( uint16_t *row = reinterpret_cast<uint16_t *>(frame->data(0) +
frame->data[0] + y * frame->linesize[0]); y * frame->linesize(0));
for (int x = 0; x < width; ++x) { for (int x = 0; x < width; ++x) {
row[x * 4 + 0] = r16; row[x * 4 + 0] = r16;
row[x * 4 + 1] = g16; row[x * 4 + 1] = g16;
@@ -81,11 +76,11 @@ TEST(FormatConversion, U8ToU16)
// Create U8 frame // Create U8 frame
AVFramePtr u8_frame = AVFramePtr u8_frame =
CreateTestFrame(width, height, AV_PIX_FMT_RGBA, test_color); CreateTestFrame(width, height, FB_PIX_FMT_RGBA, test_color);
ASSERT_NE(u8_frame, nullptr); ASSERT_NE(u8_frame, nullptr);
// Verify U8 values // Verify U8 values
uint8_t *first_pixel_u8 = u8_frame->data[0]; uint8_t *first_pixel_u8 = u8_frame->data(0);
EXPECT_EQ(first_pixel_u8[0], 0xFF); // R EXPECT_EQ(first_pixel_u8[0], 0xFF); // R
EXPECT_EQ(first_pixel_u8[1], 0x80); // G EXPECT_EQ(first_pixel_u8[1], 0x80); // G
EXPECT_EQ(first_pixel_u8[2], 0x40); // B EXPECT_EQ(first_pixel_u8[2], 0x40); // B
@@ -93,12 +88,12 @@ TEST(FormatConversion, U8ToU16)
// Create U16 frame // Create U16 frame
AVFramePtr u16_frame = AVFramePtr u16_frame =
CreateTestFrame(width, height, AV_PIX_FMT_RGBA64, test_color); CreateTestFrame(width, height, FB_PIX_FMT_RGBA64LE, test_color);
ASSERT_NE(u16_frame, nullptr); ASSERT_NE(u16_frame, nullptr);
// Verify U16 values (should be U8 value repeated: 0xFF -> 0xFFFF, 0x80 -> 0x8080) // Verify U16 values (should be U8 value repeated: 0xFF -> 0xFFFF, 0x80 -> 0x8080)
uint16_t *first_pixel_u16 = uint16_t *first_pixel_u16 =
reinterpret_cast<uint16_t *>(u16_frame->data[0]); reinterpret_cast<uint16_t *>(u16_frame->data(0));
EXPECT_EQ(first_pixel_u16[0], 0xFFFF); // R EXPECT_EQ(first_pixel_u16[0], 0xFFFF); // R
EXPECT_EQ(first_pixel_u16[1], 0x8080); // G EXPECT_EQ(first_pixel_u16[1], 0x8080); // G
EXPECT_EQ(first_pixel_u16[2], 0x4040); // B EXPECT_EQ(first_pixel_u16[2], 0x4040); // B
@@ -114,58 +109,69 @@ TEST(FormatConversion, FFmpegU16ToU8)
// Create U16 frame // Create U16 frame
AVFramePtr u16_frame = AVFramePtr u16_frame =
CreateTestFrame(width, height, AV_PIX_FMT_RGBA64, test_color); CreateTestFrame(width, height, FB_PIX_FMT_RGBA64LE, test_color);
ASSERT_NE(u16_frame, nullptr); ASSERT_NE(u16_frame, nullptr);
// Create destination U8 frame // Create destination U8 frame
AVFramePtr u8_frame = CreateTestFrame(width, height, AV_PIX_FMT_RGBA, 0); AVFramePtr u8_frame = CreateTestFrame(width, height, FB_PIX_FMT_RGBA, 0);
ASSERT_NE(u8_frame, nullptr); ASSERT_NE(u8_frame, nullptr);
// Use sws_scale to convert // Use the bridge scaler to convert
SwsContext *sws_ctx = sws_getContext(width, height, AV_PIX_FMT_RGBA64, FBScaler *sws_ctx = fb_scaler_create(width, height, FB_PIX_FMT_RGBA64LE,
width, height, AV_PIX_FMT_RGBA, width, height, FB_PIX_FMT_RGBA,
SWS_POINT, nullptr, nullptr, nullptr); FB_SCALER_POINT);
ASSERT_NE(sws_ctx, nullptr); ASSERT_NE(sws_ctx, nullptr);
sws_scale(sws_ctx, u16_frame->data, u16_frame->linesize, 0, height, uint8_t *src_data[4];
u8_frame->data, u8_frame->linesize); int src_linesize[4];
sws_freeContext(sws_ctx); uint8_t *dst_data[4];
int dst_linesize[4];
for (int i = 0; i < 4; ++i) {
src_data[i] = u16_frame->data(i);
src_linesize[i] = u16_frame->linesize(i);
dst_data[i] = u8_frame->data(i);
dst_linesize[i] = u8_frame->linesize(i);
}
fb_scaler_scale_slices(sws_ctx, src_data, src_linesize, height, dst_data,
dst_linesize);
fb_scaler_free(&sws_ctx);
// Verify conversion (U16 0xFFFF -> U8 0xFF, 0x8080 -> ~0x80, etc.) // Verify conversion (U16 0xFFFF -> U8 0xFF, 0x8080 -> ~0x80, etc.)
// Note: FFmpeg sws_scale has rounding offset, so values may be off by 1 // Note: FFmpeg sws_scale has rounding offset, so values may be off by 1
uint8_t *first_pixel = u8_frame->data[0]; uint8_t *first_pixel = u8_frame->data(0);
EXPECT_NEAR(first_pixel[0], 0xFF, 1); // R (255 vs 255) EXPECT_NEAR(first_pixel[0], 0xFF, 1); // R (255 vs 255)
EXPECT_NEAR(first_pixel[1], 0x80, 1); // G (128 vs 129) EXPECT_NEAR(first_pixel[1], 0x80, 1); // G (128 vs 129)
EXPECT_NEAR(first_pixel[2], 0x40, 1); // B (64 vs 64) EXPECT_NEAR(first_pixel[2], 0x40, 1); // B (64 vs 64)
EXPECT_NEAR(first_pixel[3], 0x20, 1); // A (32 vs 32) EXPECT_NEAR(first_pixel[3], 0x20, 1); // A (32 vs 32)
} }
// Test VideoParams to AVPixelFormat mapping // Test VideoParams to bridge pixel format mapping
TEST(FormatConversion, VideoParamsToAVFormat) TEST(FormatConversion, VideoParamsToAVFormat)
{ {
// U8 RGBA // U8 RGBA
VideoParams u8_rgba(320, 240, PixelFormat::U8, 4); VideoParams u8_rgba(320, 240, PixelFormat::U8, 4);
AVPixelFormat fmt_u8_rgba = FFmpegUtils::GetFFmpegPixelFormat( int fmt_u8_rgba = FFmpegUtils::GetFFmpegPixelFormat(
u8_rgba.format(), u8_rgba.channel_count()); u8_rgba.format(), u8_rgba.channel_count());
EXPECT_EQ(fmt_u8_rgba, AV_PIX_FMT_RGBA); EXPECT_EQ(fmt_u8_rgba, FB_PIX_FMT_RGBA);
// U16 RGBA // U16 RGBA
VideoParams u16_rgba(320, 240, PixelFormat::U16, 4); VideoParams u16_rgba(320, 240, PixelFormat::U16, 4);
AVPixelFormat fmt_u16_rgba = FFmpegUtils::GetFFmpegPixelFormat( int fmt_u16_rgba = FFmpegUtils::GetFFmpegPixelFormat(
u16_rgba.format(), u16_rgba.channel_count()); u16_rgba.format(), u16_rgba.channel_count());
EXPECT_EQ(fmt_u16_rgba, AV_PIX_FMT_RGBA64); EXPECT_EQ(fmt_u16_rgba, FB_PIX_FMT_RGBA64LE);
// U8 RGB // U8 RGB
VideoParams u8_rgb(320, 240, PixelFormat::U8, 3); VideoParams u8_rgb(320, 240, PixelFormat::U8, 3);
AVPixelFormat fmt_u8_rgb = FFmpegUtils::GetFFmpegPixelFormat( int fmt_u8_rgb = FFmpegUtils::GetFFmpegPixelFormat(
u8_rgb.format(), u8_rgb.channel_count()); u8_rgb.format(), u8_rgb.channel_count());
EXPECT_EQ(fmt_u8_rgb, AV_PIX_FMT_RGB24); EXPECT_EQ(fmt_u8_rgb, FB_PIX_FMT_RGB24);
// U16 RGB // U16 RGB
VideoParams u16_rgb(320, 240, PixelFormat::U16, 3); VideoParams u16_rgb(320, 240, PixelFormat::U16, 3);
AVPixelFormat fmt_u16_rgb = FFmpegUtils::GetFFmpegPixelFormat( int fmt_u16_rgb = FFmpegUtils::GetFFmpegPixelFormat(
u16_rgb.format(), u16_rgb.channel_count()); u16_rgb.format(), u16_rgb.channel_count());
EXPECT_EQ(fmt_u16_rgb, AV_PIX_FMT_RGB48); EXPECT_EQ(fmt_u16_rgb, FB_PIX_FMT_RGB48LE);
} }
// Test row bytes calculation // Test row bytes calculation
@@ -193,18 +199,18 @@ TEST(FormatConversion, LinesizeAlignment)
const int height = 10; const int height = 10;
AVFramePtr frame = CreateAVFramePtr(); AVFramePtr frame = CreateAVFramePtr();
frame->width = width; frame->set_width(width);
frame->height = height; frame->set_height(height);
frame->format = AV_PIX_FMT_RGBA; frame->set_format(FB_PIX_FMT_RGBA);
ASSERT_EQ(av_frame_get_buffer(frame.get(), 0), 0); ASSERT_EQ(frame->get_buffer(0), 0);
// linesize[0] should be at least width * 4 // linesize[0] should be at least width * 4
EXPECT_GE(frame->linesize[0], width * 4); EXPECT_GE(frame->linesize(0), width * 4);
// linesize may be larger due to alignment (typically 32-byte aligned) // linesize may be larger due to alignment (typically 32-byte aligned)
qDebug() << "Width:" << width << "Expected bytes:" << width * 4 qDebug() << "Width:" << width << "Expected bytes:" << width * 4
<< "Actual linesize:" << frame->linesize[0]; << "Actual linesize:" << frame->linesize(0);
} }
// Test loading actual image file // Test loading actual image file
@@ -216,34 +222,34 @@ TEST(FormatConversion, LoadImageFile)
AVFramePtr frame = CreateAVFramePtr(); AVFramePtr frame = CreateAVFramePtr();
// Just create a simple test frame instead of loading an image // Just create a simple test frame instead of loading an image
frame->width = 1920; frame->set_width(1920);
frame->height = 1080; frame->set_height(1080);
frame->format = AV_PIX_FMT_RGBA; frame->set_format(FB_PIX_FMT_RGBA);
if (av_frame_get_buffer(frame.get(), 0) < 0) { if (frame->get_buffer(0) < 0) {
return; return;
} }
// Fill with orange color (sunrise sky) // Fill with orange color (sunrise sky)
for (int y = 0; y < frame->height; ++y) { for (int y = 0; y < frame->height(); ++y) {
uint8_t *row = frame->data[0] + y * frame->linesize[0]; uint8_t *row = frame->data(0) + y * frame->linesize(0);
uint8_t r = 255; uint8_t r = 255;
uint8_t g = 128 + (y * 127) / frame->height; // Gradient from 128 to 255 uint8_t g = 128 + (y * 127) / frame->height(); // Gradient from 128 to 255
uint8_t b = 64; uint8_t b = 64;
uint8_t a = 255; uint8_t a = 255;
for (int x = 0; x < frame->width; ++x) { for (int x = 0; x < frame->width(); ++x) {
row[x * 4 + 0] = r; row[x * 4 + 0] = r;
row[x * 4 + 1] = g; row[x * 4 + 1] = g;
row[x * 4 + 2] = b; row[x * 4 + 2] = b;
row[x * 4 + 3] = a; row[x * 4 + 3] = a;
} }
} }
ASSERT_NE(frame->data[0], nullptr) << "Failed to create test frame"; ASSERT_NE(frame->data(0), nullptr) << "Failed to create test frame";
EXPECT_EQ(frame->width, 1920); EXPECT_EQ(frame->width(), 1920);
EXPECT_EQ(frame->height, 1080); EXPECT_EQ(frame->height(), 1080);
// Check first pixel (top-left corner of the sunrise image) // Check first pixel (top-left corner of the sunrise image)
// Based on the image, it should have some orange/pink color in the sky area // Based on the image, it should have some orange/pink color in the sky area
uint8_t *first_pixel = frame->data[0]; uint8_t *first_pixel = frame->data(0);
qDebug() << "First pixel RGBA:" << first_pixel[0] << first_pixel[1] qDebug() << "First pixel RGBA:" << first_pixel[0] << first_pixel[1]
<< first_pixel[2] << first_pixel[3]; << first_pixel[2] << first_pixel[3];
+10 -14
View File
@@ -2,10 +2,6 @@
#include <cstdlib> #include <cstdlib>
extern "C" {
#include <libavutil/frame.h>
}
#include "common/ffmpegutils.h" #include "common/ffmpegutils.h"
#include "node/value.h" #include "node/value.h"
#include "pluginSupport/OliveHost.h" #include "pluginSupport/OliveHost.h"
@@ -21,23 +17,23 @@ namespace
olive::TexturePtr CreateSolidTexture(const olive::VideoParams &params) olive::TexturePtr CreateSolidTexture(const olive::VideoParams &params)
{ {
olive::AVFramePtr frame = olive::CreateAVFramePtr(); olive::AVFramePtr frame = olive::CreateAVFramePtr();
frame->format = olive::FFmpegUtils::GetFFmpegPixelFormat( frame->set_format(olive::FFmpegUtils::GetFFmpegPixelFormat(
params.format(), params.channel_count()); params.format(), params.channel_count()));
frame->width = params.width(); frame->set_width(params.width());
frame->height = params.height(); frame->set_height(params.height());
if (frame->format == AV_PIX_FMT_NONE) { if (frame->format() == FB_PIX_FMT_NONE) {
return nullptr; return nullptr;
} }
if (av_frame_get_buffer(frame.get(), 0) < 0) { if (frame->get_buffer(0) < 0) {
return nullptr; return nullptr;
} }
if (av_frame_make_writable(frame.get()) < 0) { if (frame->make_writable() < 0) {
return nullptr; return nullptr;
} }
const int linesize = frame->linesize[0]; const int linesize = frame->linesize(0);
for (int y = 0; y < frame->height; ++y) { for (int y = 0; y < frame->height(); ++y) {
std::memset(frame->data[0] + y * linesize, 0x7f, linesize); std::memset(frame->data(0) + y * linesize, 0x7f, linesize);
} }
olive::TexturePtr texture = std::make_shared<olive::Texture>(params); olive::TexturePtr texture = std::make_shared<olive::Texture>(params);
+23 -27
View File
@@ -14,10 +14,6 @@
#include <cstdlib> #include <cstdlib>
extern "C" {
#include <libavutil/frame.h>
}
#include "common/ffmpegutils.h" #include "common/ffmpegutils.h"
#include "node/value.h" #include "node/value.h"
#include "pluginSupport/OliveHost.h" #include "pluginSupport/OliveHost.h"
@@ -45,24 +41,24 @@ template <typename T>
TexturePtr CreateSolidTextureT(const VideoParams &params, T fill_value) TexturePtr CreateSolidTextureT(const VideoParams &params, T fill_value)
{ {
AVFramePtr frame = CreateAVFramePtr(); AVFramePtr frame = CreateAVFramePtr();
frame->format = FFmpegUtils::GetFFmpegPixelFormat(params.format(), frame->set_format(FFmpegUtils::GetFFmpegPixelFormat(params.format(),
params.channel_count()); params.channel_count()));
frame->width = params.width(); frame->set_width(params.width());
frame->height = params.height(); frame->set_height(params.height());
if (frame->format == AV_PIX_FMT_NONE) { if (frame->format() == FB_PIX_FMT_NONE) {
return nullptr; return nullptr;
} }
if (av_frame_get_buffer(frame.get(), 0) < 0) { if (frame->get_buffer(0) < 0) {
return nullptr; return nullptr;
} }
if (av_frame_make_writable(frame.get()) < 0) { if (frame->make_writable() < 0) {
return nullptr; return nullptr;
} }
const int linesize = frame->linesize[0]; const int linesize = frame->linesize(0);
for (int y = 0; y < frame->height; ++y) { for (int y = 0; y < frame->height(); ++y) {
T *row = reinterpret_cast<T *>(frame->data[0] + y * linesize); T *row = reinterpret_cast<T *>(frame->data(0) + y * linesize);
for (int x = 0; x < frame->width * params.channel_count(); ++x) { for (int x = 0; x < frame->width() * params.channel_count(); ++x) {
row[x] = fill_value; row[x] = fill_value;
} }
} }
@@ -99,25 +95,25 @@ template <typename T>
TexturePtr CreateGradientTextureT(const VideoParams &params, float scale) TexturePtr CreateGradientTextureT(const VideoParams &params, float scale)
{ {
AVFramePtr frame = CreateAVFramePtr(); AVFramePtr frame = CreateAVFramePtr();
frame->format = FFmpegUtils::GetFFmpegPixelFormat(params.format(), frame->set_format(FFmpegUtils::GetFFmpegPixelFormat(params.format(),
params.channel_count()); params.channel_count()));
frame->width = params.width(); frame->set_width(params.width());
frame->height = params.height(); frame->set_height(params.height());
if (frame->format == AV_PIX_FMT_NONE) { if (frame->format() == FB_PIX_FMT_NONE) {
return nullptr; return nullptr;
} }
if (av_frame_get_buffer(frame.get(), 0) < 0) { if (frame->get_buffer(0) < 0) {
return nullptr; return nullptr;
} }
if (av_frame_make_writable(frame.get()) < 0) { if (frame->make_writable() < 0) {
return nullptr; return nullptr;
} }
const int linesize = frame->linesize[0]; const int linesize = frame->linesize(0);
for (int y = 0; y < frame->height; ++y) { for (int y = 0; y < frame->height(); ++y) {
T *row = reinterpret_cast<T *>(frame->data[0] + y * linesize); T *row = reinterpret_cast<T *>(frame->data(0) + y * linesize);
T value = static_cast<T>((y * scale) / frame->height); T value = static_cast<T>((y * scale) / frame->height());
for (int x = 0; x < frame->width * params.channel_count(); ++x) { for (int x = 0; x < frame->width() * params.channel_count(); ++x) {
row[x] = value; row[x] = value;
} }
} }
+10 -14
View File
@@ -43,10 +43,6 @@
#include "node/value.h" #include "node/value.h"
#include "common/ffmpegutils.h" #include "common/ffmpegutils.h"
extern "C" {
#include <libavutil/frame.h>
}
namespace olive namespace olive
{ {
namespace plugin namespace plugin
@@ -77,23 +73,23 @@ static TexturePtr CreateTestTexture(const VideoParams &params,
uint8_t fill_value = 0x7f) uint8_t fill_value = 0x7f)
{ {
AVFramePtr frame = CreateAVFramePtr(); AVFramePtr frame = CreateAVFramePtr();
frame->format = FFmpegUtils::GetFFmpegPixelFormat(params.format(), frame->set_format(FFmpegUtils::GetFFmpegPixelFormat(params.format(),
params.channel_count()); params.channel_count()));
frame->width = params.width(); frame->set_width(params.width());
frame->height = params.height(); frame->set_height(params.height());
if (frame->format == AV_PIX_FMT_NONE) { if (frame->format() == FB_PIX_FMT_NONE) {
return nullptr; return nullptr;
} }
if (av_frame_get_buffer(frame.get(), 0) < 0) { if (frame->get_buffer(0) < 0) {
return nullptr; return nullptr;
} }
if (av_frame_make_writable(frame.get()) < 0) { if (frame->make_writable() < 0) {
return nullptr; return nullptr;
} }
const int linesize = frame->linesize[0]; const int linesize = frame->linesize(0);
for (int y = 0; y < frame->height; ++y) { for (int y = 0; y < frame->height(); ++y) {
std::memset(frame->data[0] + y * linesize, fill_value, linesize); std::memset(frame->data(0) + y * linesize, fill_value, linesize);
} }
TexturePtr texture = std::make_shared<Texture>(params); TexturePtr texture = std::make_shared<Texture>(params);
+10 -10
View File
@@ -7,11 +7,11 @@ TEST(RenderAudioParams, ValidityAndEquality)
olive::core::AudioParams invalid; olive::core::AudioParams invalid;
EXPECT_FALSE(invalid.is_valid()); EXPECT_FALSE(invalid.is_valid());
olive::core::AudioParams params(48000, AV_CH_LAYOUT_STEREO, olive::core::AudioParams params(48000, olive::core::kChannelLayoutStereo,
olive::core::SampleFormat::S16); olive::core::SampleFormat::S16);
EXPECT_TRUE(params.is_valid()); EXPECT_TRUE(params.is_valid());
olive::core::AudioParams other(48000, AV_CH_LAYOUT_STEREO, olive::core::AudioParams other(48000, olive::core::kChannelLayoutStereo,
olive::core::SampleFormat::S16); olive::core::SampleFormat::S16);
EXPECT_TRUE(params == other); EXPECT_TRUE(params == other);
@@ -21,7 +21,7 @@ TEST(RenderAudioParams, ValidityAndEquality)
TEST(RenderAudioParams, TimeAndSampleConversions) TEST(RenderAudioParams, TimeAndSampleConversions)
{ {
olive::core::AudioParams params(48000, AV_CH_LAYOUT_STEREO, olive::core::AudioParams params(48000, olive::core::kChannelLayoutStereo,
olive::core::SampleFormat::S16); olive::core::SampleFormat::S16);
EXPECT_EQ(params.channel_count(), 2); EXPECT_EQ(params.channel_count(), 2);
@@ -43,33 +43,33 @@ TEST(RenderAudioParams, TimeAndSampleConversions)
TEST(RenderAudioParams, ChannelLayoutCount) TEST(RenderAudioParams, ChannelLayoutCount)
{ {
olive::core::AudioParams mono(48000, AV_CH_LAYOUT_MONO, olive::core::AudioParams mono(48000, olive::core::kChannelLayoutMono,
olive::core::SampleFormat::F32); olive::core::SampleFormat::F32);
EXPECT_EQ(mono.channel_count(), 1); EXPECT_EQ(mono.channel_count(), 1);
olive::core::AudioParams surround(48000, AV_CH_LAYOUT_5POINT1, olive::core::AudioParams surround(48000, olive::core::kChannelLayout5Point1,
olive::core::SampleFormat::F32); olive::core::SampleFormat::F32);
EXPECT_EQ(surround.channel_count(), 6); EXPECT_EQ(surround.channel_count(), 6);
} }
TEST(RenderAudioParams, SampleFormatSizes) TEST(RenderAudioParams, SampleFormatSizes)
{ {
olive::core::AudioParams u8(48000, AV_CH_LAYOUT_MONO, olive::core::AudioParams u8(48000, olive::core::kChannelLayoutMono,
olive::core::SampleFormat::U8); olive::core::SampleFormat::U8);
EXPECT_EQ(u8.bytes_per_sample_per_channel(), 1); EXPECT_EQ(u8.bytes_per_sample_per_channel(), 1);
olive::core::AudioParams f32(48000, AV_CH_LAYOUT_MONO, olive::core::AudioParams f32(48000, olive::core::kChannelLayoutMono,
olive::core::SampleFormat::F32); olive::core::SampleFormat::F32);
EXPECT_EQ(f32.bytes_per_sample_per_channel(), 4); EXPECT_EQ(f32.bytes_per_sample_per_channel(), 4);
olive::core::AudioParams f64(48000, AV_CH_LAYOUT_MONO, olive::core::AudioParams f64(48000, olive::core::kChannelLayoutMono,
olive::core::SampleFormat::F64); olive::core::SampleFormat::F64);
EXPECT_EQ(f64.bytes_per_sample_per_channel(), 8); EXPECT_EQ(f64.bytes_per_sample_per_channel(), 8);
} }
TEST(RenderAudioParams, CopyAndAssignment) TEST(RenderAudioParams, CopyAndAssignment)
{ {
olive::core::AudioParams params(96000, AV_CH_LAYOUT_STEREO, olive::core::AudioParams params(96000, olive::core::kChannelLayoutStereo,
olive::core::SampleFormat::F32); olive::core::SampleFormat::F32);
olive::core::AudioParams copy(params); olive::core::AudioParams copy(params);
@@ -85,7 +85,7 @@ TEST(RenderAudioParams, CopyAndAssignment)
TEST(RenderAudioParams, SettersModifyState) TEST(RenderAudioParams, SettersModifyState)
{ {
olive::core::AudioParams params(44100, AV_CH_LAYOUT_MONO, olive::core::AudioParams params(44100, olive::core::kChannelLayoutMono,
olive::core::SampleFormat::S16); olive::core::SampleFormat::S16);
EXPECT_TRUE(params.is_valid()); EXPECT_TRUE(params.is_valid());
@@ -1,8 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
extern "C" { #include <cstdint>
#include <libavutil/avutil.h>
}
#include <QBuffer> #include <QBuffer>
#include <QXmlStreamReader> #include <QXmlStreamReader>
@@ -86,7 +84,7 @@ TEST(RenderVideoParams, ValidityAndTimebase)
olive::VideoParams params; olive::VideoParams params;
EXPECT_FALSE(params.is_valid()); EXPECT_FALSE(params.is_valid());
EXPECT_EQ(params.get_time_in_timebase_units(olive::core::rational(1, 1)), EXPECT_EQ(params.get_time_in_timebase_units(olive::core::rational(1, 1)),
AV_NOPTS_VALUE); INT64_MIN /* AV_NOPTS_VALUE */);
params.set_width(1920); params.set_width(1920);
params.set_height(1080); params.set_height(1080);
+1 -5
View File
@@ -7,10 +7,6 @@
#include <cmath> #include <cmath>
extern "C" {
#include <libavutil/channel_layout.h>
}
#include "audio/audiovisualwaveform.h" #include "audio/audiovisualwaveform.h"
#include "node/block/clip/clip.h" #include "node/block/clip/clip.h"
#include "node/node.h" #include "node/node.h"
@@ -29,7 +25,7 @@ namespace
AudioParams MakeMonoParams(int sample_rate) AudioParams MakeMonoParams(int sample_rate)
{ {
return AudioParams(sample_rate, static_cast<uint64_t>(AV_CH_LAYOUT_MONO), return AudioParams(sample_rate, static_cast<uint64_t>(kChannelLayoutMono),
SampleFormat::F32P); SampleFormat::F32P);
} }
+1 -1
View File
@@ -323,7 +323,7 @@ TEST(ViewerSmokeAudioCache, ParameterSetters)
{ {
AudioPlaybackCache cache; AudioPlaybackCache cache;
AudioParams params(48000, AV_CH_LAYOUT_STEREO, SampleFormat::F32P); AudioParams params(48000, kChannelLayoutStereo, SampleFormat::F32P);
cache.SetParameters(params); cache.SetParameters(params);
// Parameters should be retrievable // Parameters should be retrievable