full_intra_request.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package rtcp
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. )
  6. // A FIREntry is a (SSRC, seqno) pair, as carried by FullIntraRequest.
  7. type FIREntry struct {
  8. SSRC uint32
  9. SequenceNumber uint8
  10. }
  11. // The FullIntraRequest packet is used to reliably request an Intra frame
  12. // in a video stream. See RFC 5104 Section 3.5.1. This is not for loss
  13. // recovery, which should use PictureLossIndication (PLI) instead.
  14. type FullIntraRequest struct {
  15. SenderSSRC uint32
  16. MediaSSRC uint32
  17. FIR []FIREntry
  18. }
  19. const (
  20. firOffset = 8
  21. )
  22. var _ Packet = (*FullIntraRequest)(nil)
  23. // Marshal encodes the FullIntraRequest
  24. func (p FullIntraRequest) Marshal() ([]byte, error) {
  25. rawPacket := make([]byte, firOffset+(len(p.FIR)*8))
  26. binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
  27. binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
  28. for i, fir := range p.FIR {
  29. binary.BigEndian.PutUint32(rawPacket[firOffset+8*i:], fir.SSRC)
  30. rawPacket[firOffset+8*i+4] = fir.SequenceNumber
  31. }
  32. h := p.Header()
  33. hData, err := h.Marshal()
  34. if err != nil {
  35. return nil, err
  36. }
  37. return append(hData, rawPacket...), nil
  38. }
  39. // Unmarshal decodes the TransportLayerNack
  40. func (p *FullIntraRequest) Unmarshal(rawPacket []byte) error {
  41. if len(rawPacket) < (headerLength + ssrcLength) {
  42. return errPacketTooShort
  43. }
  44. var h Header
  45. if err := h.Unmarshal(rawPacket); err != nil {
  46. return err
  47. }
  48. if len(rawPacket) < (headerLength + int(4*h.Length)) {
  49. return errPacketTooShort
  50. }
  51. if h.Type != TypePayloadSpecificFeedback || h.Count != FormatFIR {
  52. return errWrongType
  53. }
  54. p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
  55. p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
  56. for i := headerLength + firOffset; i < (headerLength + int(h.Length*4)); i += 8 {
  57. p.FIR = append(p.FIR, FIREntry{
  58. binary.BigEndian.Uint32(rawPacket[i:]),
  59. rawPacket[i+4],
  60. })
  61. }
  62. return nil
  63. }
  64. // Header returns the Header associated with this packet.
  65. func (p *FullIntraRequest) Header() Header {
  66. return Header{
  67. Count: FormatFIR,
  68. Type: TypePayloadSpecificFeedback,
  69. Length: uint16((p.len() / 4) - 1),
  70. }
  71. }
  72. func (p *FullIntraRequest) len() int {
  73. return headerLength + firOffset + len(p.FIR)*8
  74. }
  75. func (p *FullIntraRequest) String() string {
  76. out := fmt.Sprintf("FullIntraRequest %x %x",
  77. p.SenderSSRC, p.MediaSSRC)
  78. for _, e := range p.FIR {
  79. out += fmt.Sprintf(" (%x %v)", e.SSRC, e.SequenceNumber)
  80. }
  81. return out
  82. }
  83. // DestinationSSRC returns an array of SSRC values that this packet refers to.
  84. func (p *FullIntraRequest) DestinationSSRC() []uint32 {
  85. ssrcs := make([]uint32, 0, len(p.FIR))
  86. for _, entry := range p.FIR {
  87. ssrcs = append(ssrcs, entry.SSRC)
  88. }
  89. return ssrcs
  90. }