本篇从获取音视频元信息入手,顺序讲解各个处理指令。
使用avinfo接口可以非常方便地获取一个音视频资源的相关元信息:
http://.qiniudn.com/?avinfo
或
http:///?avinfo
以美剧《黑名单》第1季第12集的预告片(flv资源)为例,在浏览器中打开如下URL:
http://qiniu-developer.u.qiniudn.com/samples/黑名单-S01E12.flv?avinfo
将返回一个JSON格式组织的元信息对象:
{
"streams": [
{
"index": 0,
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"codec_type": "video",
"codec_time_base": "1001/60000",
"codec_tag_string": "avc1",
"codec_tag": "0x31637661",
"width": 1280,
"height": 720,
...省略过长内容...
},
{
"index": 1,
"codec_name": "aac",
"codec_long_name": "Advanced Audio Coding",
"codec_type": "audio",
"codec_time_base": "1/44100",
"codec_tag_string": "mp4a",
"codec_tag": "0x6134706d",
"sample_fmt": "s16",
"sample_rate": "44100",
"channels": 2,
...省略过长内容...
}
],
"format": {
"nb_streams": 2,
"format_name": "mov,mp4,m4a,3gp,3g2,mj2",
"format_long_name": "QuickTime/MPEG-4/Motion JPEG 2000 format",
"start_time": "0.000000",
"duration": "29.070000",
"size": "8702170",
"bit_rate": "2394818",
"tags": {
"major_brand": "mp42",
"minor_version": "0",
"compatible_brands": "isommp42",
"creation_time": "2014-01-13 08:43:21"
}
}
}
可以看到音频、视频和封装格式信息被准确地描述出来。
avthumb接口支持的基本音视频处理包括:
以前文的flv资源为例,若只想简单地转码为mp4格式,可以使用如下URL达成目的:
http://qiniu-developer.u.qiniudn.com/samples/黑名单-S01E12.flv?avthumb/mp4
接收到这样的请求后,七牛云将对指定资源执行实时转码操作,缓存结果后将新资源返回给请求端。点击查看转码效果。
注意:
上传时,通过在上传策略中指定persistentOps字段的值,可以触发七牛云对上传资源进行指定的数据处理。还可以同时指定persistentNotifyUrl字段的值,以便将持久化处理结果及时通知给业务端处理。
以前文的flv资源为例,若想预先转换成mp4格式并持久存储结果(计入存储空间),可以使用以下两个Ruby程序来完成。
1. [简易HTTP服务器] 接收预转持久化处理的结果,并将状态信息打印到终端上:
#!/usr/bin/env ruby
# encoding : utf-8
# persistent_notify_server.rb
require 'json'
require 'xmlrpc/httpserver'
class PersistentNotifyHandler
@@count = 0
public
def ip_auth_handler(io)
# 任何请求都允许处理
return true
end # ip_auth_handler
def request_handler(request, response)
# 读取请求报文
body = request.data.read_nonblock(65536)
# 重新格式化JSON对象
json = JSON.generate(
JSON.parse(body),
{
indent: ' ',
object_nl: "\n",
array_nl: "\n",
}
)
# 输出
puts json
# 计数
@@count += 1
# 构造响应报文(可选)
response.body = 'OK'
end # request_handler
def self.count()
return @@count
end # self.count
end # PersistentNotifyHandler
svr = HttpServer.new(
PersistentNotifyHandler.new(), # 请求处理器
9090, # 端口
'0.0.0.0' # 监听IP
)
svr.start
while (PersistentNotifyHandler.count() == 0)
puts 'waiting for notification...'
sleep(60)
end
svr.shutdown
2. [HTTP客户端] 上传flv文件并触发预转持久化处理:
#!/usr/bin/env ruby
# encoding : utf-8
# put_flv_file.rb
require 'json'
require 'net/http'
require 'base64'
require 'openssl'
# 根据传入参数,构造一个上传策略(触发预转持久化处理)
def put_policy(bucket, expires, persistentOps, persistentNotifyUrl)
# 生成一个Hash对象
put_policy = Hash.new()
# 仅指定目标存储空间,即“新增资源”语意:
# 资源不存在则创建
# 资源已存在,且与上传内容不一致则失败
put_policy['scope'] = "#{bucket}"
# 计算授权有效期截止时间,UNIX时间戳格式
put_policy['deadline'] = (Time.now() + expires).tv_sec()
# 指定预转持久化处理的指令
put_policy['persistentOps'] = persistentOps
# 指定预转持久化处理的结果通知URL
put_policy['persistentNotifyUrl'] = persistentNotifyUrl
# 序列化为JSON字符串
return JSON.generate(put_policy)
end # put_policy
# 根据传入的上传策略,生成对应的上传授权凭证
def upload_token(access_key, secret_key, put_policy)
# 对上传策略做UrlSafe-Base64编码
encoded_put_policy = Base64.urlsafe_encode64(put_policy)
# 使用SHA1作为HASH函数,生成签名
sign = OpenSSL::HMAC.digest(
'sha1',
secret_key,
encoded_put_policy
)
# 对签名做UrlSafe-Base64编码
encoded_sign = Base64.urlsafe_encode64(sign)
# 拼出上传授权凭证,以“:”作为分隔符
return "#{access_key}:#{encoded_sign}:#{encoded_put_policy}"
end # upload_token
BUCKET = 'qiniu-ts-demo' # 使用时请更换成真实的存储空间名
EXPIRES = 3600
ACCESS_KEY = 'MY_ACCESS_KEY' # 使用时请更换成真实的AccessKey
SECRET_KEY = 'MY_SECRET_KEY' # 使用时请更换成真实的SecretKey
PERSISTENT_OPS = 'avthumb/mp4' # 持久化处理指令
PERSISTENT_NOTIFY_URL = 'http://fake.com:9090' # 使用时请更换成真实的域名和端口
# 生成上传授权凭证
upload_token = upload_token(
ACCESS_KEY,
SECRET_KEY,
put_policy(
BUCKET,
EXPIRES,
PERSISTENT_OPS,
PERSISTENT_NOTIFY_URL
)
)
# 指定请求报文中的各个参数
file_name = '黑名单-S01E12.flv' # 使用时请更换成真实的文件
file_content = File.open(file_name, 'rb') do |fh|
fh.read()
end
puts 'file size is %s' % file_content.size
boundary = 'a-string-never-exists-in-the-uploading-file'
# 生成请求报文体
req_body = <<HTTP_BODY
--#{boundary}
Content-Disposition: form-data; name="token"
#{upload_token}
--#{boundary}
Content-Disposition: form-data; name="key"
#{file_name}
--#{boundary}
Content-Disposition: form-data; name="file"; filename="#{file_name}"
Content-Type: video/x-flv
Content-Transfer-Encoding: binary
HTTP_BODY
# 转换换行符
req_body.gsub!(/\n/, "\r\n")
req_body = req_body.force_encoding('ASCII-8BIT') + file_content + "\r\n--#{boundary}--\r\n"
# 生成Headers
req_headers = Hash.new()
req_headers['Host'] = "up.qiniu.com"
req_headers['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
req_headers['Content-Length'] = "#{req_body.size}"
# 发送请求
http_client = Net::HTTP.new('up.qiniu.com', 80)
resp = http_client.post(
'/',
req_body,
req_headers
)
# 解析响应
puts "HTTP Code=#{resp.code}"
puts "HTTP Msg=#{resp.msg}"
puts "HTTP Body=#{resp.body()}"
先启动服务器,然后执行上传程序,等待一段时间后便可收到预转成功的通知结果:
[Mon Jan 20 19:10:19 2014] HttpServer 0.0.0.0:9090 client:39573 115.238.138.231<115.238.138.231> connect
{
"id":"16i99r7gjlrc8r9213",
"code":0,
"desc":"The fop was completed successfully",
"items":[
{
"cmd":"avthumb/mp4",
"code":0,
"desc":"The fop was completed successfully",
"error":"",
"hash":"lpqijRaQ4c_CPoKDL1bLWK7TUoI3",
"key":"UAA-4hndfVc5V6DJX0EvslAUBBI=/ll8spobyuu_F112ZWyG6Va4qk4Ch"
}
]
}
[Mon Jan 20 19:10:19 2014] HttpServer 0.0.0.0:9090 client:39573 disconnect
[Mon Jan 20 19:10:52 2014] HttpServer 0.0.0.0:9090 stop
其中,Key字段给出持久化的mp4资源的名字,即可以通过如下URL访问转换好的mp4视频:
http://qiniu-ts-demo.qiniudn.com/UAA-4hndfVc5V6DJX0EvslAUBBI=/ll8spobyuu_F112ZWyG6Va4qk4Ch
点击查看转码效果。