github.com/cnotch/ipchub@v1.1.0/av/format/flv/flv.go (about)

     1  // Copyright (c) 2019,CAOHONGJU All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package flv
     6  
     7  import (
     8  	"encoding/binary"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  )
    13  
    14  // flv Header Size, total is 9Byte.
    15  // 	Signatures	3Byte	'FLV' = 0x46 0x4c 0x56
    16  // 	Version		1Byte	0x01
    17  // 	TypeFlags	1Byte 	bit0:audio bit2:video
    18  // 	DataOffset	4Byte	FLV Header Length
    19  const (
    20  	FlvHeaderSize   = 9
    21  	TypeFlagsVideo  = 0x04
    22  	TypeFlagsAudio  = 0x01
    23  	TypeFlagsOffset = 4
    24  )
    25  
    26  var flvHeaderTemplate = []byte{0x46, 0x4c, 0x56, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09}
    27  
    28  // Reader flv Reader
    29  type Reader struct {
    30  	r      io.Reader
    31  	Header [FlvHeaderSize]byte // flv header
    32  }
    33  
    34  // NewReader .
    35  func NewReader(r io.Reader) (*Reader, error) {
    36  	reader := &Reader{
    37  		r: r,
    38  	}
    39  
    40  	// read flv header
    41  	if _, err := io.ReadFull(r, reader.Header[:]); err != nil {
    42  		return nil, err
    43  	}
    44  	// 简单验证
    45  	if reader.Header[0] != 'F' ||
    46  		reader.Header[1] != 'L' ||
    47  		reader.Header[2] != 'V' {
    48  		return nil, errors.New("Signatures must is 'FLV'")
    49  	}
    50  
    51  	if previousTagSize, err := reader.readTagSize(); err != nil {
    52  		return nil, err
    53  	} else if previousTagSize != 0 {
    54  		return nil, errors.New("First 'PreviousTagSize' must is  0")
    55  	}
    56  
    57  	return reader, nil
    58  }
    59  
    60  func (r *Reader) readTagSize() (tagSize uint32, err error) {
    61  	var buff [4]byte
    62  	if _, err := io.ReadFull(r.r, buff[:]); err != nil {
    63  		return 0, err
    64  	}
    65  
    66  	tagSize = binary.BigEndian.Uint32(buff[:])
    67  	return
    68  }
    69  
    70  // ReadFlvTag read flv tag
    71  func (r *Reader) ReadFlvTag() (*Tag, error) {
    72  
    73  	var tag Tag
    74  	if err := tag.Read(r.r); err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	if tagSize, err := r.readTagSize(); err != nil {
    79  		return nil, err
    80  	} else if tagSize != uint32(tag.Size()) {
    81  		return nil, fmt.Errorf("PreviousTagSize mismatches, expect '%d' but  actual '%d'",
    82  			tag.Size(), tagSize)
    83  	}
    84  	return &tag, nil
    85  }
    86  
    87  // HasVideo flv include video stream.
    88  func (r *Reader) HasVideo() bool {
    89  	return r.Header[TypeFlagsOffset]&TypeFlagsVideo != 0
    90  }
    91  
    92  // HasAudio flv include audio stream.
    93  func (r *Reader) HasAudio() bool {
    94  	return r.Header[TypeFlagsOffset]&TypeFlagsAudio != 0
    95  }
    96  
    97  const uninitializedTimestampDelta = 0xffffffff
    98  
    99  // Writer flv Writer
   100  type Writer struct {
   101  	w              io.Writer
   102  	timestampDelta uint32 // 流在中间输出时的相对时间戳
   103  }
   104  
   105  // NewWriter .
   106  func NewWriter(w io.Writer, typeFlags byte) (*Writer, error) {
   107  	if typeFlags&0x05 == 0 {
   108  		return nil, errors.New("TypeFlags not include any streams")
   109  	}
   110  
   111  	writer := &Writer{
   112  		w:              w,
   113  		timestampDelta: uninitializedTimestampDelta,
   114  	}
   115  
   116  	var flvHeader [FlvHeaderSize]byte
   117  	copy(flvHeader[:], flvHeaderTemplate[:])
   118  	flvHeader[TypeFlagsOffset] = typeFlags & (TypeFlagsVideo | TypeFlagsAudio)
   119  	if _, err := w.Write(flvHeader[:]); err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	if err := writer.writeTagSize(0); err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	return writer, nil
   128  }
   129  
   130  func (w *Writer) writeTagSize(tagSize uint32) error {
   131  	var buff [4]byte
   132  	// write PreviousTagSize
   133  	binary.BigEndian.PutUint32(buff[:], tagSize)
   134  	if _, err := w.w.Write(buff[:]); err != nil {
   135  		return err
   136  	}
   137  	return nil
   138  }
   139  
   140  // WriteFlvTag write flv tag
   141  func (w *Writer) WriteFlvTag(tag *Tag) error {
   142  	// 记录第一个Tag的时间戳
   143  	if w.timestampDelta == uninitializedTimestampDelta {
   144  		w.timestampDelta = tag.Timestamp
   145  	}
   146  
   147  	if err := writeTag(w.w, tag, w.timestampDelta); err != nil {
   148  		return err
   149  	}
   150  
   151  	return w.writeTagSize(uint32(tag.Size()))
   152  }