ReadFrames updated to return RGBA image slice

This commit is contained in:
Krzysztofz01 2023-08-29 10:55:14 +02:00
parent a1d63d0f9f
commit f6a2909ea3
3 changed files with 10 additions and 15 deletions

View file

@ -16,7 +16,7 @@ go get github.com/AlexEidt/Vidio
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. 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.
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. When iteration over the entire video file is not required, we can lookup a specific frame by calling `ReadFrame(n int)`. By calling `ReadFrames(n ...int)`, we can immediately access multiple frames as `[][]byte` and skip the `framebuffer`. 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. When iteration over the entire video file is not required, we can lookup a specific frame by calling `ReadFrame(n int)`. By calling `ReadFrames(n ...int)`, we can immediately access multiple frames as a slice of RGBA images and skip the `framebuffer`.
```go ```go
vidio.NewVideo(filename string) (*vidio.Video, error) vidio.NewVideo(filename string) (*vidio.Video, error)
@ -39,7 +39,7 @@ SetFrameBuffer(buffer []byte) error
Read() bool Read() bool
ReadFrame(n int) error ReadFrame(n int) error
ReadFrames(n ...int) ([][]byte, error) ReadFrames(n ...int) ([]*image.RGBA, error)
Close() Close()
``` ```
@ -208,12 +208,9 @@ video, _ := vidio.NewVideo("video.mp4")
frames, _ := video.ReadFrames(0, video.Frames() - 1) frames, _ := video.ReadFrames(0, video.Frames() - 1)
img := image.NewRGBA(image.Rect(0, 0, video.Width(), video.Height()))
for index, frame := range frames { for index, frame := range frames {
copy(img.Pix, frame)
f, _ := os.Create(fmt.Sprintf("%d.jpg", index)) f, _ := os.Create(fmt.Sprintf("%d.jpg", index))
jpeg.Encode(f, img, nil) jpeg.Encode(f, frame, nil)
f.Close() f.Close()
} }
``` ```

View file

@ -2,6 +2,7 @@ package vidio
import ( import (
"fmt" "fmt"
"image"
"io" "io"
"os" "os"
"os/exec" "os/exec"
@ -305,9 +306,9 @@ func (video *Video) ReadFrame(n int) error {
return nil return nil
} }
// Read the N-amount of frames with the given indexes and return them as a slice of buffers. If one of // Read the N-amount of frames with the given indexes and return them as a slice of RGBA image pointers. If one of
// the indexes is out of range, the function will return an error. The frames are indexes from 0. // the indexes is out of range, the function will return an error. The frames are indexes from 0.
func (video *Video) ReadFrames(n ...int) ([][]byte, error) { func (video *Video) ReadFrames(n ...int) ([]*image.RGBA, error) {
if len(n) == 0 { if len(n) == 0 {
return nil, fmt.Errorf("vidio: no frames indexes specified") return nil, fmt.Errorf("vidio: no frames indexes specified")
} }
@ -358,11 +359,11 @@ func (video *Video) ReadFrames(n ...int) ([][]byte, error) {
os.Exit(1) os.Exit(1)
}() }()
frames := make([][]byte, len(n)) frames := make([]*image.RGBA, len(n))
for frameIndex := range frames { for frameIndex := range frames {
frames[frameIndex] = make([]byte, video.width*video.height*video.depth) frames[frameIndex] = image.NewRGBA(image.Rect(0, 0, video.width, video.height))
if _, err := io.ReadFull(stdoutPipe, frames[frameIndex]); err != nil { if _, err := io.ReadFull(stdoutPipe, frames[frameIndex].Pix); err != nil {
return nil, fmt.Errorf("vidio: failed to read the ffmpeg cmd result to the image buffer: %w", err) return nil, fmt.Errorf("vidio: failed to read the ffmpeg cmd result to the image buffer: %w", err)
} }
} }

View file

@ -410,11 +410,8 @@ func TestReadFramesShouldReturnCorrectFrames(t *testing.T) {
t.Errorf("Failed to read frames: %s", err) t.Errorf("Failed to read frames: %s", err)
} }
for index, buffer := range frames { for index, actualFrame := range frames {
expectedFrame := expectedFrames[index] expectedFrame := expectedFrames[index]
actualFrame := image.NewRGBA(image.Rect(0, 0, 480, 270))
copy(actualFrame.Pix, buffer)
for xIndex := 0; xIndex < expectedFrame.Bounds().Dx(); xIndex += 1 { for xIndex := 0; xIndex < expectedFrame.Bounds().Dx(); xIndex += 1 {
for yIndex := 0; yIndex < expectedFrame.Bounds().Dy(); yIndex += 1 { for yIndex := 0; yIndex < expectedFrame.Bounds().Dy(); yIndex += 1 {
eR, eG, eB, eA := expectedFrame.At(xIndex, yIndex).RGBA() eR, eG, eB, eA := expectedFrame.At(xIndex, yIndex).RGBA()