277 lines
7.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}