package main import ( "bytes" "encoding/binary" "fmt" "io" "log" "os" "reader/internal/processor" "github.com/bluenviron/gortsplib/v4/pkg/format" ) //port := 8080 // //http.HandleFunc("GET /download", handlers.Download) // example request: {"date": "07-03-2025", "start_time": "16-43", "end_time": "16-44"} //http.HandleFunc("GET /hls/", handlers.HLS) // //log.Println("Starting server on:") //log.Printf("Serving on HTTP port: %d\n", port) // //log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) // Интерпретируем типы пакетов: const ( PacketTypeH264 = 1 PacketTypeLPCM = 2 ) var ( h264 string g711 string ) // InterleavedPacket описывает пакет, который может быть либо H264, либо G711. type InterleavedPacket struct { Type byte Pts int64 H264AUs [][]byte // для H264 LPCMSamples []byte // для G711 } // Segment содержит строки Start и Duration, а также набор пакетов. type Segment struct { Start string Duration string Packets []InterleavedPacket } // readString читает строку: сначала длину (int32), затем данные строки. func readString(r io.Reader) (string, error) { var length int32 if err := binary.Read(r, binary.LittleEndian, &length); err != nil { return "", err } buf := make([]byte, length) if _, err := io.ReadFull(r, buf); err != nil { return "", err } return string(buf), nil } // readHeaderSegment читает сегмент, записанный функцией WriteHeader (с Start и Duration). func readHeaderSegment(r io.Reader) (Segment, error) { var seg Segment start, err := readString(r) if err != nil { return seg, err } seg.Start = start duration, err := readString(r) if err != nil { return seg, err } seg.Duration = duration return seg, nil } // readPacket читает один interleaved пакет. func readPacket(r io.Reader) (InterleavedPacket, error) { var pkt InterleavedPacket // Читаем тип пакета (1 байт). typeByte := make([]byte, 1) if _, err := io.ReadFull(r, typeByte); err != nil { return pkt, err } pkt.Type = typeByte[0] // Читаем pts (int64). if err := binary.Read(r, binary.LittleEndian, &pkt.Pts); err != nil { return pkt, err } // В зависимости от типа, читаем данные. if pkt.Type == PacketTypeH264 { var numAUs int32 if err := binary.Read(r, binary.LittleEndian, &numAUs); err != nil { return pkt, err } var auList [][]byte for i := 0; i < int(numAUs); i++ { var auLen int32 if err := binary.Read(r, binary.LittleEndian, &auLen); err != nil { return pkt, err } auData := make([]byte, auLen) if _, err := io.ReadFull(r, auData); err != nil { return pkt, err } auList = append(auList, auData) } pkt.H264AUs = auList } else if pkt.Type == PacketTypeLPCM { var auLen int32 if err := binary.Read(r, binary.LittleEndian, &auLen); err != nil { return pkt, err } auData := make([]byte, auLen) if _, err := io.ReadFull(r, auData); err != nil { return pkt, err } pkt.LPCMSamples = auData } else { return pkt, fmt.Errorf("неизвестный тип пакета: %d", pkt.Type) } return pkt, nil } // readPacketSegment читает сегмент, записанный функцией WriteInterleavedPacket: // сначала число пакетов (int32), затем каждый пакет. func readPacketSegment(r io.Reader) ([]InterleavedPacket, error) { var numPackets int32 if err := binary.Read(r, binary.LittleEndian, &numPackets); err != nil { return nil, err } var packets []InterleavedPacket for i := 0; i < int(numPackets); i++ { pkt, err := readPacket(r) if err != nil { return nil, err } packets = append(packets, pkt) } return packets, nil } func main() { filename := "/home/psa/GoRepository/data/camera44-center-skver_temnika/12-10-00_21-03-2025.insit" segment := Segment{} // Открываем файл для чтения. f, err := os.Open(filename) if err != nil { fmt.Println("Ошибка открытия файла:", err) return } defer f.Close() // Читаем streamID (первые 4 байта — длина, затем сами байты). var streamIDLen int32 if err := binary.Read(f, binary.LittleEndian, &streamIDLen); err != nil { fmt.Println("Ошибка чтения streamID длины:", err) return } streamIDBytes := make([]byte, streamIDLen) if _, err := io.ReadFull(f, streamIDBytes); err != nil { fmt.Println("Ошибка чтения streamID:", err) return } streamID := string(streamIDBytes) fmt.Println("Stream ID:", streamID) // Теперь в файле идут сегменты. Первый сегмент — заголовочный, далее — сегменты с пакетами. // Читаем первый сегмент как заголовочный. var segLen int32 if err := binary.Read(f, binary.LittleEndian, &segLen); err != nil { fmt.Println("Ошибка чтения длины заголовочного сегмента:", err) return } segData := make([]byte, segLen) if _, err := io.ReadFull(f, segData); err != nil { fmt.Println("Ошибка чтения заголовочного сегмента:", err) return } headerReader := bytes.NewReader(segData) headerSeg, err := readHeaderSegment(headerReader) if err != nil { fmt.Println("Ошибка чтения заголовочного сегмента:", err) return } fmt.Println("Заголовочный сегмент:") fmt.Println("\tStart:", headerSeg.Start) fmt.Println("\tDuration:", headerSeg.Duration) segment = headerSeg // Setup MPEG-TS muxer. var h264Format format.H264 var aacFormat *format.MPEG4Audio h264Format.PayloadTyp = 96 h264Format.PacketizationMode = 1 currentMpegtsMuxer := processor.MpegtsMuxer{ FileName: segment.Start + "_videoFragment" + "_0" + ".ts", H264Format: &h264Format, Mpeg4AudioFormat: aacFormat, } err = currentMpegtsMuxer.Initialize() if err != nil { fmt.Printf("[%v-%v]: init muxer error: %w\n", h264, g711, err) } // Читаем последующие сегменты, содержащие пакеты. segmentIndex := 1 for { var segLen int32 err := binary.Read(f, binary.LittleEndian, &segLen) if err != nil { if err == io.EOF { break // достигнут конец файла } fmt.Println("Ошибка чтения длины сегмента:", err) return } segData = make([]byte, segLen) if _, err := io.ReadFull(f, segData); err != nil { fmt.Println("Ошибка чтения данных сегмента:", err) return } packetReader := bytes.NewReader(segData) packets, err := readPacketSegment(packetReader) if err != nil { fmt.Println("Ошибка чтения сегмента пакетов:", err) return } segment.Packets = append(segment.Packets, packets...) fmt.Printf("Сегмент пакетов #%d:\n", segmentIndex) for _, pkt := range packets { switch pkt.Type { case PacketTypeH264: h264 = "h264" err = currentMpegtsMuxer.WriteH264(pkt.Pts, pkt.H264AUs) if err != nil { log.Printf("write h264 packet error: %v\n", err) } case PacketTypeLPCM: g711 = "g711" // Convert G711 to AAC. au, err := processor.ConvertLPCMToAAC(pkt.LPCMSamples) if err != nil { log.Printf("converting to AAC frame error: %v\n", err) } // Encode the access unit into MPEG-TS. err = currentMpegtsMuxer.WriteAAC([][]byte{au}, pkt.Pts) if err != nil { return } } } segmentIndex++ } currentMpegtsMuxer.Close() }