diff --git a/.github/workflows/video-intelligence.yaml b/.github/workflows/video-intelligence.yaml new file mode 100644 index 0000000000..5a562207e7 --- /dev/null +++ b/.github/workflows/video-intelligence.yaml @@ -0,0 +1,67 @@ +name: video-intelligence +on: + push: + branches: + - main + paths: + - 'video-intelligence/**' + pull_request: + paths: + - 'video-intelligence/**' + pull_request_target: + types: [labeled] + schedule: + - cron: '0 0 * * 0' +jobs: + test: + if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: 'write' + pull-requests: 'write' + id-token: 'write' + steps: + - uses: actions/checkout@v3 + with: + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} + - uses: google-github-actions/auth@v1.0.0 + with: + workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + - uses: actions/setup-node@v3 + with: + node-version: 14 + - run: npm install + working-directory: video-intelligence + - run: npm test + working-directory: video-intelligence + env: + MOCHA_REPORTER_SUITENAME: video-intelligence + MOCHA_REPORTER_OUTPUT: video_intelligence_sponge_log.xml + MOCHA_REPORTER: xunit + - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + name: 'actions:force-run', + owner: 'GoogleCloudPlatform', + repo: 'nodejs-docs-samples', + issue_number: context.payload.pull_request.number + }); + } catch (e) { + if (!e.message.includes('Label does not exist')) { + throw e; + } + } + - if: ${{ github.event_name == 'schedule' && always() }} + run: | + curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L + chmod +x ./flakybot + ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json index 09b61a0e87..14f526c4c5 100644 --- a/.github/workflows/workflows.json +++ b/.github/workflows/workflows.json @@ -56,6 +56,7 @@ "datastore/functions", "scheduler", "talent", + "video-intelligence", "contact-center-insights", "workflows" ] diff --git a/video-intelligence/.eslintrc.yml b/video-intelligence/.eslintrc.yml new file mode 100644 index 0000000000..282535f55f --- /dev/null +++ b/video-intelligence/.eslintrc.yml @@ -0,0 +1,3 @@ +--- +rules: + no-console: off diff --git a/video-intelligence/analyze-face-detection-gcs.js b/video-intelligence/analyze-face-detection-gcs.js new file mode 100644 index 0000000000..4055ef4393 --- /dev/null +++ b/video-intelligence/analyze-face-detection-gcs.js @@ -0,0 +1,81 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +function main(gcsUri = 'YOUR_STORAGE_URI') { + // [START video_detect_faces_gcs] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const gcsUri = 'GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + // Imports the Google Cloud Video Intelligence library + Node's fs library + const Video = require('@google-cloud/video-intelligence').v1; + + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + async function detectFacesGCS() { + const request = { + inputUri: gcsUri, + features: ['FACE_DETECTION'], + videoContext: { + faceDetectionConfig: { + // Must set includeBoundingBoxes to true to get facial attributes. + includeBoundingBoxes: true, + includeAttributes: true, + }, + }, + }; + // Detects faces in a video + // We get the first result because we only process 1 video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + + // Gets annotations for video + const faceAnnotations = + results[0].annotationResults[0].faceDetectionAnnotations; + + for (const {tracks} of faceAnnotations) { + console.log('Face detected:'); + + for (const {segment, timestampedObjects} of tracks) { + console.log( + `\tStart: ${segment.startTimeOffset.seconds}.` + + `${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${segment.endTimeOffset.seconds}.` + + `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + + // Each segment includes timestamped objects that + // include characteristics of the face detected. + const [firstTimestapedObject] = timestampedObjects; + + for (const {name} of firstTimestapedObject.attributes) { + // Attributes include 'glasses', 'headwear', 'smiling'. + console.log(`\tAttribute: ${name}; `); + } + } + } + } + + detectFacesGCS(); + // [END video_detect_faces_gcs] +} + +main(...process.argv.slice(2)); diff --git a/video-intelligence/analyze-face-detection.js b/video-intelligence/analyze-face-detection.js new file mode 100644 index 0000000000..a7b07e59a1 --- /dev/null +++ b/video-intelligence/analyze-face-detection.js @@ -0,0 +1,84 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +function main(path = 'YOUR_LOCAL_FILE') { + // [START video_detect_faces] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + + // Imports the Google Cloud Video Intelligence library + Node's fs library + const Video = require('@google-cloud/video-intelligence').v1; + const fs = require('fs'); + + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + // Reads a local video file and converts it to base64 + const file = fs.readFileSync(path); + const inputContent = file.toString('base64'); + + async function detectFaces() { + const request = { + inputContent: inputContent, + features: ['FACE_DETECTION'], + videoContext: { + faceDetectionConfig: { + // Must set includeBoundingBoxes to true to get facial attributes. + includeBoundingBoxes: true, + includeAttributes: true, + }, + }, + }; + // Detects faces in a video + // We get the first result because we only process 1 video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + + // Gets annotations for video + const faceAnnotations = + results[0].annotationResults[0].faceDetectionAnnotations; + for (const {tracks} of faceAnnotations) { + console.log('Face detected:'); + for (const {segment, timestampedObjects} of tracks) { + console.log( + `\tStart: ${segment.startTimeOffset.seconds}` + + `.${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${segment.endTimeOffset.seconds}.` + + `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + + // Each segment includes timestamped objects that + // include characteristics of the face detected. + const [firstTimestapedObject] = timestampedObjects; + + for (const {name} of firstTimestapedObject.attributes) { + // Attributes include 'glasses', 'headwear', 'smiling'. + console.log(`\tAttribute: ${name}; `); + } + } + } + } + + detectFaces(); + // [END video_detect_faces] +} + +main(...process.argv.slice(2)); diff --git a/video-intelligence/analyze-person-detection-gcs.js b/video-intelligence/analyze-person-detection-gcs.js new file mode 100644 index 0000000000..0ffb247b94 --- /dev/null +++ b/video-intelligence/analyze-person-detection-gcs.js @@ -0,0 +1,89 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +function main(gcsUri = 'YOUR_STORAGE_URI') { + // [START video_detect_person_gcs] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const gcsUri = 'GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + // Imports the Google Cloud Video Intelligence library + Node's fs library + const Video = require('@google-cloud/video-intelligence').v1; + + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + async function detectPersonGCS() { + const request = { + inputUri: gcsUri, + features: ['PERSON_DETECTION'], + videoContext: { + personDetectionConfig: { + // Must set includeBoundingBoxes to true to get poses and attributes. + includeBoundingBoxes: true, + includePoseLandmarks: true, + includeAttributes: true, + }, + }, + }; + // Detects faces in a video + // We get the first result because we only process 1 video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + + // Gets annotations for video + const personAnnotations = + results[0].annotationResults[0].personDetectionAnnotations; + + for (const {tracks} of personAnnotations) { + console.log('Person detected:'); + + for (const {segment, timestampedObjects} of tracks) { + console.log( + `\tStart: ${segment.startTimeOffset.seconds}` + + `.${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${segment.endTimeOffset.seconds}.` + + `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + + // Each segment includes timestamped objects that + // include characteristic--e.g. clothes, posture + // of the person detected. + const [firstTimestampedObject] = timestampedObjects; + + // Attributes include unique pieces of clothing, poses (i.e., body + // landmarks) of the person detected. + for (const {name, value} of firstTimestampedObject.attributes) { + console.log(`\tAttribute: ${name}; Value: ${value}`); + } + + // Landmarks in person detection include body parts. + for (const {name, point} of firstTimestampedObject.landmarks) { + console.log(`\tLandmark: ${name}; Vertex: ${point.x}, ${point.y}`); + } + } + } + } + + detectPersonGCS(); + // [END video_detect_person_gcs] +} + +main(...process.argv.slice(2)); diff --git a/video-intelligence/analyze-person-detection.js b/video-intelligence/analyze-person-detection.js new file mode 100644 index 0000000000..717ded3e76 --- /dev/null +++ b/video-intelligence/analyze-person-detection.js @@ -0,0 +1,98 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +function main(path = 'YOUR_LOCAL_FILE') { + // [START video_detect_person] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const gcsUri = 'GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + // Imports the Google Cloud Video Intelligence library + Node's fs library + const Video = require('@google-cloud/video-intelligence').v1; + const fs = require('fs'); + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + + // Reads a local video file and converts it to base64 + const file = fs.readFileSync(path); + const inputContent = file.toString('base64'); + + async function detectPerson() { + const request = { + inputContent: inputContent, + features: ['PERSON_DETECTION'], + videoContext: { + personDetectionConfig: { + // Must set includeBoundingBoxes to true to get poses and attributes. + includeBoundingBoxes: true, + includePoseLandmarks: true, + includeAttributes: true, + }, + }, + }; + // Detects faces in a video + // We get the first result because we only process 1 video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + + // Gets annotations for video + const personAnnotations = + results[0].annotationResults[0].personDetectionAnnotations; + + for (const {tracks} of personAnnotations) { + console.log('Person detected:'); + + for (const {segment, timestampedObjects} of tracks) { + console.log( + `\tStart: ${segment.startTimeOffset.seconds}` + + `.${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${segment.endTimeOffset.seconds}.` + + `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + + // Each segment includes timestamped objects that + // include characteristic--e.g. clothes, posture + // of the person detected. + const [firstTimestampedObject] = timestampedObjects; + + // Attributes include unique pieces of clothing, poses (i.e., body + // landmarks) of the person detected. + for (const {name, value} of firstTimestampedObject.attributes) { + console.log(`\tAttribute: ${name}; Value: ${value}`); + } + + // Landmarks in person detection include body parts. + for (const {name, point} of firstTimestampedObject.landmarks) { + console.log(`\tLandmark: ${name}; Vertex: ${point.x}, ${point.y}`); + } + } + } + } + + detectPerson(); + // [END video_detect_person] +} + +main(...process.argv.slice(2)); diff --git a/video-intelligence/analyze-streaming-annotation-to-storage.js b/video-intelligence/analyze-streaming-annotation-to-storage.js new file mode 100644 index 0000000000..7fec8a77fc --- /dev/null +++ b/video-intelligence/analyze-streaming-annotation-to-storage.js @@ -0,0 +1,72 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(path = 'YOUR_LOCAL_FILE', outputUri = 'PATH_TO_OUTPUT') { + // [START video_streaming_annotation_to_storage_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + // const outputUri = 'Path to output, e.g. gs://path_to_output'; + + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + // Streaming configuration + const configRequest = { + videoConfig: { + feature: 'STREAMING_LABEL_DETECTION', + storageConfig: { + enableStorageAnnotationResult: true, + annotationResultStorageDirectory: outputUri, + }, + }, + }; + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const stream = client.streamingAnnotateVideo().on('data', response => { + //Gets annotations for video + console.log( + `The annotation is stored at: ${response.annotationResultsUri} ` + ); + }); + // [END video_streaming_annotation_to_storage_beta] +} + +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze-streaming-automl-classification.js b/video-intelligence/analyze-streaming-automl-classification.js new file mode 100644 index 0000000000..6881d3772f --- /dev/null +++ b/video-intelligence/analyze-streaming-automl-classification.js @@ -0,0 +1,93 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + path = 'YOUR_LOCAL_FILE', + projectId = 'YOUR_GCP_PROJECT', + modelId = 'YOUR_AUTOML_MODELID' +) { + // [START video_streaming_automl_classification_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + // const modelId = 'autoMl model' + // const projectId = 'Your GCP Project' + + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + + // Streaming configuration + const modelPath = `projects/${projectId}/locations/us-central1/models/${modelId}`; + const configRequest = { + videoConfig: { + feature: 'STREAMING_AUTOML_CLASSIFICATION', + automlClassificationConfig: { + modelName: modelPath, + }, + }, + }; + + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + // Note: Input videos must have supported video codecs. See + // https://cloud.google.com/video-intelligence/docs/streaming/streaming#supported_video_codecs + // for more details. + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const stream = client + .streamingAnnotateVideo() + .on('data', response => { + //Gets annotations for video + const annotations = response.annotationResults; + const labels = annotations.labelAnnotations; + labels.forEach(label => { + console.log( + `Label ${label.entity.description} occurs at: ${ + label.frames[0].timeOffset.seconds || 0 + }` + `.${(label.frames[0].timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(` Confidence: ${label.frames[0].confidence}`); + }); + }) + .on('error', response => { + console.error(response); + }); + // [END video_streaming_automl_classification_beta] +} +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze-streaming-automl-object-tracking.js b/video-intelligence/analyze-streaming-automl-object-tracking.js new file mode 100644 index 0000000000..609dc6df4f --- /dev/null +++ b/video-intelligence/analyze-streaming-automl-object-tracking.js @@ -0,0 +1,98 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + path = 'YOUR_LOCAL_FILE', + projectId = 'YOUR_GCP_PROJECT', + modelId = 'YOUR_AUTOML_MODELID' +) { + // [START video_streaming_automl_object_tracking_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + // const modelId = 'AutoML model' + // const projectId = 'Your GCP Project' + + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + + // Streaming configuration + const modelName = `projects/${projectId}/locations/us-central1/models/${modelId}`; + const configRequest = { + videoConfig: { + feature: 'STREAMING_AUTOML_OBJECT_TRACKING', + automlObjectTrackingConfig: { + modelName: modelName, + }, + }, + }; + + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + // Note: Input videos must have supported video codecs. See + // https://cloud.google.com/video-intelligence/docs/streaming/streaming#supported_video_codecs + // for more details. + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const stream = client.streamingAnnotateVideo().on('data', response => { + //Gets annotations for video + const annotations = response.annotationResults; + const objects = annotations.objectAnnotations; + objects.forEach(object => { + console.log(`Entity description: ${object.entity.description}`); + console.log(`Entity id: ${object.entity.entityId}`); + console.log(`Track id: ${object.trackId}`); + console.log(`Confidence: ${object.confidence}`); + console.log( + `Time offset for the frame: ${ + object.frames[0].timeOffset.seconds || 0 + }` + `.${(object.frames[0].timeOffset.nanos / 1e6).toFixed(0)}s` + ); + //Every annotation has only one frame. + const box = object.frames[0].normalizedBoundingBox; + console.log('Bounding box position:'); + console.log(`\tleft: ${box.left}`); + console.log(`\ttop: ${box.top}`); + console.log(`\tright: ${box.right}`); + console.log(`\tbottom: ${box.bottom}`); + }); + }); + // [END video_streaming_automl_object_tracking_beta] +} +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze-streaming-labels.js b/video-intelligence/analyze-streaming-labels.js new file mode 100644 index 0000000000..c5eeaf8cae --- /dev/null +++ b/video-intelligence/analyze-streaming-labels.js @@ -0,0 +1,72 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(path = 'YOUR_LOCAL_FILE') { + // [START video_streaming_label_detection_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + // Streaming configuration + const configRequest = { + videoConfig: { + feature: 'STREAMING_LABEL_DETECTION', + }, + }; + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const stream = client.streamingAnnotateVideo().on('data', response => { + //Gets annotations for video + const annotations = response.annotationResults; + const labels = annotations.labelAnnotations; + labels.forEach(label => { + console.log( + `Label ${label.entity.description} occurs at: ${ + label.frames[0].timeOffset.seconds || 0 + }` + `.${(label.frames[0].timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(` Confidence: ${label.frames[0].confidence}`); + }); + }); + // [END video_streaming_label_detection_beta] +} +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze-streaming-object.js b/video-intelligence/analyze-streaming-object.js new file mode 100644 index 0000000000..534c1a6a4b --- /dev/null +++ b/video-intelligence/analyze-streaming-object.js @@ -0,0 +1,85 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(path = 'YOUR_LOCAL_FILE') { + // [START video_streaming_object_tracking_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + // Streaming configuration + const configRequest = { + videoConfig: { + feature: 'STREAMING_OBJECT_TRACKING', + }, + }; + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const options = {timeout: 120000}; + // Create a job using a long-running operation + + const stream = client.streamingAnnotateVideo(options).on('data', response => { + //Gets annotations for video + const annotations = response.annotationResults; + const objects = annotations.objectAnnotations; + objects.forEach(object => { + console.log(`Entity description: ${object.entity.description}`); + console.log(`Entity id: ${object.entity.entityId}`); + console.log(`Track id: ${object.trackId}`); + console.log(`Confidence: ${object.confidence}`); + console.log( + `Time offset for the frame: ${ + object.frames[0].timeOffset.seconds || 0 + }` + `.${(object.frames[0].timeOffset.nanos / 1e6).toFixed(0)}s` + ); + //Every annotation has only one frame. + const box = object.frames[0].normalizedBoundingBox; + console.log('Bounding box position:'); + console.log(` left :${box.left}`); + console.log(` top :${box.top}`); + console.log(` right :${box.right}`); + console.log(` bottom:${box.bottom}`); + }); + }); + // [END video_streaming_object_tracking_beta] +} +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze-streaming-safe-search.js b/video-intelligence/analyze-streaming-safe-search.js new file mode 100644 index 0000000000..4ed9c49a73 --- /dev/null +++ b/video-intelligence/analyze-streaming-safe-search.js @@ -0,0 +1,72 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(path = 'YOUR_LOCAL_FILE') { + // [START video_streaming_explicit_content_detection_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + // Streaming configuration + const configRequest = { + videoConfig: { + feature: 'STREAMING_EXPLICIT_CONTENT_DETECTION', + }, + }; + + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const stream = client.streamingAnnotateVideo().on('data', response => { + //Gets annotations for video + const annotations = response.annotationResults; + const explicitContentResults = annotations.explicitAnnotation.frames; + explicitContentResults.forEach(result => { + console.log( + `Time: ${result.timeOffset.seconds || 0}` + + `.${(result.timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(` Pornography likelihood: ${result.pornographyLikelihood}`); + }); + }); + // [END video_streaming_explicit_content_detection_beta] +} +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze-streaming-shot-change.js b/video-intelligence/analyze-streaming-shot-change.js new file mode 100644 index 0000000000..d1a93259bc --- /dev/null +++ b/video-intelligence/analyze-streaming-shot-change.js @@ -0,0 +1,77 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(path = 'YOUR_LOCAL_FILE') { + // [START video_streaming_shot_change_detection_beta] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + const {StreamingVideoIntelligenceServiceClient} = + require('@google-cloud/video-intelligence').v1p3beta1; + const fs = require('fs'); + + // Instantiates a client + const client = new StreamingVideoIntelligenceServiceClient(); + // Streaming configuration + const configRequest = { + videoConfig: { + feature: 'STREAMING_SHOT_CHANGE_DETECTION', + }, + }; + const readStream = fs.createReadStream(path, { + highWaterMark: 5 * 1024 * 1024, //chunk size set to 5MB (recommended less than 10MB) + encoding: 'base64', + }); + //Load file content + const chunks = []; + readStream + .on('data', chunk => { + const request = { + inputContent: chunk.toString(), + }; + chunks.push(request); + }) + .on('close', () => { + // configRequest should be the first in the stream of requests + stream.write(configRequest); + for (let i = 0; i < chunks.length; i++) { + stream.write(chunks[i]); + } + stream.end(); + }); + + const stream = client.streamingAnnotateVideo().on('data', response => { + //Gets annotations for video + const annotations = response.annotationResults; + const shotChanges = annotations.shotAnnotations; + console.log(JSON.stringify(shotChanges)); + if (shotChanges.length === 1) { + console.log('The entire video is one shot.'); + } + shotChanges.forEach(shot => { + console.log( + ` Shot: ${shot.startTimeOffset.seconds || 0}` + + `.${(shot.startTimeOffset.nanos / 1e6).toFixed(0)}s to ${ + shot.endTimeOffset.seconds || 0 + }` + + `.${(shot.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + }); + }); + // [END video_streaming_shot_change_detection_beta] +} +main(...process.argv.slice(2)).catch(console.error()); diff --git a/video-intelligence/analyze.js b/video-intelligence/analyze.js new file mode 100644 index 0000000000..9c8bbcaccf --- /dev/null +++ b/video-intelligence/analyze.js @@ -0,0 +1,636 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function analyzeLabelsGCS(gcsUri) { + // [START video_analyze_labels_gcs] + // Imports the Google Cloud Video Intelligence library + const video = require('@google-cloud/video-intelligence').v1; + + // Creates a client + const client = new video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const gcsUri = 'GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + const request = { + inputUri: gcsUri, + features: ['LABEL_DETECTION'], + }; + + // Detects labels in a video + const [operation] = await client.annotateVideo(request); + console.log('Waiting for operation to complete...'); + const [operationResult] = await operation.promise(); + + // Gets annotations for video + const annotations = operationResult.annotationResults[0]; + + const labels = annotations.segmentLabelAnnotations; + labels.forEach(label => { + console.log(`Label ${label.entity.description} occurs at:`); + label.segments.forEach(segment => { + const time = segment.segment; + if (time.startTimeOffset.seconds === undefined) { + time.startTimeOffset.seconds = 0; + } + if (time.startTimeOffset.nanos === undefined) { + time.startTimeOffset.nanos = 0; + } + if (time.endTimeOffset.seconds === undefined) { + time.endTimeOffset.seconds = 0; + } + if (time.endTimeOffset.nanos === undefined) { + time.endTimeOffset.nanos = 0; + } + console.log( + `\tStart: ${time.startTimeOffset.seconds}` + + `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${time.endTimeOffset.seconds}.` + + `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(`\tConfidence: ${segment.confidence}`); + }); + }); + // [END video_analyze_labels_gcs] +} + +async function analyzeLabelsLocal(path) { + // [START video_analyze_labels] + // Imports the Google Cloud Video Intelligence library + Node's fs library + const video = require('@google-cloud/video-intelligence').v1; + const fs = require('fs'); + const util = require('util'); + + // Creates a client + const client = new video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + + // Reads a local video file and converts it to base64 + const readFile = util.promisify(fs.readFile); + const file = await readFile(path); + const inputContent = file.toString('base64'); + + // Constructs request + const request = { + inputContent: inputContent, + features: ['LABEL_DETECTION'], + }; + + // Detects labels in a video + const [operation] = await client.annotateVideo(request); + console.log('Waiting for operation to complete...'); + const [operationResult] = await operation.promise(); + // Gets annotations for video + const annotations = operationResult.annotationResults[0]; + + const labels = annotations.segmentLabelAnnotations; + labels.forEach(label => { + console.log(`Label ${label.entity.description} occurs at:`); + label.segments.forEach(segment => { + const time = segment.segment; + if (time.startTimeOffset.seconds === undefined) { + time.startTimeOffset.seconds = 0; + } + if (time.startTimeOffset.nanos === undefined) { + time.startTimeOffset.nanos = 0; + } + if (time.endTimeOffset.seconds === undefined) { + time.endTimeOffset.seconds = 0; + } + if (time.endTimeOffset.nanos === undefined) { + time.endTimeOffset.nanos = 0; + } + console.log( + `\tStart: ${time.startTimeOffset.seconds}` + + `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${time.endTimeOffset.seconds}.` + + `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(`\tConfidence: ${segment.confidence}`); + }); + }); + + // [END video_analyze_labels] +} + +async function analyzeShots(gcsUri) { + // [START video_analyze_shots] + // Imports the Google Cloud Video Intelligence library + const video = require('@google-cloud/video-intelligence').v1; + + // Creates a client + const client = new video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const gcsUri = 'GCS URI of file to analyze, e.g. gs://my-bucket/my-video.mp4'; + + const request = { + inputUri: gcsUri, + features: ['SHOT_CHANGE_DETECTION'], + }; + + // Detects camera shot changes + const [operation] = await client.annotateVideo(request); + console.log('Waiting for operation to complete...'); + const [operationResult] = await operation.promise(); + // Gets shot changes + const shotChanges = operationResult.annotationResults[0].shotAnnotations; + console.log('Shot changes:'); + + if (shotChanges.length === 1) { + console.log('The entire video is one shot.'); + } else { + shotChanges.forEach((shot, shotIdx) => { + console.log(`Scene ${shotIdx} occurs from:`); + if (shot.startTimeOffset === undefined) { + shot.startTimeOffset = {}; + } + if (shot.endTimeOffset === undefined) { + shot.endTimeOffset = {}; + } + if (shot.startTimeOffset.seconds === undefined) { + shot.startTimeOffset.seconds = 0; + } + if (shot.startTimeOffset.nanos === undefined) { + shot.startTimeOffset.nanos = 0; + } + if (shot.endTimeOffset.seconds === undefined) { + shot.endTimeOffset.seconds = 0; + } + if (shot.endTimeOffset.nanos === undefined) { + shot.endTimeOffset.nanos = 0; + } + console.log( + `\tStart: ${shot.startTimeOffset.seconds}` + + `.${(shot.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${shot.endTimeOffset.seconds}.` + + `${(shot.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + }); + } + + // [END video_analyze_shots] +} + +async function analyzeSafeSearch(gcsUri) { + // [START video_analyze_explicit_content] + // Imports the Google Cloud Video Intelligence library + const video = require('@google-cloud/video-intelligence').v1; + + // Creates a client + const client = new video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const gcsUri = 'GCS URI of video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + const request = { + inputUri: gcsUri, + features: ['EXPLICIT_CONTENT_DETECTION'], + }; + + // Human-readable likelihoods + const likelihoods = [ + 'UNKNOWN', + 'VERY_UNLIKELY', + 'UNLIKELY', + 'POSSIBLE', + 'LIKELY', + 'VERY_LIKELY', + ]; + + // Detects unsafe content + const [operation] = await client.annotateVideo(request); + console.log('Waiting for operation to complete...'); + const [operationResult] = await operation.promise(); + // Gets unsafe content + const explicitContentResults = + operationResult.annotationResults[0].explicitAnnotation; + console.log('Explicit annotation results:'); + explicitContentResults.frames.forEach(result => { + if (result.timeOffset === undefined) { + result.timeOffset = {}; + } + if (result.timeOffset.seconds === undefined) { + result.timeOffset.seconds = 0; + } + if (result.timeOffset.nanos === undefined) { + result.timeOffset.nanos = 0; + } + console.log( + `\tTime: ${result.timeOffset.seconds}` + + `.${(result.timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\t\tPornography likelihood: ${likelihoods[result.pornographyLikelihood]}` + ); + }); + // [END video_analyze_explicit_content] +} + +async function analyzeVideoTranscription(gcsUri) { + // [START video_speech_transcription_gcs] + // Imports the Google Cloud Video Intelligence library + const videoIntelligence = require('@google-cloud/video-intelligence'); + + // Creates a client + const client = new videoIntelligence.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const gcsUri = 'GCS URI of video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + async function analyzeVideoTranscript() { + const videoContext = { + speechTranscriptionConfig: { + languageCode: 'en-US', + enableAutomaticPunctuation: true, + }, + }; + + const request = { + inputUri: gcsUri, + features: ['SPEECH_TRANSCRIPTION'], + videoContext: videoContext, + }; + + const [operation] = await client.annotateVideo(request); + console.log('Waiting for operation to complete...'); + const [operationResult] = await operation.promise(); + // There is only one annotation_result since only + // one video is processed. + const annotationResults = operationResult.annotationResults[0]; + + for (const speechTranscription of annotationResults.speechTranscriptions) { + // The number of alternatives for each transcription is limited by + // SpeechTranscriptionConfig.max_alternatives. + // Each alternative is a different possible transcription + // and has its own confidence score. + for (const alternative of speechTranscription.alternatives) { + console.log('Alternative level information:'); + console.log(`Transcript: ${alternative.transcript}`); + console.log(`Confidence: ${alternative.confidence}`); + + console.log('Word level information:'); + for (const wordInfo of alternative.words) { + const word = wordInfo.word; + const start_time = + wordInfo.startTime.seconds + wordInfo.startTime.nanos * 1e-9; + const end_time = + wordInfo.endTime.seconds + wordInfo.endTime.nanos * 1e-9; + console.log('\t' + start_time + 's - ' + end_time + 's: ' + word); + } + } + } + } + + analyzeVideoTranscript(); + // [END video_speech_transcription_gcs] +} + +async function analyzeTextGCS(gcsUri) { + //gcsUri - GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4 + //[START video_detect_text_gcs] + // Imports the Google Cloud Video Intelligence library + const Video = require('@google-cloud/video-intelligence'); + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const gcsUri = 'GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + const request = { + inputUri: gcsUri, + features: ['TEXT_DETECTION'], + }; + // Detects text in a video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + // Gets annotations for video + const textAnnotations = results[0].annotationResults[0].textAnnotations; + textAnnotations.forEach(textAnnotation => { + console.log(`Text ${textAnnotation.text} occurs at:`); + textAnnotation.segments.forEach(segment => { + const time = segment.segment; + console.log( + ` Start: ${time.startTimeOffset.seconds || 0}.${( + time.startTimeOffset.nanos / 1e6 + ).toFixed(0)}s` + ); + console.log( + ` End: ${time.endTimeOffset.seconds || 0}.${( + time.endTimeOffset.nanos / 1e6 + ).toFixed(0)}s` + ); + console.log(` Confidence: ${segment.confidence}`); + segment.frames.forEach(frame => { + const timeOffset = frame.timeOffset; + console.log( + `Time offset for the frame: ${timeOffset.seconds || 0}` + + `.${(timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log('Rotated Bounding Box Vertices:'); + frame.rotatedBoundingBox.vertices.forEach(vertex => { + console.log(`Vertex.x:${vertex.x}, Vertex.y:${vertex.y}`); + }); + }); + }); + }); + // [END video_detect_text_gcs] +} + +async function analyzeObjectTrackingGCS(gcsUri) { + //gcsUri - GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4 + //[START video_object_tracking_gcs] + // Imports the Google Cloud Video Intelligence library + const Video = require('@google-cloud/video-intelligence'); + + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const gcsUri = 'GCS URI of the video to analyze, e.g. gs://my-bucket/my-video.mp4'; + + const request = { + inputUri: gcsUri, + features: ['OBJECT_TRACKING'], + //recommended to use us-east1 for the best latency due to different types of processors used in this region and others + locationId: 'us-east1', + }; + // Detects objects in a video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + //Gets annotations for video + const annotations = results[0].annotationResults[0]; + const objects = annotations.objectAnnotations; + objects.forEach(object => { + console.log(`Entity description: ${object.entity.description}`); + console.log(`Entity id: ${object.entity.entityId}`); + const time = object.segment; + console.log( + `Segment: ${time.startTimeOffset.seconds || 0}` + + `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s to ${ + time.endTimeOffset.seconds || 0 + }.` + + `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(`Confidence: ${object.confidence}`); + const frame = object.frames[0]; + const box = frame.normalizedBoundingBox; + const timeOffset = frame.timeOffset; + console.log( + `Time offset for the first frame: ${timeOffset.seconds || 0}` + + `.${(timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log('Bounding box position:'); + console.log(` left :${box.left}`); + console.log(` top :${box.top}`); + console.log(` right :${box.right}`); + console.log(` bottom :${box.bottom}`); + }); + // [END video_object_tracking_gcs] +} + +async function analyzeText(path) { + //[START video_detect_text] + // Imports the Google Cloud Video Intelligence library + Node's fs library + const Video = require('@google-cloud/video-intelligence'); + const fs = require('fs'); + const util = require('util'); + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + + // Reads a local video file and converts it to base64 + const file = await util.promisify(fs.readFile)(path); + const inputContent = file.toString('base64'); + + const request = { + inputContent: inputContent, + features: ['TEXT_DETECTION'], + }; + // Detects text in a video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + + // Gets annotations for video + const textAnnotations = results[0].annotationResults[0].textAnnotations; + textAnnotations.forEach(textAnnotation => { + console.log(`Text ${textAnnotation.text} occurs at:`); + textAnnotation.segments.forEach(segment => { + const time = segment.segment; + if (time.startTimeOffset.seconds === undefined) { + time.startTimeOffset.seconds = 0; + } + if (time.startTimeOffset.nanos === undefined) { + time.startTimeOffset.nanos = 0; + } + if (time.endTimeOffset.seconds === undefined) { + time.endTimeOffset.seconds = 0; + } + if (time.endTimeOffset.nanos === undefined) { + time.endTimeOffset.nanos = 0; + } + console.log( + `\tStart: ${time.startTimeOffset.seconds || 0}` + + `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${time.endTimeOffset.seconds || 0}.` + + `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(`\tConfidence: ${segment.confidence}`); + segment.frames.forEach(frame => { + const timeOffset = frame.timeOffset; + console.log( + `Time offset for the frame: ${timeOffset.seconds || 0}` + + `.${(timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log('Rotated Bounding Box Vertices:'); + frame.rotatedBoundingBox.vertices.forEach(vertex => { + console.log(`Vertex.x:${vertex.x}, Vertex.y:${vertex.y}`); + }); + }); + }); + }); + // [END video_detect_text] +} + +async function analyzeObjectTracking(path) { + //[START video_object_tracking] + // Imports the Google Cloud Video Intelligence library + const Video = require('@google-cloud/video-intelligence'); + const fs = require('fs'); + const util = require('util'); + // Creates a client + const video = new Video.VideoIntelligenceServiceClient(); + /** + * TODO(developer): Uncomment the following line before running the sample. + */ + // const path = 'Local file to analyze, e.g. ./my-file.mp4'; + + // Reads a local video file and converts it to base64 + const file = await util.promisify(fs.readFile)(path); + const inputContent = file.toString('base64'); + + const request = { + inputContent: inputContent, + features: ['OBJECT_TRACKING'], + //recommended to use us-east1 for the best latency due to different types of processors used in this region and others + locationId: 'us-east1', + }; + // Detects objects in a video + const [operation] = await video.annotateVideo(request); + const results = await operation.promise(); + console.log('Waiting for operation to complete...'); + //Gets annotations for video + const annotations = results[0].annotationResults[0]; + const objects = annotations.objectAnnotations; + objects.forEach(object => { + console.log(`Entity description: ${object.entity.description}`); + console.log(`Entity id: ${object.entity.entityId}`); + const time = object.segment; + console.log( + `Segment: ${time.startTimeOffset.seconds || 0}` + + `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s to ${ + time.endTimeOffset.seconds || 0 + }.` + + `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log(`Confidence: ${object.confidence}`); + const frame = object.frames[0]; + const box = frame.normalizedBoundingBox; + const timeOffset = frame.timeOffset; + console.log( + `Time offset for the first frame: ${timeOffset.seconds || 0}` + + `.${(timeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log('Bounding box position:'); + console.log(` left :${box.left}`); + console.log(` top :${box.top}`); + console.log(` right :${box.right}`); + console.log(` bottom :${box.bottom}`); + }); + // [END video_object_tracking] +} + +async function main() { + require('yargs') + .demand(1) + .command( + 'shots ', + 'Analyzes shot angles in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.', + {}, + opts => analyzeShots(opts.gcsUri) + ) + .command( + 'labels-gcs ', + 'Labels objects in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.', + {}, + opts => analyzeLabelsGCS(opts.gcsUri) + ) + .command( + 'labels-file ', + 'Labels objects in a video stored locally using the Cloud Video Intelligence API.', + {}, + opts => analyzeLabelsLocal(opts.filePath) + ) + .command( + 'safe-search ', + 'Detects explicit content in a video stored in Google Cloud Storage.', + {}, + opts => analyzeSafeSearch(opts.gcsUri) + ) + .command( + 'transcription ', + 'Extract the video transcription using the Cloud Video Intelligence API.', + {}, + opts => analyzeVideoTranscription(opts.gcsUri) + ) + .command( + 'video-text-gcs ', + 'Analyzes text in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.', + {}, + opts => analyzeTextGCS(opts.gcsUri) + ) + .command( + 'track-objects-gcs ', + 'Analyzes objects in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.', + {}, + opts => analyzeObjectTrackingGCS(opts.gcsUri) + ) + .command( + 'video-text ', + 'Analyzes text in a video stored in a local file using the Cloud Video Intelligence API.', + {}, + opts => analyzeText(opts.path) + ) + .command( + 'track-objects ', + 'Analyzes objects in a video stored in a local file using the Cloud Video Intelligence API.', + {}, + opts => analyzeObjectTracking(opts.path) + ) + .example('node $0 shots gs://cloud-samples-data/video/googlework_short.mp4') + .example('node $0 labels-gcs gs://cloud-samples-data/video/cat.mp4') + .example('node $0 labels-file googlework_short.mp4') + .example( + 'node $0 safe-search gs://cloud-samples-data/video/googlework_short.mp4' + ) + .example('node $0 transcription gs://cloud-samples-data/video/cat.mp4') + .example('node $0 video-text ./resources/googlework_short.mp4') + .example( + 'node $0 video-text-gcs gs://nodejs-docs-samples/video/googlework_short.mp4' + ) + .example('node $0 track-objects ./resources/googlework_short.mp4') + .example('node $0 track-objects-gcs gs://nodejs-docs-samples/video/cat.mp4') + .wrap(120) + .recommendCommands() + .epilogue( + 'For more information, see https://cloud.google.com/video-intelligence/docs' + ) + .help() + .strict().argv; +} + +main().catch(console.error); diff --git a/video-intelligence/detect_logo.js b/video-intelligence/detect_logo.js new file mode 100644 index 0000000000..c32caf96df --- /dev/null +++ b/video-intelligence/detect_logo.js @@ -0,0 +1,108 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +function main(localFilePath = 'path/to/your/video.mp4') { + // [START video_detect_logo] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const localFilePath = 'path/to/your/video.mp4' + + // Imports the Google Cloud client libraries + const Video = require('@google-cloud/video-intelligence'); + const fs = require('fs'); + + // Instantiates a client + const client = new Video.VideoIntelligenceServiceClient(); + + // Performs asynchronous video annotation for logo recognition on a file. + async function detectLogo() { + const inputContent = fs.readFileSync(localFilePath).toString('base64'); + + // Build the request with the input content and logo recognition feature. + const request = { + inputContent: inputContent, + features: ['LOGO_RECOGNITION'], + }; + + // Make the asynchronous request + const [operation] = await client.annotateVideo(request); + + // Wait for the results + const [response] = await operation.promise(); + + // Get the first response, since we sent only one video. + const annotationResult = response.annotationResults[0]; + for (const logoRecognitionAnnotation of annotationResult.logoRecognitionAnnotations) { + const entity = logoRecognitionAnnotation.entity; + // Opaque entity ID. Some IDs may be available in + // [Google Knowledge Graph Search API](https://developers.google.com/knowledge-graph/). + console.log(`Entity Id: ${entity.entityId}`); + console.log(`Description: ${entity.description}`); + + // All logo tracks where the recognized logo appears. + // Each track corresponds to one logo instance appearing in consecutive frames. + for (const track of logoRecognitionAnnotation.tracks) { + console.log( + `\n\tStart Time Offset: ${track.segment.startTimeOffset.seconds}.${track.segment.startTimeOffset.nanos}` + ); + console.log( + `\tEnd Time Offset: ${track.segment.endTimeOffset.seconds}.${track.segment.endTimeOffset.nanos}` + ); + console.log(`\tConfidence: ${track.confidence}`); + + // The object with timestamp and attributes per frame in the track. + for (const timestampedObject of track.timestampedObjects) { + // Normalized Bounding box in a frame, where the object is located. + const normalizedBoundingBox = timestampedObject.normalizedBoundingBox; + console.log(`\n\t\tLeft: ${normalizedBoundingBox.left}`); + console.log(`\t\tTop: ${normalizedBoundingBox.top}`); + console.log(`\t\tRight: ${normalizedBoundingBox.right}`); + console.log(`\t\tBottom: ${normalizedBoundingBox.bottom}`); + // Optional. The attributes of the object in the bounding box. + for (const attribute of timestampedObject.attributes) { + console.log(`\n\t\t\tName: ${attribute.name}`); + console.log(`\t\t\tConfidence: ${attribute.confidence}`); + console.log(`\t\t\tValue: ${attribute.value}`); + } + } + + // Optional. Attributes in the track level. + for (const trackAttribute of track.attributes) { + console.log(`\n\t\tName: ${trackAttribute.name}`); + console.log(`\t\tConfidence: ${trackAttribute.confidence}`); + console.log(`\t\tValue: ${trackAttribute.value}`); + } + } + + // All video segments where the recognized logo appears. + // There might be multiple instances of the same logo class appearing in one VideoSegment. + for (const segment of logoRecognitionAnnotation.segments) { + console.log( + `\n\tStart Time Offset: ${segment.startTimeOffset.seconds}.${segment.startTimeOffset.nanos}` + ); + console.log( + `\tEnd Time Offset: ${segment.endTimeOffset.seconds}.${segment.endTimeOffset.nanos}` + ); + } + } + } + + detectLogo(); + // [END video_detect_logo] +} + +main(...process.argv.slice(2)); diff --git a/video-intelligence/detect_logo_gcs.js b/video-intelligence/detect_logo_gcs.js new file mode 100644 index 0000000000..22d8717bd1 --- /dev/null +++ b/video-intelligence/detect_logo_gcs.js @@ -0,0 +1,108 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; +/** + * Recognizes and annotates logos and brand marks in a video. + * @param {string} inputUri video file to annotate + */ +function main(inputUri = 'gs://cloud-samples-data/video/googlework_short.mp4') { + // [START video_detect_logo_gcs] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // const inputUri = 'gs://cloud-samples-data/video/googlework_short.mp4'; + + // Imports the Google Cloud client libraries + const Video = require('@google-cloud/video-intelligence'); + + // Instantiates a client + const client = new Video.VideoIntelligenceServiceClient(); + + // Performs asynchronous video annotation for logo recognition on a file hosted in GCS. + async function detectLogoGcs() { + // Build the request with the input uri and logo recognition feature. + const request = { + inputUri: inputUri, + features: ['LOGO_RECOGNITION'], + }; + + // Make the asynchronous request + const [operation] = await client.annotateVideo(request); + + // Wait for the results + const [response] = await operation.promise(); + + // Get the first response, since we sent only one video. + const annotationResult = response.annotationResults[0]; + for (const logoRecognitionAnnotation of annotationResult.logoRecognitionAnnotations) { + const entity = logoRecognitionAnnotation.entity; + // Opaque entity ID. Some IDs may be available in + // [Google Knowledge Graph Search API](https://developers.google.com/knowledge-graph/). + console.log(`Entity Id: ${entity.entityId}`); + console.log(`Description: ${entity.description}`); + + // All logo tracks where the recognized logo appears. + // Each track corresponds to one logo instance appearing in consecutive frames. + for (const track of logoRecognitionAnnotation.tracks) { + console.log( + `\n\tStart Time Offset: ${track.segment.startTimeOffset.seconds}.${track.segment.startTimeOffset.nanos}` + ); + console.log( + `\tEnd Time Offset: ${track.segment.endTimeOffset.seconds}.${track.segment.endTimeOffset.nanos}` + ); + console.log(`\tConfidence: ${track.confidence}`); + + // The object with timestamp and attributes per frame in the track. + for (const timestampedObject of track.timestampedObjects) { + // Normalized Bounding box in a frame, where the object is located. + const normalizedBoundingBox = timestampedObject.normalizedBoundingBox; + console.log(`\n\t\tLeft: ${normalizedBoundingBox.left}`); + console.log(`\t\tTop: ${normalizedBoundingBox.top}`); + console.log(`\t\tRight: ${normalizedBoundingBox.right}`); + console.log(`\t\tBottom: ${normalizedBoundingBox.bottom}`); + // Optional. The attributes of the object in the bounding box. + for (const attribute of timestampedObject.attributes) { + console.log(`\n\t\t\tName: ${attribute.name}`); + console.log(`\t\t\tConfidence: ${attribute.confidence}`); + console.log(`\t\t\tValue: ${attribute.value}`); + } + } + + // Optional. Attributes in the track level. + for (const trackAttribute of track.attributes) { + console.log(`\n\t\tName: ${trackAttribute.name}`); + console.log(`\t\tConfidence: ${trackAttribute.confidence}`); + console.log(`\t\tValue: ${trackAttribute.value}`); + } + } + + // All video segments where the recognized logo appears. + // There might be multiple instances of the same logo class appearing in one VideoSegment. + for (const segment of logoRecognitionAnnotation.segments) { + console.log( + `\n\tStart Time Offset: ${segment.startTimeOffset.seconds}.${segment.startTimeOffset.nanos}` + ); + console.log( + `\tEnd Time Offset: ${segment.endTimeOffset.seconds}.${segment.endTimeOffset.nanos}` + ); + } + } + } + + detectLogoGcs(); + // [END video_detect_logo_gcs] +} + +main(...process.argv.slice(2)); diff --git a/video-intelligence/package.json b/video-intelligence/package.json new file mode 100644 index 0000000000..ffd39d798f --- /dev/null +++ b/video-intelligence/package.json @@ -0,0 +1,25 @@ +{ + "name": "nodejs-docs-samples-videointelligence", + "private": true, + "license": "Apache-2.0", + "files": [ + "*.js", + "resources" + ], + "author": "Google Inc.", + "repository": "googleapis/nodejs-video-intelligence", + "engines": { + "node": ">=12.0.0" + }, + "scripts": { + "test": "mocha system-test --timeout=800000" + }, + "dependencies": { + "@google-cloud/video-intelligence": "^4.1.1", + "yargs": "^16.0.0" + }, + "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.0.0" + } +} diff --git a/video-intelligence/quickstart.js b/video-intelligence/quickstart.js new file mode 100644 index 0000000000..92ee050f9f --- /dev/null +++ b/video-intelligence/quickstart.js @@ -0,0 +1,64 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; +async function main() { + // [START video_quickstart] + // Imports the Google Cloud Video Intelligence library + const videoIntelligence = require('@google-cloud/video-intelligence'); + + // Creates a client + const client = new videoIntelligence.VideoIntelligenceServiceClient(); + + // The GCS uri of the video to analyze + const gcsUri = 'gs://cloud-samples-data/video/cat.mp4'; + + // Construct request + const request = { + inputUri: gcsUri, + features: ['LABEL_DETECTION'], + }; + + // Execute request + const [operation] = await client.annotateVideo(request); + + console.log( + 'Waiting for operation to complete... (this may take a few minutes)' + ); + + const [operationResult] = await operation.promise(); + + // Gets annotations for video + const annotations = operationResult.annotationResults[0]; + + // Gets labels for video from its annotations + const labels = annotations.segmentLabelAnnotations; + labels.forEach(label => { + console.log(`Label ${label.entity.description} occurs at:`); + label.segments.forEach(segment => { + segment = segment.segment; + console.log( + `\tStart: ${segment.startTimeOffset.seconds}` + + `.${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + console.log( + `\tEnd: ${segment.endTimeOffset.seconds}.` + + `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s` + ); + }); + }); + // [END video_quickstart] +} + +main().catch(console.error); diff --git a/video-intelligence/resources/cat.mp4 b/video-intelligence/resources/cat.mp4 new file mode 100644 index 0000000000..0e071b9ec6 Binary files /dev/null and b/video-intelligence/resources/cat.mp4 differ diff --git a/video-intelligence/resources/googlework_short.mp4 b/video-intelligence/resources/googlework_short.mp4 new file mode 100644 index 0000000000..30af418a6c Binary files /dev/null and b/video-intelligence/resources/googlework_short.mp4 differ diff --git a/video-intelligence/system-test/analyze-face-detection-gcs.test.js b/video-intelligence/system-test/analyze-face-detection-gcs.test.js new file mode 100644 index 0000000000..42993bb9db --- /dev/null +++ b/video-intelligence/system-test/analyze-face-detection-gcs.test.js @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-face-detection-gcs.js'; +const gcsUri = 'gs://cloud-samples-data/video/googlework_short.mp4'; + +describe.skip('analyzing faces in video', () => { + it('should identify faces in a file in Google Storage', async () => { + const output = execSync(`${cmd} ${gcsUri}`); + assert.match(output, /Face detected:/); + }); +}); diff --git a/video-intelligence/system-test/analyze-face-detection.test.js b/video-intelligence/system-test/analyze-face-detection.test.js new file mode 100644 index 0000000000..498fea695b --- /dev/null +++ b/video-intelligence/system-test/analyze-face-detection.test.js @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-face-detection.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('analyzing faces in video', () => { + it('should identify faces in a local file', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /Face detected:/); + }); +}); diff --git a/video-intelligence/system-test/analyze-person-detection-gcs.test.js b/video-intelligence/system-test/analyze-person-detection-gcs.test.js new file mode 100644 index 0000000000..bb271e257e --- /dev/null +++ b/video-intelligence/system-test/analyze-person-detection-gcs.test.js @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-person-detection-gcs.js'; +const gcsUri = 'gs://cloud-samples-data/video/googlework_short.mp4'; + +describe.skip('analyzing people in video', () => { + it('should identify people in a file in Google Storage', async () => { + const output = execSync(`${cmd} ${gcsUri}`); + assert.match(output, /Landmark/); + }); +}); diff --git a/video-intelligence/system-test/analyze-person-detection.test.js b/video-intelligence/system-test/analyze-person-detection.test.js new file mode 100644 index 0000000000..5a20efcc97 --- /dev/null +++ b/video-intelligence/system-test/analyze-person-detection.test.js @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-person-detection.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('analyzing people in video', () => { + it('should identify people in a local file', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /Landmark/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-annotation-to-storage.test.js b/video-intelligence/system-test/analyze-streaming-annotation-to-storage.test.js new file mode 100644 index 0000000000..9f0aa8ccc7 --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-annotation-to-storage.test.js @@ -0,0 +1,32 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-annotation-to-storage.js'; +const project = process.env.GCLOUD_PROJECT; +const file = 'resources/googlework_short.mp4'; +const outputUri = 'gs://' + project + '/VIDEO_STREAMING_OUTPUT'; + +describe.skip('streaming annotation to storage', () => { + it('should store the annotation results in GCS', async () => { + const output = execSync(`${cmd} ${file} ${outputUri}`); + assert.match(output, /The annotation is stored at:/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-automl-classification.test.js b/video-intelligence/system-test/analyze-streaming-automl-classification.test.js new file mode 100644 index 0000000000..f97d633fdd --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-automl-classification.test.js @@ -0,0 +1,36 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-automl-classification.js'; +const modelId = 'VCN3094808572840640512'; +const project = process.env.GCLOUD_PROJECT; +const file = 'resources/googlework_short.mp4'; + +describe.skip('streaming automl classification', function () { + this.retries(3); + it('should classify the action in the streaming video', async () => { + const output = execSync(`${cmd} ${file} ${project} ${modelId}`); + assert.match(output, /brush_hair/); + assert.match(output, /cartwheel/); + assert.match(output, /Confidence: \d+\.\d+/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-automl-object-tracking.test.js b/video-intelligence/system-test/analyze-streaming-automl-object-tracking.test.js new file mode 100644 index 0000000000..c08bb6b0b3 --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-automl-object-tracking.test.js @@ -0,0 +1,34 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-automl-object-tracking.js'; +const modelId = 'VOT409893536788381696'; +const project = process.env.GCLOUD_PROJECT; +const file = 'resources/googlework_short.mp4'; + +describe.skip('streaming automl object tracking', function () { + this.retries(3); + it('should track an object in a streaming video', async () => { + const output = execSync(`${cmd} ${file} ${project} ${modelId}`); + assert.match(output, /Track id/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-labels.test.js b/video-intelligence/system-test/analyze-streaming-labels.test.js new file mode 100644 index 0000000000..1fa210002f --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-labels.test.js @@ -0,0 +1,33 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-labels.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('streaming label', function () { + this.retries(3); + it('should analyze labels in a streaming video', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /cat/); + assert.match(output, /Confidence: \d+\.\d+/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-object.test.js b/video-intelligence/system-test/analyze-streaming-object.test.js new file mode 100644 index 0000000000..11df0b3eb4 --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-object.test.js @@ -0,0 +1,32 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-object.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('streaming object', () => { + it('should track an object in a streaming video', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /cat/); + assert.match(output, /Confidence: \d+\.\d+/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-safe-search.test.js b/video-intelligence/system-test/analyze-streaming-safe-search.test.js new file mode 100644 index 0000000000..6fbf807b9b --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-safe-search.test.js @@ -0,0 +1,31 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-safe-search.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('streaming safe search', function () { + this.retries(3); + it('should analyze explicit content in a streaming video', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /UNLIKELY/); + }); +}); diff --git a/video-intelligence/system-test/analyze-streaming-shot-change.test.js b/video-intelligence/system-test/analyze-streaming-shot-change.test.js new file mode 100644 index 0000000000..fa88282e24 --- /dev/null +++ b/video-intelligence/system-test/analyze-streaming-shot-change.test.js @@ -0,0 +1,32 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze-streaming-shot-change.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('streaming shot change', function () { + this.retries(3); + it('should analyze shot changes in a streaming video', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /The entire video is one shot./); + }); +}); diff --git a/video-intelligence/system-test/analyze.test.js b/video-intelligence/system-test/analyze.test.js new file mode 100644 index 0000000000..c1267cefc2 --- /dev/null +++ b/video-intelligence/system-test/analyze.test.js @@ -0,0 +1,59 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// https://cloud.google.com/video-intelligence/docs/ + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze.js'; +const catUrl = 'gs://cloud-samples-data/video/cat.mp4'; +const file = 'resources/googlework_short.mp4'; +const file2 = 'resources/googlework_short.mp4'; +const possibleTexts = + /Google|GOOGLE|SUR|OMAR|ROTO|Vice President|58oo9|LONDRES|PARIS|METRO|RUE|CARLO/; + +describe.skip('analyze samples', () => { + // analyze_labels_local + it('should analyze labels in a local file', async () => { + const output = execSync(`${cmd} labels-file ${file}`); + assert.match(output, /Label/); + assert.match(output, /Confidence: \d+\.\d+/); + }); + + //detect_text + it('should detect text in a local file', async () => { + const output = execSync(`${cmd} video-text ${file2}`); + assert.match(output, possibleTexts); + }); + + //object_tracking_gcs + it('should track objects in a GCS file', async () => { + const output = execSync(`${cmd} track-objects-gcs ${catUrl}`); + assert.match(output, /cat/); + assert.match(output, /Confidence: \d+\.\d+/); + }); + + //object_tracking + it('should track objects in a local file', async () => { + const output = execSync(`${cmd} track-objects ${file}`); + assert.match(output, /cat/); + assert.match(output, /Confidence: \d+\.\d+/); + }); +}); diff --git a/video-intelligence/system-test/analyze.v1p2beta1.test.js b/video-intelligence/system-test/analyze.v1p2beta1.test.js new file mode 100644 index 0000000000..ab7bb34aa1 --- /dev/null +++ b/video-intelligence/system-test/analyze.v1p2beta1.test.js @@ -0,0 +1,49 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// https://cloud.google.com/video-intelligence/docs/ + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node analyze.v1p2beta1.js'; +const url = 'gs://cloud-samples-data/video/cat.mp4'; +const file1 = 'resources/googlework_short.mp4'; +const file2 = 'resources/googlework_short.mp4'; +const possibleTexts = + /Google|GOOGLE|SUR|OMAR|ROTO|Vice President|58oo9|LONDRES|PARIS|METRO|RUE|CARLO/; + +describe.skip('analyze v1p2beta1 samples', () => { + it('should detect text in a local file', async () => { + const output = execSync(`${cmd} video-text ${file2}`); + assert.match(output, possibleTexts); + }); + + it('should track objects in a GCS file', async () => { + const output = execSync(`${cmd} track-objects-gcs ${url}`); + assert.match(output, /cat/); + assert.match(output, /Confidence: \d+\.\d+/); + }); + + it('should track objects in a local file', async () => { + const output = execSync(`${cmd} track-objects ${file1}`); + assert.match(output, /cat/); + assert.match(output, /Confidence: \d+\.\d+/); + }); +}); diff --git a/video-intelligence/system-test/detect_logo.test.js b/video-intelligence/system-test/detect_logo.test.js new file mode 100644 index 0000000000..fc89366436 --- /dev/null +++ b/video-intelligence/system-test/detect_logo.test.js @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node detect_logo.js'; +const file = 'resources/googlework_short.mp4'; + +describe.skip('analyzing logos in video', () => { + it('should detect a logo in a local file', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /Entity Id/); + }); +}); diff --git a/video-intelligence/system-test/detect_logo_gcs.test.js b/video-intelligence/system-test/detect_logo_gcs.test.js new file mode 100644 index 0000000000..22e0cc2ca3 --- /dev/null +++ b/video-intelligence/system-test/detect_logo_gcs.test.js @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const cp = require('child_process'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node detect_logo_gcs.js'; +const file = 'gs://cloud-samples-data/video/googlework_short.mp4'; + +describe.skip('analyzing logos in video on gcs', () => { + it('should detect a logo in a gcs file', async () => { + const output = execSync(`${cmd} ${file}`); + assert.match(output, /Entity Id/); + }); +}); diff --git a/video-intelligence/system-test/quickstart.test.js b/video-intelligence/system-test/quickstart.test.js new file mode 100644 index 0000000000..4b24d8b4ac --- /dev/null +++ b/video-intelligence/system-test/quickstart.test.js @@ -0,0 +1,32 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const path = require('path'); +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const cmd = 'node quickstart.js'; +const cwd = path.join(__dirname, '..'); + +describe.skip('quickstart samples', () => { + it('should analyze a hardcoded video', async () => { + const stdout = execSync(cmd, {cwd}); + assert.match(stdout, /medium sized cats/); + }); +});