package video import ( "bytes" "errors" "io" "github.com/sunfish-shogi/bufseekio" ) // Chunks represents a list of file chunks. type Chunks []Chunk // Contains tests if the chunk is contained in this list. func (c Chunks) Contains(s [4]byte) bool { if len(c) == 0 { return false } // Find matches. for i := range c { if s == c[i] { return true } } return false } // ContainsAny checks if at least one common chunk exists in this list. func (c Chunks) ContainsAny(b [][4]byte) bool { if len(c) == 0 || len(b) == 0 { return false } // Find matches. for i := range c { for j := range b { if b[j] == c[i] { return true } } } // Not found. return false } // FileTypeOffset returns the file type start offset in f, or -1 if it was not found. func (c Chunks) FileTypeOffset(file io.ReadSeeker) (int, error) { if file == nil { return -1, errors.New("file is nil") } ftyp := ChunkFTYP.Bytes() blockSize := 128 * 1024 buffer := make([]byte, blockSize) // Create buffered read seeker. r := bufseekio.NewReadSeeker(file, blockSize, 8) // Index offset. var offset int // Search in batches. for { n, err := r.Read(buffer) buffer = buffer[:n] if err != nil { if err != io.EOF { return -1, err } break } else if n == 0 { break } // Find ftyp chunk. if i := bytes.Index(buffer, ftyp); i < 0 { // Not found. } else if j := i + 4; j < 8 || len(buffer) < j+4 { // Skip. } else if k := j + 4; c.Contains(*(*[4]byte)(buffer[j:k])) { return offset + i - 4, nil } offset += n } return -1, nil }