Skip to content

Commit fc6dee2

Browse files
authored
feat: add code samples and tests for overlay creation (GoogleCloudPlatform#5464)
1 parent b3abf59 commit fc6dee2

File tree

5 files changed

+389
-0
lines changed

5 files changed

+389
-0
lines changed

media/testdata/ChromeCast.mp4

-7.11 MB
Binary file not shown.

media/testdata/overlay.jpg

23.2 KB
Loading
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2021 Google LLC
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 Transcoder sample for creating a job based on a supplied job config that includes an animated overlay.
18+
19+
Example usage:
20+
python create_job_with_animated_overlay.py --project-id <project-id> --location <location> --input-uri <uri> --overlay-image-uri <uri> --output-uri <uri>
21+
"""
22+
23+
import argparse
24+
25+
from google.cloud.video import transcoder_v1beta1
26+
from google.cloud.video.transcoder_v1beta1.services.transcoder_service import (
27+
TranscoderServiceClient,
28+
)
29+
from google.protobuf import duration_pb2 as duration
30+
31+
# [START transcoder_create_job_with_animated_overlay]
32+
33+
34+
def create_job_with_animated_overlay(
35+
project_id, location, input_uri, overlay_image_uri, output_uri
36+
):
37+
"""Creates a job based on an ad-hoc job configuration that includes an animated image overlay.
38+
39+
Args:
40+
project_id: The GCP project ID.
41+
location: The location to start the job in.
42+
input_uri: Uri of the video in the Cloud Storage bucket.
43+
overlay_image_uri: Uri of the JPEG image for the overlay in the Cloud Storage bucket. Must be a JPEG.
44+
output_uri: Uri of the video output folder in the Cloud Storage bucket."""
45+
46+
client = TranscoderServiceClient()
47+
48+
parent = f"projects/{project_id}/locations/{location}"
49+
job = transcoder_v1beta1.types.Job()
50+
job.input_uri = input_uri
51+
job.output_uri = output_uri
52+
job.config = transcoder_v1beta1.types.JobConfig(
53+
elementary_streams=[
54+
transcoder_v1beta1.types.ElementaryStream(
55+
key="video-stream0",
56+
video_stream=transcoder_v1beta1.types.VideoStream(
57+
codec="h264",
58+
height_pixels=360,
59+
width_pixels=640,
60+
bitrate_bps=550000,
61+
frame_rate=60,
62+
),
63+
),
64+
transcoder_v1beta1.types.ElementaryStream(
65+
key="audio-stream0",
66+
audio_stream=transcoder_v1beta1.types.AudioStream(
67+
codec="aac", bitrate_bps=64000
68+
),
69+
),
70+
],
71+
mux_streams=[
72+
transcoder_v1beta1.types.MuxStream(
73+
key="sd",
74+
container="mp4",
75+
elementary_streams=["video-stream0", "audio-stream0"],
76+
),
77+
],
78+
overlays=[
79+
transcoder_v1beta1.types.Overlay(
80+
image=transcoder_v1beta1.types.Overlay.Image(
81+
uri=overlay_image_uri,
82+
resolution=transcoder_v1beta1.types.Overlay.NormalizedCoordinate(
83+
x=0,
84+
y=0,
85+
),
86+
alpha=1,
87+
),
88+
animations=[
89+
transcoder_v1beta1.types.Overlay.Animation(
90+
animation_fade=transcoder_v1beta1.types.Overlay.AnimationFade(
91+
fade_type=transcoder_v1beta1.types.Overlay.FadeType.FADE_IN,
92+
xy=transcoder_v1beta1.types.Overlay.NormalizedCoordinate(
93+
x=0.5,
94+
y=0.5,
95+
),
96+
start_time_offset=duration.Duration(
97+
seconds=5,
98+
),
99+
end_time_offset=duration.Duration(
100+
seconds=10,
101+
),
102+
),
103+
),
104+
transcoder_v1beta1.types.Overlay.Animation(
105+
animation_fade=transcoder_v1beta1.types.Overlay.AnimationFade(
106+
fade_type=transcoder_v1beta1.types.Overlay.FadeType.FADE_OUT,
107+
xy=transcoder_v1beta1.types.Overlay.NormalizedCoordinate(
108+
x=0.5,
109+
y=0.5,
110+
),
111+
start_time_offset=duration.Duration(
112+
seconds=12,
113+
),
114+
end_time_offset=duration.Duration(
115+
seconds=15,
116+
),
117+
),
118+
),
119+
],
120+
),
121+
],
122+
)
123+
response = client.create_job(parent=parent, job=job)
124+
print(f"Job: {response.name}")
125+
return response
126+
127+
128+
# [END transcoder_create_job_with_animated_overlay]
129+
130+
if __name__ == "__main__":
131+
parser = argparse.ArgumentParser()
132+
parser.add_argument("--project-id", help="Your Cloud project ID.", required=True)
133+
parser.add_argument(
134+
"--location",
135+
help="The location to start this job in.",
136+
default="us-central1",
137+
)
138+
parser.add_argument(
139+
"--input-uri",
140+
help="Uri of the video in the Cloud Storage bucket.",
141+
required=True,
142+
)
143+
parser.add_argument(
144+
"--overlay-image-uri",
145+
help="Uri of the overlay JPEG image in the Cloud Storage bucket. Must be a JPEG.",
146+
required=True,
147+
)
148+
parser.add_argument(
149+
"--output-uri",
150+
help="Uri of the video output folder in the Cloud Storage bucket. Must end in '/'.",
151+
required=True,
152+
)
153+
args = parser.parse_args()
154+
create_job_with_animated_overlay(
155+
args.project_id,
156+
args.location,
157+
args.input_uri,
158+
args.overlay_image_uri,
159+
args.output_uri,
160+
)
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2021 Google LLC
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 Transcoder sample for creating a job based on a supplied job config that includes a static overlay.
18+
19+
Example usage:
20+
python create_job_with_static_overlay.py --project-id <project-id> --location <location> --input-uri <uri> --overlay-image-uri <uri> --output-uri <uri>
21+
"""
22+
23+
import argparse
24+
25+
from google.cloud.video import transcoder_v1beta1
26+
from google.cloud.video.transcoder_v1beta1.services.transcoder_service import (
27+
TranscoderServiceClient,
28+
)
29+
from google.protobuf import duration_pb2 as duration
30+
31+
# [START transcoder_create_job_with_static_overlay]
32+
33+
34+
def create_job_with_static_overlay(
35+
project_id, location, input_uri, overlay_image_uri, output_uri
36+
):
37+
"""Creates a job based on an ad-hoc job configuration that includes a static image overlay.
38+
39+
Args:
40+
project_id: The GCP project ID.
41+
location: The location to start the job in.
42+
input_uri: Uri of the video in the Cloud Storage bucket.
43+
overlay_image_uri: Uri of the JPEG image for the overlay in the Cloud Storage bucket. Must be a JPEG.
44+
output_uri: Uri of the video output folder in the Cloud Storage bucket."""
45+
46+
client = TranscoderServiceClient()
47+
48+
parent = f"projects/{project_id}/locations/{location}"
49+
job = transcoder_v1beta1.types.Job()
50+
job.input_uri = input_uri
51+
job.output_uri = output_uri
52+
job.config = transcoder_v1beta1.types.JobConfig(
53+
elementary_streams=[
54+
transcoder_v1beta1.types.ElementaryStream(
55+
key="video-stream0",
56+
video_stream=transcoder_v1beta1.types.VideoStream(
57+
codec="h264",
58+
height_pixels=360,
59+
width_pixels=640,
60+
bitrate_bps=550000,
61+
frame_rate=60,
62+
),
63+
),
64+
transcoder_v1beta1.types.ElementaryStream(
65+
key="audio-stream0",
66+
audio_stream=transcoder_v1beta1.types.AudioStream(
67+
codec="aac", bitrate_bps=64000
68+
),
69+
),
70+
],
71+
mux_streams=[
72+
transcoder_v1beta1.types.MuxStream(
73+
key="sd",
74+
container="mp4",
75+
elementary_streams=["video-stream0", "audio-stream0"],
76+
),
77+
],
78+
overlays=[
79+
transcoder_v1beta1.types.Overlay(
80+
image=transcoder_v1beta1.types.Overlay.Image(
81+
uri=overlay_image_uri,
82+
resolution=transcoder_v1beta1.types.Overlay.NormalizedCoordinate(
83+
x=1,
84+
y=0.5,
85+
),
86+
alpha=1,
87+
),
88+
animations=[
89+
transcoder_v1beta1.types.Overlay.Animation(
90+
animation_static=transcoder_v1beta1.types.Overlay.AnimationStatic(
91+
xy=transcoder_v1beta1.types.Overlay.NormalizedCoordinate(
92+
x=0,
93+
y=0,
94+
),
95+
start_time_offset=duration.Duration(
96+
seconds=0,
97+
),
98+
),
99+
),
100+
transcoder_v1beta1.types.Overlay.Animation(
101+
animation_end=transcoder_v1beta1.types.Overlay.AnimationEnd(
102+
start_time_offset=duration.Duration(
103+
seconds=10,
104+
),
105+
),
106+
),
107+
],
108+
),
109+
],
110+
)
111+
response = client.create_job(parent=parent, job=job)
112+
print(f"Job: {response.name}")
113+
return response
114+
115+
116+
# [END transcoder_create_job_with_static_overlay]
117+
118+
if __name__ == "__main__":
119+
parser = argparse.ArgumentParser()
120+
parser.add_argument("--project-id", help="Your Cloud project ID.", required=True)
121+
parser.add_argument(
122+
"--location",
123+
help="The location to start this job in.",
124+
default="us-central1",
125+
)
126+
parser.add_argument(
127+
"--input-uri",
128+
help="Uri of the video in the Cloud Storage bucket.",
129+
required=True,
130+
)
131+
parser.add_argument(
132+
"--overlay-image-uri",
133+
help="Uri of the overlay JPEG image in the Cloud Storage bucket. Must be a JPEG.",
134+
required=True,
135+
)
136+
parser.add_argument(
137+
"--output-uri",
138+
help="Uri of the video output folder in the Cloud Storage bucket. Must end in '/'.",
139+
required=True,
140+
)
141+
args = parser.parse_args()
142+
create_job_with_static_overlay(
143+
args.project_id,
144+
args.location,
145+
args.input_uri,
146+
args.overlay_image_uri,
147+
args.output_uri,
148+
)

0 commit comments

Comments
 (0)