// Package videotest provides dummy video driver for testing. package videotest import ( "context" "image" "io" "math/rand" "time" "github.com/pion/mediadevices/pkg/driver" "github.com/pion/mediadevices/pkg/frame" "github.com/pion/mediadevices/pkg/io/video" "github.com/pion/mediadevices/pkg/prop" ) func init() { driver.GetManager().Register( newVideoTest(), driver.Info{Label: "VideoTest", DeviceType: driver.Camera}, ) } type dummy struct { closed <-chan struct{} cancel func() tick *time.Ticker } func newVideoTest() *dummy { return &dummy{} } func (d *dummy) Open() error { ctx, cancel := context.WithCancel(context.Background()) d.closed = ctx.Done() d.cancel = cancel return nil } func (d *dummy) Close() error { d.cancel() if d.tick != nil { d.tick.Stop() } return nil } func (d *dummy) VideoRecord(p prop.Media) (video.Reader, error) { colors := [][3]byte{ {235, 128, 128}, {210, 16, 146}, {170, 166, 16}, {145, 54, 34}, {107, 202, 222}, {82, 90, 240}, {41, 240, 110}, } yi := p.Width * p.Height ci := yi / 2 yy := make([]byte, yi) cb := make([]byte, ci) cr := make([]byte, ci) yyBase := make([]byte, yi) cbBase := make([]byte, ci) crBase := make([]byte, ci) hColorBarEnd := p.Height * 3 / 4 wGradationEnd := p.Width * 5 / 7 for y := 0; y < hColorBarEnd; y++ { yi := p.Width * y ci := p.Width * y / 2 // Color bar for x := 0; x < p.Width; x++ { c := x * 7 / p.Width yyBase[yi+x] = uint8(uint16(colors[c][0]) * 75 / 100) cbBase[ci+x/2] = colors[c][1] crBase[ci+x/2] = colors[c][2] } } for y := hColorBarEnd; y < p.Height; y++ { yi := p.Width * y ci := p.Width * y / 2 for x := 0; x < wGradationEnd; x++ { // Gray gradation yyBase[yi+x] = uint8(x * 255 / wGradationEnd) cbBase[ci+x/2] = 128 crBase[ci+x/2] = 128 } for x := wGradationEnd; x < p.Width; x++ { // Noise area cbBase[ci+x/2] = 128 crBase[ci+x/2] = 128 } } random := rand.New(rand.NewSource(0)) tick := time.NewTicker(time.Duration(float32(time.Second) / p.FrameRate)) d.tick = tick closed := d.closed r := video.ReaderFunc(func() (image.Image, func(), error) { select { case <-closed: return nil, func() {}, io.EOF default: } <-tick.C copy(yy, yyBase) copy(cb, cbBase) copy(cr, crBase) for y := hColorBarEnd; y < p.Height; y++ { yi := p.Width * y for x := wGradationEnd; x < p.Width; x++ { // Noise yy[yi+x] = uint8(random.Int31n(2) * 255) } } return &image.YCbCr{ Y: yy, YStride: p.Width, Cb: cb, Cr: cr, CStride: p.Width / 2, SubsampleRatio: image.YCbCrSubsampleRatio422, Rect: image.Rect(0, 0, p.Width, p.Height), }, func() {}, nil }) return r, nil } func (d dummy) Properties() []prop.Media { return []prop.Media{ { Video: prop.Video{ Width: 640, Height: 480, FrameFormat: frame.FormatYUYV, FrameRate: 30, }, }, } }