Added Format for VideoWriter
This commit is contained in:
parent
9e805e183b
commit
af983f09e4
3 changed files with 36 additions and 41 deletions
58
README.md
58
README.md
|
@ -77,6 +77,7 @@ Macro() int
|
||||||
FPS() float64
|
FPS() float64
|
||||||
Quality() float64
|
Quality() float64
|
||||||
Codec() string
|
Codec() string
|
||||||
|
Format() string
|
||||||
AudioCodec() string
|
AudioCodec() string
|
||||||
|
|
||||||
Write(frame []byte) error
|
Write(frame []byte) error
|
||||||
|
@ -85,22 +86,19 @@ Close()
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Bitrate int // Bitrate
|
Bitrate int // Bitrate.
|
||||||
Loop int // For GIFs only. -1=no loop, 0=loop forever, >0=loop n times
|
Loop int // For GIFs only. -1=no loop, 0=infinite loop, >0=number of loops.
|
||||||
Delay int // Delay for Final Frame of GIFs. Default -1 (Use same delay as previous frame)
|
Delay int // Delay for final frame of GIFs.
|
||||||
Macro int // macro size for determining how to resize frames for codecs. Default 16
|
Macro int // Macroblock size for determining how to resize frames for codecs.
|
||||||
FPS float64 // Frames per second. Default 25
|
FPS float64 // Frames per second for output video.
|
||||||
Quality float64 // If bitrate not given, use quality instead. Must be between 0 and 1. 0:best, 1:worst
|
Quality float64 // If bitrate not given, use quality instead. Must be between 0 and 1. 0:best, 1:worst.
|
||||||
Codec string // Codec for video. Default libx264
|
Codec string // Codec for video.
|
||||||
Audio string // File path for audio for the video. If no audio, audio=""
|
Format string // Pixel Format for video. Default "rgb24".
|
||||||
AudioCodec string // Codec for audio. Default aac
|
Audio string // File path for audio. If no audio, audio="".
|
||||||
|
AudioCodec string // Codec for audio.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## The `SetFrameBuffer(buffer []byte)` function
|
|
||||||
|
|
||||||
For the `SetFrameBuffer()` function, the `buffer` parameter must have a length of at least `video.Width() * video.Height() * video.Depth()` bytes to store the incoming video frame. The length of the buffer is not checked. It may be useful to have multiple buffers to keep track of previous video frames without having to copy data around.
|
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
|
||||||
Vidio provides some convenience functions for reading and writing to images using an array of bytes. Currently, only `png` and `jpeg` formats are supported. When reading images, an optional `buffer` can be passed in to avoid array reallocation.
|
Vidio provides some convenience functions for reading and writing to images using an array of bytes. Currently, only `png` and `jpeg` formats are supported. When reading images, an optional `buffer` can be passed in to avoid array reallocation.
|
||||||
|
@ -115,8 +113,7 @@ Write(filename string, width, height int, buffer []byte) error
|
||||||
Copy `input.mp4` to `output.mp4`. Copy the audio from `input.mp4` to `output.mp4` as well.
|
Copy `input.mp4` to `output.mp4`. Copy the audio from `input.mp4` to `output.mp4` as well.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
video, err := vidio.NewVideo("input.mp4")
|
video, _ := vidio.NewVideo("input.mp4")
|
||||||
|
|
||||||
options := vidio.Options{
|
options := vidio.Options{
|
||||||
FPS: video.FPS(),
|
FPS: video.FPS(),
|
||||||
Bitrate: video.Bitrate(),
|
Bitrate: video.Bitrate(),
|
||||||
|
@ -125,7 +122,7 @@ if video.AudioCodec() != "" {
|
||||||
options.Audio = "input.mp4"
|
options.Audio = "input.mp4"
|
||||||
}
|
}
|
||||||
|
|
||||||
writer, err := vidio.NewVideoWriter("output.mp4", video.Width(), video.Height(), &options)
|
writer, _ := vidio.NewVideoWriter("output.mp4", video.Width(), video.Height(), &options)
|
||||||
|
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
|
|
||||||
|
@ -134,32 +131,19 @@ for video.Read() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Grayscale 1000 frames of webcam stream and store in `output.mp4`.
|
Read 1000 frames of a webcam stream and store in `output.mp4`.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
webcam, err := vidio.NewCamera(0)
|
webcam, _ := vidio.NewCamera(0)
|
||||||
|
|
||||||
defer webcam.Close()
|
defer webcam.Close()
|
||||||
|
|
||||||
options := vidio.Options{FPS: webcam.FPS()}
|
options := vidio.Options{FPS: webcam.FPS()}
|
||||||
|
writer, _ := vidio.NewVideoWriter("output.mp4", webcam.Width(), webcam.Height(), &options)
|
||||||
writer, err := vidio.NewVideoWriter("output.mp4", webcam.Width(), webcam.Height(), &options)
|
|
||||||
|
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
for webcam.Read() && count < 1000 {
|
for webcam.Read() && count < 1000 {
|
||||||
frame := webcam.FrameBuffer()
|
writer.Write(webcam.FrameBuffer())
|
||||||
for i := 0; i < len(frame); i += 3 {
|
|
||||||
r, g, b := frame[i+0], frame[i+1], frame[i+2]
|
|
||||||
gray := uint8((3*int(r) + 4*int(g) + int(b)) / 8)
|
|
||||||
frame[i] = gray
|
|
||||||
frame[i+1] = gray
|
|
||||||
frame[i+2] = gray
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(frame)
|
|
||||||
|
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -167,16 +151,14 @@ for webcam.Read() && count < 1000{
|
||||||
Create a gif from a series of `png` files enumerated from 1 to 10 that loops continuously with a final frame delay of 1000 centiseconds.
|
Create a gif from a series of `png` files enumerated from 1 to 10 that loops continuously with a final frame delay of 1000 centiseconds.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
w, h, img, err := vidio.Read("1.png") // Get frame dimensions from first image
|
w, h, img, _ := vidio.Read("1.png") // Get frame dimensions from first image
|
||||||
|
|
||||||
options := vidio.Options{FPS: 1, Loop: 0, Delay: 1000}
|
options := vidio.Options{FPS: 1, Loop: 0, Delay: 1000}
|
||||||
|
gif, _ := vidio.NewVideoWriter("output.gif", w, h, &options)
|
||||||
gif, err := vidio.NewVideoWriter("output.gif", w, h, &options)
|
|
||||||
|
|
||||||
defer gif.Close()
|
defer gif.Close()
|
||||||
|
|
||||||
for i := 1; i <= 10; i++ {
|
for i := 1; i <= 10; i++ {
|
||||||
w, h, img, err := vidio.Read(strconv.Itoa(i)+".png")
|
w, h, img, _ := vidio.Read(strconv.Itoa(i)+".png")
|
||||||
gif.Write(img)
|
gif.Write(img)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
3
video.go
3
video.go
|
@ -127,7 +127,8 @@ func initVideo(video *Video) error {
|
||||||
"-f", "image2pipe",
|
"-f", "image2pipe",
|
||||||
"-loglevel", "quiet",
|
"-loglevel", "quiet",
|
||||||
"-pix_fmt", "rgb24",
|
"-pix_fmt", "rgb24",
|
||||||
"-vcodec", "rawvideo", "-",
|
"-vcodec", "rawvideo",
|
||||||
|
"-",
|
||||||
)
|
)
|
||||||
|
|
||||||
video.cmd = cmd
|
video.cmd = cmd
|
||||||
|
|
|
@ -23,6 +23,7 @@ type VideoWriter struct {
|
||||||
fps float64 // Frames per second for output video. Default 25.
|
fps float64 // Frames per second for output video. Default 25.
|
||||||
quality float64 // Used if bitrate not given. Default 0.5.
|
quality float64 // Used if bitrate not given. Default 0.5.
|
||||||
codec string // Codec to encode video with. Default libx264.
|
codec string // Codec to encode video with. Default libx264.
|
||||||
|
format string // Output format. Default rgb24.
|
||||||
audioCodec string // Codec to encode audio with. Default aac.
|
audioCodec string // Codec to encode audio with. Default aac.
|
||||||
pipe *io.WriteCloser // Stdout pipe of ffmpeg process.
|
pipe *io.WriteCloser // Stdout pipe of ffmpeg process.
|
||||||
cmd *exec.Cmd // ffmpeg command.
|
cmd *exec.Cmd // ffmpeg command.
|
||||||
|
@ -37,6 +38,7 @@ type Options struct {
|
||||||
FPS float64 // Frames per second for output video.
|
FPS float64 // Frames per second for output video.
|
||||||
Quality float64 // If bitrate not given, use quality instead. Must be between 0 and 1. 0:best, 1:worst.
|
Quality float64 // If bitrate not given, use quality instead. Must be between 0 and 1. 0:best, 1:worst.
|
||||||
Codec string // Codec for video.
|
Codec string // Codec for video.
|
||||||
|
Format string // Pixel Format for video. Default "rgb24".
|
||||||
Audio string // File path for audio. If no audio, audio="".
|
Audio string // File path for audio. If no audio, audio="".
|
||||||
AudioCodec string // Codec for audio.
|
AudioCodec string // Codec for audio.
|
||||||
}
|
}
|
||||||
|
@ -85,6 +87,10 @@ func (writer *VideoWriter) Codec() string {
|
||||||
return writer.codec
|
return writer.codec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (writer *VideoWriter) Format() string {
|
||||||
|
return writer.format
|
||||||
|
}
|
||||||
|
|
||||||
func (writer *VideoWriter) AudioCodec() string {
|
func (writer *VideoWriter) AudioCodec() string {
|
||||||
return writer.audioCodec
|
return writer.audioCodec
|
||||||
}
|
}
|
||||||
|
@ -147,6 +153,12 @@ func NewVideoWriter(filename string, width, height int, options *Options) (*Vide
|
||||||
writer.codec = options.Codec
|
writer.codec = options.Codec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.Format == "" {
|
||||||
|
writer.format = "rgb24"
|
||||||
|
} else {
|
||||||
|
writer.format = options.Format
|
||||||
|
}
|
||||||
|
|
||||||
if options.Audio != "" {
|
if options.Audio != "" {
|
||||||
if !exists(options.Audio) {
|
if !exists(options.Audio) {
|
||||||
return nil, fmt.Errorf("audio file %s does not exist", options.Audio)
|
return nil, fmt.Errorf("audio file %s does not exist", options.Audio)
|
||||||
|
@ -183,7 +195,7 @@ func initVideoWriter(writer *VideoWriter) error {
|
||||||
"-f", "rawvideo",
|
"-f", "rawvideo",
|
||||||
"-vcodec", "rawvideo",
|
"-vcodec", "rawvideo",
|
||||||
"-s", fmt.Sprintf("%dx%d", writer.width, writer.height), // frame w x h.
|
"-s", fmt.Sprintf("%dx%d", writer.width, writer.height), // frame w x h.
|
||||||
"-pix_fmt", "rgb24",
|
"-pix_fmt", writer.format,
|
||||||
"-r", fmt.Sprintf("%.02f", writer.fps), // frames per second.
|
"-r", fmt.Sprintf("%.02f", writer.fps), // frames per second.
|
||||||
"-i", "-", // The input comes from stdin.
|
"-i", "-", // The input comes from stdin.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue