Merge branch 'main' into feature/frontend-ci-build
This commit is contained in:
commit
fd34b32e77
|
@ -21,6 +21,52 @@ const (
|
|||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type AudioFormat int32
|
||||
|
||||
const (
|
||||
AudioFormat_WAV AudioFormat = 0
|
||||
AudioFormat_MP3 AudioFormat = 1
|
||||
)
|
||||
|
||||
// Enum value maps for AudioFormat.
|
||||
var (
|
||||
AudioFormat_name = map[int32]string{
|
||||
0: "WAV",
|
||||
1: "MP3",
|
||||
}
|
||||
AudioFormat_value = map[string]int32{
|
||||
"WAV": 0,
|
||||
"MP3": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x AudioFormat) Enum() *AudioFormat {
|
||||
p := new(AudioFormat)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x AudioFormat) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (AudioFormat) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_media_set_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (AudioFormat) Type() protoreflect.EnumType {
|
||||
return &file_media_set_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x AudioFormat) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AudioFormat.Descriptor instead.
|
||||
func (AudioFormat) EnumDescriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type MediaSet struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@ -431,6 +477,148 @@ func (x *GetPeaksForSegmentResponse) GetPeaks() []int32 {
|
|||
return nil
|
||||
}
|
||||
|
||||
type GetAudioSegmentRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
StartFrame int64 `protobuf:"varint,2,opt,name=start_frame,json=startFrame,proto3" json:"start_frame,omitempty"`
|
||||
EndFrame int64 `protobuf:"varint,3,opt,name=end_frame,json=endFrame,proto3" json:"end_frame,omitempty"`
|
||||
Format AudioFormat `protobuf:"varint,4,opt,name=format,proto3,enum=media_set.AudioFormat" json:"format,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentRequest) Reset() {
|
||||
*x = GetAudioSegmentRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_media_set_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetAudioSegmentRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetAudioSegmentRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_media_set_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetAudioSegmentRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetAudioSegmentRequest) Descriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentRequest) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentRequest) GetStartFrame() int64 {
|
||||
if x != nil {
|
||||
return x.StartFrame
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentRequest) GetEndFrame() int64 {
|
||||
if x != nil {
|
||||
return x.EndFrame
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentRequest) GetFormat() AudioFormat {
|
||||
if x != nil {
|
||||
return x.Format
|
||||
}
|
||||
return AudioFormat_WAV
|
||||
}
|
||||
|
||||
type GetAudioSegmentProgress struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
MimeType string `protobuf:"bytes,1,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"`
|
||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
||||
PercentComplete float32 `protobuf:"fixed32,3,opt,name=percent_complete,json=percentComplete,proto3" json:"percent_complete,omitempty"`
|
||||
AudioData []byte `protobuf:"bytes,4,opt,name=audio_data,json=audioData,proto3" json:"audio_data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentProgress) Reset() {
|
||||
*x = GetAudioSegmentProgress{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_media_set_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentProgress) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetAudioSegmentProgress) ProtoMessage() {}
|
||||
|
||||
func (x *GetAudioSegmentProgress) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_media_set_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetAudioSegmentProgress.ProtoReflect.Descriptor instead.
|
||||
func (*GetAudioSegmentProgress) Descriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentProgress) GetMimeType() string {
|
||||
if x != nil {
|
||||
return x.MimeType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentProgress) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentProgress) GetPercentComplete() float32 {
|
||||
if x != nil {
|
||||
return x.PercentComplete
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GetAudioSegmentProgress) GetAudioData() []byte {
|
||||
if x != nil {
|
||||
return x.AudioData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetVideoRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
|
@ -442,7 +630,7 @@ type GetVideoRequest struct {
|
|||
func (x *GetVideoRequest) Reset() {
|
||||
*x = GetVideoRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_media_set_proto_msgTypes[6]
|
||||
mi := &file_media_set_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
@ -455,7 +643,7 @@ func (x *GetVideoRequest) String() string {
|
|||
func (*GetVideoRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetVideoRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_media_set_proto_msgTypes[6]
|
||||
mi := &file_media_set_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
@ -468,7 +656,7 @@ func (x *GetVideoRequest) ProtoReflect() protoreflect.Message {
|
|||
|
||||
// Deprecated: Use GetVideoRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetVideoRequest) Descriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{6}
|
||||
return file_media_set_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *GetVideoRequest) GetId() string {
|
||||
|
@ -490,7 +678,7 @@ type GetVideoProgress struct {
|
|||
func (x *GetVideoProgress) Reset() {
|
||||
*x = GetVideoProgress{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_media_set_proto_msgTypes[7]
|
||||
mi := &file_media_set_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
@ -503,7 +691,7 @@ func (x *GetVideoProgress) String() string {
|
|||
func (*GetVideoProgress) ProtoMessage() {}
|
||||
|
||||
func (x *GetVideoProgress) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_media_set_proto_msgTypes[7]
|
||||
mi := &file_media_set_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
@ -516,7 +704,7 @@ func (x *GetVideoProgress) ProtoReflect() protoreflect.Message {
|
|||
|
||||
// Deprecated: Use GetVideoProgress.ProtoReflect.Descriptor instead.
|
||||
func (*GetVideoProgress) Descriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{7}
|
||||
return file_media_set_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *GetVideoProgress) GetPercentComplete() float32 {
|
||||
|
@ -544,7 +732,7 @@ type GetVideoThumbnailRequest struct {
|
|||
func (x *GetVideoThumbnailRequest) Reset() {
|
||||
*x = GetVideoThumbnailRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_media_set_proto_msgTypes[8]
|
||||
mi := &file_media_set_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
@ -557,7 +745,7 @@ func (x *GetVideoThumbnailRequest) String() string {
|
|||
func (*GetVideoThumbnailRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetVideoThumbnailRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_media_set_proto_msgTypes[8]
|
||||
mi := &file_media_set_proto_msgTypes[10]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
@ -570,7 +758,7 @@ func (x *GetVideoThumbnailRequest) ProtoReflect() protoreflect.Message {
|
|||
|
||||
// Deprecated: Use GetVideoThumbnailRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetVideoThumbnailRequest) Descriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{8}
|
||||
return file_media_set_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *GetVideoThumbnailRequest) GetId() string {
|
||||
|
@ -593,7 +781,7 @@ type GetVideoThumbnailResponse struct {
|
|||
func (x *GetVideoThumbnailResponse) Reset() {
|
||||
*x = GetVideoThumbnailResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_media_set_proto_msgTypes[9]
|
||||
mi := &file_media_set_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
@ -606,7 +794,7 @@ func (x *GetVideoThumbnailResponse) String() string {
|
|||
func (*GetVideoThumbnailResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetVideoThumbnailResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_media_set_proto_msgTypes[9]
|
||||
mi := &file_media_set_proto_msgTypes[11]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
|
@ -619,7 +807,7 @@ func (x *GetVideoThumbnailResponse) ProtoReflect() protoreflect.Message {
|
|||
|
||||
// Deprecated: Use GetVideoThumbnailResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetVideoThumbnailResponse) Descriptor() ([]byte, []int) {
|
||||
return file_media_set_proto_rawDescGZIP(), []int{9}
|
||||
return file_media_set_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *GetVideoThumbnailResponse) GetImage() []byte {
|
||||
|
@ -703,51 +891,78 @@ var file_media_set_proto_rawDesc = []byte{
|
|||
0x46, 0x72, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b,
|
||||
0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x61, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x05, 0x52, 0x05, 0x70, 0x65, 0x61, 0x6b, 0x73, 0x22, 0x21, 0x0a, 0x0f, 0x47, 0x65, 0x74,
|
||||
0x56, 0x69, 0x64, 0x65, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4f, 0x0a, 0x10,
|
||||
0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
|
||||
0x12, 0x29, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0f, 0x70, 0x65, 0x72, 0x63,
|
||||
0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75,
|
||||
0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x2a, 0x0a,
|
||||
0x18, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61,
|
||||
0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x5f, 0x0a, 0x19, 0x47, 0x65, 0x74,
|
||||
0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x77, 0x69, 0x64,
|
||||
0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x32, 0x9f, 0x03, 0x0a, 0x0f, 0x4d,
|
||||
0x65, 0x64, 0x69, 0x61, 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33,
|
||||
0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6d,
|
||||
0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x53, 0x65,
|
||||
0x74, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x12,
|
||||
0x1a, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x50,
|
||||
0x65, 0x61, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x65,
|
||||
0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73,
|
||||
0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x00, 0x30, 0x01, 0x12, 0x63, 0x0a, 0x12,
|
||||
0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x67, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x12, 0x24, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47,
|
||||
0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61,
|
||||
0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x46, 0x6f, 0x72,
|
||||
0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x47, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x12, 0x1a, 0x2e,
|
||||
0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64,
|
||||
0x65, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x65, 0x64, 0x69,
|
||||
0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72,
|
||||
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x00, 0x30, 0x01, 0x12, 0x60, 0x0a, 0x11, 0x47, 0x65,
|
||||
0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x12,
|
||||
0x23, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x56,
|
||||
0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74,
|
||||
0x28, 0x05, 0x52, 0x05, 0x70, 0x65, 0x61, 0x6b, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x16, 0x47, 0x65,
|
||||
0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x66, 0x72,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74,
|
||||
0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x5f, 0x66, 0x72, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x46, 0x72, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x41,
|
||||
0x75, 0x64, 0x69, 0x6f, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d,
|
||||
0x61, 0x74, 0x22, 0x9a, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x53,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
|
||||
0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52,
|
||||
0x0f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x44, 0x61, 0x74, 0x61, 0x22,
|
||||
0x21, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
|
||||
0x69, 0x64, 0x22, 0x4f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x50, 0x72,
|
||||
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
|
||||
0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02,
|
||||
0x52, 0x0f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||
0x75, 0x72, 0x6c, 0x22, 0x2a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54,
|
||||
0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22,
|
||||
0x5f, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62,
|
||||
0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6d, 0x61,
|
||||
0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67,
|
||||
0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74,
|
||||
0x2a, 0x1f, 0x0a, 0x0b, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12,
|
||||
0x07, 0x0a, 0x03, 0x57, 0x41, 0x56, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x50, 0x33, 0x10,
|
||||
0x01, 0x32, 0xfd, 0x03, 0x0a, 0x0f, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x53, 0x65, 0x74, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x6d,
|
||||
0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e,
|
||||
0x4d, 0x65, 0x64, 0x69, 0x61, 0x53, 0x65, 0x74, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x08, 0x47, 0x65,
|
||||
0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x12, 0x1a, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73,
|
||||
0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47,
|
||||
0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22,
|
||||
0x00, 0x30, 0x01, 0x12, 0x63, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x46,
|
||||
0x6f, 0x72, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x2e, 0x6d, 0x65, 0x64, 0x69,
|
||||
0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x65, 0x61, 0x6b, 0x73, 0x46, 0x6f,
|
||||
0x72, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x25, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x50,
|
||||
0x65, 0x61, 0x6b, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5c, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41,
|
||||
0x75, 0x64, 0x69, 0x6f, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x2e, 0x6d, 0x65,
|
||||
0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x64, 0x69, 0x6f,
|
||||
0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22,
|
||||
0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75,
|
||||
0x64, 0x69, 0x6f, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65,
|
||||
0x73, 0x73, 0x22, 0x00, 0x30, 0x01, 0x12, 0x47, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64,
|
||||
0x65, 0x6f, 0x12, 0x1a, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47,
|
||||
0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b,
|
||||
0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69,
|
||||
0x64, 0x65, 0x6f, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x00, 0x30, 0x01, 0x12,
|
||||
0x60, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62,
|
||||
0x6e, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x2e, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74,
|
||||
0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61,
|
||||
0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x0e, 0x5a, 0x0c,
|
||||
0x70, 0x62, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x65, 0x64, 0x69,
|
||||
0x61, 0x5f, 0x73, 0x65, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x68,
|
||||
0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x42, 0x0e, 0x5a, 0x0c, 0x70, 0x62, 0x2f, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x73, 0x65,
|
||||
0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -762,37 +977,44 @@ func file_media_set_proto_rawDescGZIP() []byte {
|
|||
return file_media_set_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_media_set_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_media_set_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_media_set_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||
var file_media_set_proto_goTypes = []interface{}{
|
||||
(*MediaSet)(nil), // 0: media_set.MediaSet
|
||||
(*GetRequest)(nil), // 1: media_set.GetRequest
|
||||
(*GetPeaksRequest)(nil), // 2: media_set.GetPeaksRequest
|
||||
(*GetPeaksProgress)(nil), // 3: media_set.GetPeaksProgress
|
||||
(*GetPeaksForSegmentRequest)(nil), // 4: media_set.GetPeaksForSegmentRequest
|
||||
(*GetPeaksForSegmentResponse)(nil), // 5: media_set.GetPeaksForSegmentResponse
|
||||
(*GetVideoRequest)(nil), // 6: media_set.GetVideoRequest
|
||||
(*GetVideoProgress)(nil), // 7: media_set.GetVideoProgress
|
||||
(*GetVideoThumbnailRequest)(nil), // 8: media_set.GetVideoThumbnailRequest
|
||||
(*GetVideoThumbnailResponse)(nil), // 9: media_set.GetVideoThumbnailResponse
|
||||
(*durationpb.Duration)(nil), // 10: google.protobuf.Duration
|
||||
(AudioFormat)(0), // 0: media_set.AudioFormat
|
||||
(*MediaSet)(nil), // 1: media_set.MediaSet
|
||||
(*GetRequest)(nil), // 2: media_set.GetRequest
|
||||
(*GetPeaksRequest)(nil), // 3: media_set.GetPeaksRequest
|
||||
(*GetPeaksProgress)(nil), // 4: media_set.GetPeaksProgress
|
||||
(*GetPeaksForSegmentRequest)(nil), // 5: media_set.GetPeaksForSegmentRequest
|
||||
(*GetPeaksForSegmentResponse)(nil), // 6: media_set.GetPeaksForSegmentResponse
|
||||
(*GetAudioSegmentRequest)(nil), // 7: media_set.GetAudioSegmentRequest
|
||||
(*GetAudioSegmentProgress)(nil), // 8: media_set.GetAudioSegmentProgress
|
||||
(*GetVideoRequest)(nil), // 9: media_set.GetVideoRequest
|
||||
(*GetVideoProgress)(nil), // 10: media_set.GetVideoProgress
|
||||
(*GetVideoThumbnailRequest)(nil), // 11: media_set.GetVideoThumbnailRequest
|
||||
(*GetVideoThumbnailResponse)(nil), // 12: media_set.GetVideoThumbnailResponse
|
||||
(*durationpb.Duration)(nil), // 13: google.protobuf.Duration
|
||||
}
|
||||
var file_media_set_proto_depIdxs = []int32{
|
||||
10, // 0: media_set.MediaSet.video_duration:type_name -> google.protobuf.Duration
|
||||
1, // 1: media_set.MediaSetService.Get:input_type -> media_set.GetRequest
|
||||
2, // 2: media_set.MediaSetService.GetPeaks:input_type -> media_set.GetPeaksRequest
|
||||
4, // 3: media_set.MediaSetService.GetPeaksForSegment:input_type -> media_set.GetPeaksForSegmentRequest
|
||||
6, // 4: media_set.MediaSetService.GetVideo:input_type -> media_set.GetVideoRequest
|
||||
8, // 5: media_set.MediaSetService.GetVideoThumbnail:input_type -> media_set.GetVideoThumbnailRequest
|
||||
0, // 6: media_set.MediaSetService.Get:output_type -> media_set.MediaSet
|
||||
3, // 7: media_set.MediaSetService.GetPeaks:output_type -> media_set.GetPeaksProgress
|
||||
5, // 8: media_set.MediaSetService.GetPeaksForSegment:output_type -> media_set.GetPeaksForSegmentResponse
|
||||
7, // 9: media_set.MediaSetService.GetVideo:output_type -> media_set.GetVideoProgress
|
||||
9, // 10: media_set.MediaSetService.GetVideoThumbnail:output_type -> media_set.GetVideoThumbnailResponse
|
||||
6, // [6:11] is the sub-list for method output_type
|
||||
1, // [1:6] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
13, // 0: media_set.MediaSet.video_duration:type_name -> google.protobuf.Duration
|
||||
0, // 1: media_set.GetAudioSegmentRequest.format:type_name -> media_set.AudioFormat
|
||||
2, // 2: media_set.MediaSetService.Get:input_type -> media_set.GetRequest
|
||||
3, // 3: media_set.MediaSetService.GetPeaks:input_type -> media_set.GetPeaksRequest
|
||||
5, // 4: media_set.MediaSetService.GetPeaksForSegment:input_type -> media_set.GetPeaksForSegmentRequest
|
||||
7, // 5: media_set.MediaSetService.GetAudioSegment:input_type -> media_set.GetAudioSegmentRequest
|
||||
9, // 6: media_set.MediaSetService.GetVideo:input_type -> media_set.GetVideoRequest
|
||||
11, // 7: media_set.MediaSetService.GetVideoThumbnail:input_type -> media_set.GetVideoThumbnailRequest
|
||||
1, // 8: media_set.MediaSetService.Get:output_type -> media_set.MediaSet
|
||||
4, // 9: media_set.MediaSetService.GetPeaks:output_type -> media_set.GetPeaksProgress
|
||||
6, // 10: media_set.MediaSetService.GetPeaksForSegment:output_type -> media_set.GetPeaksForSegmentResponse
|
||||
8, // 11: media_set.MediaSetService.GetAudioSegment:output_type -> media_set.GetAudioSegmentProgress
|
||||
10, // 12: media_set.MediaSetService.GetVideo:output_type -> media_set.GetVideoProgress
|
||||
12, // 13: media_set.MediaSetService.GetVideoThumbnail:output_type -> media_set.GetVideoThumbnailResponse
|
||||
8, // [8:14] is the sub-list for method output_type
|
||||
2, // [2:8] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_media_set_proto_init() }
|
||||
|
@ -874,7 +1096,7 @@ func file_media_set_proto_init() {
|
|||
}
|
||||
}
|
||||
file_media_set_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetVideoRequest); i {
|
||||
switch v := v.(*GetAudioSegmentRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
|
@ -886,7 +1108,7 @@ func file_media_set_proto_init() {
|
|||
}
|
||||
}
|
||||
file_media_set_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetVideoProgress); i {
|
||||
switch v := v.(*GetAudioSegmentProgress); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
|
@ -898,7 +1120,7 @@ func file_media_set_proto_init() {
|
|||
}
|
||||
}
|
||||
file_media_set_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetVideoThumbnailRequest); i {
|
||||
switch v := v.(*GetVideoRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
|
@ -910,6 +1132,30 @@ func file_media_set_proto_init() {
|
|||
}
|
||||
}
|
||||
file_media_set_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetVideoProgress); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_media_set_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetVideoThumbnailRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_media_set_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetVideoThumbnailResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
|
@ -927,13 +1173,14 @@ func file_media_set_proto_init() {
|
|||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_media_set_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 10,
|
||||
NumEnums: 1,
|
||||
NumMessages: 12,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_media_set_proto_goTypes,
|
||||
DependencyIndexes: file_media_set_proto_depIdxs,
|
||||
EnumInfos: file_media_set_proto_enumTypes,
|
||||
MessageInfos: file_media_set_proto_msgTypes,
|
||||
}.Build()
|
||||
File_media_set_proto = out.File
|
||||
|
|
|
@ -21,6 +21,7 @@ type MediaSetServiceClient interface {
|
|||
Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*MediaSet, error)
|
||||
GetPeaks(ctx context.Context, in *GetPeaksRequest, opts ...grpc.CallOption) (MediaSetService_GetPeaksClient, error)
|
||||
GetPeaksForSegment(ctx context.Context, in *GetPeaksForSegmentRequest, opts ...grpc.CallOption) (*GetPeaksForSegmentResponse, error)
|
||||
GetAudioSegment(ctx context.Context, in *GetAudioSegmentRequest, opts ...grpc.CallOption) (MediaSetService_GetAudioSegmentClient, error)
|
||||
GetVideo(ctx context.Context, in *GetVideoRequest, opts ...grpc.CallOption) (MediaSetService_GetVideoClient, error)
|
||||
GetVideoThumbnail(ctx context.Context, in *GetVideoThumbnailRequest, opts ...grpc.CallOption) (*GetVideoThumbnailResponse, error)
|
||||
}
|
||||
|
@ -83,8 +84,40 @@ func (c *mediaSetServiceClient) GetPeaksForSegment(ctx context.Context, in *GetP
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *mediaSetServiceClient) GetAudioSegment(ctx context.Context, in *GetAudioSegmentRequest, opts ...grpc.CallOption) (MediaSetService_GetAudioSegmentClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &MediaSetService_ServiceDesc.Streams[1], "/media_set.MediaSetService/GetAudioSegment", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &mediaSetServiceGetAudioSegmentClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type MediaSetService_GetAudioSegmentClient interface {
|
||||
Recv() (*GetAudioSegmentProgress, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type mediaSetServiceGetAudioSegmentClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *mediaSetServiceGetAudioSegmentClient) Recv() (*GetAudioSegmentProgress, error) {
|
||||
m := new(GetAudioSegmentProgress)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *mediaSetServiceClient) GetVideo(ctx context.Context, in *GetVideoRequest, opts ...grpc.CallOption) (MediaSetService_GetVideoClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &MediaSetService_ServiceDesc.Streams[1], "/media_set.MediaSetService/GetVideo", opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &MediaSetService_ServiceDesc.Streams[2], "/media_set.MediaSetService/GetVideo", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -131,6 +164,7 @@ type MediaSetServiceServer interface {
|
|||
Get(context.Context, *GetRequest) (*MediaSet, error)
|
||||
GetPeaks(*GetPeaksRequest, MediaSetService_GetPeaksServer) error
|
||||
GetPeaksForSegment(context.Context, *GetPeaksForSegmentRequest) (*GetPeaksForSegmentResponse, error)
|
||||
GetAudioSegment(*GetAudioSegmentRequest, MediaSetService_GetAudioSegmentServer) error
|
||||
GetVideo(*GetVideoRequest, MediaSetService_GetVideoServer) error
|
||||
GetVideoThumbnail(context.Context, *GetVideoThumbnailRequest) (*GetVideoThumbnailResponse, error)
|
||||
mustEmbedUnimplementedMediaSetServiceServer()
|
||||
|
@ -149,6 +183,9 @@ func (UnimplementedMediaSetServiceServer) GetPeaks(*GetPeaksRequest, MediaSetSer
|
|||
func (UnimplementedMediaSetServiceServer) GetPeaksForSegment(context.Context, *GetPeaksForSegmentRequest) (*GetPeaksForSegmentResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetPeaksForSegment not implemented")
|
||||
}
|
||||
func (UnimplementedMediaSetServiceServer) GetAudioSegment(*GetAudioSegmentRequest, MediaSetService_GetAudioSegmentServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetAudioSegment not implemented")
|
||||
}
|
||||
func (UnimplementedMediaSetServiceServer) GetVideo(*GetVideoRequest, MediaSetService_GetVideoServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetVideo not implemented")
|
||||
}
|
||||
|
@ -225,6 +262,27 @@ func _MediaSetService_GetPeaksForSegment_Handler(srv interface{}, ctx context.Co
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _MediaSetService_GetAudioSegment_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(GetAudioSegmentRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(MediaSetServiceServer).GetAudioSegment(m, &mediaSetServiceGetAudioSegmentServer{stream})
|
||||
}
|
||||
|
||||
type MediaSetService_GetAudioSegmentServer interface {
|
||||
Send(*GetAudioSegmentProgress) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type mediaSetServiceGetAudioSegmentServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *mediaSetServiceGetAudioSegmentServer) Send(m *GetAudioSegmentProgress) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _MediaSetService_GetVideo_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(GetVideoRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
|
@ -290,6 +348,11 @@ var MediaSetService_ServiceDesc = grpc.ServiceDesc{
|
|||
Handler: _MediaSetService_GetPeaks_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "GetAudioSegment",
|
||||
Handler: _MediaSetService_GetAudioSegment_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "GetVideo",
|
||||
Handler: _MediaSetService_GetVideo_Handler,
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
package media
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CommandFunc is a function that builds an *exec.Cmd from a context, name and
|
||||
// args.
|
||||
type CommandFunc func(ctx context.Context, name string, arg ...string) *exec.Cmd
|
||||
|
||||
// AudioFormat represents an abstract audio format, e.g. MP3 or WAV.
|
||||
type AudioFormat int
|
||||
|
||||
const (
|
||||
AudioFormatWAV AudioFormat = iota
|
||||
AudioFormatMP3
|
||||
)
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
func (f AudioFormat) String() string {
|
||||
switch f {
|
||||
case AudioFormatWAV:
|
||||
return "wav"
|
||||
case AudioFormatMP3:
|
||||
return "mp3"
|
||||
default:
|
||||
panic("unknown audio format")
|
||||
}
|
||||
}
|
||||
|
||||
// AudioSegmentProgress represents a progress update for an AudioSegmentStream,
|
||||
// and contains a byte slice of audio data and indication of the approximate
|
||||
// progress.
|
||||
type AudioSegmentProgress struct {
|
||||
PercentComplete float32
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// AudioSegmentStream is a stream of AudioSegmentProgress structs.
|
||||
type AudioSegmentStream struct {
|
||||
progressChan chan AudioSegmentProgress
|
||||
errorChan chan error
|
||||
}
|
||||
|
||||
// send publishes a new partial segment and progress update to the strean.
|
||||
func (s *AudioSegmentStream) send(p []byte, percentComplete float32) {
|
||||
s.progressChan <- AudioSegmentProgress{
|
||||
Data: p,
|
||||
PercentComplete: percentComplete,
|
||||
}
|
||||
}
|
||||
|
||||
// close signals the successful end of the stream of data.
|
||||
func (s *AudioSegmentStream) close() {
|
||||
close(s.progressChan)
|
||||
}
|
||||
|
||||
// closeWithError signals the unsuccessful end of a stream of data.
|
||||
func (s *AudioSegmentStream) closeWithError(err error) {
|
||||
s.errorChan <- err
|
||||
}
|
||||
|
||||
// audioSegmentGetter gets an audio segment and streams it to the caller.
|
||||
type audioSegmentGetter struct {
|
||||
mu sync.Mutex
|
||||
commandFunc CommandFunc
|
||||
rawAudio io.ReadCloser
|
||||
channels int32
|
||||
outFormat AudioFormat
|
||||
stream *AudioSegmentStream
|
||||
bytesRead, bytesExpected int64
|
||||
}
|
||||
|
||||
// newAudioSegmentGetter returns a new audioSegmentGetter. The io.ReadCloser
|
||||
// will be consumed and closed by the getAudioSegment() function.
|
||||
func newAudioSegmentGetter(commandFunc CommandFunc, rawAudio io.ReadCloser, channels int32, bytesExpected int64, outFormat AudioFormat) *audioSegmentGetter {
|
||||
return &audioSegmentGetter{
|
||||
commandFunc: commandFunc,
|
||||
rawAudio: rawAudio,
|
||||
channels: channels,
|
||||
bytesExpected: bytesExpected,
|
||||
outFormat: outFormat,
|
||||
stream: &AudioSegmentStream{
|
||||
progressChan: make(chan AudioSegmentProgress),
|
||||
errorChan: make(chan error, 1),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Read implements io.Reader and is consumed by the stdin of the FFMPEG
|
||||
// command. It is called from a separate goroutine to Write().
|
||||
func (s *audioSegmentGetter) Read(p []byte) (int, error) {
|
||||
n, err := s.rawAudio.Read(p)
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.bytesRead += int64(n)
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Write implements io.Writer and consumes the stdout of the FFMPEG command. It
|
||||
// is called from a separate goroutine to Read().
|
||||
func (s *audioSegmentGetter) Write(p []byte) (int, error) {
|
||||
s.stream.send(p, s.percentComplete())
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (s *audioSegmentGetter) percentComplete() float32 {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
return (float32(s.bytesRead) / float32(s.bytesExpected)) * 100
|
||||
}
|
||||
|
||||
// Next implements AudioSegmentStream.
|
||||
func (s *AudioSegmentStream) Next(ctx context.Context) (AudioSegmentProgress, error) {
|
||||
select {
|
||||
case progress, ok := <-s.progressChan:
|
||||
if !ok {
|
||||
return AudioSegmentProgress{}, io.EOF
|
||||
}
|
||||
return progress, nil
|
||||
case err := <-s.errorChan:
|
||||
return AudioSegmentProgress{}, err
|
||||
case <-ctx.Done():
|
||||
return AudioSegmentProgress{}, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *audioSegmentGetter) getAudioSegment(ctx context.Context) {
|
||||
defer s.rawAudio.Close()
|
||||
|
||||
var stdErr bytes.Buffer
|
||||
cmd := s.commandFunc(ctx, "ffmpeg", "-hide_banner", "-loglevel", "error", "-f", "s16le", "-ac", itoa(int(s.channels)), "-ar", itoa(rawAudioSampleRate), "-i", "-", "-f", s.outFormat.String(), "-")
|
||||
cmd.Stderr = &stdErr
|
||||
cmd.Stdin = s
|
||||
cmd.Stdout = s
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
s.stream.closeWithError(fmt.Errorf("error starting command: %v, output: %s", err, stdErr.String()))
|
||||
return
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
s.stream.closeWithError(fmt.Errorf("error waiting for ffmpeg: %v, output: %s", err, stdErr.String()))
|
||||
return
|
||||
}
|
||||
|
||||
s.stream.close()
|
||||
}
|
||||
|
||||
func itoa(i int) string { return strconv.Itoa(i) }
|
|
@ -0,0 +1,264 @@
|
|||
package media_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.netflux.io/rob/clipper/config"
|
||||
"git.netflux.io/rob/clipper/generated/mocks"
|
||||
"git.netflux.io/rob/clipper/generated/store"
|
||||
"git.netflux.io/rob/clipper/media"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const inFixturePath = "testdata/tone-44100-stereo-int16-30000ms.raw"
|
||||
|
||||
func helperCommand(t *testing.T, wantCommand, stdoutFile, stderrString string, forceExitCode int) media.CommandFunc {
|
||||
return func(ctx context.Context, name string, args ...string) *exec.Cmd {
|
||||
cs := []string{"-test.run=TestHelperProcess", "--", name}
|
||||
cs = append(cs, args...)
|
||||
cmd := exec.CommandContext(ctx, os.Args[0], cs...)
|
||||
cmd.Env = []string{
|
||||
"GO_WANT_HELPER_PROCESS=1",
|
||||
"GO_WANT_COMMAND=" + wantCommand,
|
||||
"GO_STDOUT_FILE=" + stdoutFile,
|
||||
"GO_STDERR_STRING=" + stderrString,
|
||||
"GO_FORCE_EXIT_CODE=" + strconv.Itoa(forceExitCode),
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelperProcess(t *testing.T) {
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Stop the helper process writing to stdout after the test has finished.
|
||||
// This prevents it from writing the "PASS" string which is unwanted in
|
||||
// this context.
|
||||
if !t.Failed() {
|
||||
os.Stdout, _ = os.Open(os.DevNull)
|
||||
}
|
||||
}()
|
||||
|
||||
if exitCode := os.Getenv("GO_FORCE_EXIT_CODE"); exitCode != "0" {
|
||||
c, _ := strconv.Atoi(exitCode)
|
||||
os.Stderr.WriteString(os.Getenv("GO_STDERR_STRING"))
|
||||
os.Exit(c)
|
||||
}
|
||||
|
||||
if wantCommand := os.Getenv("GO_WANT_COMMAND"); wantCommand != "" {
|
||||
gotCmd := strings.Split(strings.Join(os.Args, " "), " -- ")[1]
|
||||
if wantCommand != gotCmd {
|
||||
fmt.Printf("GO_WANT_COMMAND assertion failed:\nwant = %v\ngot = %v", wantCommand, gotCmd)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Copy stdin to /dev/null. This is required to avoid broken pipe errors in
|
||||
// the tests:
|
||||
_, err := io.Copy(io.Discard, os.Stdin)
|
||||
require.NoError(t, err)
|
||||
|
||||
// If an output file is provided, then copy that to stdout:
|
||||
if fname := os.Getenv("GO_STDOUT_FILE"); fname != "" {
|
||||
fptr, err := os.Open(fname)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = io.Copy(os.Stdout, fptr)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func fixtureReader(t *testing.T, limit int64) io.ReadCloser {
|
||||
fptr, err := os.Open(inFixturePath)
|
||||
require.NoError(t, err)
|
||||
|
||||
// limitReader to make the mock work realistically, not intended for assertions:
|
||||
return struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: io.LimitReader(fptr, limit),
|
||||
Closer: fptr,
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSegment(t *testing.T) {
|
||||
mediaSetID := uuid.MustParse("4c440241-cca9-436f-adb0-be074588cf2b")
|
||||
|
||||
t.Run("invalid range", func(t *testing.T) {
|
||||
var mockStore mocks.Store
|
||||
var fileStore mocks.FileStore
|
||||
service := media.NewMediaSetService(&mockStore, nil, &fileStore, nil, config.Config{}, zap.NewNop().Sugar())
|
||||
|
||||
stream, err := service.GetAudioSegment(context.Background(), mediaSetID, 1, 0, media.AudioFormatMP3)
|
||||
require.Nil(t, stream)
|
||||
require.EqualError(t, err, "invalid range")
|
||||
})
|
||||
|
||||
t.Run("error fetching media set", func(t *testing.T) {
|
||||
var mockStore mocks.Store
|
||||
mockStore.On("GetMediaSet", mock.Anything, mediaSetID).Return(store.MediaSet{}, pgx.ErrNoRows)
|
||||
var fileStore mocks.FileStore
|
||||
service := media.NewMediaSetService(&mockStore, nil, &fileStore, nil, config.Config{}, zap.NewNop().Sugar())
|
||||
|
||||
stream, err := service.GetAudioSegment(context.Background(), mediaSetID, 0, 1, media.AudioFormatMP3)
|
||||
require.Nil(t, stream)
|
||||
require.EqualError(t, err, "error getting media set: no rows in result set")
|
||||
})
|
||||
|
||||
t.Run("error fetching audio data", func(t *testing.T) {
|
||||
mediaSet := store.MediaSet{ID: mediaSetID, AudioChannels: 2}
|
||||
|
||||
var mockStore mocks.Store
|
||||
mockStore.On("GetMediaSet", mock.Anything, mediaSetID).Return(mediaSet, nil)
|
||||
|
||||
var fileStore mocks.FileStore
|
||||
fileStore.On("GetObjectWithRange", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(nil, errors.New("network error"))
|
||||
|
||||
service := media.NewMediaSetService(&mockStore, nil, &fileStore, nil, config.Config{}, zap.NewNop().Sugar())
|
||||
|
||||
stream, err := service.GetAudioSegment(context.Background(), mediaSetID, 0, 1, media.AudioFormatMP3)
|
||||
require.Nil(t, stream)
|
||||
require.EqualError(t, err, "error getting object from store: network error")
|
||||
})
|
||||
|
||||
t.Run("ffmpeg returns non-zero error code", func(t *testing.T) {
|
||||
mediaSet := store.MediaSet{ID: mediaSetID, AudioChannels: 2}
|
||||
|
||||
var mockStore mocks.Store
|
||||
mockStore.On("GetMediaSet", mock.Anything, mediaSetID).Return(mediaSet, nil)
|
||||
|
||||
var fileStore mocks.FileStore
|
||||
fileStore.On("GetObjectWithRange", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(fixtureReader(t, 1), nil)
|
||||
|
||||
cmd := helperCommand(t, "", "", "something bad happened", 2)
|
||||
service := media.NewMediaSetService(&mockStore, nil, &fileStore, cmd, config.Config{}, zap.NewNop().Sugar())
|
||||
|
||||
stream, err := service.GetAudioSegment(context.Background(), mediaSetID, 0, 1, media.AudioFormatMP3)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = stream.Next(context.Background())
|
||||
require.EqualError(t, err, "error waiting for ffmpeg: exit status 2, output: something bad happened")
|
||||
|
||||
})
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
audioFormat media.AudioFormat
|
||||
audioChannels int32
|
||||
inStartFrame, inEndFrame int64
|
||||
wantStartByte, wantEndByte int64
|
||||
outFixturePath string
|
||||
wantCommand string
|
||||
wantOutput string
|
||||
}{
|
||||
{
|
||||
name: "mono to mp3",
|
||||
audioFormat: media.AudioFormatMP3,
|
||||
audioChannels: 1,
|
||||
inStartFrame: 500,
|
||||
inEndFrame: 2_000,
|
||||
wantStartByte: 1_000,
|
||||
wantEndByte: 4_000,
|
||||
outFixturePath: "testdata/fake.mp3",
|
||||
wantCommand: "ffmpeg -hide_banner -loglevel error -f s16le -ac 1 -ar 48000 -i - -f mp3 -",
|
||||
wantOutput: "this is a fake mp3",
|
||||
},
|
||||
{
|
||||
name: "stereo to mp3",
|
||||
audioFormat: media.AudioFormatMP3,
|
||||
audioChannels: 2,
|
||||
inStartFrame: 0,
|
||||
inEndFrame: 1_323_000,
|
||||
wantStartByte: 0,
|
||||
wantEndByte: 5_292_000,
|
||||
outFixturePath: "testdata/fake.mp3",
|
||||
wantCommand: "ffmpeg -hide_banner -loglevel error -f s16le -ac 2 -ar 48000 -i - -f mp3 -",
|
||||
wantOutput: "this is a fake mp3",
|
||||
},
|
||||
{
|
||||
name: "mono to wav",
|
||||
audioFormat: media.AudioFormatWAV,
|
||||
audioChannels: 1,
|
||||
inStartFrame: 16_384,
|
||||
inEndFrame: 32_768,
|
||||
wantStartByte: 32_768,
|
||||
wantEndByte: 65_536,
|
||||
outFixturePath: "testdata/fake.wav",
|
||||
wantCommand: "ffmpeg -hide_banner -loglevel error -f s16le -ac 1 -ar 48000 -i - -f wav -",
|
||||
wantOutput: "this is a fake wav",
|
||||
},
|
||||
{
|
||||
name: "stereo to wav",
|
||||
audioFormat: media.AudioFormatWAV,
|
||||
audioChannels: 2,
|
||||
inStartFrame: 2_048,
|
||||
inEndFrame: 4_096,
|
||||
wantStartByte: 8_192,
|
||||
wantEndByte: 16_384,
|
||||
outFixturePath: "testdata/fake.wav",
|
||||
wantCommand: "ffmpeg -hide_banner -loglevel error -f s16le -ac 2 -ar 48000 -i - -f wav -",
|
||||
wantOutput: "this is a fake wav",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
mediaSet := store.MediaSet{ID: mediaSetID, AudioChannels: tc.audioChannels}
|
||||
var mockStore mocks.Store
|
||||
mockStore.On("GetMediaSet", mock.Anything, mediaSetID).Return(mediaSet, nil)
|
||||
defer mockStore.AssertExpectations(t)
|
||||
|
||||
var fileStore mocks.FileStore
|
||||
fileStore.
|
||||
On("GetObjectWithRange", mock.Anything, "media_sets/4c440241-cca9-436f-adb0-be074588cf2b/audio.raw", tc.wantStartByte, tc.wantEndByte).
|
||||
Return(fixtureReader(t, tc.wantEndByte-tc.wantStartByte), nil)
|
||||
defer fileStore.AssertExpectations(t)
|
||||
|
||||
cmd := helperCommand(t, tc.wantCommand, tc.outFixturePath, "", 0)
|
||||
service := media.NewMediaSetService(&mockStore, nil, &fileStore, cmd, config.Config{}, zap.NewNop().Sugar())
|
||||
|
||||
stream, err := service.GetAudioSegment(ctx, mediaSetID, tc.inStartFrame, tc.inEndFrame, tc.audioFormat)
|
||||
require.NoError(t, err)
|
||||
|
||||
var data bytes.Buffer
|
||||
var lastPercentComplete float32
|
||||
var progress media.AudioSegmentProgress
|
||||
for {
|
||||
progress, err = stream.Next(ctx)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, progress.PercentComplete, lastPercentComplete)
|
||||
lastPercentComplete = progress.PercentComplete
|
||||
data.Write(progress.Data)
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.wantOutput, data.String())
|
||||
assert.Equal(t, float32(100), lastPercentComplete)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -34,20 +33,22 @@ const (
|
|||
|
||||
// MediaSetService exposes logical flows handling MediaSets.
|
||||
type MediaSetService struct {
|
||||
store Store
|
||||
youtube YoutubeClient
|
||||
fileStore FileStore
|
||||
config config.Config
|
||||
logger *zap.SugaredLogger
|
||||
store Store
|
||||
youtube YoutubeClient
|
||||
fileStore FileStore
|
||||
commandFunc CommandFunc
|
||||
config config.Config
|
||||
logger *zap.SugaredLogger
|
||||
}
|
||||
|
||||
func NewMediaSetService(store Store, youtubeClient YoutubeClient, fileStore FileStore, config config.Config, logger *zap.SugaredLogger) *MediaSetService {
|
||||
func NewMediaSetService(store Store, youtubeClient YoutubeClient, fileStore FileStore, commandFunc CommandFunc, config config.Config, logger *zap.SugaredLogger) *MediaSetService {
|
||||
return &MediaSetService{
|
||||
store: store,
|
||||
youtube: youtubeClient,
|
||||
fileStore: fileStore,
|
||||
config: config,
|
||||
logger: logger,
|
||||
store: store,
|
||||
youtube: youtubeClient,
|
||||
fileStore: fileStore,
|
||||
commandFunc: commandFunc,
|
||||
config: config,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,7 +251,7 @@ func (s *MediaSetService) GetVideo(ctx context.Context, id uuid.UUID) (GetVideoP
|
|||
)
|
||||
}
|
||||
|
||||
// GetAudio fetches the audio part of a MediaSet.
|
||||
// GetPeaks fetches the audio part of a MediaSet.
|
||||
func (s *MediaSetService) GetPeaks(ctx context.Context, id uuid.UUID, numBins int) (GetPeaksProgressReader, error) {
|
||||
mediaSet, err := s.store.GetMediaSet(ctx, id)
|
||||
if err != nil {
|
||||
|
@ -437,101 +438,30 @@ func (s *MediaSetService) GetPeaksForSegment(ctx context.Context, id uuid.UUID,
|
|||
return peaks, nil
|
||||
}
|
||||
|
||||
func sqlString(s string) sql.NullString {
|
||||
return sql.NullString{String: s, Valid: true}
|
||||
}
|
||||
func (s *MediaSetService) GetAudioSegment(ctx context.Context, id uuid.UUID, startFrame, endFrame int64, outFormat AudioFormat) (*AudioSegmentStream, error) {
|
||||
if startFrame > endFrame {
|
||||
return nil, errors.New("invalid range")
|
||||
}
|
||||
|
||||
func sqlInt64(i int64) sql.NullInt64 {
|
||||
return sql.NullInt64{Int64: i, Valid: true}
|
||||
}
|
||||
|
||||
func sqlInt32(i int32) sql.NullInt32 {
|
||||
return sql.NullInt32{Int32: i, Valid: true}
|
||||
}
|
||||
|
||||
type VideoThumbnail struct {
|
||||
Data []byte
|
||||
Width, Height int
|
||||
}
|
||||
|
||||
func (s *MediaSetService) GetVideoThumbnail(ctx context.Context, id uuid.UUID) (VideoThumbnail, error) {
|
||||
mediaSet, err := s.store.GetMediaSet(ctx, id)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error getting media set: %v", err)
|
||||
}
|
||||
|
||||
if mediaSet.VideoThumbnailS3UploadedAt.Valid {
|
||||
return s.getThumbnailFromFileStore(ctx, mediaSet)
|
||||
}
|
||||
|
||||
return s.getThumbnailFromYoutube(ctx, mediaSet)
|
||||
}
|
||||
|
||||
func (s *MediaSetService) getThumbnailFromFileStore(ctx context.Context, mediaSet store.MediaSet) (VideoThumbnail, error) {
|
||||
object, err := s.fileStore.GetObject(ctx, mediaSet.VideoThumbnailS3Key.String)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error fetching thumbnail from file store: %v", err)
|
||||
}
|
||||
defer object.Close()
|
||||
|
||||
imageData, err := io.ReadAll(object)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error reading thumbnail from file store: %v", err)
|
||||
}
|
||||
|
||||
return VideoThumbnail{
|
||||
Width: int(mediaSet.VideoThumbnailWidth.Int32),
|
||||
Height: int(mediaSet.VideoThumbnailHeight.Int32),
|
||||
Data: imageData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *MediaSetService) getThumbnailFromYoutube(ctx context.Context, mediaSet store.MediaSet) (VideoThumbnail, error) {
|
||||
video, err := s.youtube.GetVideoContext(ctx, mediaSet.YoutubeID)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error fetching video: %v", err)
|
||||
}
|
||||
|
||||
if len(video.Formats) == 0 {
|
||||
return VideoThumbnail{}, errors.New("no format available")
|
||||
}
|
||||
|
||||
thumbnails := video.Thumbnails
|
||||
SortYoutubeThumbnails(thumbnails)
|
||||
thumbnail := thumbnails[0]
|
||||
|
||||
resp, err := http.Get(thumbnail.URL)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error fetching thumbnail: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
imageData, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error reading thumbnail: %v", err)
|
||||
return nil, fmt.Errorf("error getting media set: %v", err)
|
||||
}
|
||||
|
||||
// TODO: use mediaSet func to fetch key
|
||||
thumbnailKey := fmt.Sprintf("media_sets/%s/thumbnail.jpg", mediaSet.ID)
|
||||
key := fmt.Sprintf("media_sets/%s/audio.raw", mediaSet.ID)
|
||||
startByte := startFrame * int64(mediaSet.AudioChannels) * SizeOfInt16
|
||||
endByte := endFrame * int64(mediaSet.AudioChannels) * SizeOfInt16
|
||||
|
||||
const mimeType = "application/jpeg"
|
||||
_, err = s.fileStore.PutObject(ctx, thumbnailKey, bytes.NewReader(imageData), mimeType)
|
||||
rawAudio, err := s.fileStore.GetObjectWithRange(ctx, key, startByte, endByte)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error uploading thumbnail: %v", err)
|
||||
return nil, fmt.Errorf("error getting object from store: %v", err)
|
||||
}
|
||||
|
||||
storeParams := store.SetVideoThumbnailUploadedParams{
|
||||
ID: mediaSet.ID,
|
||||
VideoThumbnailMimeType: sqlString(mimeType),
|
||||
VideoThumbnailS3Key: sqlString(thumbnailKey),
|
||||
VideoThumbnailWidth: sqlInt32(int32(thumbnail.Width)),
|
||||
VideoThumbnailHeight: sqlInt32(int32(thumbnail.Height)),
|
||||
}
|
||||
if _, err := s.store.SetVideoThumbnailUploaded(ctx, storeParams); err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error updating media set: %v", err)
|
||||
}
|
||||
g := newAudioSegmentGetter(s.commandFunc, rawAudio, mediaSet.AudioChannels, endByte-startByte, outFormat)
|
||||
go g.getAudioSegment(ctx)
|
||||
|
||||
return VideoThumbnail{Width: int(thumbnail.Width), Height: int(thumbnail.Height), Data: imageData}, nil
|
||||
return g.stream, nil
|
||||
}
|
||||
|
||||
// logProgressReader is a reader that prints progress logs as it reads.
|
||||
|
@ -558,3 +488,15 @@ func (r *logProgressReader) Read(p []byte) (int, error) {
|
|||
|
||||
return n, err
|
||||
}
|
||||
|
||||
func sqlString(s string) sql.NullString {
|
||||
return sql.NullString{String: s, Valid: true}
|
||||
}
|
||||
|
||||
func sqlInt64(i int64) sql.NullInt64 {
|
||||
return sql.NullInt64{Int64: i, Valid: true}
|
||||
}
|
||||
|
||||
func sqlInt32(i int32) sql.NullInt32 {
|
||||
return sql.NullInt32{Int32: i, Valid: true}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"database/sql"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"git.netflux.io/rob/clipper/config"
|
||||
|
@ -110,7 +111,7 @@ func TestPeaksForSegment(t *testing.T) {
|
|||
On("GetObjectWithRange", mock.Anything, "foo", startByte, endByte).
|
||||
Return(audioData, nil)
|
||||
|
||||
service := media.NewMediaSetService(store, nil, fileStore, config.Config{}, zap.NewNop().Sugar())
|
||||
service := media.NewMediaSetService(store, nil, fileStore, exec.CommandContext, config.Config{}, zap.NewNop().Sugar())
|
||||
peaks, err := service.GetPeaksForSegment(context.Background(), mediaSet.ID, tc.startFrame, tc.endFrame, tc.numBins)
|
||||
|
||||
if tc.wantErr == "" {
|
||||
|
@ -153,7 +154,7 @@ func BenchmarkGetPeaksForSegment(b *testing.B) {
|
|||
On("GetObjectWithRange", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
|
||||
Return(readCloser, nil)
|
||||
|
||||
service := media.NewMediaSetService(store, nil, fileStore, config.Config{}, zap.NewNop().Sugar())
|
||||
service := media.NewMediaSetService(store, nil, fileStore, exec.CommandContext, config.Config{}, zap.NewNop().Sugar())
|
||||
b.StartTimer()
|
||||
|
||||
_, err = service.GetPeaksForSegment(context.Background(), mediaSetID, startFrame, endFrame, numBins)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
this is a fake mp3
|
|
@ -0,0 +1 @@
|
|||
this is a fake wav
|
|
@ -0,0 +1,98 @@
|
|||
package media
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"git.netflux.io/rob/clipper/generated/store"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type VideoThumbnail struct {
|
||||
Data []byte
|
||||
Width, Height int
|
||||
}
|
||||
|
||||
func (s *MediaSetService) GetVideoThumbnail(ctx context.Context, id uuid.UUID) (VideoThumbnail, error) {
|
||||
mediaSet, err := s.store.GetMediaSet(ctx, id)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error getting media set: %v", err)
|
||||
}
|
||||
|
||||
if mediaSet.VideoThumbnailS3UploadedAt.Valid {
|
||||
return s.getThumbnailFromFileStore(ctx, mediaSet)
|
||||
}
|
||||
|
||||
return s.getThumbnailFromYoutube(ctx, mediaSet)
|
||||
}
|
||||
|
||||
func (s *MediaSetService) getThumbnailFromFileStore(ctx context.Context, mediaSet store.MediaSet) (VideoThumbnail, error) {
|
||||
object, err := s.fileStore.GetObject(ctx, mediaSet.VideoThumbnailS3Key.String)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error fetching thumbnail from file store: %v", err)
|
||||
}
|
||||
defer object.Close()
|
||||
|
||||
imageData, err := io.ReadAll(object)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error reading thumbnail from file store: %v", err)
|
||||
}
|
||||
|
||||
return VideoThumbnail{
|
||||
Width: int(mediaSet.VideoThumbnailWidth.Int32),
|
||||
Height: int(mediaSet.VideoThumbnailHeight.Int32),
|
||||
Data: imageData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *MediaSetService) getThumbnailFromYoutube(ctx context.Context, mediaSet store.MediaSet) (VideoThumbnail, error) {
|
||||
video, err := s.youtube.GetVideoContext(ctx, mediaSet.YoutubeID)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error fetching video: %v", err)
|
||||
}
|
||||
|
||||
if len(video.Formats) == 0 {
|
||||
return VideoThumbnail{}, errors.New("no format available")
|
||||
}
|
||||
|
||||
thumbnails := video.Thumbnails
|
||||
SortYoutubeThumbnails(thumbnails)
|
||||
thumbnail := thumbnails[0]
|
||||
|
||||
resp, err := http.Get(thumbnail.URL)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error fetching thumbnail: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
imageData, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error reading thumbnail: %v", err)
|
||||
}
|
||||
|
||||
// TODO: use mediaSet func to fetch key
|
||||
thumbnailKey := fmt.Sprintf("media_sets/%s/thumbnail.jpg", mediaSet.ID)
|
||||
|
||||
const mimeType = "application/jpeg"
|
||||
_, err = s.fileStore.PutObject(ctx, thumbnailKey, bytes.NewReader(imageData), mimeType)
|
||||
if err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error uploading thumbnail: %v", err)
|
||||
}
|
||||
|
||||
storeParams := store.SetVideoThumbnailUploadedParams{
|
||||
ID: mediaSet.ID,
|
||||
VideoThumbnailMimeType: sqlString(mimeType),
|
||||
VideoThumbnailS3Key: sqlString(thumbnailKey),
|
||||
VideoThumbnailWidth: sqlInt32(int32(thumbnail.Width)),
|
||||
VideoThumbnailHeight: sqlInt32(int32(thumbnail.Height)),
|
||||
}
|
||||
if _, err := s.store.SetVideoThumbnailUploaded(ctx, storeParams); err != nil {
|
||||
return VideoThumbnail{}, fmt.Errorf("error updating media set: %v", err)
|
||||
}
|
||||
|
||||
return VideoThumbnail{Width: int(thumbnail.Width), Height: int(thumbnail.Height), Data: imageData}, nil
|
||||
}
|
|
@ -2,9 +2,11 @@ package server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"git.netflux.io/rob/clipper/config"
|
||||
|
@ -35,6 +37,7 @@ const (
|
|||
const (
|
||||
getPeaksTimeout = time.Minute * 5
|
||||
getPeaksForSegmentTimeout = time.Second * 10
|
||||
getAudioSegmentTimeout = time.Minute * 2
|
||||
getVideoTimeout = time.Minute * 5
|
||||
)
|
||||
|
||||
|
@ -167,6 +170,51 @@ func (c *mediaSetServiceController) GetPeaksForSegment(ctx context.Context, requ
|
|||
return &pbmediaset.GetPeaksForSegmentResponse{Peaks: peaks32}, nil
|
||||
}
|
||||
|
||||
func (c *mediaSetServiceController) GetAudioSegment(request *pbmediaset.GetAudioSegmentRequest, outStream pbmediaset.MediaSetService_GetAudioSegmentServer) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), getPeaksForSegmentTimeout)
|
||||
defer cancel()
|
||||
|
||||
id, err := uuid.Parse(request.GetId())
|
||||
if err != nil {
|
||||
return newResponseError(err)
|
||||
}
|
||||
|
||||
var format media.AudioFormat
|
||||
switch request.Format {
|
||||
case pbmediaset.AudioFormat_MP3:
|
||||
format = media.AudioFormatMP3
|
||||
case pbmediaset.AudioFormat_WAV:
|
||||
format = media.AudioFormatWAV
|
||||
default:
|
||||
return newResponseError(errors.New("unknown format"))
|
||||
}
|
||||
|
||||
stream, err := c.mediaSetService.GetAudioSegment(ctx, id, request.StartFrame, request.EndFrame, format)
|
||||
if err != nil {
|
||||
return newResponseError(err)
|
||||
}
|
||||
|
||||
for {
|
||||
progress, err := stream.Next(ctx)
|
||||
if err != nil && err != io.EOF {
|
||||
return newResponseError(err)
|
||||
}
|
||||
|
||||
progressPb := pbmediaset.GetAudioSegmentProgress{
|
||||
PercentComplete: progress.PercentComplete,
|
||||
AudioData: progress.Data,
|
||||
}
|
||||
|
||||
outStream.Send(&progressPb)
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *mediaSetServiceController) GetVideo(request *pbmediaset.GetVideoRequest, stream pbmediaset.MediaSetService_GetVideoServer) error {
|
||||
// TODO: reduce timeout when already fetched from Youtube
|
||||
ctx, cancel := context.WithTimeout(context.Background(), getVideoTimeout)
|
||||
|
@ -227,6 +275,7 @@ func Start(options Options) error {
|
|||
options.Store,
|
||||
options.YoutubeClient,
|
||||
options.FileStore,
|
||||
exec.CommandContext,
|
||||
options.Config,
|
||||
options.Logger.Sugar().Named("mediaSetService"),
|
||||
)
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/wicg-file-system-access": "^2020.9.4",
|
||||
"@typescript-eslint/eslint-plugin": "^4.31.0",
|
||||
"@typescript-eslint/parser": "^4.31.0",
|
||||
"eslint": "^7.32.0",
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
} from './generated/media_set';
|
||||
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { AudioFormat } from './generated/media_set';
|
||||
import { VideoPreview } from './VideoPreview';
|
||||
import { Overview, CanvasLogicalWidth } from './Overview';
|
||||
import { Waveform } from './Waveform';
|
||||
|
@ -246,6 +247,35 @@ function App(): JSX.Element {
|
|||
}
|
||||
}, [audio, video, selection]);
|
||||
|
||||
const handleClip = useCallback(() => {
|
||||
(async function () {
|
||||
console.debug('clip', selection);
|
||||
|
||||
if (mediaSet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: support File System Access API fallback
|
||||
const h = await window.showSaveFilePicker({ suggestedName: 'clip.mp3' });
|
||||
const fileStream = await h.createWritable();
|
||||
|
||||
const rpc = newRPC();
|
||||
const service = new MediaSetServiceClientImpl(rpc);
|
||||
const stream = service.GetAudioSegment({
|
||||
id: mediaSet.id,
|
||||
format: AudioFormat.MP3,
|
||||
startFrame: selection.start,
|
||||
endFrame: selection.end,
|
||||
});
|
||||
|
||||
await stream.forEach((p) => fileStream.write(p.audioData));
|
||||
console.debug('finished writing stream');
|
||||
|
||||
await fileStream.close();
|
||||
console.debug('closed stream');
|
||||
})();
|
||||
}, [mediaSet, selection]);
|
||||
|
||||
const setPositionFromFrame = useCallback(
|
||||
(frame: number) => {
|
||||
if (mediaSet == null) {
|
||||
|
@ -297,7 +327,11 @@ function App(): JSX.Element {
|
|||
<>
|
||||
<div className="App">
|
||||
<div style={containerStyles}>
|
||||
<ControlBar onPlay={handlePlay} onPause={handlePause} />
|
||||
<ControlBar
|
||||
onPlay={handlePlay}
|
||||
onPause={handlePause}
|
||||
onClip={handleClip}
|
||||
/>
|
||||
|
||||
<Overview
|
||||
peaks={overviewPeaks}
|
||||
|
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
interface Props {
|
||||
onPlay: () => void;
|
||||
onPause: () => void;
|
||||
onClip: () => void;
|
||||
}
|
||||
|
||||
const ControlBar: React.FC<Props> = React.memo((props: Props) => {
|
||||
|
@ -26,6 +27,9 @@ const ControlBar: React.FC<Props> = React.memo((props: Props) => {
|
|||
<button style={buttonStyles} onClick={props.onPause}>
|
||||
Pause
|
||||
</button>
|
||||
<button style={buttonStyles} onClick={props.onClip}>
|
||||
Clip
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -9,6 +9,38 @@ import { share } from "rxjs/operators";
|
|||
|
||||
export const protobufPackage = "media_set";
|
||||
|
||||
export enum AudioFormat {
|
||||
WAV = 0,
|
||||
MP3 = 1,
|
||||
UNRECOGNIZED = -1,
|
||||
}
|
||||
|
||||
export function audioFormatFromJSON(object: any): AudioFormat {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "WAV":
|
||||
return AudioFormat.WAV;
|
||||
case 1:
|
||||
case "MP3":
|
||||
return AudioFormat.MP3;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return AudioFormat.UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
|
||||
export function audioFormatToJSON(object: AudioFormat): string {
|
||||
switch (object) {
|
||||
case AudioFormat.WAV:
|
||||
return "WAV";
|
||||
case AudioFormat.MP3:
|
||||
return "MP3";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
export interface MediaSet {
|
||||
id: string;
|
||||
youtubeId: string;
|
||||
|
@ -49,6 +81,20 @@ export interface GetPeaksForSegmentResponse {
|
|||
peaks: number[];
|
||||
}
|
||||
|
||||
export interface GetAudioSegmentRequest {
|
||||
id: string;
|
||||
startFrame: number;
|
||||
endFrame: number;
|
||||
format: AudioFormat;
|
||||
}
|
||||
|
||||
export interface GetAudioSegmentProgress {
|
||||
mimeType: string;
|
||||
message: string;
|
||||
percentComplete: number;
|
||||
audioData: Uint8Array;
|
||||
}
|
||||
|
||||
export interface GetVideoRequest {
|
||||
id: string;
|
||||
}
|
||||
|
@ -652,6 +698,213 @@ export const GetPeaksForSegmentResponse = {
|
|||
},
|
||||
};
|
||||
|
||||
const baseGetAudioSegmentRequest: object = {
|
||||
id: "",
|
||||
startFrame: 0,
|
||||
endFrame: 0,
|
||||
format: 0,
|
||||
};
|
||||
|
||||
export const GetAudioSegmentRequest = {
|
||||
encode(
|
||||
message: GetAudioSegmentRequest,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.id !== "") {
|
||||
writer.uint32(10).string(message.id);
|
||||
}
|
||||
if (message.startFrame !== 0) {
|
||||
writer.uint32(16).int64(message.startFrame);
|
||||
}
|
||||
if (message.endFrame !== 0) {
|
||||
writer.uint32(24).int64(message.endFrame);
|
||||
}
|
||||
if (message.format !== 0) {
|
||||
writer.uint32(32).int32(message.format);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(
|
||||
input: _m0.Reader | Uint8Array,
|
||||
length?: number
|
||||
): GetAudioSegmentRequest {
|
||||
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = { ...baseGetAudioSegmentRequest } as GetAudioSegmentRequest;
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1:
|
||||
message.id = reader.string();
|
||||
break;
|
||||
case 2:
|
||||
message.startFrame = longToNumber(reader.int64() as Long);
|
||||
break;
|
||||
case 3:
|
||||
message.endFrame = longToNumber(reader.int64() as Long);
|
||||
break;
|
||||
case 4:
|
||||
message.format = reader.int32() as any;
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
fromJSON(object: any): GetAudioSegmentRequest {
|
||||
const message = { ...baseGetAudioSegmentRequest } as GetAudioSegmentRequest;
|
||||
message.id =
|
||||
object.id !== undefined && object.id !== null ? String(object.id) : "";
|
||||
message.startFrame =
|
||||
object.startFrame !== undefined && object.startFrame !== null
|
||||
? Number(object.startFrame)
|
||||
: 0;
|
||||
message.endFrame =
|
||||
object.endFrame !== undefined && object.endFrame !== null
|
||||
? Number(object.endFrame)
|
||||
: 0;
|
||||
message.format =
|
||||
object.format !== undefined && object.format !== null
|
||||
? audioFormatFromJSON(object.format)
|
||||
: 0;
|
||||
return message;
|
||||
},
|
||||
|
||||
toJSON(message: GetAudioSegmentRequest): unknown {
|
||||
const obj: any = {};
|
||||
message.id !== undefined && (obj.id = message.id);
|
||||
message.startFrame !== undefined && (obj.startFrame = message.startFrame);
|
||||
message.endFrame !== undefined && (obj.endFrame = message.endFrame);
|
||||
message.format !== undefined &&
|
||||
(obj.format = audioFormatToJSON(message.format));
|
||||
return obj;
|
||||
},
|
||||
|
||||
fromPartial<I extends Exact<DeepPartial<GetAudioSegmentRequest>, I>>(
|
||||
object: I
|
||||
): GetAudioSegmentRequest {
|
||||
const message = { ...baseGetAudioSegmentRequest } as GetAudioSegmentRequest;
|
||||
message.id = object.id ?? "";
|
||||
message.startFrame = object.startFrame ?? 0;
|
||||
message.endFrame = object.endFrame ?? 0;
|
||||
message.format = object.format ?? 0;
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
const baseGetAudioSegmentProgress: object = {
|
||||
mimeType: "",
|
||||
message: "",
|
||||
percentComplete: 0,
|
||||
};
|
||||
|
||||
export const GetAudioSegmentProgress = {
|
||||
encode(
|
||||
message: GetAudioSegmentProgress,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.mimeType !== "") {
|
||||
writer.uint32(10).string(message.mimeType);
|
||||
}
|
||||
if (message.message !== "") {
|
||||
writer.uint32(18).string(message.message);
|
||||
}
|
||||
if (message.percentComplete !== 0) {
|
||||
writer.uint32(29).float(message.percentComplete);
|
||||
}
|
||||
if (message.audioData.length !== 0) {
|
||||
writer.uint32(34).bytes(message.audioData);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(
|
||||
input: _m0.Reader | Uint8Array,
|
||||
length?: number
|
||||
): GetAudioSegmentProgress {
|
||||
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = {
|
||||
...baseGetAudioSegmentProgress,
|
||||
} as GetAudioSegmentProgress;
|
||||
message.audioData = new Uint8Array();
|
||||
while (reader.pos < end) {
|
||||
const tag = reader.uint32();
|
||||
switch (tag >>> 3) {
|
||||
case 1:
|
||||
message.mimeType = reader.string();
|
||||
break;
|
||||
case 2:
|
||||
message.message = reader.string();
|
||||
break;
|
||||
case 3:
|
||||
message.percentComplete = reader.float();
|
||||
break;
|
||||
case 4:
|
||||
message.audioData = reader.bytes();
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return message;
|
||||
},
|
||||
|
||||
fromJSON(object: any): GetAudioSegmentProgress {
|
||||
const message = {
|
||||
...baseGetAudioSegmentProgress,
|
||||
} as GetAudioSegmentProgress;
|
||||
message.mimeType =
|
||||
object.mimeType !== undefined && object.mimeType !== null
|
||||
? String(object.mimeType)
|
||||
: "";
|
||||
message.message =
|
||||
object.message !== undefined && object.message !== null
|
||||
? String(object.message)
|
||||
: "";
|
||||
message.percentComplete =
|
||||
object.percentComplete !== undefined && object.percentComplete !== null
|
||||
? Number(object.percentComplete)
|
||||
: 0;
|
||||
message.audioData =
|
||||
object.audioData !== undefined && object.audioData !== null
|
||||
? bytesFromBase64(object.audioData)
|
||||
: new Uint8Array();
|
||||
return message;
|
||||
},
|
||||
|
||||
toJSON(message: GetAudioSegmentProgress): unknown {
|
||||
const obj: any = {};
|
||||
message.mimeType !== undefined && (obj.mimeType = message.mimeType);
|
||||
message.message !== undefined && (obj.message = message.message);
|
||||
message.percentComplete !== undefined &&
|
||||
(obj.percentComplete = message.percentComplete);
|
||||
message.audioData !== undefined &&
|
||||
(obj.audioData = base64FromBytes(
|
||||
message.audioData !== undefined ? message.audioData : new Uint8Array()
|
||||
));
|
||||
return obj;
|
||||
},
|
||||
|
||||
fromPartial<I extends Exact<DeepPartial<GetAudioSegmentProgress>, I>>(
|
||||
object: I
|
||||
): GetAudioSegmentProgress {
|
||||
const message = {
|
||||
...baseGetAudioSegmentProgress,
|
||||
} as GetAudioSegmentProgress;
|
||||
message.mimeType = object.mimeType ?? "";
|
||||
message.message = object.message ?? "";
|
||||
message.percentComplete = object.percentComplete ?? 0;
|
||||
message.audioData = object.audioData ?? new Uint8Array();
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
const baseGetVideoRequest: object = { id: "" };
|
||||
|
||||
export const GetVideoRequest = {
|
||||
|
@ -938,6 +1191,10 @@ export interface MediaSetService {
|
|||
request: DeepPartial<GetPeaksForSegmentRequest>,
|
||||
metadata?: grpc.Metadata
|
||||
): Promise<GetPeaksForSegmentResponse>;
|
||||
GetAudioSegment(
|
||||
request: DeepPartial<GetAudioSegmentRequest>,
|
||||
metadata?: grpc.Metadata
|
||||
): Observable<GetAudioSegmentProgress>;
|
||||
GetVideo(
|
||||
request: DeepPartial<GetVideoRequest>,
|
||||
metadata?: grpc.Metadata
|
||||
|
@ -956,6 +1213,7 @@ export class MediaSetServiceClientImpl implements MediaSetService {
|
|||
this.Get = this.Get.bind(this);
|
||||
this.GetPeaks = this.GetPeaks.bind(this);
|
||||
this.GetPeaksForSegment = this.GetPeaksForSegment.bind(this);
|
||||
this.GetAudioSegment = this.GetAudioSegment.bind(this);
|
||||
this.GetVideo = this.GetVideo.bind(this);
|
||||
this.GetVideoThumbnail = this.GetVideoThumbnail.bind(this);
|
||||
}
|
||||
|
@ -993,6 +1251,17 @@ export class MediaSetServiceClientImpl implements MediaSetService {
|
|||
);
|
||||
}
|
||||
|
||||
GetAudioSegment(
|
||||
request: DeepPartial<GetAudioSegmentRequest>,
|
||||
metadata?: grpc.Metadata
|
||||
): Observable<GetAudioSegmentProgress> {
|
||||
return this.rpc.invoke(
|
||||
MediaSetServiceGetAudioSegmentDesc,
|
||||
GetAudioSegmentRequest.fromPartial(request),
|
||||
metadata
|
||||
);
|
||||
}
|
||||
|
||||
GetVideo(
|
||||
request: DeepPartial<GetVideoRequest>,
|
||||
metadata?: grpc.Metadata
|
||||
|
@ -1086,6 +1355,28 @@ export const MediaSetServiceGetPeaksForSegmentDesc: UnaryMethodDefinitionish = {
|
|||
} as any,
|
||||
};
|
||||
|
||||
export const MediaSetServiceGetAudioSegmentDesc: UnaryMethodDefinitionish = {
|
||||
methodName: "GetAudioSegment",
|
||||
service: MediaSetServiceDesc,
|
||||
requestStream: false,
|
||||
responseStream: true,
|
||||
requestType: {
|
||||
serializeBinary() {
|
||||
return GetAudioSegmentRequest.encode(this).finish();
|
||||
},
|
||||
} as any,
|
||||
responseType: {
|
||||
deserializeBinary(data: Uint8Array) {
|
||||
return {
|
||||
...GetAudioSegmentProgress.decode(data),
|
||||
toObject() {
|
||||
return this;
|
||||
},
|
||||
};
|
||||
},
|
||||
} as any,
|
||||
};
|
||||
|
||||
export const MediaSetServiceGetVideoDesc: UnaryMethodDefinitionish = {
|
||||
methodName: "GetVideo",
|
||||
service: MediaSetServiceDesc,
|
||||
|
|
|
@ -17,6 +17,9 @@ var global = Function('return this')();
|
|||
|
||||
var google_protobuf_duration_pb = require('google-protobuf/google/protobuf/duration_pb.js');
|
||||
goog.object.extend(proto, google_protobuf_duration_pb);
|
||||
goog.exportSymbol('proto.media_set.AudioFormat', null, global);
|
||||
goog.exportSymbol('proto.media_set.GetAudioSegmentProgress', null, global);
|
||||
goog.exportSymbol('proto.media_set.GetAudioSegmentRequest', null, global);
|
||||
goog.exportSymbol('proto.media_set.GetPeaksForSegmentRequest', null, global);
|
||||
goog.exportSymbol('proto.media_set.GetPeaksForSegmentResponse', null, global);
|
||||
goog.exportSymbol('proto.media_set.GetPeaksProgress', null, global);
|
||||
|
@ -153,6 +156,48 @@ if (goog.DEBUG && !COMPILED) {
|
|||
*/
|
||||
proto.media_set.GetPeaksForSegmentResponse.displayName = 'proto.media_set.GetPeaksForSegmentResponse';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.media_set.GetAudioSegmentRequest, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.displayName = 'proto.media_set.GetAudioSegmentRequest';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.media_set.GetAudioSegmentProgress, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.displayName = 'proto.media_set.GetAudioSegmentProgress';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
|
@ -1577,6 +1622,470 @@ proto.media_set.GetPeaksForSegmentResponse.prototype.clearPeaksList = function()
|
|||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.media_set.GetAudioSegmentRequest.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.media_set.GetAudioSegmentRequest} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
id: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
startFrame: jspb.Message.getFieldWithDefault(msg, 2, 0),
|
||||
endFrame: jspb.Message.getFieldWithDefault(msg, 3, 0),
|
||||
format: jspb.Message.getFieldWithDefault(msg, 4, 0)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.media_set.GetAudioSegmentRequest}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.media_set.GetAudioSegmentRequest;
|
||||
return proto.media_set.GetAudioSegmentRequest.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.media_set.GetAudioSegmentRequest} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.media_set.GetAudioSegmentRequest}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setId(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {number} */ (reader.readInt64());
|
||||
msg.setStartFrame(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {number} */ (reader.readInt64());
|
||||
msg.setEndFrame(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {!proto.media_set.AudioFormat} */ (reader.readEnum());
|
||||
msg.setFormat(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.media_set.GetAudioSegmentRequest.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.media_set.GetAudioSegmentRequest} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getId();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getStartFrame();
|
||||
if (f !== 0) {
|
||||
writer.writeInt64(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getEndFrame();
|
||||
if (f !== 0) {
|
||||
writer.writeInt64(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getFormat();
|
||||
if (f !== 0.0) {
|
||||
writer.writeEnum(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string id = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.getId = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.media_set.GetAudioSegmentRequest} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.setId = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional int64 start_frame = 2;
|
||||
* @return {number}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.getStartFrame = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @return {!proto.media_set.GetAudioSegmentRequest} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.setStartFrame = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional int64 end_frame = 3;
|
||||
* @return {number}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.getEndFrame = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @return {!proto.media_set.GetAudioSegmentRequest} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.setEndFrame = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional AudioFormat format = 4;
|
||||
* @return {!proto.media_set.AudioFormat}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.getFormat = function() {
|
||||
return /** @type {!proto.media_set.AudioFormat} */ (jspb.Message.getFieldWithDefault(this, 4, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.media_set.AudioFormat} value
|
||||
* @return {!proto.media_set.GetAudioSegmentRequest} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentRequest.prototype.setFormat = function(value) {
|
||||
return jspb.Message.setProto3EnumField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.media_set.GetAudioSegmentProgress.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.media_set.GetAudioSegmentProgress} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
mimeType: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
message: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
percentComplete: jspb.Message.getFloatingPointFieldWithDefault(msg, 3, 0.0),
|
||||
audioData: msg.getAudioData_asB64()
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.media_set.GetAudioSegmentProgress}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.media_set.GetAudioSegmentProgress;
|
||||
return proto.media_set.GetAudioSegmentProgress.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.media_set.GetAudioSegmentProgress} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.media_set.GetAudioSegmentProgress}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMimeType(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMessage(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {number} */ (reader.readFloat());
|
||||
msg.setPercentComplete(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {!Uint8Array} */ (reader.readBytes());
|
||||
msg.setAudioData(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.media_set.GetAudioSegmentProgress.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.media_set.GetAudioSegmentProgress} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getMimeType();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getMessage();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getPercentComplete();
|
||||
if (f !== 0.0) {
|
||||
writer.writeFloat(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getAudioData_asU8();
|
||||
if (f.length > 0) {
|
||||
writer.writeBytes(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string mime_type = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.getMimeType = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.media_set.GetAudioSegmentProgress} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.setMimeType = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string message = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.getMessage = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.media_set.GetAudioSegmentProgress} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.setMessage = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional float percent_complete = 3;
|
||||
* @return {number}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.getPercentComplete = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFloatingPointFieldWithDefault(this, 3, 0.0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @return {!proto.media_set.GetAudioSegmentProgress} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.setPercentComplete = function(value) {
|
||||
return jspb.Message.setProto3FloatField(this, 3, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bytes audio_data = 4;
|
||||
* @return {!(string|Uint8Array)}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.getAudioData = function() {
|
||||
return /** @type {!(string|Uint8Array)} */ (jspb.Message.getFieldWithDefault(this, 4, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bytes audio_data = 4;
|
||||
* This is a type-conversion wrapper around `getAudioData()`
|
||||
* @return {string}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.getAudioData_asB64 = function() {
|
||||
return /** @type {string} */ (jspb.Message.bytesAsB64(
|
||||
this.getAudioData()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bytes audio_data = 4;
|
||||
* Note that Uint8Array is not supported on all browsers.
|
||||
* @see http://caniuse.com/Uint8Array
|
||||
* This is a type-conversion wrapper around `getAudioData()`
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.getAudioData_asU8 = function() {
|
||||
return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8(
|
||||
this.getAudioData()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!(string|Uint8Array)} value
|
||||
* @return {!proto.media_set.GetAudioSegmentProgress} returns this
|
||||
*/
|
||||
proto.media_set.GetAudioSegmentProgress.prototype.setAudioData = function(value) {
|
||||
return jspb.Message.setProto3BytesField(this, 4, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
|
@ -2208,4 +2717,12 @@ proto.media_set.GetVideoThumbnailResponse.prototype.setHeight = function(value)
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
proto.media_set.AudioFormat = {
|
||||
WAV: 0,
|
||||
MP3: 1
|
||||
};
|
||||
|
||||
goog.object.extend(exports, proto.media_set);
|
||||
|
|
|
@ -2056,6 +2056,11 @@
|
|||
anymatch "^3.0.0"
|
||||
source-map "^0.6.0"
|
||||
|
||||
"@types/wicg-file-system-access@^2020.9.4":
|
||||
version "2020.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/wicg-file-system-access/-/wicg-file-system-access-2020.9.4.tgz#83f255d6bd20b0ae131d555693473d15a0574e92"
|
||||
integrity sha512-o43jUljwP0ZrQ927mPjGdJaBMfS12nf3VPj6Z52fMucxILrSs8tnfLbMDSn6cP3hrrLChc3SYneeEvecknNVtA==
|
||||
|
||||
"@types/yargs-parser@*":
|
||||
version "20.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
|
||||
|
|
|
@ -49,6 +49,23 @@ message GetPeaksForSegmentResponse {
|
|||
repeated int32 peaks = 1;
|
||||
}
|
||||
|
||||
enum AudioFormat {
|
||||
WAV = 0;
|
||||
MP3 = 1;
|
||||
}
|
||||
|
||||
message GetAudioSegmentRequest {
|
||||
string id = 1;
|
||||
int64 start_frame = 2;
|
||||
int64 end_frame = 3;
|
||||
AudioFormat format = 4;
|
||||
}
|
||||
|
||||
message GetAudioSegmentProgress {
|
||||
float percent_complete = 3;
|
||||
bytes audio_data = 4;
|
||||
}
|
||||
|
||||
message GetVideoRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
@ -72,6 +89,7 @@ service MediaSetService {
|
|||
rpc Get(GetRequest) returns (MediaSet) {}
|
||||
rpc GetPeaks(GetPeaksRequest) returns (stream GetPeaksProgress) {}
|
||||
rpc GetPeaksForSegment(GetPeaksForSegmentRequest) returns (GetPeaksForSegmentResponse) {}
|
||||
rpc GetAudioSegment(GetAudioSegmentRequest) returns (stream GetAudioSegmentProgress) {}
|
||||
rpc GetVideo(GetVideoRequest) returns (stream GetVideoProgress) {}
|
||||
rpc GetVideoThumbnail(GetVideoThumbnailRequest) returns (GetVideoThumbnailResponse) {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue