Skip to content

Commit 4ca4bc7

Browse files
committed
Merge remote-tracking branch 'migration/main' into python-video-live-stream-migration
2 parents 24a1664 + f834671 commit 4ca4bc7

24 files changed

+1798
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2022 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
import uuid
17+
18+
import pytest
19+
20+
import create_channel
21+
import create_channel_event
22+
import create_input
23+
import delete_channel
24+
import delete_channel_event
25+
import delete_input
26+
import get_channel_event
27+
import list_channel_events
28+
import start_channel
29+
import stop_channel
30+
31+
project_name = os.environ["GOOGLE_CLOUD_PROJECT"]
32+
location = "us-central1"
33+
input_id = f"python-test-input-{uuid.uuid4()}"
34+
channel_id = f"python-test-channel-{uuid.uuid4()}"
35+
event_id = f"python-test-event-{uuid.uuid4()}"
36+
output_bucket_name = f"python-test-bucket-{uuid.uuid4()}"
37+
output_uri = f"gs://{output_bucket_name}/channel-test/"
38+
39+
40+
def test_channel_event_operations(capsys: pytest.fixture) -> None:
41+
42+
# Set up
43+
44+
channel_name_project_id = (
45+
f"projects/{project_name}/locations/{location}/channels/{channel_id}"
46+
)
47+
event_name_project_id = f"projects/{project_name}/locations/{location}/channels/{channel_id}/events/{event_id}"
48+
49+
create_input.create_input(project_name, location, input_id)
50+
51+
create_channel.create_channel(
52+
project_name, location, channel_id, input_id, output_uri
53+
)
54+
out, _ = capsys.readouterr()
55+
assert channel_name_project_id in out
56+
57+
start_channel.start_channel(project_name, location, channel_id)
58+
out, _ = capsys.readouterr()
59+
assert "Started channel" in out
60+
61+
# Tests
62+
63+
create_channel_event.create_channel_event(
64+
project_name, location, channel_id, event_id
65+
)
66+
out, _ = capsys.readouterr()
67+
assert event_name_project_id in out
68+
69+
get_channel_event.get_channel_event(project_name, location, channel_id, event_id)
70+
out, _ = capsys.readouterr()
71+
assert event_name_project_id in out
72+
73+
list_channel_events.list_channel_events(project_name, location, channel_id)
74+
out, _ = capsys.readouterr()
75+
assert event_name_project_id in out
76+
77+
delete_channel_event.delete_channel_event(
78+
project_name, location, channel_id, event_id
79+
)
80+
out, _ = capsys.readouterr()
81+
assert "Deleted channel event" in out
82+
83+
# Clean up
84+
85+
stop_channel.stop_channel(project_name, location, channel_id)
86+
out, _ = capsys.readouterr()
87+
assert "Stopped channel" in out
88+
89+
delete_channel.delete_channel(project_name, location, channel_id)
90+
out, _ = capsys.readouterr()
91+
assert "Deleted channel" in out
92+
93+
delete_input.delete_input(project_name, location, input_id)

video/livestream/channel_test.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Copyright 2022 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
import uuid
17+
18+
from google.api_core.exceptions import FailedPrecondition, NotFound
19+
import pytest
20+
21+
import create_channel
22+
import create_channel_with_backup_input
23+
import create_input
24+
import delete_channel
25+
import delete_channel_event
26+
import delete_input
27+
import get_channel
28+
import list_channel_events
29+
import list_channels
30+
import start_channel
31+
import stop_channel
32+
import update_channel
33+
import utils
34+
35+
project_name = os.environ["GOOGLE_CLOUD_PROJECT"]
36+
location = "us-central1"
37+
input_id = f"python-test-input-{uuid.uuid4()}"
38+
updated_input_id = f"python-test-up-input-{uuid.uuid4()}"
39+
channel_id = f"python-test-channel-{uuid.uuid4()}"
40+
output_bucket_name = f"python-test-bucket-{uuid.uuid4()}"
41+
output_uri = f"gs://{output_bucket_name}/channel-test/"
42+
43+
44+
def test_channel_operations(capsys: pytest.fixture) -> None:
45+
46+
# Clean up old resources in the test project
47+
channel_responses = list_channels.list_channels(project_name, location)
48+
49+
for response in channel_responses:
50+
next_channel_id = response.name.rsplit("/", 1)[-1]
51+
input_attachments = response.input_attachments
52+
if utils.is_resource_stale(response.create_time):
53+
try:
54+
event_responses = list_channel_events.list_channel_events(
55+
project_name, location, next_channel_id
56+
)
57+
for response in event_responses:
58+
next_event_id = response.name.rsplit("/", 1)[-1]
59+
try:
60+
delete_channel_event.delete_channel_event(
61+
project_name, location, next_channel_id, next_event_id
62+
)
63+
except NotFound as e:
64+
print(f"Ignoring NotFound, details: {e}")
65+
try:
66+
stop_channel.stop_channel(project_name, location, next_channel_id)
67+
except FailedPrecondition as e:
68+
print(f"Ignoring FailedPrecondition, details: {e}")
69+
try:
70+
delete_channel.delete_channel(
71+
project_name, location, next_channel_id
72+
)
73+
except FailedPrecondition as e:
74+
print(f"Ignoring FailedPrecondition, try to stop channel: {e}")
75+
try:
76+
stop_channel.stop_channel(
77+
project_name, location, next_channel_id
78+
)
79+
except FailedPrecondition as e:
80+
print(f"Ignoring FailedPrecondition, details: {e}")
81+
except NotFound as e:
82+
print(f"Ignoring NotFound, details: {e}")
83+
except NotFound as e:
84+
print(f"Ignoring NotFound, details: {e}")
85+
86+
for input_attachment in input_attachments:
87+
next_input_id = input_attachment.input.rsplit("/", 1)[-1]
88+
try:
89+
delete_input.delete_input(project_name, location, next_input_id)
90+
except NotFound as e:
91+
print(f"Ignoring NotFound, details: {e}")
92+
93+
# Set up
94+
95+
channel_name_project_id = (
96+
f"projects/{project_name}/locations/{location}/channels/{channel_id}"
97+
)
98+
99+
create_input.create_input(project_name, location, input_id)
100+
create_input.create_input(project_name, location, updated_input_id)
101+
102+
# Tests
103+
104+
create_channel.create_channel(
105+
project_name, location, channel_id, input_id, output_uri
106+
)
107+
out, _ = capsys.readouterr()
108+
assert channel_name_project_id in out
109+
110+
list_channels.list_channels(project_name, location)
111+
out, _ = capsys.readouterr()
112+
assert channel_name_project_id in out
113+
114+
response = update_channel.update_channel(
115+
project_name, location, channel_id, updated_input_id
116+
)
117+
out, _ = capsys.readouterr()
118+
assert channel_name_project_id in out
119+
for input_attachment in response.input_attachments:
120+
assert "updated-input" in input_attachment.key
121+
122+
get_channel.get_channel(project_name, location, channel_id)
123+
out, _ = capsys.readouterr()
124+
assert channel_name_project_id in out
125+
126+
start_channel.start_channel(project_name, location, channel_id)
127+
out, _ = capsys.readouterr()
128+
assert "Started channel" in out
129+
130+
stop_channel.stop_channel(project_name, location, channel_id)
131+
out, _ = capsys.readouterr()
132+
assert "Stopped channel" in out
133+
134+
delete_channel.delete_channel(project_name, location, channel_id)
135+
out, _ = capsys.readouterr()
136+
assert "Deleted channel" in out
137+
138+
create_channel_with_backup_input.create_channel_with_backup_input(
139+
project_name, location, channel_id, input_id, updated_input_id, output_uri
140+
)
141+
out, _ = capsys.readouterr()
142+
assert channel_name_project_id in out
143+
144+
# Clean up
145+
146+
delete_channel.delete_channel(project_name, location, channel_id)
147+
delete_input.delete_input(project_name, location, input_id)
148+
delete_input.delete_input(project_name, location, updated_input_id)

video/livestream/create_channel.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2022 Google Inc. All Rights Reserved.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""Google Cloud Live Stream sample for creating a channel. A channel resource
18+
represents the processor that performs a user-defined "streaming" operation.
19+
Example usage:
20+
python create_channel.py --project_id <project-id> --location <location> \
21+
--channel_id <channel-id> --input_id <input-id> --output_uri <uri>
22+
"""
23+
24+
# [START livestream_create_channel]
25+
26+
import argparse
27+
28+
from google.cloud.video import live_stream_v1
29+
from google.cloud.video.live_stream_v1.services.livestream_service import (
30+
LivestreamServiceClient,
31+
)
32+
from google.protobuf import duration_pb2 as duration
33+
34+
35+
def create_channel(
36+
project_id: str, location: str, channel_id: str, input_id: str, output_uri: str
37+
) -> str:
38+
"""Creates a channel.
39+
Args:
40+
project_id: The GCP project ID.
41+
location: The location in which to create the channel.
42+
channel_id: The user-defined channel ID.
43+
input_id: The user-defined input ID.
44+
output_uri: Uri of the channel output folder in a Cloud Storage bucket."""
45+
46+
client = LivestreamServiceClient()
47+
parent = f"projects/{project_id}/locations/{location}"
48+
input = f"projects/{project_id}/locations/{location}/inputs/{input_id}"
49+
name = f"projects/{project_id}/locations/{location}/channels/{channel_id}"
50+
51+
channel = live_stream_v1.types.Channel(
52+
name=name,
53+
input_attachments=[
54+
live_stream_v1.types.InputAttachment(
55+
key="my-input",
56+
input=input,
57+
),
58+
],
59+
output=live_stream_v1.types.Channel.Output(
60+
uri=output_uri,
61+
),
62+
elementary_streams=[
63+
live_stream_v1.types.ElementaryStream(
64+
key="es_video",
65+
video_stream=live_stream_v1.types.VideoStream(
66+
h264=live_stream_v1.types.VideoStream.H264CodecSettings(
67+
profile="high",
68+
width_pixels=1280,
69+
height_pixels=720,
70+
bitrate_bps=3000000,
71+
frame_rate=30,
72+
),
73+
),
74+
),
75+
live_stream_v1.types.ElementaryStream(
76+
key="es_audio",
77+
audio_stream=live_stream_v1.types.AudioStream(
78+
codec="aac", channel_count=2, bitrate_bps=160000
79+
),
80+
),
81+
],
82+
mux_streams=[
83+
live_stream_v1.types.MuxStream(
84+
key="mux_video",
85+
elementary_streams=["es_video"],
86+
segment_settings=live_stream_v1.types.SegmentSettings(
87+
segment_duration=duration.Duration(
88+
seconds=2,
89+
),
90+
),
91+
),
92+
live_stream_v1.types.MuxStream(
93+
key="mux_audio",
94+
elementary_streams=["es_audio"],
95+
segment_settings=live_stream_v1.types.SegmentSettings(
96+
segment_duration=duration.Duration(
97+
seconds=2,
98+
),
99+
),
100+
),
101+
],
102+
manifests=[
103+
live_stream_v1.types.Manifest(
104+
file_name="manifest.m3u8",
105+
type_="HLS",
106+
mux_streams=["mux_video", "mux_audio"],
107+
max_segment_count=5,
108+
),
109+
],
110+
)
111+
operation = client.create_channel(
112+
parent=parent, channel=channel, channel_id=channel_id
113+
)
114+
response = operation.result(600)
115+
print(f"Channel: {response.name}")
116+
117+
return response
118+
119+
120+
# [END livestream_create_channel]
121+
122+
if __name__ == "__main__":
123+
parser = argparse.ArgumentParser()
124+
parser.add_argument("--project_id", help="Your Cloud project ID.", required=True)
125+
parser.add_argument(
126+
"--location",
127+
help="The location in which to create the channel.",
128+
default="us-central1",
129+
)
130+
parser.add_argument(
131+
"--channel_id",
132+
help="The user-defined channel ID.",
133+
required=True,
134+
)
135+
parser.add_argument(
136+
"--input_id",
137+
help="The user-defined input ID.",
138+
required=True,
139+
)
140+
parser.add_argument(
141+
"--output_uri",
142+
help="The Cloud Storage bucket (and optional folder) in which to save the livestream output.",
143+
required=True,
144+
)
145+
args = parser.parse_args()
146+
create_channel(
147+
args.project_id,
148+
args.location,
149+
args.channel_id,
150+
args.input_id,
151+
args.output_uri,
152+
)

0 commit comments

Comments
 (0)