diff --git a/tools/chatgui/tests/test_stream_publish.cpp b/tools/chatgui/tests/test_stream_publish.cpp index 00cb0f6f..43e90daf 100644 --- a/tools/chatgui/tests/test_stream_publish.cpp +++ b/tools/chatgui/tests/test_stream_publish.cpp @@ -166,6 +166,34 @@ private slots: gui_stream_publish_stop(id); QVERIFY(record(viewer, StreamRecordKind::End, out)); QTRY_VERIFY_WITH_TIMEOUT(ended(id), 4000); QCOMPARE(gui_stream_publish_feed(id, true, 300000, true, second, &format), -1); gui_stream_stop(viewer); } + void liveSoftwareBitrateKeepsDecoder() { +#ifdef HAVE_FFMPEG + StreamVideoEncoder encoder; StreamVideoConfig config; config.width = config.height = 16; + QVERIFY(encoder.open(config)); + if (encoder.name() != "libx264") QSKIP("The available hardware encoder uses video-only replacement for bitrate changes"); + QImage image(16, 16, QImage::Format_RGB32); image.fill(Qt::red); QList output; + QVERIFY(encoder.encode(image, 100000, true, output)); QVERIFY(!output.isEmpty() && output.front().key); + const uint8_t *configuration, *frame; size_t configLength, frameLength; + auto first = output.front().data; + QCOMPARE(stream_media_key_parse((const uint8_t*)first.constData(), first.size(), &configuration, &configLength, &frame, &frameLength), STREAM_OK); + auto* decoder = avcodec_alloc_context3(avcodec_find_decoder(AV_CODEC_ID_H264)); QVERIFY(decoder); + decoder->extradata = (uint8_t*)av_mallocz(configLength + AV_INPUT_BUFFER_PADDING_SIZE); QVERIFY(decoder->extradata); + memcpy(decoder->extradata, configuration, configLength); decoder->extradata_size = (int)configLength; + QCOMPARE(avcodec_open2(decoder, decoder->codec, nullptr), 0); + AVPacket* packet = av_packet_alloc(); AVFrame* decoded = av_frame_alloc(); QVERIFY(packet && decoded); + QCOMPARE(av_new_packet(packet, (int)frameLength), 0); memcpy(packet->data, frame, frameLength); + QCOMPARE(avcodec_send_packet(decoder, packet), 0); QCOMPARE(avcodec_receive_frame(decoder, decoded), 0); + av_packet_unref(packet); av_frame_unref(decoded); + QVERIFY(encoder.setBitrate(500000)); image.fill(Qt::blue); output.clear(); + QVERIFY(encoder.encode(image, 133333, false, output)); QVERIFY(!output.isEmpty() && !output.front().key); + QCOMPARE(av_new_packet(packet, output.front().data.size()), 0); memcpy(packet->data, output.front().data.constData(), packet->size); + QCOMPARE(avcodec_send_packet(decoder, packet), 0); QCOMPARE(avcodec_receive_frame(decoder, decoded), 0); + QCOMPARE(decoded->width, 16); QCOMPARE(decoded->height, 16); + av_packet_free(&packet); av_frame_free(&decoded); avcodec_free_context(&decoder); +#else + QSKIP("FFmpeg unavailable"); +#endif + } void overloadRequiresKey() { uint64_t id = 102; stream_media_format format{160, 90, 0, STREAM_MEDIA_H264, 0, 1}; QVERIFY(gui_stream_publish_open(id, group, format)); QTRY_VERIFY(live(id)); diff --git a/tools/chatgui/tests/test_windows_installer.py b/tools/chatgui/tests/test_windows_installer.py index 48066221..a5b99e36 100644 --- a/tools/chatgui/tests/test_windows_installer.py +++ b/tools/chatgui/tests/test_windows_installer.py @@ -120,6 +120,23 @@ files = sorted(str(p.relative_to(package)) for p in package.rglob('*') if p.is_f assert result2['files'] == result['files'] print('PASS: repeated packaging and paths containing spaces') + capture = {'Qt6Multimedia.dll': ['Qt6Core.dll'], 'Qt6MultimediaWidgets.dll': ['Qt6Multimedia.dll'], + 'multimedia/ffmpegmediaplugin.dll': ['capture-helper.dll', 'MFPlat.dll'], 'capture-helper.dll': ['KERNEL32.dll']} + write(root / 'Windows/System32/MFPlat.dll', 'system multimedia file\n') + for name, imports in capture.items(): + content = ''.join(f'DLL Name: {dll}\n' for dll in imports) + write(build / name, content) + write(prefix / ('share/qt6/plugins' if '/' in name else 'bin') / name, content) + write(build / 'chatgui_capture_enabled.txt', '1\n') + captured = package() + assert set(captured['files']) == expected | set(capture) + (build / 'capture-helper.dll').unlink() + failed = run(ok=False) + assert 'ffmpegmediaplugin.dll requires capture-helper.dll' in failed.stderr + write(build / 'capture-helper.dll', 'DLL Name: KERNEL32.dll\n') + write(build / 'chatgui_capture_enabled.txt', '0\n') + print('PASS: capture installer includes Multimedia plugin dependencies and rejects incomplete capture runtime') + missing = build / 'jpeg-helper.dll' saved = missing.read_text() missing.unlink()