Verify decoded video content, AAC signal timing and FFmpeg-free stubs
This commit is contained in:
1 parent
9163025912
commit
9f1825dbf8
3 files changed
+64
-4
No files matched your search
@@ -10,6 +10,7 @@ EXTRA_DIST = fixtures/reality_openssl_hello.hex data/silero_speech.pcm data/sile
|
||||
# Быстрые проверки (до 100мс).
|
||||
check_PROGRAMS = \
|
||||
test_video \
|
||||
test_video_no_ffmpeg \
|
||||
test_video_plane \
|
||||
test_route_tx_stats \
|
||||
test_call_video_rate \
|
||||
@@ -786,6 +787,8 @@ test_call_video_LDADD = $(LIBUTUN) $(COMMON_LIBS)
|
||||
|
||||
test_video_SOURCES = test_video.c
|
||||
test_video_LDADD = $(LIBUTUN) $(COMMON_LIBS)
|
||||
test_video_no_ffmpeg_SOURCES = test_video_no_ffmpeg.c
|
||||
test_video_no_ffmpeg_LDADD = $(COMMON_LIBS)
|
||||
if HAVE_FFMPEG
|
||||
if OS_LINUX
|
||||
test_video_LDFLAGS = -Wl,--wrap=fdopen -Wl,--wrap=fwrite -Wl,--wrap=fflush -Wl,--wrap=fclose -Wl,--wrap=rename \
|
||||
|
||||
+34
-4
@@ -134,6 +134,8 @@ static void fixture_packets(AVFormatContext* mux, AVCodecContext* enc, AVStream*
|
||||
int error;
|
||||
while ((error = avcodec_receive_packet(enc, packet)) == 0) {
|
||||
av_packet_rescale_ts(packet, enc->time_base, stream->time_base);
|
||||
if (enc->codec_type == AVMEDIA_TYPE_VIDEO && packet->duration <= 0)
|
||||
packet->duration = av_rescale_q(1, enc->time_base, stream->time_base);
|
||||
packet->stream_index = stream->index;
|
||||
assert(av_interleaved_write_frame(mux, packet) >= 0);
|
||||
}
|
||||
@@ -161,7 +163,14 @@ static void fixture(const char* path, const char* format, enum AVCodecID video,
|
||||
codec = avcodec_find_encoder(audio); assert(codec);
|
||||
aenc = avcodec_alloc_context3(codec); assert(aenc);
|
||||
aenc->sample_rate = 32000; aenc->time_base = (AVRational){1, 32000};
|
||||
aenc->sample_fmt = codec->sample_fmts[0]; aenc->bit_rate = 64000; aenc->thread_count = 1;
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 61
|
||||
const void* formats;
|
||||
assert(avcodec_get_supported_config(aenc, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, &formats, NULL) >= 0 && formats);
|
||||
aenc->sample_fmt = ((const enum AVSampleFormat*)formats)[0];
|
||||
#else
|
||||
aenc->sample_fmt = codec->sample_fmts[0];
|
||||
#endif
|
||||
aenc->bit_rate = 64000; aenc->thread_count = 1;
|
||||
av_channel_layout_default(&aenc->ch_layout, 1);
|
||||
if (mux->oformat->flags & AVFMT_GLOBALHEADER) aenc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
||||
assert(avcodec_open2(aenc, codec, NULL) >= 0);
|
||||
@@ -192,6 +201,14 @@ static void fixture(const char* path, const char* format, enum AVCodecID video,
|
||||
frame->nb_samples = block; frame->pts = sample + audio_offset_ms * aenc->sample_rate / 1000;
|
||||
assert(av_frame_get_buffer(frame, 0) >= 0);
|
||||
assert(av_samples_set_silence(frame->extended_data, 0, block, 1, aenc->sample_fmt) >= 0);
|
||||
enum AVSampleFormat packed = av_get_packed_sample_fmt(aenc->sample_fmt);
|
||||
for (int i = 0; i < block; i++) {
|
||||
float value = (sample + i) % 64 < 32 ? 0.25f : -0.25f;
|
||||
if (packed == AV_SAMPLE_FMT_FLT) ((float*)frame->data[0])[i] = value;
|
||||
else if (packed == AV_SAMPLE_FMT_S16) ((int16_t*)frame->data[0])[i] = (int16_t)(value * 32767);
|
||||
else if (packed == AV_SAMPLE_FMT_S32) ((int32_t*)frame->data[0])[i] = (int32_t)(value * 2147483647.0);
|
||||
else assert(!"unsupported fixture sample format");
|
||||
}
|
||||
assert(avcodec_send_frame(aenc, frame) >= 0); fixture_packets(mux, aenc, astream);
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
@@ -256,6 +273,7 @@ static void decode_result(const char* path, unsigned expected_frames, int expect
|
||||
av_packet_unref(packet);
|
||||
while ((error = avcodec_receive_frame(dec, frame)) >= 0) {
|
||||
assert(frame->width > 0 && frame->height > 0);
|
||||
if (expected_frames == 6) assert(abs(frame->data[0][0] - (40 + (int)frames * 20)) <= 6);
|
||||
if (last != AV_NOPTS_VALUE && frame->best_effort_timestamp != AV_NOPTS_VALUE) assert(frame->best_effort_timestamp > last);
|
||||
last = frame->best_effort_timestamp; frames++;
|
||||
}
|
||||
@@ -274,7 +292,7 @@ static void decode_audio(const char* path, int minimum_samples, int offset_ms) {
|
||||
AVCodecContext* decoder = avcodec_alloc_context3(avcodec_find_decoder(stream->codecpar->codec_id)); assert(decoder);
|
||||
assert(avcodec_parameters_to_context(decoder, stream->codecpar) >= 0 && avcodec_open2(decoder, decoder->codec, NULL) >= 0);
|
||||
AVPacket* packet = av_packet_alloc(); AVFrame* frame = av_frame_alloc(); assert(packet && frame);
|
||||
int samples = 0, eof = 0; int64_t first_us = AV_NOPTS_VALUE;
|
||||
int samples = 0, eof = 0; int64_t first_us = AV_NOPTS_VALUE, signal_us = AV_NOPTS_VALUE;
|
||||
while (!eof) {
|
||||
int error = av_read_frame(format, packet);
|
||||
if (error == AVERROR_EOF) eof = 1;
|
||||
@@ -282,14 +300,26 @@ static void decode_audio(const char* path, int minimum_samples, int offset_ms) {
|
||||
assert(avcodec_send_packet(decoder, eof ? NULL : packet) >= 0); av_packet_unref(packet);
|
||||
while ((error = avcodec_receive_frame(decoder, frame)) >= 0) {
|
||||
if (first_us == AV_NOPTS_VALUE) first_us = av_rescale_q(frame->best_effort_timestamp, stream->time_base, AV_TIME_BASE_Q);
|
||||
assert(frame->format == AV_SAMPLE_FMT_FLTP);
|
||||
if (signal_us == AV_NOPTS_VALUE) {
|
||||
for (int sample = 0; sample < frame->nb_samples; sample++) {
|
||||
float value = ((const float*)frame->extended_data[0])[sample];
|
||||
if (value > 0.05f || value < -0.05f) {
|
||||
signal_us = av_rescale_q(frame->best_effort_timestamp, stream->time_base, AV_TIME_BASE_Q) +
|
||||
av_rescale(sample, 1000000, decoder->sample_rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
samples += frame->nb_samples;
|
||||
}
|
||||
assert(error == AVERROR_EOF || error == AVERROR(EAGAIN));
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "test_video decoded audio samples=%d first_us=%lld expected_offset_ms=%d",
|
||||
samples, (long long)first_us, offset_ms);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "test_video decoded audio samples=%d first_us=%lld signal_us=%lld expected_offset_ms=%d",
|
||||
samples, (long long)first_us, (long long)signal_us, offset_ms);
|
||||
assert(samples >= minimum_samples && samples <= minimum_samples + 2048);
|
||||
assert(first_us != AV_NOPTS_VALUE && llabs(first_us - (int64_t)offset_ms * 1000) <= 33000);
|
||||
assert(signal_us != AV_NOPTS_VALUE && llabs(signal_us - (int64_t)offset_ms * 1000) <= 10000);
|
||||
av_packet_free(&packet); av_frame_free(&frame); avcodec_free_context(&decoder); avformat_close_input(&format);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Компилировать сам модуль без FFmpeg независимо от конфигурации основной сборки. */
|
||||
#undef HAVE_FFMPEG
|
||||
#include "../src/video/video.c"
|
||||
#include <assert.h>
|
||||
|
||||
static unsigned callbacks;
|
||||
static void unexpected_done(void* arg, int error, const struct video_info* info) {
|
||||
(void)arg; (void)error; (void)info; callbacks++;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
|
||||
struct video_info actual, zero = {0}; memset(&actual, 0x5a, sizeof(actual));
|
||||
video_ffmpeg_init();
|
||||
assert(video_probe("unused") == 0);
|
||||
assert(video_get_info("unused", &actual) == -1 && !memcmp(&actual, &zero, sizeof(actual)));
|
||||
assert(video_get_info(NULL, NULL) == -1 && video_needs_transcode(NULL) == 1);
|
||||
assert(video_transcode_start(NULL, NULL, "src", "dst", unexpected_done, NULL) == -1 && !callbacks);
|
||||
assert(video_extract_thumbnail("src", "dst", 320) == -1);
|
||||
assert(video_transcode_get_progress() == -1 && !video_transcode_is_active());
|
||||
video_codec_probe_begin(); video_codec_probe_begin();
|
||||
assert(video_codec_log_level(DEBUG_LEVEL_ERROR) == DEBUG_LEVEL_DEBUG);
|
||||
video_codec_probe_end(); assert(video_codec_log_level(DEBUG_LEVEL_WARN) == DEBUG_LEVEL_DEBUG);
|
||||
video_codec_probe_end(); assert(video_codec_log_level(DEBUG_LEVEL_ERROR) == DEBUG_LEVEL_ERROR);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_VIDEO, "PASS video build without FFmpeg");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user