Skip to content

Commit 8b6b0a2

Browse files
author
Ace Nassri
authored
Address comments (#388)
* Address sgreenberg's comments * Massage package.json + generate README
1 parent 5c8491a commit 8b6b0a2

File tree

6 files changed

+100
-53
lines changed

6 files changed

+100
-53
lines changed

video/README.md

+19-19
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,27 @@
22

33
# Google Cloud Video Intelligence API Node.js Samples
44

5-
The [Cloud Video Intelligence API][video_docs] allows developers to easily
6-
integrate video analysis within applications, including video labeling, safe search
7-
, and shot change detection.
5+
[![Build](https://storage.googleapis.com/cloud-docs-samples-badges/GoogleCloudPlatform/nodejs-docs-samples/nodejs-docs-samples-videointelligence.svg)]()
86

9-
[video_docs]: https://cloud.google.com/video-intelligence/docs/
7+
The [Cloud Video Intelligence API](https://cloud.google.com/video-intelligence) allows developers to use Google video analysis technology as part of their applications.
108

119
## Table of Contents
1210

1311
* [Setup](#setup)
1412
* [Samples](#samples)
15-
* [Analyze](#analyze)
13+
* [Video Intelligence](#video-intelligence)
1614
* [Running the tests](#running-the-tests)
1715

1816
## Setup
1917

2018
1. Read [Prerequisites][prereq] and [How to run a sample][run] first.
2119
1. Install dependencies:
2220

23-
With `npm`:
21+
With **npm**:
2422

2523
npm install
2624

27-
With `yarn`:
25+
With **yarn**:
2826

2927
yarn install
3028

@@ -33,45 +31,47 @@ integrate video analysis within applications, including video labeling, safe sea
3331

3432
## Samples
3533

36-
### Analyze
34+
### Video Intelligence
3735

38-
View the [documentation][analyze_docs] or the [source code][analyze_code].
36+
View the [documentation][video_0_docs] or the [source code][video_0_code].
3937

4038
__Usage:__ `node analyze.js --help`
4139

4240
```
4341
Commands:
42+
faces <gcsUri> Analyzes faces in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.
4443
shots <gcsUri> Analyzes shot angles in a video stored in Google Cloud Storage using the Cloud Video
4544
Intelligence API.
4645
labels-gcs <gcsUri> Labels objects in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.
4746
labels-file <gcsUri> Labels objects in a video stored locally using the Cloud Video Intelligence API.
47+
safe-search <gcsUri> Detects adult content in a video stored in Google Cloud Storage.
4848
4949
Options:
5050
--help Show help [boolean]
5151
5252
Examples:
53-
node analyze.js shots gs://my-bucket/my-video.mp4
54-
node analyze.js labels-gcs gs://my-bucket/my-video.mp4
55-
node analyze.js labels-file my-video.mp4
56-
node analyze.js unsafe-content gs://my-bucket/my-video.mp4
53+
node analyze.js faces gs://demomaker/volleyball_court.mp4
54+
node analyze.js shots gs://demomaker/volleyball_court.mp4
55+
node analyze.js labels-gcs gs://demomaker/volleyball_court.mp4
56+
node analyze.js labels-file cat.mp4
57+
node analyze.js safe-search gs://demomaker/volleyball_court.mp4
5758
5859
For more information, see https://cloud.google.com/video-intelligence/docs
5960
```
6061

61-
[analyze_docs]: https://cloud.google.com/video-intelligence/docs
62-
[analyze_code]: analyze.js
62+
[video_0_docs]: https://cloud.google.com/video-intelligence/docs
63+
[video_0_code]: analyze.js
6364

6465
## Running the tests
6566

66-
1. Set the `GCLOUD_PROJECT` and `GOOGLE_APPLICATION_CREDENTIALS` environment
67-
variables.
67+
1. Set the **GCLOUD_PROJECT** and **GOOGLE_APPLICATION_CREDENTIALS** environment variables.
6868

6969
1. Run the tests:
7070

71-
With `npm`:
71+
With **npm**:
7272

7373
npm test
7474

75-
With `yarn`:
75+
With **yarn**:
7676

7777
yarn test

video/analyze.js

+38-16
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@ function analyzeFaces (gcsUri) {
4545
faces.forEach((face, faceIdx) => {
4646
console.log('\tThumbnail size:', face.thumbnail.length);
4747
face.segments.forEach((segment, segmentIdx) => {
48-
console.log(`\tTrack ${segmentIdx} of face ${faceIdx}: frames ${segment.startTimeOffset} to ${segment.endTimeOffset}`);
48+
if (segment.startTimeOffset === -1 && segment.endTimeOffset === -1) {
49+
console.log(`\tEntire video`);
50+
} else {
51+
console.log(`\tStart: ${segment.startTimeOffset / 1e6}s`);
52+
console.log(`\tEnd: ${segment.endTimeOffset / 1e6}s`);
53+
}
4954
});
5055
});
5156
})
@@ -86,7 +91,12 @@ function analyzeLabelsGCS (gcsUri) {
8691
console.log('Label description:', label.description);
8792
console.log('Locations:');
8893
label.locations.forEach((location) => {
89-
console.log(`\tFrames ${location.segment.startTimeOffset} to ${location.segment.endTimeOffset}`);
94+
if (location.segment.startTimeOffset === -1 && location.segment.endTimeOffset === -1) {
95+
console.log(`\tEntire video`);
96+
} else {
97+
console.log(`\tStart: ${location.segment.startTimeOffset / 1e6}s`);
98+
console.log(`\tEnd: ${location.segment.endTimeOffset / 1e6}s`);
99+
}
90100
});
91101
});
92102
})
@@ -133,7 +143,12 @@ function analyzeLabelsLocal (path) {
133143
console.log('Label description:', label.description);
134144
console.log('Locations:');
135145
label.locations.forEach((location) => {
136-
console.log(`\tFrames ${location.segment.startTimeOffset} to ${location.segment.endTimeOffset}`);
146+
if (location.segment.startTimeOffset === -1 && location.segment.endTimeOffset === -1) {
147+
console.log(`\tEntire video`);
148+
} else {
149+
console.log(`\tStart: ${location.segment.startTimeOffset / 1e6}s`);
150+
console.log(`\tEnd: ${location.segment.endTimeOffset / 1e6}s`);
151+
}
137152
});
138153
});
139154
})
@@ -172,8 +187,12 @@ function analyzeShots (gcsUri) {
172187
console.log('Shot changes:');
173188
shotChanges.forEach((shot, shotIdx) => {
174189
console.log(`Scene ${shotIdx}:`);
175-
console.log(`\tStart: ${shot.startTimeOffset}`);
176-
console.log(`\tEnd: ${shot.endTimeOffset}`);
190+
if (shot.startTimeOffset === -1 && shot.endTimeOffset === -1) {
191+
console.log(`\tEntire video`);
192+
} else {
193+
console.log(`\tStart: ${shot.startTimeOffset}`);
194+
console.log(`\tEnd: ${shot.endTimeOffset}`);
195+
}
177196
});
178197
})
179198
.catch((err) => {
@@ -198,6 +217,9 @@ function analyzeSafeSearch (gcsUri) {
198217
features: ['SAFE_SEARCH_DETECTION']
199218
};
200219

220+
// Human-readable likelihoods
221+
const likelihoods = ['UNKNOWN', 'VERY_UNLIKELY', 'UNLIKELY', 'POSSIBLE', 'LIKELY', 'VERY_LIKELY'];
222+
201223
// Detects unsafe content
202224
video.annotateVideo(request)
203225
.then((results) => {
@@ -210,12 +232,12 @@ function analyzeSafeSearch (gcsUri) {
210232
const safeSearchResults = results[0].annotationResults[0].safeSearchAnnotations;
211233
console.log('Safe search results:');
212234
safeSearchResults.forEach((result) => {
213-
console.log(`Frame ${result.timeOffset}:`);
214-
console.log(`\tAdult: ${result.adult}`);
215-
console.log(`\tSpoof: ${result.spoof}`);
216-
console.log(`\tMedical: ${result.medical}`);
217-
console.log(`\tViolent: ${result.violent}`);
218-
console.log(`\tRacy: ${result.racy}`);
235+
console.log(`Time: ${result.timeOffset / 1e6}s`);
236+
console.log(`\tAdult: ${likelihoods[result.adult]}`);
237+
console.log(`\tSpoof: ${likelihoods[result.spoof]}`);
238+
console.log(`\tMedical: ${likelihoods[result.medical]}`);
239+
console.log(`\tViolent: ${likelihoods[result.violent]}`);
240+
console.log(`\tRacy: ${likelihoods[result.racy]}`);
219241
});
220242
})
221243
.catch((err) => {
@@ -256,11 +278,11 @@ require(`yargs`) // eslint-disable-line
256278
{},
257279
(opts) => analyzeSafeSearch(opts.gcsUri)
258280
)
259-
.example(`node $0 faces gs://my-bucket/my-video.mp4`)
260-
.example(`node $0 shots gs://my-bucket/my-video.mp4`)
261-
.example(`node $0 labels-gcs gs://my-bucket/my-video.mp4`)
262-
.example(`node $0 labels-file my-video.mp4`)
263-
.example(`node $0 safe-search gs://my-bucket/my-video.mp4`)
281+
.example(`node $0 faces gs://demomaker/volleyball_court.mp4`)
282+
.example(`node $0 shots gs://demomaker/volleyball_court.mp4`)
283+
.example(`node $0 labels-gcs gs://demomaker/volleyball_court.mp4`)
284+
.example(`node $0 labels-file cat.mp4`)
285+
.example(`node $0 safe-search gs://demomaker/volleyball_court.mp4`)
264286
.wrap(120)
265287
.recommendCommands()
266288
.epilogue(`For more information, see https://cloud.google.com/video-intelligence/docs`)

video/package.json

+16-3
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,27 @@
1919
},
2020
"dependencies": {
2121
"@google-cloud/videointelligence": "https://storage.googleapis.com/videointelligence-alpha/videointelligence-nodejs.tar.gz",
22+
"googleapis": "19.0.0",
23+
"safe-buffer": "5.0.1",
2224
"yargs": "7.1.0"
2325
},
2426
"devDependencies": {
25-
"@google-cloud/nodejs-repo-tools": "1.4.7",
26-
"ava": "0.19.1"
27+
"@google-cloud/nodejs-repo-tools": "1.4.13",
28+
"ava": "0.19.1",
29+
"proxyquire": "1.7.11"
2730
},
2831
"cloud-repo-tools": {
2932
"requiresKeyFile": true,
30-
"requiresProjectId": true
33+
"requiresProjectId": true,
34+
"product": "video",
35+
"samples": [
36+
{
37+
"id": "video",
38+
"name": "Video Intelligence",
39+
"file": "analyze.js",
40+
"docs_link": "https://cloud.google.com/video-intelligence/docs",
41+
"usage": "node analyze.js --help"
42+
}
43+
]
3144
}
3245
}

video/quickstart.js

+22-8
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const video = Video.videoIntelligenceServiceClient({
2525
});
2626

2727
// The GCS filepath of the video to analyze
28-
const gcsUri = 'gs://nodejs-docs-samples/videointelligence_quickstart.mp4';
28+
const gcsUri = 'gs://demomaker/volleyball_court.mp4';
2929

3030
// Construct request
3131
const request = {
@@ -49,26 +49,40 @@ video.annotateVideo(request)
4949
faces.forEach((face, faceIdx) => {
5050
console.log('Thumbnail size:', face.thumbnail.length);
5151
face.segments.forEach((segment, segmentIdx) => {
52-
console.log(`Track ${segmentIdx} of face ${faceIdx}: frames ${segment.startTimeOffset} to ${segment.endTimeOffset}`);
52+
console.log(`Face #${faceIdx}, appearance #${segmentIdx}:`);
53+
if (segment.startTimeOffset === -1 && segment.endTimeOffset === -1) {
54+
console.log(`\tEntire video`);
55+
} else {
56+
console.log(`\tStart: ${segment.startTimeOffset / 1e6}s`);
57+
console.log(`\tEnd: ${segment.endTimeOffset / 1e6}s`);
58+
}
5359
});
5460
});
5561

5662
// Gets labels for video from its annotations
5763
const labels = annotations.labelAnnotations;
5864
labels.forEach((label) => {
59-
console.log('Label description:', label.description);
60-
console.log('Locations:');
65+
console.log(`Label ${label.description} occurs at:`);
6166
label.locations.forEach((location) => {
62-
console.log(`\tFrames ${location.segment.startTimeOffset} to ${location.segment.endTimeOffset}`);
67+
if (location.segment.startTimeOffset === -1 && location.segment.endTimeOffset === -1) {
68+
console.log(`\tEntire video`);
69+
} else {
70+
console.log(`\tStart: ${location.segment.startTimeOffset / 1e6}s`);
71+
console.log(`\tEnd: ${location.segment.endTimeOffset / 1e6}s`);
72+
}
6373
});
6474
});
6575

6676
// Gets shot changes for video from its annotations
6777
const shotChanges = annotations.shotAnnotations;
6878
shotChanges.forEach((shot, shotIdx) => {
69-
console.log(`Scene ${shotIdx}:`);
70-
console.log(`\tStart: ${shot.startTimeOffset}`);
71-
console.log(`\tEnd: ${shot.endTimeOffset}`);
79+
console.log(`Scene ${shotIdx} occurs from:`);
80+
if (shot.startTimeOffset === -1 && shot.endTimeOffset === -1) {
81+
console.log(`\tEntire video`);
82+
} else {
83+
console.log(`\tStart: ${shot.startTimeOffset / 1e6}s`);
84+
console.log(`\tEnd: ${shot.endTimeOffset / 1e6}s`);
85+
}
7286
});
7387
})
7488
.catch((err) => {

video/system-test/analyze.test.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@ test(`should analyze labels in a local file`, async (t) => {
4444

4545
// analyze_shots
4646
test(`should analyze shots in a GCS file`, async (t) => {
47-
const output = await tools.runAsync(`${cmd} shots gs://nodejs-docs-samples/video/gbike_dinosaur.mp4`, cwd);
47+
const output = await tools.runAsync(`${cmd} shots gs://nodejs-docs-samples/video/google_gmail.mp4`, cwd);
4848
t.regex(output, /Scene 0:/);
4949
});
5050

5151
// analyze_safe_search
5252
test(`should analyze safe search results in a GCS file`, async (t) => {
5353
const output = await tools.runAsync(`${cmd} safe-search gs://nodejs-docs-samples/video/google_gmail.mp4`, cwd);
54-
t.regex(output, /Frame \d+/);
55-
t.regex(output, /Spoof: \d+/);
54+
t.regex(output, /Time: \d\.\d+s/);
55+
t.regex(output, /Spoof:/);
5656
});

video/system-test/quickstart.test.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ const cwd = path.join(__dirname, `..`);
2424

2525
test(`should analyze a hardcoded video`, async (t) => {
2626
const output = await tools.runAsync(cmd, cwd);
27-
t.regex(output, /Label description:/);
28-
t.regex(output, /Frames \d+ to \d+/);
29-
t.regex(output, /Track \d+ of face \d+: frames \d+ to \d+/);
30-
t.regex(output, /Scene \d+/);
27+
t.regex(output, /Label Property occurs at:/);
28+
t.regex(output, /Scene \d+ occurs from:/);
3129
});

0 commit comments

Comments
 (0)