You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
EasyDarwin/routers/record.go

189 lines
5.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package routers
import (
"bytes"
"log"
"math"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/penggy/EasyGoLib/utils"
)
/**
* @apiDefine record 录像
*/
/**
* @apiDefine fileInfo
* @apiSuccess (200) {String} duration 格式化好的录像时长
* @apiSuccess (200) {Number} durationMillis 录像时长,毫秒为单位
* @apiSuccess (200) {String} path 录像文件的相对路径,其绝对路径为http[s]://host:port/record/[path]。
* @apiSuccess (200) {String} folder 录像文件夹,录像文件夹以推流路径命名。
*/
/**
* @api {get} /api/v1/record/folders 获取所有录像文件夹
* @apiGroup record
* @apiName RecordFolders
* @apiParam {Number} [start] 分页开始,从零开始
* @apiParam {Number} [limit] 分页大小
* @apiParam {String} [sort] 排序字段
* @apiParam {String=ascending,descending} [order] 排序顺序
* @apiParam {String} [q] 查询参数
* @apiSuccess (200) {Number} total 总数
* @apiSuccess (200) {Array} rows 文件夹列表
* @apiSuccess (200) {String} rows.folder 录像文件夹名称
*/
func (h *APIHandler) RecordFolders(c *gin.Context) {
mp4Path := utils.Conf().Section("rtsp").Key("m3u8_dir_path").MustString("")
form := utils.NewPageForm()
if err := c.Bind(form); err != nil {
log.Printf("record folder bind err:%v", err)
return
}
var files = make([]interface{}, 0)
if mp4Path != "" {
visit := func(files *[]interface{}) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == mp4Path {
return nil
}
if !info.IsDir() {
return nil
}
*files = append(*files, map[string]interface{}{"folder": info.Name()})
return filepath.SkipDir
}
}
err := filepath.Walk(mp4Path, visit(&files))
if err != nil {
log.Printf("Query RecordFolders err:%v", err)
}
}
pr := utils.NewPageResult(files)
if form.Sort != "" {
pr.Sort(form.Sort, form.Order)
}
pr.Slice(form.Start, form.Limit)
c.IndentedJSON(200, pr)
}
/**
* @api {get} /api/v1/record/files 获取所有录像文件
* @apiGroup record
* @apiName RecordFiles
* @apiParam {Number} folder 录像文件所在的文件夹
* @apiParam {Number} [start] 分页开始,从零开始
* @apiParam {Number} [limit] 分页大小
* @apiParam {String} [sort] 排序字段
* @apiParam {String=ascending,descending} [order] 排序顺序
* @apiParam {String} [q] 查询参数
* @apiSuccess (200) {Number} total 总数
* @apiSuccess (200) {Array} rows 文件列表
* @apiSuccess (200) {String} rows.duration 格式化好的录像时长
* @apiSuccess (200) {Number} rows.durationMillis 录像时长,毫秒为单位
* @apiSuccess (200) {String} rows.path 录像文件的相对路径,录像文件为m3u8格式将其放到video标签中便可直接播放。其绝对路径为http[s]://host:port/record/[path]。
*/
func (h *APIHandler) RecordFiles(c *gin.Context) {
type Form struct {
utils.PageForm
Folder string `form:"folder" binding:"required"`
StartAt int `form:"beginUTCSecond"`
StopAt int `form:"endUTCSecond"`
}
var form = Form{}
form.Limit = math.MaxUint32
err := c.Bind(&form)
if err != nil {
log.Printf("record file bind err:%v", err)
return
}
files := make([]interface{}, 0)
mp4Path := utils.Conf().Section("rtsp").Key("m3u8_dir_path").MustString("")
if mp4Path != "" {
ffmpeg_path := utils.Conf().Section("rtsp").Key("ffmpeg_path").MustString("")
ffmpeg_folder, executable := filepath.Split(ffmpeg_path)
split := strings.Split(executable, ".")
suffix := ""
if len(split) > 1 {
suffix = split[1]
}
ffprobe := ffmpeg_folder + "ffprobe" + suffix
folder := filepath.Join(mp4Path, form.Folder)
visit := func(files *[]interface{}) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if path == folder {
return nil
}
if info.IsDir() {
return nil
}
if info.Size() == 0 {
return nil
}
if info.Name() == ".DS_Store" {
return nil
}
if !strings.HasSuffix(strings.ToLower(info.Name()), ".m3u8") && !strings.HasSuffix(strings.ToLower(info.Name()), ".ts") {
return nil
}
cmd := exec.Command(ffprobe, "-i", path)
cmdOutput := &bytes.Buffer{}
//cmd.Stdout = cmdOutput
cmd.Stderr = cmdOutput
err = cmd.Run()
bytes := cmdOutput.Bytes()
output := string(bytes)
//log.Printf("%v result:%v", cmd, output)
var average = regexp.MustCompile(`Duration: ((\d+):(\d+):(\d+).(\d+))`)
result := average.FindStringSubmatch(output)
duration := time.Duration(0)
durationStr := ""
if len(result) > 0 {
durationStr = result[1]
h, _ := strconv.Atoi(result[2])
duration += time.Duration(h) * time.Hour
m, _ := strconv.Atoi(result[3])
duration += time.Duration(m) * time.Minute
s, _ := strconv.Atoi(result[4])
duration += time.Duration(s) * time.Second
millis, _ := strconv.Atoi(result[5])
duration += time.Duration(millis) * time.Millisecond
}
*files = append(*files, map[string]interface{}{
"path": path[len(mp4Path):],
"durationMillis": duration / time.Millisecond,
"duration": durationStr})
return nil
}
}
err = filepath.Walk(folder, visit(&files))
if err != nil {
log.Printf("Query RecordFolders err:%v", err)
}
}
pr := utils.NewPageResult(files)
if form.Sort != "" {
pr.Sort(form.Sort, form.Order)
}
pr.Slice(form.Start, form.Limit)
c.IndentedJSON(200, pr)
}