2025-03-25 16:19:46 +05:00

127 lines
3.2 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 storage
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
// Constants for detection video and audio types.
const (
PacketTypeAV1 = 1
PacketTypeH264 = 2
PacketTypeH265 = 3
PacketTypeMJPEG = 4
PacketTypeVP8 = 5
PacketTypeVP9 = 6
PacketTypeG711 = 21
PacketTypeAAC = 22
PacketTypeLPCM = 23
PacketTypeOPUS = 24
)
// InterleavedPacket is the structure of each inner packet.
type InterleavedPacket struct {
Type byte
Pts int64
H264AUs [][]byte
LPCMSamples []byte
}
// Segment is overall structure according to each period.
type Segment struct {
Date string
Duration string
Packet InterleavedPacket
Packets []InterleavedPacket
}
// writeString записывает строку: сначала int32 длина, затем данные.
func writeString(w io.Writer, s string) error {
if err := binary.Write(w, binary.LittleEndian, int32(len(s))); err != nil {
return err
}
_, err := w.Write([]byte(s))
return err
}
// WritePacket записывает один interleaved пакет.
func WritePacket(w io.Writer, pkt InterleavedPacket) error {
// Записываем тип пакета (1 байт)
if err := binary.Write(w, binary.LittleEndian, pkt.Type); err != nil {
return err
}
// Записываем pts (int64)
if err := binary.Write(w, binary.LittleEndian, pkt.Pts); err != nil {
return err
}
if pkt.Type == PacketTypeH264 {
// Для H264 AU как [][]byte.
numAUs := int32(len(pkt.H264AUs))
if err := binary.Write(w, binary.LittleEndian, numAUs); err != nil {
return err
}
for _, au := range pkt.H264AUs {
if err := binary.Write(w, binary.LittleEndian, int32(len(au))); err != nil {
return err
}
if _, err := w.Write(au); err != nil {
return err
}
}
} else if pkt.Type == PacketTypeLPCM {
// Для LPCM просто длина и данные.
if err := binary.Write(w, binary.LittleEndian, int32(len(pkt.LPCMSamples))); err != nil {
return err
}
if _, err := w.Write(pkt.LPCMSamples); err != nil {
return err
}
} else {
return fmt.Errorf("неизвестный тип пакета: %d", pkt.Type)
}
return nil
}
// WriteHeader записывает заголовок сегмента (Start и Duration).
func WriteHeader(w io.Writer, seg Segment) error {
var buf bytes.Buffer
if err := writeString(&buf, seg.Date); err != nil {
return err
}
if err := writeString(&buf, seg.Duration); err != nil {
return err
}
segData := buf.Bytes()
if err := binary.Write(w, binary.LittleEndian, int32(len(segData))); err != nil {
return err
}
_, err := w.Write(segData)
return err
}
// WriteInterleavedPacket записывает сегмент с пакетами.
// Теперь количество пакетов определяется динамически.
func WriteInterleavedPacket(w io.Writer, seg Segment) error {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.LittleEndian, int32(1)); err != nil {
return err
}
// Записываем каждый пакет.
if err := WritePacket(&buf, seg.Packet); err != nil {
return err
}
segData := buf.Bytes()
if err := binary.Write(w, binary.LittleEndian, int32(len(segData))); err != nil {
return err
}
_, err := w.Write(segData)
return err
}