Live video on the AT Protocol
79
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v0.9.7 180 lines 3.8 kB view raw
1package main 2 3import ( 4 "encoding/json" 5 "errors" 6 "flag" 7 "fmt" 8 "io" 9 "log" 10 "math" 11 "os" 12 "time" 13 14 "stream.place/streamplace/pkg/rtcrec" 15) 16 17func main() { 18 err := Start() 19 if err != nil { 20 log.Fatal(err) 21 } 22} 23 24func Start() error { 25 if len(os.Args) == 1 { 26 return fmt.Errorf("usage: rtcrec [decode|trim]") 27 } 28 if len(os.Args) > 1 && os.Args[1] == "decode" { 29 return Decode() 30 } 31 if len(os.Args) > 1 && os.Args[1] == "trim" { 32 return Trim() 33 } 34 return fmt.Errorf("unknown command: %s", os.Args[1]) 35} 36 37func Trim() error { 38 var startDuration time.Duration 39 flag.DurationVar(&startDuration, "start", 0, "timestamp where we should start our clip") 40 var endDuration time.Duration 41 flag.DurationVar(&endDuration, "end", 0, "timestamp where we should end our clip") 42 var inPath string 43 flag.StringVar(&inPath, "in-path", "", "path to the file to decode") 44 var outPath string 45 flag.StringVar(&outPath, "out-path", "", "path to the file to write the trimmed file to") 46 err := flag.CommandLine.Parse(os.Args[2:]) 47 if err != nil { 48 return err 49 } 50 if startDuration == 0 && endDuration == 0 { 51 return fmt.Errorf("start or end duration is required (otherwise, you know, the cp command is right there)") 52 } 53 if inPath == "" { 54 return fmt.Errorf("in-path is required") 55 } 56 if outPath == "" { 57 return fmt.Errorf("out-path is required") 58 } 59 inFile, err := os.Open(inPath) 60 if err != nil { 61 return err 62 } 63 defer inFile.Close() 64 outFile, err := os.Create(outPath) 65 if err != nil { 66 return err 67 } 68 defer outFile.Close() 69 dec, err := rtcrec.MakeWebRTCDecoder(inFile) 70 if err != nil { 71 return err 72 } 73 encoder, err := rtcrec.MakeWebRTCEncoder(outFile) 74 if err != nil { 75 return err 76 } 77 var startCutoff *time.Time 78 var endCutoff *time.Time 79 if startDuration == 0 { 80 startCutoff = &time.Time{} 81 } 82 if endDuration == 0 { 83 t := time.Unix(math.MaxInt64/2, 0) // i had it set to max but there were rollover issues 84 endCutoff = &t 85 } 86 included := 0 87 dropped := 0 88 for { 89 ev, err := dec.Next() 90 if errors.Is(err, io.EOF) { 91 break 92 } 93 if startCutoff == nil { 94 t := ev.Time.Add(startDuration) 95 startCutoff = &t 96 } 97 if endCutoff == nil { 98 t := ev.Time.Add(endDuration) 99 endCutoff = &t 100 } 101 // we only rewrite trackread events 102 if ev.TrackRead == nil { 103 if ev.Time.Before(*endCutoff) { 104 // included++ 105 encoder.Event(*ev) 106 } 107 continue 108 } 109 // fmt.Printf("ev.Time: %+v, startCutoff: %+v, endCutoff: %+v\n", ev.Time, *startCutoff, *endCutoff) 110 if ev.Time.Before(*startCutoff) { 111 dropped++ 112 continue 113 } 114 included++ 115 ev.Time = ev.Time.Add(-startDuration) 116 encoder.Event(*ev) 117 } 118 fmt.Printf("included: %d, dropped: %d\n", included, dropped) 119 return nil 120} 121 122func Decode() error { 123 var path string 124 flag.StringVar(&path, "path", "", "path to the file to decode") 125 err := flag.CommandLine.Parse(os.Args[2:]) 126 if err != nil { 127 return err 128 } 129 if path == "" { 130 return fmt.Errorf("path is required") 131 } 132 return DecodeFile(path) 133} 134 135func DecodeFile(path string) error { 136 f, err := os.Open(path) 137 if err != nil { 138 return err 139 } 140 defer f.Close() 141 dec, err := rtcrec.MakeWebRTCDecoder(f) 142 if err != nil { 143 return err 144 } 145 for { 146 ev, err := dec.Next() 147 if errors.Is(err, io.EOF) { 148 return nil 149 } 150 if err != nil { 151 return err 152 } 153 if ev.TrackRead != nil { 154 // spitting out the data as base64 is pointless, replace with a label 155 n := len(ev.TrackRead.Data) 156 byteString := fmt.Sprintf("%d bytes", n) 157 bs, err := json.Marshal(ev) 158 if err != nil { 159 return err 160 } 161 var m map[string]any 162 err = json.Unmarshal(bs, &m) 163 if err != nil { 164 return err 165 } 166 m["trackRead"].(map[string]any)["data"] = byteString 167 bs, err = json.Marshal(m) 168 if err != nil { 169 return err 170 } 171 fmt.Println(string(bs)) 172 } else { 173 bs, err := json.Marshal(ev) 174 if err != nil { 175 return err 176 } 177 fmt.Println(string(bs)) 178 } 179 } 180}