func convertShard(opts pam.WriteOpts, pamPath string, in bamprovider.Provider, startShard, limitShard bamShardBound) (int64, error) {
	header, e := in.GetHeader()
	if e != nil {
		return 0, e
	}
	getRef := func(id int32) *sam.Reference {
		if id == biopb.UnmappedRefID {
			return nil
		}
		return header.Refs()[id]
	}
	iter := in.NewIterator(gbam.Shard{
		StartRef: getRef(startShard.rec.RefId),
		Start:    int(startShard.rec.Pos),
		EndRef:   getRef(limitShard.rec.RefId),
		End:      int(limitShard.rec.Pos),
	})
	opts.Range = biopb.CoordRange{Start: startShard.rec, Limit: limitShard.rec}
	w := pam.NewWriter(opts, header, pamPath)
	err := errors.Once{}
	var nRecs int64
	for iter.Scan() {
		rec := iter.Record()
		w.Write(rec)
		if w.Err() != nil {
			break
		}
		nRecs++
		sam.PutInFreePool(rec)
	}
	err.Set(iter.Close())
	err.Set(w.Close())
	vlog.Infof("%v: Finished converting [%+v, %+v) with %d recs read: %v",
		pamPath, startShard, limitShard, nRecs, err.Err())
	return nRecs, err.Err()
}
convertShard converts range [startShard, limitShard) of the BAM file to
PAM. Returns the number of sam.Records converted.
package converter
import (
	"fmt"
	"math"
	"runtime"
	"sort"
	"sync"
	"sync/atomic"
	"github.com/grailbio/base/errors"
	"github.com/grailbio/base/file"
	"github.com/grailbio/base/traverse"
	"github.com/grailbio/base/vcontext"
	"github.com/grailbio/bio/biopb"
	gbam "github.com/grailbio/bio/encoding/bam"
	"github.com/grailbio/bio/encoding/bamprovider"
	"github.com/grailbio/bio/encoding/pam"
	"github.com/grailbio/bio/encoding/pam/pamutil"
	"github.com/grailbio/hts/bam"
	"github.com/grailbio/hts/bgzf"
	"github.com/grailbio/hts/sam"
	"github.com/klauspost/compress/gzip"
	"v.io/x/lib/vlog"
)
type bamShardBound struct {
	rec biopb.Coord
	off bgzf.Offset
}
func generateShardBoundaries(bamPath, baiPath string, bytesPerShard int64) ([]bamShardBound, error) {
	ctx := vcontext.Background()
	bamIn, err := file.Open(ctx, bamPath)
	if err != nil {
		return nil, err
	}
	defer bamIn.Close(ctx)
	bamr, err := bam.NewReader(bamIn.Reader(ctx), 1)
	if err != nil {
		return nil, err
	}
	indexIn, err := file.Open(ctx, baiPath)
	if err != nil {
		return nil, err
	}
	defer indexIn.Close(ctx)
	index, err := gbam.ReadIndex(indexIn.Reader(ctx))
	if err != nil {
		return nil, err
	}
	allChunks := []bgzf.Offset{}  
	for _, chunks := range index.AllOffsets() {
		allChunks = append(allChunks, chunks...)
	}
	if len(allChunks) <= 0 {
		return nil, fmt.Errorf("%v: no chunk found in the index", bamPath)
	}
	sort.SliceStable(allChunks, func(i, j int) bool {
		c0 := allChunks[i]
		c1 := allChunks[j]
		if c0.File != c1.File {
			return c0.File < c1.File
		}
		return c0.Block < c1.Block
	})
	bamStat, err := bamIn.Stat(ctx)
	if err != nil {
		return nil, err
	}
	bounds := []bamShardBound{
		bamShardBound{
			rec: biopb.Coord{0, 0, 0},
			off: bgzf.Offset{0, 0},
		},
	}
	if bytesPerShard <= 0 {
		return bounds, nil
	}
	nextGoalOff := bytesPerShard
	for _, chunk := range allChunks[1:] {
		if chunk.File >= nextGoalOff {
			coord, err := gbam.GetCoordAtOffset(bamr, chunk)
			if err != nil {
				vlog.Panic(err)
				continue
			}
			if len(bounds) > 0 {
				cmp := coord.Compare(bounds[len(bounds)-1].rec)
				if cmp < 0 {
					vlog.Panicf("BAM record not sorted properly: %+v %+v", coord, bounds)
				}
				if cmp == 0 {
					continue
				}
			}
			bounds = append(bounds, bamShardBound{rec: coord, off: chunk})
			nextGoalOff = chunk.File + bytesPerShard
		}
	}
	vlog.Infof("Found %d chunk bounds (file size: %d, goal shard size: %d)", len(bounds), bamStat.Size(), bytesPerShard)
	return bounds, nil
}