视频单帧截取

当您需要获取视频封面、提取视频关键帧图像进行视频编辑,或者提取视频中特定场景帧图像用于视频监控时,可以将视频上传至OSS存储空间,通过视频截帧提取关键帧图片。

注意事项

  • 仅支持对视频编码格式为H264H265的视频文件进行视频截帧。

  • OSS默认不保存视频截帧的图片,视频截帧的图片需手动下载并保存至本地。

  • 使用视频截帧时,按视频截帧截取的图片数量计费。有关计费详情的更多信息,请参见数据处理费用

如何使用

前提条件

已在OSS创建存储空间(Bucket),上传需要进行截帧的视频Bucket中。

视频截帧

OSS中,当您携带?x-oss-process=video/snapshot,parame_value参数时,OSS会实时处理并返回处理后的结果。video/snapshot表示进行视频截帧处理;parame为支持的参数,value为参数取值。对于参数的详细说明在下文参数说明中给出,且支持多个参数间的组合使用。

对于公共读的视频,您可以直接在文件URL后添加处理参数,以允许任何人永久匿名访问处理后的文件URL。如果您的视频为私有类型,您需要调用SDK携带签名信息处理视频。

公共读文件

以下是公共读文件URL添加?x-oss-process=video/snapshot,parame_value参数的操作说明,您只需要根据您的业务需求将parame_value替换为具体的参数和值。

原始URL

添加处理参数后的URL

https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/video.mp4

https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/video.mp4?x-oss-process=video/snapshot,t_7000,f_jpg,w_800,h_600,m_fast

私有文件

您可以使用OSS SDK生成带有处理参数的签名URL,允许持有该URL的用户临时访问处理后的视频。使用SDK为私有视频生成带?x-oss-process=video/snapshot_value参数的签名URL的示例如下:

Java

package com.aliyun.oss.demo;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.net.URL;
import java.util.Date;

public class Demo {
    public static void main(String[] args) throws Throwable {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写视频文件的完整路径。若视频文件不在Bucket根目录,需携带文件访问路径,例如examplefolder/videotest.mp4。
        String objectName = "examplefolder/videotest.mp4";
        // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
        String region = "cn-hangzhou";

        // 创建OSSClient实例。
        // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        OSS ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialsProvider)
                .clientConfiguration(clientBuilderConfiguration)
                .region(region)
                .build();

        try {
            // 使用精确时间模式截取视频17s处的内容,输出为JPG格式的图片,宽度为800,高度为600。
            String style = "video/snapshot,t_17000,f_jpg,w_800,h_600";
            // 指定签名URL过期时间为3600秒)
            Date expiration = new Date(new Date().getTime() + 3600 );
            GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
            req.setExpiration(expiration);
            req.setProcess(style);
            URL signedUrl = ossClient.generatePresignedUrl(req);
            System.out.println(signedUrl);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

Python

# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())

# 填写Bucket名称
bucket = 'examplebucket'

# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例
endpoint = 'https://oss-cn-hangzhou.aliyuncs.com'

# 填写阿里云通用Region ID
region = 'cn-hangzhou'
bucket = oss2.Bucket(auth, endpoint, bucket, region=region)

# 填写视频文件的完整路径。若视频文件不在Bucket根目录,需携带文件访问路径,例如examplefolder/videotest.mp4。
key = 'examplefolder/videotest.mp4'

# 指定过期时间,单位秒
expire_time = 3600

# 使用精确时间模式截取视频17s处的内容,输出为JPG格式的图片,宽度为800,高度为600。
image_process = 'video/snapshot,t_17000,f_jpg,w_800,h_600'

# 生成签名URL,带上处理参数
url = bucket.sign_url('GET', key, expire_time, params={'x-oss-process': image_process}, slash_safe=True)

# 打印签名URL
print(url)

PHP

<?php

if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
$endpoint = "yourEndpoint";
// 填写Bucket名称,例如examplebucket。
$bucket= "examplebucket";
// 填写视频文件的完整路径。若视频文件不在Bucket根目录,需携带文件访问路径,例如examplefolder/videotest.mp4。
$object = "examplefolder/videotest.mp4";

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
        "signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
        "region"=> "cn-hangzhou"
    );
    $ossClient = new OssClient($config);

// 生成一个带处理参数的签名的URL,有效期是3600秒,可以直接使用浏览器访问。
$timeout = 3600;

$options = array(
    // 使用精确时间模式截取视频17s处的内容,输出为JPG格式的图片,宽度为800,高度为600。
    OssClient::OSS_PROCESS => "video/snapshot,t_17000,f_jpg,w_800,h_600");

$signedUrl = $ossClient->signUrl($bucket, $object, $timeout, "GET", $options);
print("url: \n" . $signedUrl);

Go

package main

import (
	"fmt"
	"os"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func HandleError(err error) {
	fmt.Println("Error:", err)
	os.Exit(-1)
}

func main() {
	// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
	provider, err := oss.NewEnvironmentVariableCredentialsProvider()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(-1)
	}

	// 创建OSSClient实例。
	// yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
	// yourRegion填写Bucket所在地域,以华东1(杭州)为例,填写为cn-hangzhou。其它Region请按实际情况填写。
	clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
	clientOptions = append(clientOptions, oss.Region("yourRegion"))
	// 设置签名版本
	clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
	client, err := oss.New("yourEndpoint", "", "", clientOptions...)
	if err != nil {
		HandleError(err)
	}

	// 指定图片所在Bucket的名称,例如examplebucket。
	bucketName := "examplebucket"
	bucket, err := client.Bucket(bucketName)
	if err != nil {
		HandleError(err)
	}
	// 填写视频文件的完整路径。若视频文件不在Bucket根目录,需携带文件访问路径,例如examplefolder/videotest.mp4。
	ossName := "examplefolder/videotest.mp4"
	// 生成带签名的URL,并指定过期时间为3600s。
	// 使用精确时间模式截取视频17s处的内容,输出为JPG格式的图片,宽度为800,高度为600。
	signedURL, err := bucket.SignURL(ossName, oss.HTTPGet, 3600, oss.Process("video/snapshot,t_17000,f_jpg,w_800,h_600"))
	if err != nil {
		HandleError(err)
	} else {
		fmt.Println(signedURL)
	}
}

Node.js

const OSS = require("ali-oss");

const client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: "oss-cn-hangzhou",
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  authorizationV4: true,
  // yourbucketname填写存储空间名称。
  bucket: "examplebucket",
});
// 处理样式"video/snapshot,t_17000,f_jpg,w_800,h_600"。
const signUrl = client.signatureUrl("examplefolder/videotest.mp4", {
  expires: 3600,
  process: "video/snapshot,t_17000,f_jpg,w_800,h_600",
});
console.log("signUrl=" + signUrl);

.NET

using Aliyun.OSS;
using Aliyun.OSS.Common;

// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID"); 
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 指定视频所在Bucket的名称,例如examplebucket。
var bucketName = "examplebucket";
// 指定名称。如果视频不在Bucket根目录,需携带文件完整路径。
var objectName = "examplefolder/videotest.mp4";
// 填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn-hangzhou。
const string region = "cn-hangzhou";

// 创建ClientConfiguration实例,按照您的需要修改默认参数。
var conf = new ClientConfiguration();

// 设置v4签名。
conf.SignatureVersion = SignatureVersion.V4;

// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
client.SetRegion(region);
try
{
    // 视频截帧。
    var process = "video/snapshot,t_17000,f_jpg,w_800,h_600";
    var req = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Get)
    {
        Expiration = DateTime.Now.AddHours(1),
        Process = process
    };
    // 生成带有签名的URI。
    var uri = client.GeneratePresignedUri(req);
    Console.WriteLine("Generate Presigned Uri:{0} with process:{1} succeeded ", uri, process);
}
catch (OssException ex)
{
    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}

C

#include "oss_api.h"
#include "aos_http_io.h"
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
const char *endpoint = "yourEndpoint";
/* 填写Bucket名称,例如examplebucket。*/
const char *bucket_name = "examplebucket";
/* 填写Object完整路径,完整路径中不能包含Bucket名称。*/
const char *object_name = "examplefolder/videotest.mp4";
/* yourRegion填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn-hangzhou。*/
const char *region = "yourRegion";
void init_options(oss_request_options_t *options)
{
    options->config = oss_config_create(options->pool);
    /* 用char*类型的字符串初始化aos_string_t类型。*/
    aos_str_set(&options->config->endpoint, endpoint);
    /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
    aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
    //需要额外配置以下两个参数
    aos_str_set(&options->config->region, region);
    options->config->signature_version = 4;
    /* 是否使用了CNAME。0表示不使用。*/
    options->config->is_cname = 0;
    /* 设置网络相关参数,比如超时时间等。*/
    options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
    /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
    if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
        exit(1);
    }
    /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
    aos_pool_t *pool;
    /* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
    aos_pool_create(&pool, NULL);
    /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
    oss_request_options_t *oss_client_options;
    /* 在内存池中分配内存给options。*/
    oss_client_options = oss_request_options_create(pool);
    /* 初始化Client的选项oss_client_options。*/
    init_options(oss_client_options);
    /* 初始化参数。*/
    aos_string_t bucket;
    aos_string_t object;
    aos_table_t *params = NULL;
    aos_http_request_t *req;
    char *url_str;
    apr_time_t now;
    int64_t expire_time; 
    aos_str_set(&bucket, bucket_name);
    aos_str_set(&object, object_name);
    params = aos_table_make(pool, 1);
    apr_table_set(params, OSS_PROCESS, "video/snapshot,t_17000,f_jpg,w_800,h_600");
    req = aos_http_request_create(pool);
    req->method = HTTP_GET;
    req->query_params = params;
    /* 指定过期时间(expire_time),单位为秒。*/
    now = apr_time_now();
    expire_time = now / 1000000 + 10 * 60;
    /* 生成签名url。*/
    url_str = oss_gen_signed_url(oss_client_options, &bucket, &object, expire_time, req);
    printf("url: %s\n", url_str);
    /* 释放该内存池,相当于释放了请求过程中各资源分配的内存。*/
    aos_pool_destroy(pool);
    /* 释放之前分配的全局资源。*/
    aos_http_io_deinitialize();
    return 0;
}

C++

#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* 初始化OSS账号信息。*/
            
    /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "yourEndpoint";
    /* yourRegion填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn-hangzhou。*/
    std::string Region = "yourRegion";
    /* 填写视频所在的Bucket名称,例如examplebucket。*/
    std::string BucketName = "examplebucket";
    /* 指定视频名称。如果图片不在Bucket根目录,需携带文件完整路径。*/
    std::string ObjectName = "examplefolder/videotest.mp4";

    /* 初始化网络等资源。*/
    InitializeSdk();

    ClientConfiguration conf;
    conf.signatureVersion = SignatureVersionType::V4;
    /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);
    client.SetRegion(Region);


    /* 生成带处理参数的文件签名URL。*/
    std::string Process = "video/snapshot,t_17000,f_jpg,w_800,h_600";
    GeneratePresignedUrlRequest request(BucketName, ObjectName, Http::Get);
    request.setProcess(Process);
    auto outcome = client.GeneratePresignedUrl(request);
	
    if (outcome.isSuccess()) {
    std::cout << "Generated presigned URL: " << outcome.result() << std::endl;
    } else {
    std::cout << "Failed to generate presigned URL. Error code: " << outcome.error().Code()
              << ", Message: " << outcome.error().Message()
              << ", RequestId: " << outcome.error().RequestId() << std::endl;
    }
    
    /* 释放网络等资源。*/
    ShutdownSdk();
    return 0;
}

生成的签名URL示例如下:

https://examplebucket.oss-cn-hangzhou.aliyuncs.com/examplefolder/videotest.mp4?x-oss-process=video%2Fsnapshot%2Ct_17000%2Cf_jpg%2Cw_800%2Ch_600&x-oss-date=20250311T083843Z&x-oss-expires=3600&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI********************%2F20241111%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=6fd07a2ba50bf6891474dc56aed976b556b6fbcd901cfd01bcde5399bf4802cb

参数说明

操作名称:video/snapshot

参数

描述

取值范围

t

指定截图时间。如果设置的截图时间t超过了视频时长,则返回视频的最后一个关键帧。

说明

如果需要截取视频封面,则t设置为0。

[0,视频时长]

单位:ms

w

指定截图宽度,如果指定为0,则根据截图高度与源视频高度比例自动计算。

[0,视频宽度]

单位:像素(px)

h

指定截图高度,如果指定为0,则根据截图宽度与源视频宽度的比例自动计算;如果wh都为0,则输出为原视频宽高。

[0,视频高度]

单位:像素(px)

m

指定截图模式,不指定则为默认模式,根据时间精确截图。如果指定为fast,则截取该时间点之前的最近的一个关键帧。

枚举值:fast

f

指定输出图片的格式。

枚举值:jpgpng

ar

指定是否根据视频信息自动旋转图片。

枚举值:autohw

各枚举值说明如下:

  • auto:指定在截图生成之后根据视频信息进行自动旋转。

  • h:指定在截图生成之后根据视频信息强制按高大于宽的模式旋转。

  • w:指定在截图生成之后根据视频信息强制按宽大于高的模式旋转。

使用示例

使用默认模式截取图片

以下是添加?x-oss-process=video/snapshot,t_17000,f_jpg,w_800,h_600参数使用默认的精确时间模式截取视频17s处的内容,输出为JPG格式的图片,宽度为800,高度为600:

原始URL

添加处理参数后的URL

https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/video.mp4

https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/video.mp4?x-oss-process=video/snapshot,t_17000,f_jpg,w_800,h_600

获取到截帧后的图片如下:

2

使用fast模式截取图片

以下是添加?x-oss-process=video/snapshot,t_7000,f_jpg,w_800,h_600,m_fast参数使用fast模式截取视频7s处的内容,输出宽度为800,高度为600JPG格式的图片:

原始URL

添加处理参数后的URL

https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/video.mp4

https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/video.mp4?x-oss-process=video/snapshot,t_7000,f_jpg,w_800,h_600,m_fast

获取到截帧后的图片如下:

1

常见问题

私有文件能否通过链接拼接参数进行文件处理?

不可以。对于不允许匿名访问的私有视频文件,不支持通过文件URL直接添加参数的方式处理视频,您需要通过SDK的方式将视频处理操作加入签名URL中。

如何查看OSS中视频的长宽尺寸?

您可以使用视频信息提取功能,获取视频的长宽尺寸。

视频截帧得到的图片出现失真

目前暂不支持对杜比视界的源视频进行视频截帧。

OSS上面视频的封面可以通过视频截帧获取吗,如何使它永久化?

可以,在获取到该封面后,可以通过网络流的方式将其上传至OSS,OSS将生成一个截图文件,此时该文件即可实现永久保存。