HasAudio() generalized to HasStreams()
This commit is contained in:
parent
bbbb23041a
commit
0bce47ccae
4 changed files with 72 additions and 62 deletions
18
README.md
18
README.md
|
@ -32,7 +32,7 @@ Stream() int
|
||||||
Duration() float64
|
Duration() float64
|
||||||
FPS() float64
|
FPS() float64
|
||||||
Codec() string
|
Codec() string
|
||||||
HasAudio() bool
|
HasStreams() bool
|
||||||
FrameBuffer() []byte
|
FrameBuffer() []byte
|
||||||
MetaData() map[string]string
|
MetaData() map[string]string
|
||||||
SetFrameBuffer(buffer []byte) error
|
SetFrameBuffer(buffer []byte) error
|
||||||
|
@ -45,7 +45,7 @@ If all frames have been read, `video` will be closed automatically. If not all f
|
||||||
|
|
||||||
## `Camera`
|
## `Camera`
|
||||||
|
|
||||||
The `Camera` can read from any cameras on the device running Vidio. It takes in the stream index. On most machines the webcam device has index 0.
|
The `Camera` can read from any cameras on the device running `Vidio`. It takes in the stream index. On most machines the webcam device has index 0.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
vidio.NewCamera(stream int) (*vidio.Camera, error)
|
vidio.NewCamera(stream int) (*vidio.Camera, error)
|
||||||
|
@ -71,7 +71,7 @@ The `VideoWriter` is used to write frames to a video file. The only required par
|
||||||
vidio.NewVideoWriter(filename string, width, height int, options *vidio.Options) (*vidio.VideoWriter, error)
|
vidio.NewVideoWriter(filename string, width, height int, options *vidio.Options) (*vidio.VideoWriter, error)
|
||||||
|
|
||||||
FileName() string
|
FileName() string
|
||||||
Audio() string
|
StreamFile() string
|
||||||
Width() int
|
Width() int
|
||||||
Height() int
|
Height() int
|
||||||
Bitrate() int
|
Bitrate() int
|
||||||
|
@ -97,17 +97,17 @@ type Options struct {
|
||||||
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".
|
Format string // Pixel Format for video. Default "rgb24".
|
||||||
Audio string // File path for extra stream data.
|
StreamFile string // File path for extra stream data.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Options.Audio` parameter is intended for users who wish to process a video stream and keep the audio. Instead of having to process the video and store in a file and then combine with the original audio later, the user can simply pass in the original file path via the `Options.Video` parameter. This will combine the video with all other streams in the given file (Audio, Subtitle, Data, and Attachments Streams) and will cut all streams to be the same length. Note that `vidio` is not a audio/video editing library.
|
The `Options.StreamFile` parameter is intended for users who wish to process a video stream and keep the audio (or other streams). Instead of having to process the video and store in a file and then combine with the original audio later, the user can simply pass in the original file path via the `Options.StreamFile` parameter. This will combine the video with all other streams in the given file (Audio, Subtitle, Data, and Attachments Streams) and will cut all streams to be the same length. **Note that `Vidio` is not a audio/video editing library.**
|
||||||
|
|
||||||
Note that this means that adding extra stream data from a file will only work if the filename being written to is a container format.
|
This means that adding extra stream data from a file will only work if the filename being written to is a container format.
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
Read(filename string, buffer ...[]byte) (int, int, []byte, error)
|
Read(filename string, buffer ...[]byte) (int, int, []byte, error)
|
||||||
|
@ -124,8 +124,8 @@ options := vidio.Options{
|
||||||
FPS: video.FPS(),
|
FPS: video.FPS(),
|
||||||
Bitrate: video.Bitrate(),
|
Bitrate: video.Bitrate(),
|
||||||
}
|
}
|
||||||
if video.HasAudio() {
|
if video.HasStreams() {
|
||||||
options.Audio = video.FileName()
|
options.StreamFile = video.FileName()
|
||||||
}
|
}
|
||||||
|
|
||||||
writer, _ := vidio.NewVideoWriter("output.mp4", video.Width(), video.Height(), &options)
|
writer, _ := vidio.NewVideoWriter("output.mp4", video.Width(), video.Height(), &options)
|
||||||
|
|
19
video.go
19
video.go
|
@ -21,7 +21,7 @@ type Video struct {
|
||||||
duration float64 // Duration of video in seconds.
|
duration float64 // Duration of video in seconds.
|
||||||
fps float64 // Frames per second.
|
fps float64 // Frames per second.
|
||||||
codec string // Codec used for video encoding.
|
codec string // Codec used for video encoding.
|
||||||
hasaudio bool // Flag storing whether file has Audio.
|
hasstreams bool // Flag storing whether file has additional data streams.
|
||||||
framebuffer []byte // Raw frame data.
|
framebuffer []byte // Raw frame data.
|
||||||
metadata map[string]string // Video metadata.
|
metadata map[string]string // Video metadata.
|
||||||
pipe *io.ReadCloser // Stdout pipe for ffmpeg process.
|
pipe *io.ReadCloser // Stdout pipe for ffmpeg process.
|
||||||
|
@ -72,8 +72,9 @@ func (video *Video) Codec() string {
|
||||||
return video.codec
|
return video.codec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (video *Video) HasAudio() bool {
|
// Returns true if file has any audio, subtitle, data or attachment streams.
|
||||||
return video.hasaudio
|
func (video *Video) HasStreams() bool {
|
||||||
|
return video.hasstreams
|
||||||
}
|
}
|
||||||
|
|
||||||
func (video *Video) FrameBuffer() []byte {
|
func (video *Video) FrameBuffer() []byte {
|
||||||
|
@ -125,10 +126,18 @@ func NewVideoStreams(filename string) ([]*Video, error) {
|
||||||
return nil, fmt.Errorf("no video data found in %s", filename)
|
return nil, fmt.Errorf("no video data found in %s", filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
audioData, err := ffprobe(filename, "a")
|
// Loop over all stream types. a: Audio, s: Subtitle, d: Data, t: Attachments
|
||||||
|
hasstream := false
|
||||||
|
for _, c := range "asdt" {
|
||||||
|
data, err := ffprobe(filename, string(c))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(data) > 0 {
|
||||||
|
hasstream = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
streams := make([]*Video, len(videoData))
|
streams := make([]*Video, len(videoData))
|
||||||
for i, data := range videoData {
|
for i, data := range videoData {
|
||||||
|
@ -136,7 +145,7 @@ func NewVideoStreams(filename string) ([]*Video, error) {
|
||||||
filename: filename,
|
filename: filename,
|
||||||
depth: 3,
|
depth: 3,
|
||||||
stream: i,
|
stream: i,
|
||||||
hasaudio: len(audioData) > 0,
|
hasstreams: hasstream,
|
||||||
metadata: data,
|
metadata: data,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
type VideoWriter struct {
|
type VideoWriter struct {
|
||||||
filename string // Output filename.
|
filename string // Output filename.
|
||||||
audio string // Extra stream data filename.
|
streamfile string // Extra stream data filename.
|
||||||
width int // Frame width.
|
width int // Frame width.
|
||||||
height int // Frame height.
|
height int // Frame height.
|
||||||
bitrate int // Output video bitrate.
|
bitrate int // Output video bitrate.
|
||||||
|
@ -38,7 +38,7 @@ type Options struct {
|
||||||
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".
|
Format string // Pixel Format for video. Default "rgb24".
|
||||||
Audio string // File path for extra stream data.
|
StreamFile string // File path for extra stream data.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (writer *VideoWriter) FileName() string {
|
func (writer *VideoWriter) FileName() string {
|
||||||
|
@ -46,8 +46,8 @@ func (writer *VideoWriter) FileName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// File used to fill in extra stream data.
|
// File used to fill in extra stream data.
|
||||||
func (writer *VideoWriter) Audio() string {
|
func (writer *VideoWriter) StreamFile() string {
|
||||||
return writer.audio
|
return writer.streamfile
|
||||||
}
|
}
|
||||||
|
|
||||||
func (writer *VideoWriter) Width() int {
|
func (writer *VideoWriter) Width() int {
|
||||||
|
@ -155,11 +155,11 @@ func NewVideoWriter(filename string, width, height int, options *Options) (*Vide
|
||||||
writer.format = options.Format
|
writer.format = options.Format
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.Audio != "" {
|
if options.StreamFile != "" {
|
||||||
if !exists(options.Audio) {
|
if !exists(options.StreamFile) {
|
||||||
return nil, fmt.Errorf("file %s does not exist", options.Audio)
|
return nil, fmt.Errorf("file %s does not exist", options.StreamFile)
|
||||||
}
|
}
|
||||||
writer.audio = options.Audio
|
writer.streamfile = options.StreamFile
|
||||||
}
|
}
|
||||||
|
|
||||||
return writer, nil
|
return writer, nil
|
||||||
|
@ -184,12 +184,12 @@ func (writer *VideoWriter) init() error {
|
||||||
|
|
||||||
gif := strings.HasSuffix(strings.ToLower(writer.filename), ".gif")
|
gif := strings.HasSuffix(strings.ToLower(writer.filename), ".gif")
|
||||||
|
|
||||||
// Assumes "writer.file" is a container format.
|
// Assumes "writer.streamfile" is a container format.
|
||||||
// gif check is included since they are a common format.
|
// gif check is included since they are a common format.
|
||||||
if writer.audio != "" && !gif {
|
if writer.streamfile != "" && !gif {
|
||||||
command = append(
|
command = append(
|
||||||
command,
|
command,
|
||||||
"-i", writer.audio,
|
"-i", writer.streamfile,
|
||||||
"-map", "0:v:0",
|
"-map", "0:v:0",
|
||||||
"-map", "1:a?", // Add Audio streams if present.
|
"-map", "1:a?", // Add Audio streams if present.
|
||||||
"-c:a", "copy",
|
"-c:a", "copy",
|
||||||
|
|
|
@ -46,6 +46,7 @@ func TestVideoMetaData(t *testing.T) {
|
||||||
assertEquals(video.fps, float64(30))
|
assertEquals(video.fps, float64(30))
|
||||||
assertEquals(video.codec, "h264")
|
assertEquals(video.codec, "h264")
|
||||||
assertEquals(video.stream, 0)
|
assertEquals(video.stream, 0)
|
||||||
|
assertEquals(video.hasstreams, true)
|
||||||
assertEquals(len(video.framebuffer), 0)
|
assertEquals(len(video.framebuffer), 0)
|
||||||
|
|
||||||
if video.pipe != nil {
|
if video.pipe != nil {
|
||||||
|
@ -92,8 +93,8 @@ func TestVideoWriting(t *testing.T) {
|
||||||
Bitrate: video.Bitrate(),
|
Bitrate: video.Bitrate(),
|
||||||
Codec: video.Codec(),
|
Codec: video.Codec(),
|
||||||
}
|
}
|
||||||
if video.HasAudio() {
|
if video.HasStreams() {
|
||||||
options.Audio = video.FileName()
|
options.StreamFile = video.FileName()
|
||||||
}
|
}
|
||||||
|
|
||||||
writer, err := NewVideoWriter(output, video.width, video.height, &options)
|
writer, err := NewVideoWriter(output, video.width, video.height, &options)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue