Concatenating multiple input videos

This page explains how to combine multiple input videos into a single output video. You can also trim the timelines of the input videos.

For each input video, add an Input object to the inputs array. Each Input object defines the key and URI for the associated input video. You can add an optional PreprocessingConfig object to an Input to crop , pad, or perform other preprocessing on the input video. The inputs array is not ordered; you can add input videos in any order.

To add an input video to the output video timeline, add an EditAtom object to the editList array. The editList array is ordered. The first input designated in this array will be used first in the output video, the second input will be used next, and so on. You identify an input video by its key.

You can also designate a startTimeOffset and endTimeOffset to trim the input video. These fields are optional. If you don't specify these fields, the entire input video is used.

The following configuration concatenates two input videos into a single output video.

  "inputs" 
 : 
  
 [ 
  
 { 
  
 "key" 
 : 
  
 "input1" 
 , 
  
 "uri" 
 : 
  
 "gs:// STORAGE_BUCKET_NAME 
/ STORAGE_INPUT_VIDEO1 
" 
  
 }, 
  
 { 
  
 "key" 
 : 
  
 "input2" 
 , 
  
 "uri" 
 : 
  
 "gs:// STORAGE_BUCKET_NAME 
/ STORAGE_INPUT_VIDEO2 
" 
  
 } 
 ], 
 "editList" 
 : 
  
 [ 
  
 { 
  
 "key" 
 : 
  
 "atom1" 
 , 
  
 "inputs" 
 : 
  
 [ 
  
 "input1" 
  
 ], 
  
 "startTimeOffset" 
 : 
  
 " START_TIME_OFFSET1 
s" 
 , 
  
 "endTimeOffset" 
 : 
  
 " END_TIME_OFFSET1 
s" 
  
 }, 
  
 { 
  
 "key" 
 : 
  
 "atom2" 
 , 
  
 "inputs" 
 : 
  
 [ 
  
 "input2" 
  
 ], 
  
 "startTimeOffset" 
 : 
  
 " START_TIME_OFFSET2 
s" 
 , 
  
 "endTimeOffset" 
 : 
  
 " END_TIME_OFFSET2 
s" 
  
 } 
 ], 
 

You can add this configuration to a job template or include it in an ad-hoc job configuration :

REST

Before using any of the request data, make the following replacements:

  • PROJECT_ID : Your Google Cloud project ID listed in the IAM Settings .
  • LOCATION : The location where your job will run. Use one of the supported regions .
    Show locations
    • us-central1
    • us-west1
    • us-west2
    • us-east1
    • us-east4
    • southamerica-east1
    • northamerica-northeast1
    • asia-east1
    • asia-northeast1
    • asia-northeast3
    • asia-south1
    • asia-southeast1
    • australia-southeast1
    • europe-west1
    • europe-west2
    • europe-west4
    • me-west1
    • me-central1
    • me-central2
  • STORAGE_BUCKET_NAME : The name of the Cloud Storage bucket you created.
  • STORAGE_INPUT_VIDEO1 : The name of a video in your Cloud Storage bucket that you are transcoding, such as my-vid.mp4 . This field should take into account any folders that you created in the bucket (for example, input/my-vid.mp4 ). This video will be used first in the output video timeline.
  • START_TIME_OFFSET1 : The start time, in fractional seconds (for example, 0.0 ), relative to the first input video timeline. Use this field to trim content from the beginning of the video.
  • END_TIME_OFFSET1 : The end time, in fractional seconds (for example, 8.1 ), relative to the first input video timeline. Use this field to trim content from the end of the video.
  • STORAGE_INPUT_VIDEO2 : The name of a video in your Cloud Storage bucket that you are transcoding, such as my-vid.mp4 . This field should take into account any folders that you created in the bucket (for example, input/my-vid.mp4 ). This video will be used second in the output video timeline.
  • START_TIME_OFFSET2 : The start time, in fractional seconds (for example, 3.5 ), relative to the second input video timeline. Use this field to trim content from the beginning of the second video.
  • END_TIME_OFFSET2 : The end time, in fractional seconds (for example, 15 ), relative to the second input video timeline. Use this field to trim content from the end of the second video.
  • STORAGE_OUTPUT_FOLDER : The Cloud Storage folder name where you want to save the encoded video outputs.

To send your request, expand one of these options:

You should receive a JSON response similar to the following:

{
  "name": "projects/ PROJECT_NUMBER 
/locations/ LOCATION 
/jobs/ JOB_ID 
",
  "config": {
   ...
  },
  "state": "PENDING",
  "createTime": CREATE_TIME 
,
  "ttlAfterCompletionDays": 30
}

gcloud

  1. Create a request.json file that defines the job fields. Make the following replacements for the gcloud command:
    • LOCATION : The location where your job will run. Use one of the supported regions .
      Show locations
      • us-central1
      • us-west1
      • us-west2
      • us-east1
      • us-east4
      • southamerica-east1
      • northamerica-northeast1
      • asia-east1
      • asia-northeast1
      • asia-northeast3
      • asia-south1
      • asia-southeast1
      • australia-southeast1
      • europe-west1
      • europe-west2
      • europe-west4
      • me-west1
      • me-central1
      • me-central2
    • STORAGE_BUCKET_NAME : The name of the Cloud Storage bucket you created.
    • STORAGE_INPUT_VIDEO1 : The name of a video in your Cloud Storage bucket that you are transcoding, such as my-vid.mp4 . This field should take into account any folders that you created in the bucket (for example, input/my-vid.mp4 ). This video will be used first in the output video timeline.
    • START_TIME_OFFSET1 : The start time, in fractional seconds (for example, 0.0 ), relative to the first input video timeline. Use this field to trim content from the beginning of the video.
    • END_TIME_OFFSET1 : The end time, in fractional seconds (for example, 8.1 ), relative to the first input video timeline. Use this field to trim content from the end of the video.
    • STORAGE_INPUT_VIDEO2 : The name of a video in your Cloud Storage bucket that you are transcoding, such as my-vid.mp4 . This field should take into account any folders that you created in the bucket (for example, input/my-vid.mp4 ). This video will be used second in the output video timeline.
    • START_TIME_OFFSET2 : The start time, in fractional seconds (for example, 3.5 ), relative to the second input video timeline. Use this field to trim content from the beginning of the second video.
    • END_TIME_OFFSET2 : The end time, in fractional seconds (for example, 15 ), relative to the second input video timeline. Use this field to trim content from the end of the second video.
    • STORAGE_OUTPUT_FOLDER : The Cloud Storage folder name where you want to save the encoded video outputs.
     { 
      
     "config" 
    :  
     { 
      
     "inputs" 
    :  
     [ 
      
     { 
      
     "key" 
    :  
     "input1" 
    ,  
     "uri" 
    :  
     "gs:// STORAGE_BUCKET_NAME 
    / STORAGE_INPUT_VIDEO1 
    " 
      
     } 
    ,  
     { 
      
     "key" 
    :  
     "input2" 
    ,  
     "uri" 
    :  
     "gs:// STORAGE_BUCKET_NAME 
    / STORAGE_INPUT_VIDEO2 
    " 
      
     } 
      
     ] 
    ,  
     "editList" 
    :  
     [ 
      
     { 
      
     "key" 
    :  
     "atom1" 
    ,  
     "inputs" 
    :  
     [ 
      
     "input1" 
      
     ] 
    ,  
     "startTimeOffset" 
    :  
     " START_TIME_OFFSET1 
    s" 
    ,  
     "endTimeOffset" 
    :  
     " END_TIME_OFFSET1 
    s" 
      
     } 
    ,  
     { 
      
     "key" 
    :  
     "atom2" 
    ,  
     "inputs" 
    :  
     [ 
      
     "input2" 
      
     ] 
    ,  
     "startTimeOffset" 
    :  
     " START_TIME_OFFSET2 
    s" 
    ,  
     "endTimeOffset" 
    :  
     " END_TIME_OFFSET2 
    s" 
      
     } 
      
     ] 
    ,  
     "elementaryStreams" 
    :  
     [ 
      
     { 
      
     "key" 
    :  
     "video-stream0" 
    ,  
     "videoStream" 
    :  
     { 
      
     "h264" 
    :  
     { 
      
     "heightPixels" 
    :  
     360 
    ,  
     "widthPixels" 
    :  
     640 
    ,  
     "bitrateBps" 
    :  
     550000 
    ,  
     "frameRate" 
    :  
     60 
      
     } 
      
     } 
      
     } 
    ,  
     { 
      
     "key" 
    :  
     "audio-stream0" 
    ,  
     "audioStream" 
    :  
     { 
      
     "codec" 
    :  
     "aac" 
    ,  
     "bitrateBps" 
    :  
     64000 
      
     } 
      
     } 
      
     ] 
    ,  
     "muxStreams" 
    :  
     [ 
      
     { 
      
     "key" 
    :  
     "sd" 
    ,  
     "container" 
    :  
     "mp4" 
    ,  
     "elementaryStreams" 
    :  
     [ 
      
     "video-stream0" 
    ,  
     "audio-stream0" 
      
     ] 
      
     } 
      
     ] 
    ,  
     "output" 
    :  
     { 
      
     "uri" 
    :  
     "gs:// STORAGE_BUCKET_NAME 
    / STORAGE_OUTPUT_FOLDER 
    /" 
      
     } 
      
     } 
     } 
    
  2. Run the following command:
    gcloud  
    transcoder  
     jobs 
      
    create  
    --location = 
     LOCATION 
      
    --file = 
     "request.json" 
    
    You should see a response similar to the following:
    {
      "name": "projects/ PROJECT_NUMBER 
    /locations/ LOCATION 
    /jobs/ JOB_ID 
    ",
      "config": {
       ...
      },
      "state": "PENDING",
      "createTime": CREATE_TIME 
    ,
      "ttlAfterCompletionDays": 30
    }

C#

Before trying this sample, follow the C# setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API C# API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  using 
  
  Google.Api.Gax.ResourceNames 
 
 ; 
 using 
  
  Google.Cloud.Video.Transcoder.V1 
 
 ; 
 using 
  
  Google.Protobuf.WellKnownTypes 
 
 ; 
 using 
  
 System 
 ; 
 public 
  
 class 
  
 CreateJobWithConcatenatedInputsSample 
 { 
  
 public 
  
 Job 
  
 CreateJobWithConcatenatedInputs 
 ( 
  
 string 
  
 projectId 
 , 
  
 string 
  
 location 
 , 
  
 string 
  
 inputUri1 
 , 
  
 TimeSpan 
  
 startTimeInput1 
 , 
  
 TimeSpan 
  
 endTimeInput1 
 , 
  
 string 
  
 inputUri2 
 , 
  
 TimeSpan 
  
 startTimeInput2 
 , 
  
 TimeSpan 
  
 endTimeInput2 
 , 
  
 string 
  
 outputUri 
 ) 
  
 { 
  
 // Create the client. 
  
  TranscoderServiceClient 
 
  
 client 
  
 = 
  
  TranscoderServiceClient 
 
 . 
  Create 
 
 (); 
  
 // Build the parent location name. 
  
  LocationName 
 
  
 parent 
  
 = 
  
 new 
  
  LocationName 
 
 ( 
 projectId 
 , 
  
 location 
 ); 
  
 // Build the job config. 
  
  VideoStream 
 
  
 videoStream0 
  
 = 
  
 new 
  
  VideoStream 
 
  
 { 
  
 H264 
  
 = 
  
 new 
  
 VideoStream 
 . 
 Types 
 . 
 H264CodecSettings 
  
 { 
  
 BitrateBps 
  
 = 
  
 550000 
 , 
  
 FrameRate 
  
 = 
  
 60 
 , 
  
 HeightPixels 
  
 = 
  
 360 
 , 
  
 WidthPixels 
  
 = 
  
 640 
  
 } 
  
 }; 
  
  AudioStream 
 
  
 audioStream0 
  
 = 
  
 new 
  
  AudioStream 
 
  
 { 
  
 Codec 
  
 = 
  
 "aac" 
 , 
  
 BitrateBps 
  
 = 
  
 64000 
  
 }; 
  
  ElementaryStream 
 
  
 elementaryStream0 
  
 = 
  
 new 
  
  ElementaryStream 
 
  
 { 
  
 Key 
  
 = 
  
 "video_stream0" 
 , 
  
 VideoStream 
  
 = 
  
 videoStream0 
  
 }; 
  
  ElementaryStream 
 
  
 elementaryStream1 
  
 = 
  
 new 
  
  ElementaryStream 
 
  
 { 
  
 Key 
  
 = 
  
 "audio_stream0" 
 , 
  
 AudioStream 
  
 = 
  
 audioStream0 
  
 }; 
  
  MuxStream 
 
  
 muxStream0 
  
 = 
  
 new 
  
  MuxStream 
 
  
 { 
  
 Key 
  
 = 
  
 "sd" 
 , 
  
 Container 
  
 = 
  
 "mp4" 
 , 
  
 ElementaryStreams 
  
 = 
  
 { 
  
 "video_stream0" 
 , 
  
 "audio_stream0" 
  
 } 
  
 }; 
  
  Input 
 
  
 input1 
  
 = 
  
 new 
  
  Input 
 
  
 { 
  
 Key 
  
 = 
  
 "input1" 
 , 
  
 Uri 
  
 = 
  
 inputUri1 
  
 }; 
  
  Input 
 
  
 input2 
  
 = 
  
 new 
  
  Input 
 
  
 { 
  
 Key 
  
 = 
  
 "input2" 
 , 
  
 Uri 
  
 = 
  
 inputUri2 
  
 }; 
  
  EditAtom 
 
  
 atom1 
  
 = 
  
 new 
  
  EditAtom 
 
  
 { 
  
 Key 
  
 = 
  
 "atom1" 
 , 
  
 StartTimeOffset 
  
 = 
  
  Duration 
 
 . 
  FromTimeSpan 
 
 ( 
 startTimeInput1 
 ), 
  
 EndTimeOffset 
  
 = 
  
  Duration 
 
 . 
  FromTimeSpan 
 
 ( 
 endTimeInput1 
 ), 
  
 Inputs 
  
 = 
  
 { 
  
 input1 
 . 
  Key 
 
  
 } 
  
 }; 
  
  EditAtom 
 
  
 atom2 
  
 = 
  
 new 
  
  EditAtom 
 
  
 { 
  
 Key 
  
 = 
  
 "atom2" 
 , 
  
 StartTimeOffset 
  
 = 
  
  Duration 
 
 . 
  FromTimeSpan 
 
 ( 
 startTimeInput2 
 ), 
  
 EndTimeOffset 
  
 = 
  
  Duration 
 
 . 
  FromTimeSpan 
 
 ( 
 endTimeInput2 
 ), 
  
 Inputs 
  
 = 
  
 { 
  
 input2 
 . 
  Key 
 
  
 } 
  
 }; 
  
  Output 
 
  
 output 
  
 = 
  
 new 
  
  Output 
 
  
 { 
  
 Uri 
  
 = 
  
 outputUri 
  
 }; 
  
  JobConfig 
 
  
 jobConfig 
  
 = 
  
 new 
  
  JobConfig 
 
  
 { 
  
 Inputs 
  
 = 
  
 { 
  
 input1 
 , 
  
 input2 
  
 }, 
  
 EditList 
  
 = 
  
 { 
  
 atom1 
 , 
  
 atom2 
  
 }, 
  
 Output 
  
 = 
  
 output 
 , 
  
 ElementaryStreams 
  
 = 
  
 { 
  
 elementaryStream0 
 , 
  
 elementaryStream1 
  
 }, 
  
 MuxStreams 
  
 = 
  
 { 
  
 muxStream0 
  
 } 
  
 }; 
  
 // Build the job. 
  
  Job 
 
  
 newJob 
  
 = 
  
 new 
  
  Job 
 
  
 { 
  
 OutputUri 
  
 = 
  
 outputUri 
 , 
  
 Config 
  
 = 
  
 jobConfig 
  
 }; 
  
 // Call the API. 
  
  Job 
 
  
 job 
  
 = 
  
 client 
 . 
  CreateJob 
 
 ( 
 parent 
 , 
  
 newJob 
 ); 
  
 // Return the result. 
  
 return 
  
 job 
 ; 
  
 } 
 } 
 

Go

Before trying this sample, follow the Go setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API Go API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 ( 
  
 "context" 
  
 "fmt" 
  
 "io" 
  
 "time" 
  
 transcoder 
  
 "cloud.google.com/go/video/transcoder/apiv1" 
  
 "cloud.google.com/go/video/transcoder/apiv1/transcoderpb" 
  
 "google.golang.org/protobuf/types/known/durationpb" 
 ) 
 // createJobWithConcatenatedInputs creates a job that concatenates two input 
 // videos. See https://cloud.google.com/transcoder/docs/how-to/concatenate-videos 
 // for more information. 
 func 
  
 createJobWithConcatenatedInputs 
 ( 
 w 
  
 io 
 . 
 Writer 
 , 
  
 projectID 
  
 string 
 , 
  
 location 
  
 string 
 , 
  
 input1URI 
  
 string 
 , 
  
 startTimeInput1 
  
 time 
 . 
 Duration 
 , 
  
 endTimeInput1 
  
 time 
 . 
 Duration 
 , 
  
 input2URI 
  
 string 
 , 
  
 startTimeInput2 
  
 time 
 . 
 Duration 
 , 
  
 endTimeInput2 
  
 time 
 . 
 Duration 
 , 
  
 outputURI 
  
 string 
 ) 
  
 error 
  
 { 
  
 // projectID := "my-project-id" 
  
 // location := "us-central1" 
  
 // 
  
 // input1URI := "gs://my-bucket/my-video-file1" 
  
 // startTimeInput1 := 0*time.Second 
  
 // endTimeInput1 := 8*time.Second + 100*time.Millisecond 
  
 // 
  
 // input2URI := "gs://my-bucket/my-video-file2" 
  
 // startTimeInput2 := 3*time.Second + 500*time.Millisecond 
  
 // endTimeInput2 := 15*time.Second 
  
 // 
  
 // outputURI := "gs://my-bucket/my-output-folder/" 
  
 ctx 
  
 := 
  
 context 
 . 
 Background 
 () 
  
 client 
 , 
  
 err 
  
 := 
  
 transcoder 
 . 
  NewClient 
 
 ( 
 ctx 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 fmt 
 . 
 Errorf 
 ( 
 "NewClient: %w" 
 , 
  
 err 
 ) 
  
 } 
  
 defer 
  
 client 
 . 
  Close 
 
 () 
  
 req 
  
 := 
  
& transcoderpb 
 . 
 CreateJobRequest 
 { 
  
 Parent 
 : 
  
 fmt 
 . 
 Sprintf 
 ( 
 "projects/%s/locations/%s" 
 , 
  
 projectID 
 , 
  
 location 
 ), 
  
 Job 
 : 
  
& transcoderpb 
 . 
 Job 
 { 
  
 OutputUri 
 : 
  
 outputURI 
 , 
  
 JobConfig 
 : 
  
& transcoderpb 
 . 
 Job_Config 
 { 
  
 Config 
 : 
  
& transcoderpb 
 . 
 JobConfig 
 { 
  
 Inputs 
 : 
  
 [] 
 * 
 transcoderpb 
 . 
 Input 
 { 
  
 { 
  
 Key 
 : 
  
 "input1" 
 , 
  
 Uri 
 : 
  
 input1URI 
 , 
  
 }, 
  
 { 
  
 Key 
 : 
  
 "input2" 
 , 
  
 Uri 
 : 
  
 input2URI 
 , 
  
 }, 
  
 }, 
  
 EditList 
 : 
  
 [] 
 * 
 transcoderpb 
 . 
 EditAtom 
 { 
  
 { 
  
 Key 
 : 
  
 "atom1" 
 , 
  
 Inputs 
 : 
  
 [] 
 string 
 { 
 "input1" 
 }, 
  
 StartTimeOffset 
 : 
  
 durationpb 
 . 
 New 
 ( 
 startTimeInput1 
 ), 
  
 EndTimeOffset 
 : 
  
 durationpb 
 . 
 New 
 ( 
 endTimeInput1 
 ), 
  
 }, 
  
 { 
  
 Key 
 : 
  
 "atom2" 
 , 
  
 Inputs 
 : 
  
 [] 
 string 
 { 
 "input2" 
 }, 
  
 StartTimeOffset 
 : 
  
 durationpb 
 . 
 New 
 ( 
 startTimeInput2 
 ), 
  
 EndTimeOffset 
 : 
  
 durationpb 
 . 
 New 
 ( 
 endTimeInput2 
 ), 
  
 }, 
  
 }, 
  
 ElementaryStreams 
 : 
  
 [] 
 * 
 transcoderpb 
 . 
 ElementaryStream 
 { 
  
 { 
  
 Key 
 : 
  
 "video_stream0" 
 , 
  
 ElementaryStream 
 : 
  
& transcoderpb 
 . 
 ElementaryStream_VideoStream 
 { 
  
 VideoStream 
 : 
  
& transcoderpb 
 . 
 VideoStream 
 { 
  
 CodecSettings 
 : 
  
& transcoderpb 
 . 
 VideoStream_H264 
 { 
  
 H264 
 : 
  
& transcoderpb 
 . 
 VideoStream_H264CodecSettings 
 { 
  
 BitrateBps 
 : 
  
 550000 
 , 
  
 FrameRate 
 : 
  
 60 
 , 
  
 HeightPixels 
 : 
  
 360 
 , 
  
 WidthPixels 
 : 
  
 640 
 , 
  
 }, 
  
 }, 
  
 }, 
  
 }, 
  
 }, 
  
 { 
  
 Key 
 : 
  
 "audio_stream0" 
 , 
  
 ElementaryStream 
 : 
  
& transcoderpb 
 . 
 ElementaryStream_AudioStream 
 { 
  
 AudioStream 
 : 
  
& transcoderpb 
 . 
 AudioStream 
 { 
  
 Codec 
 : 
  
 "aac" 
 , 
  
 BitrateBps 
 : 
  
 64000 
 , 
  
 }, 
  
 }, 
  
 }, 
  
 }, 
  
 MuxStreams 
 : 
  
 [] 
 * 
 transcoderpb 
 . 
 MuxStream 
 { 
  
 { 
  
 Key 
 : 
  
 "sd" 
 , 
  
 Container 
 : 
  
 "mp4" 
 , 
  
 ElementaryStreams 
 : 
  
 [] 
 string 
 { 
 "video_stream0" 
 , 
  
 "audio_stream0" 
 }, 
  
 }, 
  
 }, 
  
 }, 
  
 }, 
  
 }, 
  
 } 
  
 // Creates the job. Jobs take a variable amount of time to run. 
  
 // You can query for the job state; see getJob() in get_job.go. 
  
 response 
 , 
  
 err 
  
 := 
  
 client 
 . 
 CreateJob 
 ( 
 ctx 
 , 
  
 req 
 ) 
  
 if 
  
 err 
  
 != 
  
 nil 
  
 { 
  
 return 
  
 fmt 
 . 
 Errorf 
 ( 
 "CreateJob: %w" 
 , 
  
 err 
 ) 
  
 } 
  
 fmt 
 . 
 Fprintf 
 ( 
 w 
 , 
  
 "Job: %v" 
 , 
  
 response 
 . 
 GetName 
 ()) 
  
 return 
  
 nil 
 } 
 

Java

Before trying this sample, follow the Java setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API Java API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 com.google.cloud.video.transcoder.v1. AudioStream 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. CreateJobRequest 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. EditAtom 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. ElementaryStream 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. Input 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. Job 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. JobConfig 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. LocationName 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. MuxStream 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. Output 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. TranscoderServiceClient 
 
 ; 
 import 
  
 com.google.cloud.video.transcoder.v1. VideoStream 
 
 ; 
 import 
  
 com.google.protobuf. Duration 
 
 ; 
 import 
  
 java.io.IOException 
 ; 
 public 
  
 class 
 CreateJobWithConcatenatedInputs 
  
 { 
  
 public 
  
 static 
  
 void 
  
 main 
 ( 
 String 
 [] 
  
 args 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 // TODO(developer): Replace these variables before running the sample. 
  
 String 
  
 projectId 
  
 = 
  
 "my-project-id" 
 ; 
  
 String 
  
 location 
  
 = 
  
 "us-central1" 
 ; 
  
 String 
  
 inputUri1 
  
 = 
  
 "gs://my-bucket/my-video-file1" 
 ; 
  
  Duration 
 
  
 startTimeInput1 
  
 = 
  
  Duration 
 
 . 
 newBuilder 
 (). 
 setSeconds 
 ( 
 0 
 ). 
 setNanos 
 ( 
 0 
 ). 
 build 
 (); 
  
  Duration 
 
  
 endTimeInput1 
  
 = 
  
  Duration 
 
 . 
 newBuilder 
 (). 
 setSeconds 
 ( 
 8 
 ). 
 setNanos 
 ( 
 100000000 
 ). 
 build 
 (); 
  
 String 
  
 inputUri2 
  
 = 
  
 "gs://my-bucket/my-video-file2" 
 ; 
  
  Duration 
 
  
 startTimeInput2 
  
 = 
  
  Duration 
 
 . 
 newBuilder 
 (). 
 setSeconds 
 ( 
 3 
 ). 
 setNanos 
 ( 
 500000000 
 ). 
 build 
 (); 
  
  Duration 
 
  
 endTimeInput2 
  
 = 
  
  Duration 
 
 . 
 newBuilder 
 (). 
 setSeconds 
 ( 
 15 
 ). 
 setNanos 
 ( 
 0 
 ). 
 build 
 (); 
  
 String 
  
 outputUri 
  
 = 
  
 "gs://my-bucket/my-output-folder/" 
 ; 
  
 createJobWithConcatenatedInputs 
 ( 
  
 projectId 
 , 
  
 location 
 , 
  
 inputUri1 
 , 
  
 startTimeInput1 
 , 
  
 endTimeInput1 
 , 
  
 inputUri2 
 , 
  
 startTimeInput2 
 , 
  
 endTimeInput2 
 , 
  
 outputUri 
 ); 
  
 } 
  
 // Creates a job from an ad-hoc configuration that concatenates two input videos. 
  
 public 
  
 static 
  
 void 
  
 createJobWithConcatenatedInputs 
 ( 
  
 String 
  
 projectId 
 , 
  
 String 
  
 location 
 , 
  
 String 
  
 inputUri1 
 , 
  
  Duration 
 
  
 startTimeInput1 
 , 
  
  Duration 
 
  
 endTimeInput1 
 , 
  
 String 
  
 inputUri2 
 , 
  
  Duration 
 
  
 startTimeInput2 
 , 
  
  Duration 
 
  
 endTimeInput2 
 , 
  
 String 
  
 outputUri 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 // Initialize client that will be used to send requests. This client only needs to be created 
  
 // once, and can be reused for multiple requests. 
  
 try 
  
 ( 
  TranscoderServiceClient 
 
  
 transcoderServiceClient 
  
 = 
  
  TranscoderServiceClient 
 
 . 
 create 
 ()) 
  
 { 
  
  VideoStream 
 
  
 videoStream0 
  
 = 
  
  VideoStream 
 
 . 
 newBuilder 
 () 
  
 . 
  setH264 
 
 ( 
  
  VideoStream 
 
 . 
 H264CodecSettings 
 . 
 newBuilder 
 () 
  
 . 
 setBitrateBps 
 ( 
 550000 
 ) 
  
 . 
 setFrameRate 
 ( 
 60 
 ) 
  
 . 
 setHeightPixels 
 ( 
 360 
 ) 
  
 . 
 setWidthPixels 
 ( 
 640 
 )) 
  
 . 
 build 
 (); 
  
  AudioStream 
 
  
 audioStream0 
  
 = 
  
  AudioStream 
 
 . 
 newBuilder 
 (). 
 setCodec 
 ( 
 "aac" 
 ). 
 setBitrateBps 
 ( 
 64000 
 ). 
 build 
 (); 
  
  JobConfig 
 
  
 config 
  
 = 
  
  JobConfig 
 
 . 
 newBuilder 
 () 
  
 . 
 addInputs 
 ( 
  Input 
 
 . 
 newBuilder 
 (). 
 setKey 
 ( 
 "input1" 
 ). 
 setUri 
 ( 
 inputUri1 
 )) 
  
 . 
 addInputs 
 ( 
  Input 
 
 . 
 newBuilder 
 (). 
 setKey 
 ( 
 "input2" 
 ). 
 setUri 
 ( 
 inputUri2 
 )) 
  
 . 
  setOutput 
 
 ( 
  Output 
 
 . 
 newBuilder 
 (). 
 setUri 
 ( 
 outputUri 
 )) 
  
 . 
 addElementaryStreams 
 ( 
  
  ElementaryStream 
 
 . 
 newBuilder 
 () 
  
 . 
 setKey 
 ( 
 "video_stream0" 
 ) 
  
 . 
  setVideoStream 
 
 ( 
 videoStream0 
 )) 
  
 . 
 addElementaryStreams 
 ( 
  
  ElementaryStream 
 
 . 
 newBuilder 
 () 
  
 . 
 setKey 
 ( 
 "audio_stream0" 
 ) 
  
 . 
  setAudioStream 
 
 ( 
 audioStream0 
 )) 
  
 . 
 addMuxStreams 
 ( 
  
  MuxStream 
 
 . 
 newBuilder 
 () 
  
 . 
 setKey 
 ( 
 "sd" 
 ) 
  
 . 
  setContainer 
 
 ( 
 "mp4" 
 ) 
  
 . 
 addElementaryStreams 
 ( 
 "video_stream0" 
 ) 
  
 . 
 addElementaryStreams 
 ( 
 "audio_stream0" 
 ) 
  
 . 
 build 
 ()) 
  
 . 
  addEditList 
 
 ( 
  
 0 
 , 
  
 // Index in the edit list 
  
  EditAtom 
 
 . 
 newBuilder 
 () 
  
 . 
 setKey 
 ( 
 "atom1" 
 ) 
  
 . 
 addInputs 
 ( 
 "input1" 
 ) 
  
 . 
 setStartTimeOffset 
 ( 
 startTimeInput1 
 ) 
  
 . 
 setEndTimeOffset 
 ( 
 endTimeInput1 
 ) 
  
 . 
 build 
 ()) 
  
 . 
  addEditList 
 
 ( 
  
 1 
 , 
  
 // Index in the edit list 
  
  EditAtom 
 
 . 
 newBuilder 
 () 
  
 . 
 setKey 
 ( 
 "atom2" 
 ) 
  
 . 
 addInputs 
 ( 
 "input2" 
 ) 
  
 . 
 setStartTimeOffset 
 ( 
 startTimeInput2 
 ) 
  
 . 
 setEndTimeOffset 
 ( 
 endTimeInput2 
 ) 
  
 . 
 build 
 ()) 
  
 . 
 build 
 (); 
  
  CreateJobRequest 
 
  
 createJobRequest 
  
 = 
  
  CreateJobRequest 
 
 . 
 newBuilder 
 () 
  
 . 
 setJob 
 ( 
  Job 
 
 . 
 newBuilder 
 (). 
  setOutputUri 
 
 ( 
 outputUri 
 ). 
 setConfig 
 ( 
 config 
 ). 
 build 
 ()) 
  
 . 
 setParent 
 ( 
  LocationName 
 
 . 
 of 
 ( 
 projectId 
 , 
  
 location 
 ). 
 toString 
 ()) 
  
 . 
 build 
 (); 
  
 // Send the job creation request and process the response. 
  
  Job 
 
  
 job 
  
 = 
  
 transcoderServiceClient 
 . 
 createJob 
 ( 
 createJobRequest 
 ); 
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "Job: " 
  
 + 
  
 job 
 . 
  getName 
 
 ()); 
  
 } 
  
 } 
 } 
 

Node.js

Before trying this sample, follow the Node.js setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API Node.js API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  /** 
 * TODO(developer): Uncomment these variables before running the sample. 
 */ 
 // projectId = 'my-project-id'; 
 // location = 'us-central1'; 
 // inputUri1 = 'gs://my-bucket/my-video-file1'; 
 // startTimeOffset1 = 0; 
 // endTimeOffset1 = 8.1; 
 // inputUri2 = 'gs://my-bucket/my-video-file2'; 
 // startTimeOffset2 = 3.5; 
 // endTimeOffset2 = 15; 
 // outputUri = 'gs://my-bucket/my-output-folder/'; 
 function 
  
 calcOffsetNanoSec 
 ( 
 offsetValueFractionalSecs 
 ) 
  
 { 
  
 if 
  
 ( 
 offsetValueFractionalSecs 
 . 
 toString 
 (). 
 indexOf 
 ( 
 '.' 
 ) 
  
 !== 
  
 - 
 1 
 ) 
  
 { 
  
 return 
  
 ( 
  
 1000000000 
  
 * 
  
 Number 
 ( 
 '.' 
  
 + 
  
 offsetValueFractionalSecs 
 . 
 toString 
 (). 
 split 
 ( 
 '.' 
 )[ 
 1 
 ]) 
  
 ); 
  
 } 
  
 return 
  
 0 
 ; 
 } 
 const 
  
 startTimeOffset1Sec 
  
 = 
  
 Math 
 . 
 trunc 
 ( 
 startTimeOffset1 
 ); 
 const 
  
 startTimeOffset1NanoSec 
  
 = 
  
 calcOffsetNanoSec 
 ( 
 startTimeOffset1 
 ); 
 const 
  
 endTimeOffset1Sec 
  
 = 
  
 Math 
 . 
 trunc 
 ( 
 endTimeOffset1 
 ); 
 const 
  
 endTimeOffset1NanoSec 
  
 = 
  
 calcOffsetNanoSec 
 ( 
 endTimeOffset1 
 ); 
 const 
  
 startTimeOffset2Sec 
  
 = 
  
 Math 
 . 
 trunc 
 ( 
 startTimeOffset2 
 ); 
 const 
  
 startTimeOffset2NanoSec 
  
 = 
  
 calcOffsetNanoSec 
 ( 
 startTimeOffset2 
 ); 
 const 
  
 endTimeOffset2Sec 
  
 = 
  
 Math 
 . 
 trunc 
 ( 
 endTimeOffset2 
 ); 
 const 
  
 endTimeOffset2NanoSec 
  
 = 
  
 calcOffsetNanoSec 
 ( 
 endTimeOffset2 
 ); 
 // Imports the Transcoder library 
 const 
  
 { 
 TranscoderServiceClient 
 } 
  
 = 
  
 require 
 ( 
 ' @google-cloud/video-transcoder 
' 
 ). 
 v1 
 ; 
 // Instantiates a client 
 const 
  
 transcoderServiceClient 
  
 = 
  
 new 
  
  TranscoderServiceClient 
 
 (); 
 async 
  
 function 
  
 createJobWithConcatenatedInputs 
 () 
  
 { 
  
 // Construct request 
  
 const 
  
 request 
  
 = 
  
 { 
  
 parent 
 : 
  
 transcoderServiceClient 
 . 
  locationPath 
 
 ( 
 projectId 
 , 
  
 location 
 ), 
  
 job 
 : 
  
 { 
  
 outputUri 
 : 
  
 outputUri 
 , 
  
 config 
 : 
  
 { 
  
 inputs 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 'input1' 
 , 
  
 uri 
 : 
  
 inputUri1 
 , 
  
 }, 
  
 { 
  
 key 
 : 
  
 'input2' 
 , 
  
 uri 
 : 
  
 inputUri2 
 , 
  
 }, 
  
 ], 
  
 editList 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 'atom1' 
 , 
  
 inputs 
 : 
  
 [ 
 'input1' 
 ], 
  
 startTimeOffset 
 : 
  
 { 
  
 seconds 
 : 
  
 startTimeOffset1Sec 
 , 
  
 nanos 
 : 
  
 startTimeOffset1NanoSec 
 , 
  
 }, 
  
 endTimeOffset 
 : 
  
 { 
  
 seconds 
 : 
  
 endTimeOffset1Sec 
 , 
  
 nanos 
 : 
  
 endTimeOffset1NanoSec 
 , 
  
 }, 
  
 }, 
  
 { 
  
 key 
 : 
  
 'atom2' 
 , 
  
 inputs 
 : 
  
 [ 
 'input2' 
 ], 
  
 startTimeOffset 
 : 
  
 { 
  
 seconds 
 : 
  
 startTimeOffset2Sec 
 , 
  
 nanos 
 : 
  
 startTimeOffset2NanoSec 
 , 
  
 }, 
  
 endTimeOffset 
 : 
  
 { 
  
 seconds 
 : 
  
 endTimeOffset2Sec 
 , 
  
 nanos 
 : 
  
 endTimeOffset2NanoSec 
 , 
  
 }, 
  
 }, 
  
 ], 
  
 elementaryStreams 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 'video-stream0' 
 , 
  
 videoStream 
 : 
  
 { 
  
 h264 
 : 
  
 { 
  
 heightPixels 
 : 
  
 360 
 , 
  
 widthPixels 
 : 
  
 640 
 , 
  
 bitrateBps 
 : 
  
 550000 
 , 
  
 frameRate 
 : 
  
 60 
 , 
  
 }, 
  
 }, 
  
 }, 
  
 { 
  
 key 
 : 
  
 'audio-stream0' 
 , 
  
 audioStream 
 : 
  
 { 
  
 codec 
 : 
  
 'aac' 
 , 
  
 bitrateBps 
 : 
  
 64000 
 , 
  
 }, 
  
 }, 
  
 ], 
  
 muxStreams 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 'sd' 
 , 
  
 container 
 : 
  
 'mp4' 
 , 
  
 elementaryStreams 
 : 
  
 [ 
 'video-stream0' 
 , 
  
 'audio-stream0' 
 ], 
  
 }, 
  
 ], 
  
 }, 
  
 }, 
  
 }; 
  
 // Run request 
  
 const 
  
 [ 
 response 
 ] 
  
 = 
  
 await 
  
 transcoderServiceClient 
 . 
 createJob 
 ( 
 request 
 ); 
  
 console 
 . 
 log 
 ( 
 `Job: 
 ${ 
 response 
 . 
 name 
 } 
 ` 
 ); 
 } 
 createJobWithConcatenatedInputs 
 (); 
 

PHP

Before trying this sample, follow the PHP setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API PHP API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  use Google\Cloud\Video\Transcoder\V1\AudioStream; 
 use Google\Cloud\Video\Transcoder\V1\Client\TranscoderServiceClient; 
 use Google\Cloud\Video\Transcoder\V1\CreateJobRequest; 
 use Google\Cloud\Video\Transcoder\V1\EditAtom; 
 use Google\Cloud\Video\Transcoder\V1\ElementaryStream; 
 use Google\Cloud\Video\Transcoder\V1\Input; 
 use Google\Cloud\Video\Transcoder\V1\Job; 
 use Google\Cloud\Video\Transcoder\V1\JobConfig; 
 use Google\Cloud\Video\Transcoder\V1\MuxStream; 
 use Google\Cloud\Video\Transcoder\V1\VideoStream; 
 use Google\Protobuf\Duration; 
 /** 
 * Creates a job based on a supplied job config that concatenates two input videos. 
 * 
 * @param string $projectId The ID of your Google Cloud Platform project. 
 * @param string $location The location of the job. 
 * @param string $input1Uri Uri of the first video in the Cloud Storage bucket. 
 * @param float  $startTimeInput1 Start time, in fractional seconds, relative to the first input video timeline. 
 * @param float  $endTimeInput1 End time, in fractional seconds, relative to the first input video timeline. 
 * @param string $input2Uri Uri of the second video in the Cloud Storage bucket. 
 * @param float  $startTimeInput2 Start time, in fractional seconds, relative to the second input video timeline. 
 * @param float  $endTimeInput2 End time, in fractional seconds, relative to the second input video timeline. 
 * @param string $outputUri Uri of the video output folder in the Cloud Storage bucket. 
 */ 
 function create_job_with_concatenated_inputs($projectId, $location, $input1Uri, $startTimeInput1, $endTimeInput1, $input2Uri, $startTimeInput2, $endTimeInput2, $outputUri) 
 { 
 $startTimeInput1Sec = (int) floor(abs($startTimeInput1)); 
 $startTimeInput1Nanos = (int) (1000000000 * bcsub((string) abs($startTimeInput1), (string) floor(abs($startTimeInput1)), 4)); 
 $endTimeInput1Sec = (int) floor(abs($endTimeInput1)); 
 $endTimeInput1Nanos = (int) (1000000000 * bcsub((string) abs($endTimeInput1), (string) floor(abs($endTimeInput1)), 4)); 
 $startTimeInput2Sec = (int) floor(abs($startTimeInput2)); 
 $startTimeInput2Nanos = (int) (1000000000 * bcsub((string) abs($startTimeInput2), (string) floor(abs($startTimeInput2)), 4)); 
 $endTimeInput2Sec = (int) floor(abs($endTimeInput2)); 
 $endTimeInput2Nanos = (int) (1000000000 * bcsub((string) abs($endTimeInput2), (string) floor(abs($endTimeInput2)), 4)); 
 // Instantiate a client. 
 $transcoderServiceClient = new TranscoderServiceClient(); 
 $formattedParent = $transcoderServiceClient->locationName($projectId, $location); 
 $jobConfig = 
 (new JobConfig())->setInputs([ 
 (new Input()) 
 ->setKey('input1') 
 ->setUri($input1Uri), 
 (new Input()) 
 ->setKey('input2') 
 ->setUri($input2Uri) 
 ])->setEditList([ 
 (new EditAtom()) 
 ->setKey('atom1') 
 ->setInputs(['input1']) 
 ->setStartTimeOffset(new Duration(['seconds' => $startTimeInput1Sec, 'nanos' => $startTimeInput1Nanos])) 
 ->setEndTimeOffset(new Duration(['seconds' => $endTimeInput1Sec, 'nanos' => $endTimeInput1Nanos])), 
 (new EditAtom()) 
 ->setKey('atom2') 
 ->setInputs(['input2']) 
 ->setStartTimeOffset(new Duration(['seconds' => $startTimeInput2Sec, 'nanos' => $startTimeInput2Nanos])) 
 ->setEndTimeOffset(new Duration(['seconds' => $endTimeInput2Sec, 'nanos' => $endTimeInput2Nanos])), 
 ])->setElementaryStreams([ 
 (new ElementaryStream()) 
 ->setKey('video-stream0') 
 ->setVideoStream( 
 (new VideoStream())->setH264( 
 (new VideoStream\H264CodecSettings()) 
 ->setBitrateBps(550000) 
 ->setFrameRate(60) 
 ->setHeightPixels(360) 
 ->setWidthPixels(640) 
 ) 
 ), 
 (new ElementaryStream()) 
 ->setKey('audio-stream0') 
 ->setAudioStream( 
 (new AudioStream()) 
 ->setCodec('aac') 
 ->setBitrateBps(64000) 
 ) 
 ])->setMuxStreams([ 
 (new MuxStream()) 
 ->setKey('sd') 
 ->setContainer('mp4') 
 ->setElementaryStreams(['video-stream0', 'audio-stream0']) 
 ]); 
 $job = (new Job()) 
 ->setOutputUri($outputUri) 
 ->setConfig($jobConfig); 
 $request = (new CreateJobRequest()) 
 ->setParent($formattedParent) 
 ->setJob($job); 
 $response = $transcoderServiceClient->createJob($request); 
 // Print job name. 
 printf('Job: %s' . PHP_EOL, $response->getName()); 
 } 
 

Python

Before trying this sample, follow the Python setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API Python API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  import 
  
 argparse 
 from 
  
 google.cloud.video 
  
 import 
  transcoder_v1 
 
 from 
  
 google.cloud.video.transcoder_v1.services.transcoder_service 
  
 import 
 ( 
  TranscoderServiceClient 
 
 , 
 ) 
 from 
  
 google.protobuf 
  
 import 
 duration_pb2 
 as 
 duration 
 def 
  
 create_job_with_concatenated_inputs 
 ( 
 project_id 
 : 
 str 
 , 
 location 
 : 
 str 
 , 
 input1_uri 
 : 
 str 
 , 
 start_time_input1 
 : 
 str 
 , 
 end_time_input1 
 : 
 str 
 , 
 input2_uri 
 : 
 str 
 , 
 start_time_input2 
 : 
 str 
 , 
 end_time_input2 
 : 
 str 
 , 
 output_uri 
 : 
 str 
 , 
 ) 
 - 
> transcoder_v1 
 . 
 types 
 . 
 resources 
 . 
 Job 
 : 
  
 """Creates a job based on an ad-hoc job configuration that concatenates two input videos. 
 Args: 
 project_id (str): The GCP project ID. 
 location (str): The location to start the job in. 
 input1_uri (str): Uri of the first video in the Cloud Storage bucket. 
 start_time_input1 (str): Start time, in fractional seconds ending in 's' 
 (e.g., '0s'), relative to the first input video timeline. 
 end_time_input1 (str): End time, in fractional seconds ending in 's' 
 (e.g., '8.1s'), relative to the first input video timeline. 
 input2_uri (str): Uri of the second video in the Cloud Storage bucket. 
 start_time_input2 (str): Start time, in fractional seconds ending in 's' 
 (e.g., '3.5s'), relative to the second input video timeline. 
 end_time_input2 (str): End time, in fractional seconds ending in 's' 
 (e.g., '15s'), relative to the second input video timeline. 
 output_uri (str): Uri of the video output folder in the Cloud Storage 
 bucket. 
 Returns: 
 The job resource. 
 """ 
 s1 
 = 
 duration 
 . 
 Duration 
 () 
 s1 
 . 
 FromJsonString 
 ( 
 start_time_input1 
 ) 
 e1 
 = 
 duration 
 . 
 Duration 
 () 
 e1 
 . 
 FromJsonString 
 ( 
 end_time_input1 
 ) 
 s2 
 = 
 duration 
 . 
 Duration 
 () 
 s2 
 . 
 FromJsonString 
 ( 
 start_time_input2 
 ) 
 e2 
 = 
 duration 
 . 
 Duration 
 () 
 e2 
 . 
 FromJsonString 
 ( 
 end_time_input2 
 ) 
 client 
 = 
 TranscoderServiceClient 
 () 
 parent 
 = 
 f 
 "projects/ 
 { 
 project_id 
 } 
 /locations/ 
 { 
 location 
 } 
 " 
 job 
 = 
  transcoder_v1 
 
 . 
  types 
 
 . 
  Job 
 
 () 
 job 
 . 
 output_uri 
 = 
 output_uri 
 job 
 . 
 config 
 = 
  transcoder_v1 
 
 . 
  types 
 
 . 
  JobConfig 
 
 ( 
 inputs 
 = 
 [ 
  transcoder_v1 
 
 . 
  types 
 
 . 
  Input 
 
 ( 
 key 
 = 
 "input1" 
 , 
 uri 
 = 
 input1_uri 
 , 
 ), 
  transcoder_v1 
 
 . 
  types 
 
 . 
  Input 
 
 ( 
 key 
 = 
 "input2" 
 , 
 uri 
 = 
 input2_uri 
 , 
 ), 
 ], 
 edit_list 
 = 
 [ 
  transcoder_v1 
 
 . 
  types 
 
 . 
  EditAtom 
 
 ( 
 key 
 = 
 "atom1" 
 , 
 inputs 
 = 
 [ 
 "input1" 
 ], 
 start_time_offset 
 = 
 s1 
 , 
 end_time_offset 
 = 
 e1 
 , 
 ), 
  transcoder_v1 
 
 . 
  types 
 
 . 
  EditAtom 
 
 ( 
 key 
 = 
 "atom2" 
 , 
 inputs 
 = 
 [ 
 "input2" 
 ], 
 start_time_offset 
 = 
 s2 
 , 
 end_time_offset 
 = 
 e2 
 , 
 ), 
 ], 
 elementary_streams 
 = 
 [ 
  transcoder_v1 
 
 . 
  types 
 
 . 
  ElementaryStream 
 
 ( 
 key 
 = 
 "video-stream0" 
 , 
 video_stream 
 = 
  transcoder_v1 
 
 . 
  types 
 
 . 
  VideoStream 
 
 ( 
 h264 
 = 
  transcoder_v1 
 
 . 
  types 
 
 . 
  VideoStream 
 
 . 
  H264CodecSettings 
 
 ( 
 height_pixels 
 = 
 360 
 , 
 width_pixels 
 = 
 640 
 , 
 bitrate_bps 
 = 
 550000 
 , 
 frame_rate 
 = 
 60 
 , 
 ), 
 ), 
 ), 
  transcoder_v1 
 
 . 
  types 
 
 . 
  ElementaryStream 
 
 ( 
 key 
 = 
 "audio-stream0" 
 , 
 audio_stream 
 = 
  transcoder_v1 
 
 . 
  types 
 
 . 
  AudioStream 
 
 ( 
 codec 
 = 
 "aac" 
 , 
 bitrate_bps 
 = 
 64000 
 ), 
 ), 
 ], 
 mux_streams 
 = 
 [ 
  transcoder_v1 
 
 . 
  types 
 
 . 
  MuxStream 
 
 ( 
 key 
 = 
 "sd" 
 , 
 container 
 = 
 "mp4" 
 , 
 elementary_streams 
 = 
 [ 
 "video-stream0" 
 , 
 "audio-stream0" 
 ], 
 ), 
 ], 
 ) 
 response 
 = 
 client 
 . 
  create_job 
 
 ( 
 parent 
 = 
 parent 
 , 
 job 
 = 
 job 
 ) 
 print 
 ( 
 f 
 "Job: 
 { 
 response 
 . 
 name 
 } 
 " 
 ) 
 return 
 response 
 

Ruby

Before trying this sample, follow the Ruby setup instructions in the Transcoder API quickstart using client libraries . For more information, see the Transcoder API Ruby API reference documentation .

To authenticate to Transcoder API, set up Application Default Credentials. For more information, see Set up authentication for a local development environment .

  # project_id        = # Your project ID, e.g. "my-project" 
 # location          = # Data location, e.g. "us-central1" 
 # input1_uri        = # First video, e.g. "gs://my-bucket/my-video-file1" 
 # start_time_input1 = # Start time in fractional seconds relative to the 
 #                     # first input video timeline, e.g. 0.0 
 # end_time_input1   = # End time in fractional seconds relative to the 
 #                     # first input video timeline, e.g. 8.125 
 # input2_uri        = # Second video, e.g. "gs://my-bucket/my-video-file2" 
 # start_time_input2 = # Start time in fractional seconds relative to the 
 #                     # second input video timeline, e.g. 3.5 
 # end_time_input2   = # End time in fractional seconds relative to the 
 #                     # second input video timeline, e.g. 15 
 # output_uri        = # Output folder, e.g. "gs://my-bucket/my-output-folder/" 
 s1_sec 
  
 = 
  
 start_time_input1 
 . 
 to_i 
 s1_nanos 
  
 = 
  
 ( 
 start_time_input1 
 . 
 to_f 
 . 
 remainder 
 ( 
 1 
 ) 
  
 * 
  
 1_000_000_000 
 ) 
 . 
 round 
 e1_sec 
  
 = 
  
 end_time_input1 
 . 
 to_i 
 e1_nanos 
  
 = 
  
 ( 
 end_time_input1 
 . 
 to_f 
 . 
 remainder 
 ( 
 1 
 ) 
  
 * 
  
 1_000_000_000 
 ) 
 . 
 round 
 s2_sec 
  
 = 
  
 start_time_input2 
 . 
 to_i 
 s2_nanos 
  
 = 
  
 ( 
 start_time_input2 
 . 
 to_f 
 . 
 remainder 
 ( 
 1 
 ) 
  
 * 
  
 1_000_000_000 
 ) 
 . 
 round 
 e2_sec 
  
 = 
  
 end_time_input2 
 . 
 to_i 
 e2_nanos 
  
 = 
  
 ( 
 end_time_input2 
 . 
 to_f 
 . 
 remainder 
 ( 
 1 
 ) 
  
 * 
  
 1_000_000_000 
 ) 
 . 
 round 
 # Require the Transcoder client library. 
 require 
  
 "google/cloud/video/transcoder" 
 # Create a Transcoder client. 
 client 
  
 = 
  
 Google 
 :: 
 Cloud 
 :: 
 Video 
 :: 
 Transcoder 
 . 
 transcoder_service 
 # Build the resource name of the parent. 
 parent 
  
 = 
  
 client 
 . 
 location_path 
  
 project 
 : 
  
 project_id 
 , 
  
 location 
 : 
  
 location 
 # Build the job config. 
 new_job 
  
 = 
  
 { 
  
 output_uri 
 : 
  
 output_uri 
 , 
  
 config 
 : 
  
 { 
  
 inputs 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 "input1" 
 , 
  
 uri 
 : 
  
 input1_uri 
  
 }, 
  
 { 
  
 key 
 : 
  
 "input2" 
 , 
  
 uri 
 : 
  
 input2_uri 
  
 } 
  
 ] 
 , 
  
 edit_list 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 "atom1" 
 , 
  
 inputs 
 : 
  
 [ 
 "input1" 
 ] 
 , 
  
 start_time_offset 
 : 
  
 { 
  
 seconds 
 : 
  
 s1_sec 
 , 
  
 nanos 
 : 
  
 s1_nanos 
  
 }, 
  
 end_time_offset 
 : 
  
 { 
  
 seconds 
 : 
  
 e1_sec 
 , 
  
 nanos 
 : 
  
 e1_nanos 
  
 } 
  
 }, 
  
 { 
  
 key 
 : 
  
 "atom2" 
 , 
  
 inputs 
 : 
  
 [ 
 "input2" 
 ] 
 , 
  
 start_time_offset 
 : 
  
 { 
  
 seconds 
 : 
  
 s2_sec 
 , 
  
 nanos 
 : 
  
 s2_nanos 
  
 }, 
  
 end_time_offset 
 : 
  
 { 
  
 seconds 
 : 
  
 e2_sec 
 , 
  
 nanos 
 : 
  
 e2_nanos 
  
 } 
  
 } 
  
 ] 
 , 
  
 elementary_streams 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 "video-stream0" 
 , 
  
 video_stream 
 : 
  
 { 
  
 h264 
 : 
  
 { 
  
 height_pixels 
 : 
  
 360 
 , 
  
 width_pixels 
 : 
  
 640 
 , 
  
 bitrate_bps 
 : 
  
 550_000 
 , 
  
 frame_rate 
 : 
  
 60 
  
 } 
  
 } 
  
 }, 
  
 { 
  
 key 
 : 
  
 "audio-stream0" 
 , 
  
 audio_stream 
 : 
  
 { 
  
 codec 
 : 
  
 "aac" 
 , 
  
 bitrate_bps 
 : 
  
 64_000 
  
 } 
  
 } 
  
 ] 
 , 
  
 mux_streams 
 : 
  
 [ 
  
 { 
  
 key 
 : 
  
 "sd" 
 , 
  
 container 
 : 
  
 "mp4" 
 , 
  
 elementary_streams 
 : 
  
 [ 
  
 "video-stream0" 
 , 
  
 "audio-stream0" 
  
 ] 
  
 } 
  
 ] 
  
 } 
 } 
 job 
  
 = 
  
 client 
 . 
 create_job 
  
 parent 
 : 
  
 parent 
 , 
  
 job 
 : 
  
 new_job 
 # Print the job name. 
 puts 
  
 "Job: 
 #{ 
 job 
 . 
 name 
 } 
 " 
 

Example

Consider the following sample videos:

Both videos are similar in that they contain three parts:

  1. Watching a movie or game on a mobile device
  2. Watching the same content on a big screen
  3. Show brief ad copy for the product

As an example, you can concatenate these two videos together such that the output video shows parts one and two from the first video, and then parts two and three from the second video. You can accomplish this concatenation using the following time offsets:

Use the preceding code along with these two videos and their time offsets to see an action-packed result video .

Design a Mobile Site
View Site in Mobile | Classic
Share by: