You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: tag_video.go
    path of file: ./repos/bililive-go/src/pkg/parser/native/flv
    
    the code of the file until where you have to start completion: package flv

import (
	"context"
	"errors"
)

type (
	FrameType     uint8
	CodeID        uint8
	AVCPacketType uint8

	VideoTagHeader struct {
		FrameType       FrameType
		CodeID          CodeID
		AVCPacketType   AVCPacketType
		CompositionTime uint32
	}
)

const (
	// Frame Type
	KeyFrame             FrameType = 1 // for AVC, a seekable frame
	
    
func (p *Parser) parseVideoTag(ctx context.Context, length, timestamp uint32) (*VideoTagHeader, error) {
	// header
	b, err := p.i.ReadByte()
	l := length - 1
	if err != nil {
		return nil, err
	}
	tag := new(VideoTagHeader)
	tag.FrameType = FrameType(b >> 4 & 15)
	tag.CodeID = CodeID(b & 15)

	if tag.CodeID == AVCCode {
		// read AVCPacketType
		b, err := p.i.ReadByte()
		l -= 1
		if err != nil {
			return nil, err
		}
		tag.AVCPacketType = AVCPacketType(b)
		switch tag.AVCPacketType {
		case AVCNALU:
			// read CompositionTime
			b, err := p.i.ReadN(3)
			l -= 3
			if err != nil {
				return nil, err
			}
			tag.CompositionTime = uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2])
		case AVCSeqHeader:
			p.avcHeaderCount++
			if p.avcHeaderCount > 1 {
				// new sps pps
				return nil, errors.New("EOF new sps pps")
			}
		}
	}

	// write tag header && video tag header & AVCPacketType & CompositionTime
	if err := p.doWrite(ctx, p.i.AllBytes()); err != nil {
		return nil, err
	}
	p.i.Reset()
	// write body
	if err := p.doCopy(ctx, l); err != nil {
		return nil, err
	}

	return tag, nil
}