Skip to content

Commit f6eaee9

Browse files
committed
rgb to rgba
1 parent 2f07344 commit f6eaee9

File tree

6 files changed

+51
-59
lines changed

6 files changed

+51
-59
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A simple Video I/O library written in Go. This library relies on [FFmpeg](https://www.ffmpeg.org/), and [FFProbe](https://www.ffmpeg.org/) which must be downloaded before usage and added to the system path.
44

5-
All frames are encoded and decoded in 8-bit RGB format.
5+
All frames are encoded and decoded in 8-bit RGBA format.
66

77
For Audio I/O using FFmpeg, see the [`aio`](https://github.com/AlexEidt/aio) project.
88

@@ -16,7 +16,7 @@ go get github.com/AlexEidt/Vidio
1616

1717
The `Video` struct stores data about a video file you give it. The code below shows an example of sequentially reading the frames of the given video.
1818

19-
Calling the `Read()` function will fill in the `Video` struct `framebuffer` with the next frame data as 8-bit RGB data, stored in a flattened byte array in row-major order where each pixel is represented by three consecutive bytes representing the R, G and B component of that pixel.
19+
Calling the `Read()` function will fill in the `Video` struct `framebuffer` with the next frame data as 8-bit RGBA data, stored in a flattened byte array in row-major order where each pixel is represented by four consecutive bytes representing the R, G, B and A components of that pixel. Note that the A (alpha) component will always be 255.
2020

2121
```go
2222
vidio.NewVideo(filename string) (*vidio.Video, error)
@@ -81,7 +81,6 @@ Macro() int
8181
FPS() float64
8282
Quality() float64
8383
Codec() string
84-
Format() string
8584

8685
Write(frame []byte) error
8786
Close()
@@ -96,7 +95,6 @@ type Options struct {
9695
FPS float64 // Frames per second for output video.
9796
Quality float64 // If bitrate not given, use quality instead. Must be between 0 and 1. 0:best, 1:worst.
9897
Codec string // Codec for video.
99-
Format string // Pixel Format for video. Default "rgb24".
10098
StreamFile string // File path for extra stream data.
10199
}
102100
```

camera.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func NewCamera(stream int) (*Camera, error) {
9090
return nil, fmt.Errorf("unsupported OS: %s", runtime.GOOS)
9191
}
9292

93-
camera := &Camera{name: device, depth: 3}
93+
camera := &Camera{name: device, depth: 4}
9494
if err := camera.getCameraData(device); err != nil {
9595
return nil, err
9696
}
@@ -205,7 +205,7 @@ func (camera *Camera) init() error {
205205
"-f", webcamDeviceName,
206206
"-i", camera.name,
207207
"-f", "image2pipe",
208-
"-pix_fmt", "rgb24",
208+
"-pix_fmt", "rgba",
209209
"-vcodec", "rawvideo",
210210
"-",
211211
)

imageio.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"image/png"
1212
)
1313

14-
// Reads an image from a file. Currently only supports png and jpeg.
14+
// Reads an image into an rgba byte buffer from a file. Currently only supports png and jpeg.
1515
func Read(filename string, buffer ...[]byte) (int, int, []byte, error) {
1616
f, err := os.Open(filename)
1717
if err != nil {
@@ -25,7 +25,7 @@ func Read(filename string, buffer ...[]byte) (int, int, []byte, error) {
2525
}
2626

2727
bounds := image.Bounds().Max
28-
size := bounds.X * bounds.Y * 3
28+
size := bounds.X * bounds.Y * 4
2929

3030
var data []byte
3131
if len(buffer) > 0 {
@@ -45,13 +45,14 @@ func Read(filename string, buffer ...[]byte) (int, int, []byte, error) {
4545
data[index+0] = byte(r)
4646
data[index+1] = byte(g)
4747
data[index+2] = byte(b)
48-
index += 3
48+
data[index+3] = 255
49+
index += 4
4950
}
5051
}
5152
return bounds.X, bounds.Y, data, nil
5253
}
5354

54-
// Writes an image to a file. Currently only supports png and jpeg.
55+
// Writes a rgba byte buffer to a file. Currently only supports png and jpeg.
5556
func Write(filename string, width, height int, buffer []byte) error {
5657
f, err := os.Create(filename)
5758
if err != nil {
@@ -63,9 +64,9 @@ func Write(filename string, width, height int, buffer []byte) error {
6364
index := 0
6465
for h := 0; h < height; h++ {
6566
for w := 0; w < width; w++ {
66-
r, g, b := buffer[index], buffer[index+1], buffer[index+2]
67+
r, g, b := buffer[index+0], buffer[index+1], buffer[index+2]
6768
image.Set(w, h, color.RGBA{r, g, b, 255})
68-
index += 3
69+
index += 4
6970
}
7071
}
7172

video.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func NewVideoStreams(filename string) ([]*Video, error) {
143143
for i, data := range videoData {
144144
video := &Video{
145145
filename: filename,
146-
depth: 3,
146+
depth: 4,
147147
stream: i,
148148
hasstreams: hasstream,
149149
metadata: data,
@@ -190,13 +190,13 @@ func (video *Video) addVideoData(data map[string]string) {
190190
func (video *Video) init() error {
191191
// If user exits with Ctrl+C, stop ffmpeg process.
192192
video.cleanup()
193-
// ffmpeg command to pipe video data to stdout in 8-bit RGB format.
193+
// ffmpeg command to pipe video data to stdout in 8-bit RGBA format.
194194
cmd := exec.Command(
195195
"ffmpeg",
196196
"-i", video.filename,
197197
"-f", "image2pipe",
198198
"-loglevel", "quiet",
199-
"-pix_fmt", "rgb24",
199+
"-pix_fmt", "rgba",
200200
"-vcodec", "rawvideo",
201201
"-map", fmt.Sprintf("0:v:%d", video.stream),
202202
"-",

videowriter.go

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ type VideoWriter struct {
2323
fps float64 // Frames per second for output video. Default 25.
2424
quality float64 // Used if bitrate not given. Default 0.5.
2525
codec string // Codec to encode video with. Default libx264.
26-
format string // Output format. Default rgb24.
2726
pipe *io.WriteCloser // Stdout pipe of ffmpeg process.
2827
cmd *exec.Cmd // ffmpeg command.
2928
}
@@ -37,7 +36,6 @@ type Options struct {
3736
FPS float64 // Frames per second for output video.
3837
Quality float64 // If bitrate not given, use quality instead. Must be between 0 and 1. 0:best, 1:worst.
3938
Codec string // Codec for video.
40-
Format string // Pixel Format for video. Default "rgb24".
4139
StreamFile string // File path for extra stream data.
4240
}
4341

@@ -86,10 +84,6 @@ func (writer *VideoWriter) Codec() string {
8684
return writer.codec
8785
}
8886

89-
func (writer *VideoWriter) Format() string {
90-
return writer.format
91-
}
92-
9387
// Creates a new VideoWriter struct with default values from the Options struct.
9488
func NewVideoWriter(filename string, width, height int, options *Options) (*VideoWriter, error) {
9589
// Check if ffmpeg is installed on the users machine.
@@ -149,12 +143,6 @@ func NewVideoWriter(filename string, width, height int, options *Options) (*Vide
149143
writer.codec = options.Codec
150144
}
151145

152-
if options.Format == "" {
153-
writer.format = "rgb24"
154-
} else {
155-
writer.format = options.Format
156-
}
157-
158146
if options.StreamFile != "" {
159147
if !exists(options.StreamFile) {
160148
return nil, fmt.Errorf("file %s does not exist", options.StreamFile)
@@ -177,7 +165,7 @@ func (writer *VideoWriter) init() error {
177165
"-f", "rawvideo",
178166
"-vcodec", "rawvideo",
179167
"-s", fmt.Sprintf("%dx%d", writer.width, writer.height), // frame w x h.
180-
"-pix_fmt", writer.format,
168+
"-pix_fmt", "rgba",
181169
"-r", fmt.Sprintf("%.02f", writer.fps), // frames per second.
182170
"-i", "-", // The input comes from stdin.
183171
}
@@ -206,7 +194,7 @@ func (writer *VideoWriter) init() error {
206194
command = append(
207195
command,
208196
"-vcodec", writer.codec,
209-
"-pix_fmt", "yuv420p", // Output is 8-bit RGB, no alpha.
197+
"-pix_fmt", "yuv420p", // Output is 8-bit RGB, ignore alpha.
210198
)
211199

212200
// Code from the imageio-ffmpeg project.
@@ -246,6 +234,8 @@ func (writer *VideoWriter) init() error {
246234
if writer.height%writer.macro > 0 {
247235
height += writer.macro - (writer.height % writer.macro)
248236
}
237+
writer.width = width
238+
writer.height = height
249239
command = append(
250240
command,
251241
"-vf", fmt.Sprintf("scale=%d:%d", width, height),

vidio_test.go

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestVideoMetaData(t *testing.T) {
3939
assertEquals(video.filename, "test/koala.mp4")
4040
assertEquals(video.width, 480)
4141
assertEquals(video.height, 270)
42-
assertEquals(video.depth, 3)
42+
assertEquals(video.depth, 4)
4343
assertEquals(video.bitrate, 170549)
4444
assertEquals(video.frames, 101)
4545
assertEquals(video.duration, 3.366667)
@@ -67,17 +67,23 @@ func TestVideoFrame(t *testing.T) {
6767
defer video.Close()
6868

6969
video.Read()
70-
// [203 222 134 203 222 134 203 222 134 203]
70+
// [203 222 134 255 203 222 134 255 203 222 134 255 203]
7171
assertEquals(video.framebuffer[0], uint8(203))
7272
assertEquals(video.framebuffer[1], uint8(222))
7373
assertEquals(video.framebuffer[2], uint8(134))
74-
assertEquals(video.framebuffer[3], uint8(203))
75-
assertEquals(video.framebuffer[4], uint8(222))
76-
assertEquals(video.framebuffer[5], uint8(134))
77-
assertEquals(video.framebuffer[6], uint8(203))
78-
assertEquals(video.framebuffer[7], uint8(222))
79-
assertEquals(video.framebuffer[8], uint8(134))
80-
assertEquals(video.framebuffer[9], uint8(203))
74+
assertEquals(video.framebuffer[3], uint8(255))
75+
76+
assertEquals(video.framebuffer[4], uint8(203))
77+
assertEquals(video.framebuffer[5], uint8(222))
78+
assertEquals(video.framebuffer[6], uint8(134))
79+
assertEquals(video.framebuffer[7], uint8(255))
80+
81+
assertEquals(video.framebuffer[8], uint8(203))
82+
assertEquals(video.framebuffer[9], uint8(222))
83+
assertEquals(video.framebuffer[10], uint8(134))
84+
assertEquals(video.framebuffer[11], uint8(255))
85+
86+
assertEquals(video.framebuffer[12], uint8(203))
8187

8288
fmt.Println("Video Frame Test Passed")
8389
}
@@ -90,8 +96,8 @@ func TestVideoWriting(t *testing.T) {
9096
}
9197
options := Options{
9298
FPS: video.FPS(),
93-
Bitrate: video.Bitrate(),
9499
Codec: video.Codec(),
100+
Bitrate: video.Bitrate(),
95101
}
96102
if video.HasStreams() {
97103
options.StreamFile = video.FileName()
@@ -101,12 +107,11 @@ func TestVideoWriting(t *testing.T) {
101107
if err != nil {
102108
panic(err)
103109
}
110+
104111
for video.Read() {
105-
err := writer.Write(video.FrameBuffer())
106-
if err != nil {
107-
panic(err)
108-
}
112+
writer.Write(video.FrameBuffer())
109113
}
114+
110115
writer.Close()
111116

112117
os.Remove(output)
@@ -134,14 +139,6 @@ func TestCameraIO(t *testing.T) {
134139
count := 0
135140
for webcam.Read() {
136141
frame := webcam.FrameBuffer()
137-
for i := 0; i < len(frame); i += 3 {
138-
rgb := frame[i : i+3]
139-
r, g, b := int(rgb[0]), int(rgb[1]), int(rgb[2])
140-
gray := uint8((3*r + 4*g + b) / 8)
141-
frame[i] = gray
142-
frame[i+1] = gray
143-
frame[i+2] = gray
144-
}
145142
err := writer.Write(frame)
146143
if err != nil {
147144
panic(err)
@@ -250,18 +247,24 @@ func TestImageRead(t *testing.T) {
250247

251248
assertEquals(w, 200)
252249
assertEquals(h, 133)
253-
assertEquals(len(img), 200*133*3)
254-
// [255 221 189 255 221 189 255 222 186 255]
250+
assertEquals(len(img), 200*133*4)
251+
// [255 221 189 255 255 221 189 255 255 222 186 255 255]
255252
assertEquals(img[0], uint8(255))
256253
assertEquals(img[1], uint8(221))
257254
assertEquals(img[2], uint8(189))
258255
assertEquals(img[3], uint8(255))
259-
assertEquals(img[4], uint8(221))
260-
assertEquals(img[5], uint8(189))
261-
assertEquals(img[6], uint8(255))
262-
assertEquals(img[7], uint8(222))
263-
assertEquals(img[8], uint8(186))
264-
assertEquals(img[9], uint8(255))
256+
257+
assertEquals(img[4], uint8(255))
258+
assertEquals(img[5], uint8(221))
259+
assertEquals(img[6], uint8(189))
260+
assertEquals(img[7], uint8(255))
261+
262+
assertEquals(img[8], uint8(255))
263+
assertEquals(img[9], uint8(222))
264+
assertEquals(img[10], uint8(186))
265+
assertEquals(img[11], uint8(255))
266+
267+
assertEquals(img[12], uint8(255))
265268

266269
fmt.Println("Image Reading Test Passed")
267270
}

0 commit comments

Comments
 (0)