Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/e2e-test-intel-vpl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
push:
paths:
- ".github/workflows/e2e-test-intel-vpl.yml"
- "tests/test_intel_vpl.py"
- "tests/test_intel_vpl**"
# C++ SDK のアップデートしたときテストするため
- "VERSION"
schedule:
Expand Down Expand Up @@ -52,7 +52,7 @@ jobs:
- run: uv python pin ${{ matrix.python_version }}
- run: uv sync
- run: uv run python run.py ubuntu-24.04_x86_64
- run: uv run pytest tests/test_intel_vpl.py -v
- run: uv run pytest tests/test_intel_vpl* -v

# slack_notify_succeeded:
# needs: [e2e_test_intel_vpl]
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ on:
- "**.md"
- ".github/workflows/e2e-test-intel-vpl.yml"
- ".github/workflows/e2e-test-apple-video-toolbox.yml"
- "tests/test_intel_vpl.py"
- "tests/test_apple_video_toolbox.py"
- "tests/test_intel_vpl**"
- "tests/test_apple_video_toolbox**"
schedule:
# UTC の 01:00 は JST だと 10:00 。
# 1-5 で 月曜日から金曜日
Expand Down
5 changes: 5 additions & 0 deletions tests/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ def _fake_audio_loop(self):
if self._audio_source is not None:
self._audio_source.on_data(numpy.zeros((320, 1), dtype=numpy.int16))

# video の解像度を変更する
def set_video_resolution(self, width: int, height: int):
self._video_width = width
self._video_height = height

def _fake_video_loop(self):
while not self._disconnected.is_set():
time.sleep(1.0 / 30)
Expand Down
4 changes: 1 addition & 3 deletions tests/test_intel_vpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,6 @@ def test_intel_vpl_sendonly_recvonly_sw_hw(

# codec が無かったら StopIteration 例外が上がる
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
# H.264/H.265 が採用されているかどうか確認する
assert sendonly_codec_stats["mimeType"] == f"video/{video_codec_type}"

# outbound-rtp が無かったら StopIteration 例外が上がる
Expand All @@ -776,11 +775,10 @@ def test_intel_vpl_sendonly_recvonly_sw_hw(

# codec が無かったら StopIteration 例外が上がる
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
# H.264/H.265 が採用されているかどうか確認する
assert recvonly_codec_stats["mimeType"] == f"video/{video_codec_type}"

# inbound-rtp が無かったら StopIteration 例外が上がる
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
assert inbound_rtp_stats["decoderImplementation"] == expected_decoder_implementation
assert inbound_rtp_stats["bytesReceived"] > 0
assert inbound_rtp_stats["packetsReceived"] > 0
assert inbound_rtp_stats["packetsReceived"] > 0
243 changes: 243 additions & 0 deletions tests/test_intel_vpl_av1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import os
import sys
import time
import uuid

import pytest
from client import (
SoraClient,
SoraRole,
)

from sora_sdk import (
SoraVideoCodecImplementation,
SoraVideoCodecPreference,
SoraVideoCodecType,
)


@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
def test_intel_vpl_av1_decoder_dynamic_resolution(setup):
"""
- AV1 の映像の解像度が変わっても正常に動作するかを確認する
"""

signaling_urls = setup.get("signaling_urls")
channel_id_prefix = setup.get("channel_id_prefix")
metadata = setup.get("metadata")

channel_id = f"{channel_id_prefix}_{__name__}_{sys._getframe().f_code.co_name}_{uuid.uuid4()}"

# 送信側は libaom を利用してソフトウェアエンコードを利用する
sendonly = SoraClient(
signaling_urls,
SoraRole.SENDONLY,
channel_id,
audio=False,
video=True,
video_codec_type="AV1",
video_bit_rate=5000,
metadata=metadata,
video_codec_preference=SoraVideoCodecPreference(
codecs=[
SoraVideoCodecPreference.Codec(
type=SoraVideoCodecType.AV1,
encoder=SoraVideoCodecImplementation.INTERNAL,
),
]
),
video_width=1280,
video_height=720,
)
sendonly.connect(fake_video=True)

# 受信側は libvpl を利用してハードウェアデコードを利用する
recvonly = SoraClient(
signaling_urls,
SoraRole.RECVONLY,
channel_id,
metadata=metadata,
video_codec_preference=SoraVideoCodecPreference(
codecs=[
SoraVideoCodecPreference.Codec(
type=SoraVideoCodecType.AV1,
decoder=SoraVideoCodecImplementation.INTEL_VPL,
),
]
),
)
recvonly.connect()

time.sleep(5)

# offer の sdp に video_codec_type が含まれているかどうかを確認している
assert sendonly.offer_message is not None
assert "sdp" in sendonly.offer_message
assert "AV1" in sendonly.offer_message["sdp"]

# answer の sdp に video_codec_type が含まれているかどうかを確認している
assert sendonly.answer_message is not None
assert "sdp" in sendonly.answer_message
assert "AV1" in sendonly.answer_message["sdp"]

sendonly_stats = sendonly.get_stats()
recvonly_stats = recvonly.get_stats()

# codec が無かったら StopIteration 例外が上がる
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
assert sendonly_codec_stats["mimeType"] == "video/AV1"

# outbound-rtp が無かったら StopIteration 例外が上がる
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
assert outbound_rtp_stats["encoderImplementation"] == "libaom"
assert outbound_rtp_stats["bytesSent"] > 0
assert outbound_rtp_stats["packetsSent"] > 0
assert outbound_rtp_stats["frameWidth"] == 1280
assert outbound_rtp_stats["frameHeight"] == 720

# codec が無かったら StopIteration 例外が上がる
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
assert recvonly_codec_stats["mimeType"] == "video/AV1"

# inbound-rtp が無かったら StopIteration 例外が上がる
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
assert inbound_rtp_stats["decoderImplementation"] == "libvpl"
assert inbound_rtp_stats["bytesReceived"] > 0
assert inbound_rtp_stats["packetsReceived"] > 0
assert inbound_rtp_stats["frameWidth"] == 1280
assert inbound_rtp_stats["frameHeight"] == 720

# 解像度を回転させる
sendonly.set_video_resolution(720, 1280)

time.sleep(5)

sendonly_stats = sendonly.get_stats()
recvonly_stats = recvonly.get_stats()

# outbound-rtp が無かったら StopIteration 例外が上がる
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
assert outbound_rtp_stats["encoderImplementation"] == "libaom"
assert outbound_rtp_stats["bytesSent"] > 0
assert outbound_rtp_stats["packetsSent"] > 0
# 送信側の解像度が回転していることを確認する
assert outbound_rtp_stats["frameWidth"] == 720
assert outbound_rtp_stats["frameHeight"] == 1280

# codec が無かったら StopIteration 例外が上がる
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
assert recvonly_codec_stats["mimeType"] == "video/AV1"

# inbound-rtp が無かったら StopIteration 例外が上がる
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
assert inbound_rtp_stats["decoderImplementation"] == "libvpl"
assert inbound_rtp_stats["bytesReceived"] > 0
assert inbound_rtp_stats["packetsReceived"] > 0
# 受信側の解像度が回転していることを確認する
assert inbound_rtp_stats["frameWidth"] == 720
assert inbound_rtp_stats["frameHeight"] == 1280

sendonly.disconnect()
recvonly.disconnect()


@pytest.mark.skipif(os.environ.get("INTEL_VPL") is None, reason="Intel VPL でのみ実行する")
@pytest.mark.parametrize(
"video_bit_rate,video_width, video_height",
[
(7500, 2160, 3840),
(500, 320, 240),
],
)
def test_intel_vpl_av1_decoder(setup, video_bit_rate, video_width, video_height):
"""
- 8K でも正常に動作するかを確認する
"""

signaling_urls = setup.get("signaling_urls")
channel_id_prefix = setup.get("channel_id_prefix")
metadata = setup.get("metadata")

channel_id = f"{channel_id_prefix}_{__name__}_{sys._getframe().f_code.co_name}_{uuid.uuid4()}"

# 送信側は libaom を利用してソフトウェアエンコードを利用する
sendonly = SoraClient(
signaling_urls,
SoraRole.SENDONLY,
channel_id,
audio=False,
video=True,
video_codec_type="AV1",
video_bit_rate=video_bit_rate,
metadata=metadata,
video_codec_preference=SoraVideoCodecPreference(
codecs=[
SoraVideoCodecPreference.Codec(
type=SoraVideoCodecType.AV1,
encoder=SoraVideoCodecImplementation.INTERNAL,
),
]
),
video_width=video_width,
video_height=video_height,
)
sendonly.connect(fake_video=True)

# 受信側は libvpl を利用してハードウェアデコードを利用する
recvonly = SoraClient(
signaling_urls,
SoraRole.RECVONLY,
channel_id,
metadata=metadata,
video_codec_preference=SoraVideoCodecPreference(
codecs=[
SoraVideoCodecPreference.Codec(
type=SoraVideoCodecType.AV1,
decoder=SoraVideoCodecImplementation.INTEL_VPL,
),
]
),
)
recvonly.connect()

time.sleep(10)

# offer の sdp に video_codec_type が含まれているかどうかを確認している
assert sendonly.offer_message is not None
assert "sdp" in sendonly.offer_message
assert "AV1" in sendonly.offer_message["sdp"]

# answer の sdp に video_codec_type が含まれているかどうかを確認している
assert sendonly.answer_message is not None
assert "sdp" in sendonly.answer_message
assert "AV1" in sendonly.answer_message["sdp"]

sendonly_stats = sendonly.get_stats()
recvonly_stats = recvonly.get_stats()

# codec が無かったら StopIteration 例外が上がる
sendonly_codec_stats = next(s for s in sendonly_stats if s.get("type") == "codec")
assert sendonly_codec_stats["mimeType"] == "video/AV1"

# outbound-rtp が無かったら StopIteration 例外が上がる
outbound_rtp_stats = next(s for s in sendonly_stats if s.get("type") == "outbound-rtp")
assert outbound_rtp_stats["encoderImplementation"] == "libaom"
assert outbound_rtp_stats["bytesSent"] > 0
assert outbound_rtp_stats["packetsSent"] > 0
assert outbound_rtp_stats["frameWidth"] == video_width
assert outbound_rtp_stats["frameHeight"] == video_height

# codec が無かったら StopIteration 例外が上がる
recvonly_codec_stats = next(s for s in recvonly_stats if s.get("type") == "codec")
assert recvonly_codec_stats["mimeType"] == "video/AV1"

# inbound-rtp が無かったら StopIteration 例外が上がる
inbound_rtp_stats = next(s for s in recvonly_stats if s.get("type") == "inbound-rtp")
assert inbound_rtp_stats["decoderImplementation"] == "libvpl"
assert inbound_rtp_stats["bytesReceived"] > 0
assert inbound_rtp_stats["packetsReceived"] > 0
assert inbound_rtp_stats["frameWidth"] == video_width
assert inbound_rtp_stats["frameHeight"] == video_height

sendonly.disconnect()
recvonly.disconnect()