Browse Source

Exercise codec output delay explicitly in the desktop fixture

master
evgeny 5 days ago
parent
commit
8d0504c759
  1. 3
      tools/chatgui/CMakeLists.txt
  2. 34
      tools/chatgui/tests/test_stream_view.cpp

3
tools/chatgui/CMakeLists.txt

@ -537,7 +537,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_options(test_stream_view PRIVATE "-Wl,--wrap=ma_context_init" "-Wl,--wrap=ma_device_init"
"-Wl,--wrap=audio_stream_frame_time")
if(FFMPEG_FOUND)
target_link_options(test_stream_view PRIVATE "-Wl,--wrap=avcodec_open2")
target_link_options(test_stream_view PRIVATE "-Wl,--wrap=avcodec_open2" "-Wl,--wrap=avcodec_receive_frame"
"-Wl,--wrap=avcodec_free_context")
endif()
endif()
add_test(NAME test_stream_view COMMAND test_stream_view)

34
tools/chatgui/tests/test_stream_view.cpp

@ -10,6 +10,7 @@
#include <atomic>
#include <cmath>
#include <chrono>
#include <deque>
extern "C" {
#include "utun_instance.h"
@ -29,12 +30,39 @@ extern "C" {
static QList<QByteArray> snapshots;
#if defined(TEST_NULL_AUDIO) && defined(HAVE_FFMPEG)
static std::atomic<bool> delayedDecoder{false};
static AVCodecContext* delayedContext = nullptr;
static std::deque<AVFrame*> delayedFrames;
static bool delayedDraining = false;
extern "C" int __real_avcodec_open2(AVCodecContext*, const AVCodec*, AVDictionary**);
extern "C" int __wrap_avcodec_open2(AVCodecContext* context, const AVCodec* codec, AVDictionary** options) {
if (delayedDecoder && av_codec_is_decoder(codec)) {
context->thread_count = 4; context->thread_type = FF_THREAD_FRAME;
int result = __real_avcodec_open2(context, codec, options);
if (!result && delayedDecoder && codec && av_codec_is_decoder(codec)) {
delayedContext = context; delayedDraining = false;
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "fixture decoder name=%s holds four real decoded frames before output", codec->name);
}
return __real_avcodec_open2(context, codec, options);
return result;
}
extern "C" int __real_avcodec_receive_frame(AVCodecContext*, AVFrame*);
extern "C" int __wrap_avcodec_receive_frame(AVCodecContext* context, AVFrame* frame) {
if (context != delayedContext) return __real_avcodec_receive_frame(context, frame);
int result = __real_avcodec_receive_frame(context, frame);
if (!result) {
AVFrame* held = av_frame_clone(frame); if (!held) return AVERROR(ENOMEM);
delayedFrames.push_back(held); av_frame_unref(frame);
} else if (result == AVERROR_EOF) delayedDraining = true;
else if (result != AVERROR(EAGAIN)) return result;
if ((delayedDraining || delayedFrames.size() >= 4) && !delayedFrames.empty()) {
AVFrame* held = delayedFrames.front(); delayedFrames.pop_front(); av_frame_move_ref(frame, held); av_frame_free(&held); return 0;
}
return delayedDraining ? AVERROR_EOF : AVERROR(EAGAIN);
}
extern "C" void __real_avcodec_free_context(AVCodecContext**);
extern "C" void __wrap_avcodec_free_context(AVCodecContext** context) {
if (context && *context == delayedContext) {
for (auto* frame : delayedFrames) av_frame_free(&frame);
delayedFrames.clear(); delayedContext = nullptr; delayedDraining = false;
}
__real_avcodec_free_context(context);
}
#endif
#ifdef TEST_NULL_AUDIO

Loading…
Cancel
Save