gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

mp4.go (3530B)


      1 package mp4
      2 
      3 import (
      4 	"errors"
      5 	"fmt"
      6 	"reflect"
      7 	"strings"
      8 )
      9 
     10 var ErrBoxInfoNotFound = errors.New("box info not found")
     11 
     12 // BoxType is mpeg box type
     13 type BoxType [4]byte
     14 
     15 func StrToBoxType(code string) BoxType {
     16 	if len(code) != 4 {
     17 		panic(fmt.Errorf("invalid box type id length: [%s]", code))
     18 	}
     19 	return BoxType{code[0], code[1], code[2], code[3]}
     20 }
     21 
     22 func (boxType BoxType) String() string {
     23 	if isPrintable(boxType[0]) && isPrintable(boxType[1]) && isPrintable(boxType[2]) && isPrintable(boxType[3]) {
     24 		s := string([]byte{boxType[0], boxType[1], boxType[2], boxType[3]})
     25 		s = strings.ReplaceAll(s, string([]byte{0xa9}), "(c)")
     26 		return s
     27 	}
     28 	return fmt.Sprintf("0x%02x%02x%02x%02x", boxType[0], boxType[1], boxType[2], boxType[3])
     29 }
     30 
     31 func isASCII(c byte) bool {
     32 	return c >= 0x20 && c <= 0x7e
     33 }
     34 
     35 func isPrintable(c byte) bool {
     36 	return isASCII(c) || c == 0xa9
     37 }
     38 
     39 func (lhs BoxType) MatchWith(rhs BoxType) bool {
     40 	if lhs == boxTypeAny || rhs == boxTypeAny {
     41 		return true
     42 	}
     43 	return lhs == rhs
     44 }
     45 
     46 var boxTypeAny = BoxType{0x00, 0x00, 0x00, 0x00}
     47 
     48 func BoxTypeAny() BoxType {
     49 	return boxTypeAny
     50 }
     51 
     52 type boxDef struct {
     53 	dataType reflect.Type
     54 	versions []uint8
     55 	isTarget func(Context) bool
     56 	fields   []*field
     57 }
     58 
     59 var boxMap = make(map[BoxType][]boxDef, 64)
     60 
     61 func AddBoxDef(payload IBox, versions ...uint8) {
     62 	boxMap[payload.GetType()] = append(boxMap[payload.GetType()], boxDef{
     63 		dataType: reflect.TypeOf(payload).Elem(),
     64 		versions: versions,
     65 		fields:   buildFields(payload),
     66 	})
     67 }
     68 
     69 func AddBoxDefEx(payload IBox, isTarget func(Context) bool, versions ...uint8) {
     70 	boxMap[payload.GetType()] = append(boxMap[payload.GetType()], boxDef{
     71 		dataType: reflect.TypeOf(payload).Elem(),
     72 		versions: versions,
     73 		isTarget: isTarget,
     74 		fields:   buildFields(payload),
     75 	})
     76 }
     77 
     78 func AddAnyTypeBoxDef(payload IAnyType, boxType BoxType, versions ...uint8) {
     79 	boxMap[boxType] = append(boxMap[boxType], boxDef{
     80 		dataType: reflect.TypeOf(payload).Elem(),
     81 		versions: versions,
     82 		fields:   buildFields(payload),
     83 	})
     84 }
     85 
     86 func AddAnyTypeBoxDefEx(payload IAnyType, boxType BoxType, isTarget func(Context) bool, versions ...uint8) {
     87 	boxMap[boxType] = append(boxMap[boxType], boxDef{
     88 		dataType: reflect.TypeOf(payload).Elem(),
     89 		versions: versions,
     90 		isTarget: isTarget,
     91 		fields:   buildFields(payload),
     92 	})
     93 }
     94 
     95 func (boxType BoxType) getBoxDef(ctx Context) *boxDef {
     96 	boxDefs := boxMap[boxType]
     97 	for i := len(boxDefs) - 1; i >= 0; i-- {
     98 		boxDef := &boxDefs[i]
     99 		if boxDef.isTarget == nil || boxDef.isTarget(ctx) {
    100 			return boxDef
    101 		}
    102 	}
    103 	return nil
    104 }
    105 
    106 func (boxType BoxType) IsSupported(ctx Context) bool {
    107 	return boxType.getBoxDef(ctx) != nil
    108 }
    109 
    110 func (boxType BoxType) New(ctx Context) (IBox, error) {
    111 	boxDef := boxType.getBoxDef(ctx)
    112 	if boxDef == nil {
    113 		return nil, ErrBoxInfoNotFound
    114 	}
    115 
    116 	box, ok := reflect.New(boxDef.dataType).Interface().(IBox)
    117 	if !ok {
    118 		return nil, fmt.Errorf("box type not implements IBox interface: %s", boxType.String())
    119 	}
    120 
    121 	anyTypeBox, ok := box.(IAnyType)
    122 	if ok {
    123 		anyTypeBox.SetType(boxType)
    124 	}
    125 
    126 	return box, nil
    127 }
    128 
    129 func (boxType BoxType) GetSupportedVersions(ctx Context) ([]uint8, error) {
    130 	boxDef := boxType.getBoxDef(ctx)
    131 	if boxDef == nil {
    132 		return nil, ErrBoxInfoNotFound
    133 	}
    134 	return boxDef.versions, nil
    135 }
    136 
    137 func (boxType BoxType) IsSupportedVersion(ver uint8, ctx Context) bool {
    138 	boxDef := boxType.getBoxDef(ctx)
    139 	if boxDef == nil {
    140 		return false
    141 	}
    142 	if len(boxDef.versions) == 0 {
    143 		return true
    144 	}
    145 	for _, sver := range boxDef.versions {
    146 		if ver == sver {
    147 			return true
    148 		}
    149 	}
    150 	return false
    151 }