Compare commits

...

1 Commits

Author SHA1 Message Date
langhuihui
d68fdf1c37 feat: add ffmpeg plugin 2025-10-09 14:44:00 +08:00
16 changed files with 4309 additions and 993 deletions

View File

@@ -7,6 +7,7 @@ import (
"m7s.live/v5"
_ "m7s.live/v5/plugin/cascade"
_ "m7s.live/v5/plugin/ffmpeg"
_ "m7s.live/v5/plugin/debug"
_ "m7s.live/v5/plugin/flv"
_ "m7s.live/v5/plugin/gb28181"

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v6.31.1
// protoc v5.29.3
// source: auth.proto
package pb

View File

@@ -10,7 +10,6 @@ package pb
import (
"context"
"errors"
"io"
"net/http"
@@ -25,118 +24,116 @@ import (
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
func request_Auth_Login_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LoginRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
var protoReq LoginRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
msg, err := client.Login(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Auth_Login_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LoginRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
var protoReq LoginRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Login(ctx, &protoReq)
return msg, metadata, err
}
func request_Auth_Logout_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LogoutRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
var protoReq LogoutRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
msg, err := client.Logout(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Auth_Logout_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq LogoutRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
var protoReq LogoutRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.Logout(ctx, &protoReq)
return msg, metadata, err
}
var filter_Auth_GetUserInfo_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
var (
filter_Auth_GetUserInfo_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Auth_GetUserInfo_0(ctx context.Context, marshaler runtime.Marshaler, client AuthClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq UserInfoRequest
metadata runtime.ServerMetadata
)
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
var protoReq UserInfoRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Auth_GetUserInfo_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetUserInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Auth_GetUserInfo_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq UserInfoRequest
metadata runtime.ServerMetadata
)
var protoReq UserInfoRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Auth_GetUserInfo_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetUserInfo(ctx, &protoReq)
return msg, metadata, err
}
// RegisterAuthHandlerServer registers the http handlers for service Auth to "mux".
// UnaryRPC :call AuthServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterAuthHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterAuthHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthServer) error {
mux.Handle(http.MethodPost, pattern_Auth_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("POST", pattern_Auth_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/pb.Auth/Login", runtime.WithHTTPPathPattern("/api/auth/login"))
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/pb.Auth/Login", runtime.WithHTTPPathPattern("/api/auth/login"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -148,15 +145,20 @@ func RegisterAuthHandlerServer(ctx context.Context, mux *runtime.ServeMux, serve
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Auth_Login_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodPost, pattern_Auth_Logout_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("POST", pattern_Auth_Logout_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/pb.Auth/Logout", runtime.WithHTTPPathPattern("/api/auth/logout"))
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/pb.Auth/Logout", runtime.WithHTTPPathPattern("/api/auth/logout"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -168,15 +170,20 @@ func RegisterAuthHandlerServer(ctx context.Context, mux *runtime.ServeMux, serve
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Auth_Logout_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_Auth_GetUserInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("GET", pattern_Auth_GetUserInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/pb.Auth/GetUserInfo", runtime.WithHTTPPathPattern("/api/auth/userinfo"))
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/pb.Auth/GetUserInfo", runtime.WithHTTPPathPattern("/api/auth/userinfo"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -188,7 +195,9 @@ func RegisterAuthHandlerServer(ctx context.Context, mux *runtime.ServeMux, serve
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Auth_GetUserInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
@@ -197,24 +206,25 @@ func RegisterAuthHandlerServer(ctx context.Context, mux *runtime.ServeMux, serve
// RegisterAuthHandlerFromEndpoint is same as RegisterAuthHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterAuthHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
conn, err := grpc.DialContext(ctx, endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterAuthHandler(ctx, mux, conn)
}
@@ -228,13 +238,16 @@ func RegisterAuthHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AuthClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AuthClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "AuthClient" to call the correct interceptors. This client ignores the HTTP middlewares.
// "AuthClient" to call the correct interceptors.
func RegisterAuthHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AuthClient) error {
mux.Handle(http.MethodPost, pattern_Auth_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("POST", pattern_Auth_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/pb.Auth/Login", runtime.WithHTTPPathPattern("/api/auth/login"))
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/pb.Auth/Login", runtime.WithHTTPPathPattern("/api/auth/login"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -245,13 +258,18 @@ func RegisterAuthHandlerClient(ctx context.Context, mux *runtime.ServeMux, clien
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Auth_Login_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodPost, pattern_Auth_Logout_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("POST", pattern_Auth_Logout_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/pb.Auth/Logout", runtime.WithHTTPPathPattern("/api/auth/logout"))
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/pb.Auth/Logout", runtime.WithHTTPPathPattern("/api/auth/logout"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -262,13 +280,18 @@ func RegisterAuthHandlerClient(ctx context.Context, mux *runtime.ServeMux, clien
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Auth_Logout_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle(http.MethodGet, pattern_Auth_GetUserInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("GET", pattern_Auth_GetUserInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/pb.Auth/GetUserInfo", runtime.WithHTTPPathPattern("/api/auth/userinfo"))
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/pb.Auth/GetUserInfo", runtime.WithHTTPPathPattern("/api/auth/userinfo"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
@@ -279,19 +302,26 @@ func RegisterAuthHandlerClient(ctx context.Context, mux *runtime.ServeMux, clien
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Auth_GetUserInfo_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Auth_Login_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "auth", "login"}, ""))
pattern_Auth_Logout_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "auth", "logout"}, ""))
pattern_Auth_GetUserInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "auth", "userinfo"}, ""))
)
var (
forward_Auth_Login_0 = runtime.ForwardResponseMessage
forward_Auth_Logout_0 = runtime.ForwardResponseMessage
forward_Auth_GetUserInfo_0 = runtime.ForwardResponseMessage
)

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.31.1
// - protoc v5.29.3
// source: auth.proto
package pb

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v6.31.1
// protoc v5.29.3
// source: global.proto
package pb

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.31.1
// - protoc v5.29.3
// source: global.proto
package pb

80
plugin/ffmpeg/README.md Normal file
View File

@@ -0,0 +1,80 @@
# FFmpeg 插件
FFmpeg 插件用于在 Monibuca 中创建和管理 FFmpeg 进程。该插件提供 gRPC 接口,允许用户创建、更新、查询、重启和关闭 FFmpeg 进程。所有 FFmpeg 进程配置将存储在数据库中,以便反复使用。
## 功能特性
- 创建 FFmpeg 进程配置并持久化存储
- 更新现有 FFmpeg 进程配置
- 查询 FFmpeg 进程(包括运行中和未运行的)
- 启动/重启 FFmpeg 进程
- 停止 FFmpeg 进程
- 在 task 框架中运行 FFmpeg 进程
## API 接口
### 创建 FFmpeg 进程
```
POST /ffmpeg/api/process
```
### 更新 FFmpeg 进程
```
PUT /ffmpeg/api/process/{id}
```
### 删除 FFmpeg 进程
```
DELETE /ffmpeg/api/process/{id}
```
### 获取 FFmpeg 进程列表
```
GET /ffmpeg/api/processes
```
### 获取单个 FFmpeg 进程详情
```
GET /ffmpeg/api/process/{id}
```
### 启动 FFmpeg 进程
```
POST /ffmpeg/api/process/{id}/start
```
### 停止 FFmpeg 进程
```
POST /ffmpeg/api/process/{id}/stop
```
### 重启 FFmpeg 进程
```
POST /ffmpeg/api/process/{id}/restart
```
## 配置选项
```yaml
ffmpeg:
# 数据库配置
db:
dsn: "ffmpeg.db"
dbtype: "sqlite"
# 默认 FFmpeg 路径
ffmpegPath: "ffmpeg"
# 进程管理配置
maxProcesses: 100
autoRestart: true
restartInterval: 5s
```

213
plugin/ffmpeg/api.go Normal file
View File

@@ -0,0 +1,213 @@
package ffmpeg
import (
"context"
task "github.com/langhuihui/gotask"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
globalPb "m7s.live/v5/pb"
"m7s.live/v5/pkg"
"m7s.live/v5/plugin/ffmpeg/pb"
)
// CreateProcess 创建 FFmpeg 进程
func (p *FFmpegPlugin) CreateProcess(ctx context.Context, req *pb.CreateProcessRequest) (*pb.ProcessResponse, error) {
process := &FFmpegProcess{
Description: req.Description,
Arguments: req.Arguments,
AutoStart: req.AutoStart,
Status: "stopped",
}
// 保存到数据库
if err := p.DB.Create(process).Error; err != nil {
return nil, status.Errorf(codes.Internal, "Failed to create process: %v", err)
}
// 如果设置了自动启动,则启动进程
if process.AutoStart {
p.startProcess(process)
}
return &pb.ProcessResponse{
Code: 0,
Message: "success",
Data: &pb.FFmpegProcess{
Id: uint32(process.ID),
Description: process.Description,
Arguments: process.Arguments,
Status: process.Status,
Pid: int32(process.PID),
AutoStart: process.AutoStart,
CreatedAt: timestamppb.New(process.CreatedAt),
UpdatedAt: timestamppb.New(process.UpdatedAt),
},
}, nil
}
// UpdateProcess 更新 FFmpeg 进程
func (p *FFmpegPlugin) UpdateProcess(ctx context.Context, req *pb.UpdateProcessRequest) (*pb.ProcessResponse, error) {
process := &FFmpegProcess{}
if err := p.DB.First(process, req.Id).Error; err != nil {
return nil, status.Errorf(codes.NotFound, "Process not found: %v", err)
}
process.Description = req.Description
process.Arguments = req.Arguments
process.AutoStart = req.AutoStart
// 更新数据库
if err := p.DB.Save(process).Error; err != nil {
return nil, status.Errorf(codes.Internal, "Failed to update process: %v", err)
}
return &pb.ProcessResponse{
Code: 0,
Message: "success",
Data: &pb.FFmpegProcess{
Id: uint32(process.ID),
Description: process.Description,
Arguments: process.Arguments,
Status: process.Status,
Pid: int32(process.PID),
AutoStart: process.AutoStart,
CreatedAt: timestamppb.New(process.CreatedAt),
UpdatedAt: timestamppb.New(process.UpdatedAt),
},
}, nil
}
// DeleteProcess 删除 FFmpeg 进程
func (p *FFmpegPlugin) DeleteProcess(ctx context.Context, req *pb.ProcessIdRequest) (*globalPb.SuccessResponse, error) {
process := &FFmpegProcess{}
if err := p.DB.First(process, req.Id).Error; err != nil {
return nil, status.Errorf(codes.NotFound, "Process not found: %v", err)
}
if process, exists := p.processes.Get(uint(req.Id)); exists {
process.Stop(task.ErrStopByUser)
process.WaitStopped()
}
if err := p.DB.Delete(process).Error; err != nil {
return nil, status.Errorf(codes.Internal, "Failed to delete process: %v", err)
}
return &globalPb.SuccessResponse{
Code: 0,
Message: "success",
}, nil
}
// ListProcesses 获取 FFmpeg 进程列表
func (p *FFmpegPlugin) ListProcesses(ctx context.Context, req *emptypb.Empty) (*pb.ListProcessesResponse, error) {
var processes []FFmpegProcess
query := p.DB.Model(&FFmpegProcess{})
if err := query.Find(&processes).Error; err != nil {
return nil, status.Errorf(codes.Internal, "Failed to list processes: %v", err)
}
data := make([]*pb.FFmpegProcess, len(processes))
for i, process := range processes {
runtimeProcess, ok := p.processes.Get(process.ID)
if ok {
process = *runtimeProcess.process
}
data[i] = &pb.FFmpegProcess{
Id: uint32(process.ID),
Description: process.Description,
Arguments: process.Arguments,
AutoStart: process.AutoStart,
Status: process.Status,
Pid: int32(process.PID),
CreatedAt: timestamppb.New(process.CreatedAt),
UpdatedAt: timestamppb.New(process.UpdatedAt),
}
}
return &pb.ListProcessesResponse{
Code: 0,
Message: "success",
Data: data,
}, nil
}
// StartProcess 启动 FFmpeg 进程
func (p *FFmpegPlugin) StartProcess(ctx context.Context, req *pb.ProcessIdRequest) (*globalPb.SuccessResponse, error) {
process := &FFmpegProcess{}
if err := p.DB.First(process, req.Id).Error; err != nil {
return nil, status.Errorf(codes.NotFound, "Process not found: %v", err)
}
// 启动进程
if err := p.startProcess(process); err != nil {
return nil, status.Errorf(codes.Internal, "Failed to start process: %v", err)
}
return &globalPb.SuccessResponse{
Code: 0,
Message: "success",
}, nil
}
// StopProcess 停止 FFmpeg 进程
func (p *FFmpegPlugin) StopProcess(ctx context.Context, req *pb.ProcessIdRequest) (*globalPb.SuccessResponse, error) {
// 停止进程
if process, exists := p.processes.Get(uint(req.Id)); exists {
process.Stop(task.ErrStopByUser)
process.WaitStopped()
} else {
return nil, pkg.ErrNotFound
}
return &globalPb.SuccessResponse{
Code: 0,
Message: "success",
}, nil
}
// RestartProcess 重启 FFmpeg 进程
func (p *FFmpegPlugin) RestartProcess(ctx context.Context, req *pb.ProcessIdRequest) (*globalPb.SuccessResponse, error) {
process := &FFmpegProcess{}
if err := p.DB.First(process, req.Id).Error; err != nil {
return nil, status.Errorf(codes.NotFound, "Process not found: %v", err)
}
// 如果进程正在运行,先停止它
if task, exists := p.processes.Get(uint(req.Id)); exists {
task.Stop(pkg.ErrRestart)
task.WaitStopped()
}
err := p.startProcess(process).WaitStarted()
if err != nil {
return nil, err
}
return &globalPb.SuccessResponse{
Code: 0,
Message: "success",
}, nil
}
// GetVersion 获取 FFmpeg 版本信息
func (p *FFmpegPlugin) GetVersion(ctx context.Context, req *emptypb.Empty) (*pb.VersionResponse, error) {
version, _, err := getFFmpegVersion()
if err != nil {
return &pb.VersionResponse{
Code: 1,
Message: "Failed to get FFmpeg version: " + err.Error(),
}, nil
}
return &pb.VersionResponse{
Code: 0,
Message: "success",
Data: version,
}, nil
}
// startProcess 启动进程的内部方法
func (p *FFmpegPlugin) startProcess(process *FFmpegProcess) *task.Task {
return p.AddTask(NewFFmpegTask(process))
}

41
plugin/ffmpeg/index.go Normal file
View File

@@ -0,0 +1,41 @@
package ffmpeg
import (
task "github.com/langhuihui/gotask"
"m7s.live/v5"
"m7s.live/v5/plugin/ffmpeg/pb"
)
var _ = m7s.InstallPlugin[FFmpegPlugin](m7s.PluginMeta{
ServiceDesc: &pb.Api_ServiceDesc,
RegisterGRPCHandler: pb.RegisterApiHandler,
})
var _ pb.ApiServer = (*FFmpegPlugin)(nil)
type FFmpegPlugin struct {
pb.UnimplementedApiServer
m7s.Plugin
processes task.WorkCollection[uint, *FFmpegTask]
}
func (p *FFmpegPlugin) Start() error {
if p.DB != nil {
// 注册数据模型
p.DB.AutoMigrate(&FFmpegProcess{})
// 启动时加载自动启动的进程
var processes []*FFmpegProcess
p.DB.Where("auto_start = ?", true).Find(&processes)
for _, process := range processes {
p.startProcess(process)
}
}
version, _, err := getFFmpegVersion()
if err != nil {
return err
}
p.Info("Found FFmpeg", "version", version)
return nil
}

19
plugin/ffmpeg/model.go Normal file
View File

@@ -0,0 +1,19 @@
package ffmpeg
import (
"gorm.io/gorm"
)
type FFmpegProcess struct {
Arguments string // 参数
gorm.Model
Description string // 描述
Status string `gorm:"-"` // 状态: stopped, running, error
PID int `gorm:"-"` // 进程 ID
AutoStart bool `gorm:"default:false"` // 是否自动启动
}
// TableName 设置表名
func (FFmpegProcess) TableName() string {
return "ffmpeg_processes"
}

View File

@@ -0,0 +1,603 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc v5.29.3
// source: ffmpeg.proto
package pb
import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
pb "m7s.live/v5/pb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type FFmpegProcess struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
Arguments string `protobuf:"bytes,3,opt,name=arguments,proto3" json:"arguments,omitempty"`
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
Pid int32 `protobuf:"varint,5,opt,name=pid,proto3" json:"pid,omitempty"`
AutoStart bool `protobuf:"varint,6,opt,name=autoStart,proto3" json:"autoStart,omitempty"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=createdAt,proto3" json:"createdAt,omitempty"`
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=updatedAt,proto3" json:"updatedAt,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FFmpegProcess) Reset() {
*x = FFmpegProcess{}
mi := &file_ffmpeg_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FFmpegProcess) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FFmpegProcess) ProtoMessage() {}
func (x *FFmpegProcess) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use FFmpegProcess.ProtoReflect.Descriptor instead.
func (*FFmpegProcess) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{0}
}
func (x *FFmpegProcess) GetId() uint32 {
if x != nil {
return x.Id
}
return 0
}
func (x *FFmpegProcess) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *FFmpegProcess) GetArguments() string {
if x != nil {
return x.Arguments
}
return ""
}
func (x *FFmpegProcess) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
func (x *FFmpegProcess) GetPid() int32 {
if x != nil {
return x.Pid
}
return 0
}
func (x *FFmpegProcess) GetAutoStart() bool {
if x != nil {
return x.AutoStart
}
return false
}
func (x *FFmpegProcess) GetCreatedAt() *timestamppb.Timestamp {
if x != nil {
return x.CreatedAt
}
return nil
}
func (x *FFmpegProcess) GetUpdatedAt() *timestamppb.Timestamp {
if x != nil {
return x.UpdatedAt
}
return nil
}
type CreateProcessRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
Arguments string `protobuf:"bytes,2,opt,name=arguments,proto3" json:"arguments,omitempty"`
AutoStart bool `protobuf:"varint,3,opt,name=autoStart,proto3" json:"autoStart,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CreateProcessRequest) Reset() {
*x = CreateProcessRequest{}
mi := &file_ffmpeg_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CreateProcessRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateProcessRequest) ProtoMessage() {}
func (x *CreateProcessRequest) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreateProcessRequest.ProtoReflect.Descriptor instead.
func (*CreateProcessRequest) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{1}
}
func (x *CreateProcessRequest) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *CreateProcessRequest) GetArguments() string {
if x != nil {
return x.Arguments
}
return ""
}
func (x *CreateProcessRequest) GetAutoStart() bool {
if x != nil {
return x.AutoStart
}
return false
}
type UpdateProcessRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
Arguments string `protobuf:"bytes,3,opt,name=arguments,proto3" json:"arguments,omitempty"`
AutoStart bool `protobuf:"varint,4,opt,name=autoStart,proto3" json:"autoStart,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *UpdateProcessRequest) Reset() {
*x = UpdateProcessRequest{}
mi := &file_ffmpeg_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UpdateProcessRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UpdateProcessRequest) ProtoMessage() {}
func (x *UpdateProcessRequest) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UpdateProcessRequest.ProtoReflect.Descriptor instead.
func (*UpdateProcessRequest) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{2}
}
func (x *UpdateProcessRequest) GetId() uint32 {
if x != nil {
return x.Id
}
return 0
}
func (x *UpdateProcessRequest) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *UpdateProcessRequest) GetArguments() string {
if x != nil {
return x.Arguments
}
return ""
}
func (x *UpdateProcessRequest) GetAutoStart() bool {
if x != nil {
return x.AutoStart
}
return false
}
type ProcessIdRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProcessIdRequest) Reset() {
*x = ProcessIdRequest{}
mi := &file_ffmpeg_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProcessIdRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProcessIdRequest) ProtoMessage() {}
func (x *ProcessIdRequest) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProcessIdRequest.ProtoReflect.Descriptor instead.
func (*ProcessIdRequest) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{3}
}
func (x *ProcessIdRequest) GetId() uint32 {
if x != nil {
return x.Id
}
return 0
}
type ProcessResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Data *FFmpegProcess `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProcessResponse) Reset() {
*x = ProcessResponse{}
mi := &file_ffmpeg_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProcessResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProcessResponse) ProtoMessage() {}
func (x *ProcessResponse) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProcessResponse.ProtoReflect.Descriptor instead.
func (*ProcessResponse) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{4}
}
func (x *ProcessResponse) GetCode() uint32 {
if x != nil {
return x.Code
}
return 0
}
func (x *ProcessResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *ProcessResponse) GetData() *FFmpegProcess {
if x != nil {
return x.Data
}
return nil
}
type ListProcessesResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Data []*FFmpegProcess `protobuf:"bytes,3,rep,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListProcessesResponse) Reset() {
*x = ListProcessesResponse{}
mi := &file_ffmpeg_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListProcessesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListProcessesResponse) ProtoMessage() {}
func (x *ListProcessesResponse) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListProcessesResponse.ProtoReflect.Descriptor instead.
func (*ListProcessesResponse) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{5}
}
func (x *ListProcessesResponse) GetCode() uint32 {
if x != nil {
return x.Code
}
return 0
}
func (x *ListProcessesResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *ListProcessesResponse) GetData() []*FFmpegProcess {
if x != nil {
return x.Data
}
return nil
}
type VersionResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VersionResponse) Reset() {
*x = VersionResponse{}
mi := &file_ffmpeg_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VersionResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VersionResponse) ProtoMessage() {}
func (x *VersionResponse) ProtoReflect() protoreflect.Message {
mi := &file_ffmpeg_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead.
func (*VersionResponse) Descriptor() ([]byte, []int) {
return file_ffmpeg_proto_rawDescGZIP(), []int{6}
}
func (x *VersionResponse) GetCode() uint32 {
if x != nil {
return x.Code
}
return 0
}
func (x *VersionResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *VersionResponse) GetData() string {
if x != nil {
return x.Data
}
return ""
}
var File_ffmpeg_proto protoreflect.FileDescriptor
const file_ffmpeg_proto_rawDesc = "" +
"\n" +
"\fffmpeg.proto\x12\x06ffmpeg\x1a\x1cgoogle/api/annotations.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\fglobal.proto\"\x9b\x02\n" +
"\rFFmpegProcess\x12\x0e\n" +
"\x02id\x18\x01 \x01(\rR\x02id\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription\x12\x1c\n" +
"\targuments\x18\x03 \x01(\tR\targuments\x12\x16\n" +
"\x06status\x18\x04 \x01(\tR\x06status\x12\x10\n" +
"\x03pid\x18\x05 \x01(\x05R\x03pid\x12\x1c\n" +
"\tautoStart\x18\x06 \x01(\bR\tautoStart\x128\n" +
"\tcreatedAt\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x128\n" +
"\tupdatedAt\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\tupdatedAt\"t\n" +
"\x14CreateProcessRequest\x12 \n" +
"\vdescription\x18\x01 \x01(\tR\vdescription\x12\x1c\n" +
"\targuments\x18\x02 \x01(\tR\targuments\x12\x1c\n" +
"\tautoStart\x18\x03 \x01(\bR\tautoStart\"\x84\x01\n" +
"\x14UpdateProcessRequest\x12\x0e\n" +
"\x02id\x18\x01 \x01(\rR\x02id\x12 \n" +
"\vdescription\x18\x02 \x01(\tR\vdescription\x12\x1c\n" +
"\targuments\x18\x03 \x01(\tR\targuments\x12\x1c\n" +
"\tautoStart\x18\x04 \x01(\bR\tautoStart\"\"\n" +
"\x10ProcessIdRequest\x12\x0e\n" +
"\x02id\x18\x01 \x01(\rR\x02id\"j\n" +
"\x0fProcessResponse\x12\x12\n" +
"\x04code\x18\x01 \x01(\rR\x04code\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessage\x12)\n" +
"\x04data\x18\x03 \x01(\v2\x15.ffmpeg.FFmpegProcessR\x04data\"p\n" +
"\x15ListProcessesResponse\x12\x12\n" +
"\x04code\x18\x01 \x01(\rR\x04code\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessage\x12)\n" +
"\x04data\x18\x03 \x03(\v2\x15.ffmpeg.FFmpegProcessR\x04data\"S\n" +
"\x0fVersionResponse\x12\x12\n" +
"\x04code\x18\x01 \x01(\rR\x04code\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessage\x12\x12\n" +
"\x04data\x18\x03 \x01(\tR\x04data2\xa6\x06\n" +
"\x03api\x12e\n" +
"\rCreateProcess\x12\x1c.ffmpeg.CreateProcessRequest\x1a\x17.ffmpeg.ProcessResponse\"\x1d\x82\xd3\xe4\x93\x02\x17:\x01*\"\x12/ffmpeg/api/create\x12j\n" +
"\rUpdateProcess\x12\x1c.ffmpeg.UpdateProcessRequest\x1a\x17.ffmpeg.ProcessResponse\"\"\x82\xd3\xe4\x93\x02\x1c:\x01*\"\x17/ffmpeg/api/update/{id}\x12c\n" +
"\rDeleteProcess\x12\x18.ffmpeg.ProcessIdRequest\x1a\x17.global.SuccessResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\"\x17/ffmpeg/api/delete/{id}\x12`\n" +
"\rListProcesses\x12\x16.google.protobuf.Empty\x1a\x1d.ffmpeg.ListProcessesResponse\"\x18\x82\xd3\xe4\x93\x02\x12\x12\x10/ffmpeg/api/list\x12a\n" +
"\fStartProcess\x12\x18.ffmpeg.ProcessIdRequest\x1a\x17.global.SuccessResponse\"\x1e\x82\xd3\xe4\x93\x02\x18\"\x16/ffmpeg/api/start/{id}\x12_\n" +
"\vStopProcess\x12\x18.ffmpeg.ProcessIdRequest\x1a\x17.global.SuccessResponse\"\x1d\x82\xd3\xe4\x93\x02\x17\"\x15/ffmpeg/api/stop/{id}\x12e\n" +
"\x0eRestartProcess\x12\x18.ffmpeg.ProcessIdRequest\x1a\x17.global.SuccessResponse\" \x82\xd3\xe4\x93\x02\x1a\"\x18/ffmpeg/api/restart/{id}\x12Z\n" +
"\n" +
"GetVersion\x12\x16.google.protobuf.Empty\x1a\x17.ffmpeg.VersionResponse\"\x1b\x82\xd3\xe4\x93\x02\x15\x12\x13/ffmpeg/api/versionB\x1eZ\x1cm7s.live/v5/plugin/ffmpeg/pbb\x06proto3"
var (
file_ffmpeg_proto_rawDescOnce sync.Once
file_ffmpeg_proto_rawDescData []byte
)
func file_ffmpeg_proto_rawDescGZIP() []byte {
file_ffmpeg_proto_rawDescOnce.Do(func() {
file_ffmpeg_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ffmpeg_proto_rawDesc), len(file_ffmpeg_proto_rawDesc)))
})
return file_ffmpeg_proto_rawDescData
}
var file_ffmpeg_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
var file_ffmpeg_proto_goTypes = []any{
(*FFmpegProcess)(nil), // 0: ffmpeg.FFmpegProcess
(*CreateProcessRequest)(nil), // 1: ffmpeg.CreateProcessRequest
(*UpdateProcessRequest)(nil), // 2: ffmpeg.UpdateProcessRequest
(*ProcessIdRequest)(nil), // 3: ffmpeg.ProcessIdRequest
(*ProcessResponse)(nil), // 4: ffmpeg.ProcessResponse
(*ListProcessesResponse)(nil), // 5: ffmpeg.ListProcessesResponse
(*VersionResponse)(nil), // 6: ffmpeg.VersionResponse
(*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp
(*emptypb.Empty)(nil), // 8: google.protobuf.Empty
(*pb.SuccessResponse)(nil), // 9: global.SuccessResponse
}
var file_ffmpeg_proto_depIdxs = []int32{
7, // 0: ffmpeg.FFmpegProcess.createdAt:type_name -> google.protobuf.Timestamp
7, // 1: ffmpeg.FFmpegProcess.updatedAt:type_name -> google.protobuf.Timestamp
0, // 2: ffmpeg.ProcessResponse.data:type_name -> ffmpeg.FFmpegProcess
0, // 3: ffmpeg.ListProcessesResponse.data:type_name -> ffmpeg.FFmpegProcess
1, // 4: ffmpeg.api.CreateProcess:input_type -> ffmpeg.CreateProcessRequest
2, // 5: ffmpeg.api.UpdateProcess:input_type -> ffmpeg.UpdateProcessRequest
3, // 6: ffmpeg.api.DeleteProcess:input_type -> ffmpeg.ProcessIdRequest
8, // 7: ffmpeg.api.ListProcesses:input_type -> google.protobuf.Empty
3, // 8: ffmpeg.api.StartProcess:input_type -> ffmpeg.ProcessIdRequest
3, // 9: ffmpeg.api.StopProcess:input_type -> ffmpeg.ProcessIdRequest
3, // 10: ffmpeg.api.RestartProcess:input_type -> ffmpeg.ProcessIdRequest
8, // 11: ffmpeg.api.GetVersion:input_type -> google.protobuf.Empty
4, // 12: ffmpeg.api.CreateProcess:output_type -> ffmpeg.ProcessResponse
4, // 13: ffmpeg.api.UpdateProcess:output_type -> ffmpeg.ProcessResponse
9, // 14: ffmpeg.api.DeleteProcess:output_type -> global.SuccessResponse
5, // 15: ffmpeg.api.ListProcesses:output_type -> ffmpeg.ListProcessesResponse
9, // 16: ffmpeg.api.StartProcess:output_type -> global.SuccessResponse
9, // 17: ffmpeg.api.StopProcess:output_type -> global.SuccessResponse
9, // 18: ffmpeg.api.RestartProcess:output_type -> global.SuccessResponse
6, // 19: ffmpeg.api.GetVersion:output_type -> ffmpeg.VersionResponse
12, // [12:20] is the sub-list for method output_type
4, // [4:12] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_ffmpeg_proto_init() }
func file_ffmpeg_proto_init() {
if File_ffmpeg_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ffmpeg_proto_rawDesc), len(file_ffmpeg_proto_rawDesc)),
NumEnums: 0,
NumMessages: 7,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_ffmpeg_proto_goTypes,
DependencyIndexes: file_ffmpeg_proto_depIdxs,
MessageInfos: file_ffmpeg_proto_msgTypes,
}.Build()
File_ffmpeg_proto = out.File
file_ffmpeg_proto_goTypes = nil
file_ffmpeg_proto_depIdxs = nil
}

View File

@@ -0,0 +1,825 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: ffmpeg.proto
/*
Package pb is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package pb
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/emptypb"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
func request_Api_CreateProcess_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CreateProcessRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.CreateProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_CreateProcess_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq CreateProcessRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.CreateProcess(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_UpdateProcess_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UpdateProcessRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.UpdateProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_UpdateProcess_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UpdateProcessRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.UpdateProcess(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_DeleteProcess_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.DeleteProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_DeleteProcess_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.DeleteProcess(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_ListProcesses_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := client.ListProcesses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_ListProcesses_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := server.ListProcesses(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_StartProcess_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.StartProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_StartProcess_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.StartProcess(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_StopProcess_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.StopProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_StopProcess_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.StopProcess(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_RestartProcess_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.RestartProcess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_RestartProcess_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProcessIdRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := server.RestartProcess(ctx, &protoReq)
return msg, metadata, err
}
func request_Api_GetVersion_0(ctx context.Context, marshaler runtime.Marshaler, client ApiClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := client.GetVersion(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Api_GetVersion_0(ctx context.Context, marshaler runtime.Marshaler, server ApiServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq emptypb.Empty
var metadata runtime.ServerMetadata
msg, err := server.GetVersion(ctx, &protoReq)
return msg, metadata, err
}
// RegisterApiHandlerServer registers the http handlers for service Api to "mux".
// UnaryRPC :call ApiServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterApiHandlerFromEndpoint instead.
func RegisterApiHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ApiServer) error {
mux.Handle("POST", pattern_Api_CreateProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/CreateProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/create"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_CreateProcess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_CreateProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_UpdateProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/UpdateProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/update/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_UpdateProcess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_UpdateProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_DeleteProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/DeleteProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/delete/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_DeleteProcess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_DeleteProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Api_ListProcesses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/ListProcesses", runtime.WithHTTPPathPattern("/ffmpeg/api/list"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_ListProcesses_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_ListProcesses_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_StartProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/StartProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/start/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_StartProcess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_StartProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_StopProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/StopProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/stop/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_StopProcess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_StopProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_RestartProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/RestartProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/restart/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_RestartProcess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_RestartProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Api_GetVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/ffmpeg.Api/GetVersion", runtime.WithHTTPPathPattern("/ffmpeg/api/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Api_GetVersion_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_GetVersion_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterApiHandlerFromEndpoint is same as RegisterApiHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterApiHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.DialContext(ctx, endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterApiHandler(ctx, mux, conn)
}
// RegisterApiHandler registers the http handlers for service Api to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterApiHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterApiHandlerClient(ctx, mux, NewApiClient(conn))
}
// RegisterApiHandlerClient registers the http handlers for service Api
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ApiClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ApiClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "ApiClient" to call the correct interceptors.
func RegisterApiHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ApiClient) error {
mux.Handle("POST", pattern_Api_CreateProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/CreateProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/create"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_CreateProcess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_CreateProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_UpdateProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/UpdateProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/update/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_UpdateProcess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_UpdateProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_DeleteProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/DeleteProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/delete/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_DeleteProcess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_DeleteProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Api_ListProcesses_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/ListProcesses", runtime.WithHTTPPathPattern("/ffmpeg/api/list"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_ListProcesses_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_ListProcesses_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_StartProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/StartProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/start/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_StartProcess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_StartProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_StopProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/StopProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/stop/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_StopProcess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_StopProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Api_RestartProcess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/RestartProcess", runtime.WithHTTPPathPattern("/ffmpeg/api/restart/{id}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_RestartProcess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_RestartProcess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Api_GetVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/ffmpeg.Api/GetVersion", runtime.WithHTTPPathPattern("/ffmpeg/api/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Api_GetVersion_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Api_GetVersion_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Api_CreateProcess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ffmpeg", "api", "create"}, ""))
pattern_Api_UpdateProcess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ffmpeg", "api", "update", "id"}, ""))
pattern_Api_DeleteProcess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ffmpeg", "api", "delete", "id"}, ""))
pattern_Api_ListProcesses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ffmpeg", "api", "list"}, ""))
pattern_Api_StartProcess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ffmpeg", "api", "start", "id"}, ""))
pattern_Api_StopProcess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ffmpeg", "api", "stop", "id"}, ""))
pattern_Api_RestartProcess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"ffmpeg", "api", "restart", "id"}, ""))
pattern_Api_GetVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"ffmpeg", "api", "version"}, ""))
)
var (
forward_Api_CreateProcess_0 = runtime.ForwardResponseMessage
forward_Api_UpdateProcess_0 = runtime.ForwardResponseMessage
forward_Api_DeleteProcess_0 = runtime.ForwardResponseMessage
forward_Api_ListProcesses_0 = runtime.ForwardResponseMessage
forward_Api_StartProcess_0 = runtime.ForwardResponseMessage
forward_Api_StopProcess_0 = runtime.ForwardResponseMessage
forward_Api_RestartProcess_0 = runtime.ForwardResponseMessage
forward_Api_GetVersion_0 = runtime.ForwardResponseMessage
)

View File

@@ -0,0 +1,114 @@
syntax = "proto3";
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
import "global.proto";
package ffmpeg;
option go_package="m7s.live/v5/plugin/ffmpeg/pb";
service api {
// 创建 FFmpeg 进程
rpc CreateProcess (CreateProcessRequest) returns (ProcessResponse) {
option (google.api.http) = {
post: "/ffmpeg/api/create"
body: "*"
};
}
// 更新 FFmpeg 进程
rpc UpdateProcess (UpdateProcessRequest) returns (ProcessResponse) {
option (google.api.http) = {
post: "/ffmpeg/api/update/{id}"
body: "*"
};
}
// 删除 FFmpeg 进程
rpc DeleteProcess (ProcessIdRequest) returns (global.SuccessResponse) {
option (google.api.http) = {
post: "/ffmpeg/api/delete/{id}"
};
}
// 获取 FFmpeg 进程列表
rpc ListProcesses (google.protobuf.Empty) returns (ListProcessesResponse) {
option (google.api.http) = {
get: "/ffmpeg/api/list"
};
}
// 启动 FFmpeg 进程
rpc StartProcess (ProcessIdRequest) returns (global.SuccessResponse) {
option (google.api.http) = {
post: "/ffmpeg/api/start/{id}"
};
}
// 停止 FFmpeg 进程
rpc StopProcess (ProcessIdRequest) returns (global.SuccessResponse) {
option (google.api.http) = {
post: "/ffmpeg/api/stop/{id}"
};
}
// 重启 FFmpeg 进程
rpc RestartProcess (ProcessIdRequest) returns (global.SuccessResponse) {
option (google.api.http) = {
post: "/ffmpeg/api/restart/{id}"
};
}
// 检查 FFmpeg 版本
rpc GetVersion (google.protobuf.Empty) returns (VersionResponse) {
option (google.api.http) = {
get: "/ffmpeg/api/version"
};
}
}
message FFmpegProcess {
uint32 id = 1;
string description = 2;
string arguments = 3;
string status = 4;
int32 pid = 5;
bool autoStart = 6;
google.protobuf.Timestamp createdAt = 7;
google.protobuf.Timestamp updatedAt = 8;
}
message CreateProcessRequest {
string description = 1;
string arguments = 2;
bool autoStart = 3;
}
message UpdateProcessRequest {
uint32 id = 1;
string description = 2;
string arguments = 3;
bool autoStart = 4;
}
message ProcessIdRequest {
uint32 id = 1;
}
message ProcessResponse {
uint32 code = 1;
string message = 2;
FFmpegProcess data = 3;
}
message ListProcessesResponse {
uint32 code = 1;
string message = 2;
repeated FFmpegProcess data = 3;
}
message VersionResponse {
uint32 code = 1;
string message = 2;
string data = 3;
}

View File

@@ -0,0 +1,405 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v5.29.3
// source: ffmpeg.proto
package pb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
pb "m7s.live/v5/pb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Api_CreateProcess_FullMethodName = "/ffmpeg.api/CreateProcess"
Api_UpdateProcess_FullMethodName = "/ffmpeg.api/UpdateProcess"
Api_DeleteProcess_FullMethodName = "/ffmpeg.api/DeleteProcess"
Api_ListProcesses_FullMethodName = "/ffmpeg.api/ListProcesses"
Api_StartProcess_FullMethodName = "/ffmpeg.api/StartProcess"
Api_StopProcess_FullMethodName = "/ffmpeg.api/StopProcess"
Api_RestartProcess_FullMethodName = "/ffmpeg.api/RestartProcess"
Api_GetVersion_FullMethodName = "/ffmpeg.api/GetVersion"
)
// ApiClient is the client API for Api service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ApiClient interface {
// 创建 FFmpeg 进程
CreateProcess(ctx context.Context, in *CreateProcessRequest, opts ...grpc.CallOption) (*ProcessResponse, error)
// 更新 FFmpeg 进程
UpdateProcess(ctx context.Context, in *UpdateProcessRequest, opts ...grpc.CallOption) (*ProcessResponse, error)
// 删除 FFmpeg 进程
DeleteProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error)
// 获取 FFmpeg 进程列表
ListProcesses(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListProcessesResponse, error)
// 启动 FFmpeg 进程
StartProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error)
// 停止 FFmpeg 进程
StopProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error)
// 重启 FFmpeg 进程
RestartProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error)
// 检查 FFmpeg 版本
GetVersion(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error)
}
type apiClient struct {
cc grpc.ClientConnInterface
}
func NewApiClient(cc grpc.ClientConnInterface) ApiClient {
return &apiClient{cc}
}
func (c *apiClient) CreateProcess(ctx context.Context, in *CreateProcessRequest, opts ...grpc.CallOption) (*ProcessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ProcessResponse)
err := c.cc.Invoke(ctx, Api_CreateProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) UpdateProcess(ctx context.Context, in *UpdateProcessRequest, opts ...grpc.CallOption) (*ProcessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ProcessResponse)
err := c.cc.Invoke(ctx, Api_UpdateProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) DeleteProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(pb.SuccessResponse)
err := c.cc.Invoke(ctx, Api_DeleteProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) ListProcesses(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ListProcessesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListProcessesResponse)
err := c.cc.Invoke(ctx, Api_ListProcesses_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) StartProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(pb.SuccessResponse)
err := c.cc.Invoke(ctx, Api_StartProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) StopProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(pb.SuccessResponse)
err := c.cc.Invoke(ctx, Api_StopProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) RestartProcess(ctx context.Context, in *ProcessIdRequest, opts ...grpc.CallOption) (*pb.SuccessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(pb.SuccessResponse)
err := c.cc.Invoke(ctx, Api_RestartProcess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *apiClient) GetVersion(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*VersionResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(VersionResponse)
err := c.cc.Invoke(ctx, Api_GetVersion_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ApiServer is the server API for Api service.
// All implementations must embed UnimplementedApiServer
// for forward compatibility.
type ApiServer interface {
// 创建 FFmpeg 进程
CreateProcess(context.Context, *CreateProcessRequest) (*ProcessResponse, error)
// 更新 FFmpeg 进程
UpdateProcess(context.Context, *UpdateProcessRequest) (*ProcessResponse, error)
// 删除 FFmpeg 进程
DeleteProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error)
// 获取 FFmpeg 进程列表
ListProcesses(context.Context, *emptypb.Empty) (*ListProcessesResponse, error)
// 启动 FFmpeg 进程
StartProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error)
// 停止 FFmpeg 进程
StopProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error)
// 重启 FFmpeg 进程
RestartProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error)
// 检查 FFmpeg 版本
GetVersion(context.Context, *emptypb.Empty) (*VersionResponse, error)
mustEmbedUnimplementedApiServer()
}
// UnimplementedApiServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedApiServer struct{}
func (UnimplementedApiServer) CreateProcess(context.Context, *CreateProcessRequest) (*ProcessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateProcess not implemented")
}
func (UnimplementedApiServer) UpdateProcess(context.Context, *UpdateProcessRequest) (*ProcessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateProcess not implemented")
}
func (UnimplementedApiServer) DeleteProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteProcess not implemented")
}
func (UnimplementedApiServer) ListProcesses(context.Context, *emptypb.Empty) (*ListProcessesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListProcesses not implemented")
}
func (UnimplementedApiServer) StartProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StartProcess not implemented")
}
func (UnimplementedApiServer) StopProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method StopProcess not implemented")
}
func (UnimplementedApiServer) RestartProcess(context.Context, *ProcessIdRequest) (*pb.SuccessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RestartProcess not implemented")
}
func (UnimplementedApiServer) GetVersion(context.Context, *emptypb.Empty) (*VersionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented")
}
func (UnimplementedApiServer) mustEmbedUnimplementedApiServer() {}
func (UnimplementedApiServer) testEmbeddedByValue() {}
// UnsafeApiServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ApiServer will
// result in compilation errors.
type UnsafeApiServer interface {
mustEmbedUnimplementedApiServer()
}
func RegisterApiServer(s grpc.ServiceRegistrar, srv ApiServer) {
// If the following call pancis, it indicates UnimplementedApiServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Api_ServiceDesc, srv)
}
func _Api_CreateProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateProcessRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).CreateProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_CreateProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).CreateProcess(ctx, req.(*CreateProcessRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Api_UpdateProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateProcessRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).UpdateProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_UpdateProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).UpdateProcess(ctx, req.(*UpdateProcessRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Api_DeleteProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessIdRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).DeleteProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_DeleteProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).DeleteProcess(ctx, req.(*ProcessIdRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Api_ListProcesses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).ListProcesses(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_ListProcesses_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).ListProcesses(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _Api_StartProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessIdRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).StartProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_StartProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).StartProcess(ctx, req.(*ProcessIdRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Api_StopProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessIdRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).StopProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_StopProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).StopProcess(ctx, req.(*ProcessIdRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Api_RestartProcess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessIdRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).RestartProcess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_RestartProcess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).RestartProcess(ctx, req.(*ProcessIdRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Api_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApiServer).GetVersion(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Api_GetVersion_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApiServer).GetVersion(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
// Api_ServiceDesc is the grpc.ServiceDesc for Api service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Api_ServiceDesc = grpc.ServiceDesc{
ServiceName: "ffmpeg.api",
HandlerType: (*ApiServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateProcess",
Handler: _Api_CreateProcess_Handler,
},
{
MethodName: "UpdateProcess",
Handler: _Api_UpdateProcess_Handler,
},
{
MethodName: "DeleteProcess",
Handler: _Api_DeleteProcess_Handler,
},
{
MethodName: "ListProcesses",
Handler: _Api_ListProcesses_Handler,
},
{
MethodName: "StartProcess",
Handler: _Api_StartProcess_Handler,
},
{
MethodName: "StopProcess",
Handler: _Api_StopProcess_Handler,
},
{
MethodName: "RestartProcess",
Handler: _Api_RestartProcess_Handler,
},
{
MethodName: "GetVersion",
Handler: _Api_GetVersion_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "ffmpeg.proto",
}

106
plugin/ffmpeg/process.go Normal file
View File

@@ -0,0 +1,106 @@
package ffmpeg
import (
"fmt"
"os/exec"
"strings"
task "github.com/langhuihui/gotask"
)
type FFmpegTask struct {
task.Task
process *FFmpegProcess
cmd *exec.Cmd
}
func NewFFmpegTask(process *FFmpegProcess) *FFmpegTask {
t := &FFmpegTask{
process: process,
}
return t
}
func (t *FFmpegTask) GetKey() uint {
return t.process.ID
}
func (t *FFmpegTask) Start() error {
// 解析参数
args := []string{}
if t.process.Arguments != "" {
// 这里应该解析JSON格式的参数
// 为简化实现我们直接将Arguments作为参数传递
args = append(args, t.process.Arguments)
}
// 创建命令
t.cmd = exec.Command("ffmpeg", args...)
// 启动进程
err := t.cmd.Start()
if err != nil {
t.process.Status = "error"
return err
}
// 更新进程信息
t.process.PID = t.cmd.Process.Pid
t.process.Status = "running"
t.OnStop(t.cmd.Process.Kill)
return nil
}
func (t *FFmpegTask) Run() error {
if t.cmd == nil || t.cmd.Process == nil {
return fmt.Errorf("FFmpeg process not started")
}
// 等待进程结束
err := t.cmd.Wait()
if err != nil {
t.process.Status = "error"
return err
}
t.process.Status = "stopped"
return nil
}
// getFFmpegVersion 获取 FFmpeg 版本信息
func getFFmpegVersion() (version, buildInfo string, err error) {
// 执行 ffmpeg -version 命令
cmd := exec.Command("ffmpeg", "-version")
output, err := cmd.Output()
if err != nil {
return "", "", fmt.Errorf("failed to execute ffmpeg -version: %v", err)
}
outputStr := string(output)
lines := strings.Split(outputStr, "\n")
if len(lines) == 0 {
return "", "", fmt.Errorf("no output from ffmpeg -version")
}
// 第一行通常包含版本信息格式类似ffmpeg version 4.4.2
firstLine := strings.TrimSpace(lines[0])
// 提取版本号
parts := strings.Fields(firstLine)
var versionPart string
for i, part := range parts {
if part == "version" && i+1 < len(parts) {
versionPart = parts[i+1]
break
}
}
if versionPart == "" {
versionPart = firstLine
}
// 构建信息包含所有输出行
buildInfo = strings.TrimSpace(outputStr)
return versionPart, buildInfo, nil
}