Skip to content

Commit

Permalink
Updates to media and added audio
Browse files Browse the repository at this point in the history
  • Loading branch information
djthorpe committed Mar 14, 2021
1 parent 4fad023 commit 55d359d
Show file tree
Hide file tree
Showing 19 changed files with 592 additions and 239 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,9 @@ dxtest: dispmanx egl rpi
ffextract: builddir ffmpeg
PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(GO) build -o ${BUILDDIR}/ffextract -tags "$(TAGS)" ${GOFLAGS} ./cmd/ffextract

audioid: builddir ffmpeg chromaprint
PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" $(GO) build -o ${BUILDDIR}/audioid -tags "$(TAGS)" ${GOFLAGS} ./cmd/audioid

# Build rules - dependencies
nfpm:
$(GO) get github.com/goreleaser/nfpm/cmd/nfpm@v1.10.1
Expand Down
97 changes: 97 additions & 0 deletions audio.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package gopi

/*
This file contains definitions for audio data:
* Audio representation
* Input and output audio devices
Resampling of audio is represented in the "media" interfaces
*/

////////////////////////////////////////////////////////////////////////////////
// TYPES

// AudioFormat defines the audio format
type AudioFormat uint

// AudioChannelLayout represents number of channels and layout of those channels
type AudioChannelLayout struct {
Channels uint
}

////////////////////////////////////////////////////////////////////////////////
// AUDIO INTERFACES

type AudioManager interface {
// OpenDefaultSink opens default output device
OpenDefaultSink() (AudioContext, error)

// Close audio stream
Close(AudioContext) error
}

type AudioContext interface {
// Write data to audio output device
Write(MediaFrame) error
}

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

const (
AUDIO_FMT_NONE AudioFormat = iota
AUDIO_FMT_U8 // unsigned 8 bits
AUDIO_FMT_U8P // unsigned 8 bits, planar
AUDIO_FMT_S16 // signed 16 bits
AUDIO_FMT_S16P // signed 16 bits, planar
AUDIO_FMT_S32 // signed 32 bits
AUDIO_FMT_S32P // signed 32 bits, planar
AUDIO_FMT_F32 // float32
AUDIO_FMT_F32P // float32, planar
AUDIO_FMT_F64 // float64
AUDIO_FMT_F64P // float64, planar
AUDIO_FMT_S64 // signed 64 bits
AUDIO_FMT_S64P // signed 64 bits, planar
)

var (
AudioLayoutMono = AudioChannelLayout{1}
AudioLayoutStereo = AudioChannelLayout{2}
)

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

func (f AudioFormat) String() string {
switch f {
case AUDIO_FMT_NONE:
return "AUDIO_FMT_NONE"
case AUDIO_FMT_U8:
return "AUDIO_FMT_U8"
case AUDIO_FMT_U8P:
return "AUDIO_FMT_U8P"
case AUDIO_FMT_S16:
return "AUDIO_FMT_S16"
case AUDIO_FMT_S16P:
return "AUDIO_FMT_S16P"
case AUDIO_FMT_S32:
return "AUDIO_FMT_S32"
case AUDIO_FMT_S32P:
return "AUDIO_FMT_S32P"
case AUDIO_FMT_F32:
return "AUDIO_FMT_F32"
case AUDIO_FMT_F32P:
return "AUDIO_FMT_F32P"
case AUDIO_FMT_F64:
return "AUDIO_FMT_F64"
case AUDIO_FMT_F64P:
return "AUDIO_FMT_F64P"
case AUDIO_FMT_S64:
return "AUDIO_FMT_S64"
case AUDIO_FMT_S64P:
return "AUDIO_FMT_S64P"
default:
return "[?? Invalid AudioFormat value]"
}
}
67 changes: 67 additions & 0 deletions cmd/audioid/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package main

import (
"context"
"os"

"github.com/djthorpe/gopi/v3"
)

type app struct {
gopi.Unit
gopi.MediaManager
gopi.Logger

filename string
}

func (this *app) Define(cfg gopi.Config) error {
return nil
}

func (this *app) New(cfg gopi.Config) error {
this.Require(this.Logger, this.MediaManager)

if args := cfg.Args(); len(args) != 1 {
return gopi.ErrBadParameter.WithPrefix("Missing filename")
} else if stat, err := os.Stat(args[0]); err != nil {
return gopi.ErrBadParameter.WithPrefix(args[0])
} else if stat.Mode().IsRegular() == false {
return gopi.ErrBadParameter.WithPrefix(args[0])
} else {
this.filename = args[0]
}

// Return success
return nil
}

func (this *app) Run(ctx context.Context) error {
// Open the file, decode the audio
if file, err := this.OpenFile(this.filename); err != nil {
return err
} else if err := this.Decode(ctx, file); err != nil {
return err
}

// Return success
return nil
}

func (this *app) Decode(ctx context.Context, file gopi.MediaInput) error {
// Use the first video stream found
streams := file.StreamsForFlag(gopi.MEDIA_FLAG_AUDIO)
if len(streams) == 0 {
return gopi.ErrNotFound.WithPrefix("Audio stream")
} else {
this.Print(file.StreamForIndex(streams[0]))
}

// Decode frames
return file.Read(ctx, streams[0:1], func(ctx gopi.MediaDecodeContext, packet gopi.MediaPacket) error {
return file.DecodeFrameIterator(ctx, packet, func(frame gopi.MediaFrame) error {
this.Print("Decoded", ctx.Frame(), " => ", frame)
return nil
})
})
}
11 changes: 11 additions & 0 deletions cmd/audioid/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import (
"os"

"github.com/djthorpe/gopi/v3/pkg/tool"
)

func main() {
os.Exit(tool.CommandLine("audioid", os.Args[1:], new(app)))
}
5 changes: 5 additions & 0 deletions cmd/audioid/units.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package main

import (
_ "github.com/djthorpe/gopi/v3/pkg/media/ffmpeg"
)
2 changes: 1 addition & 1 deletion cmd/ffextract/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,6 @@ func (this *app) DecodeFrame(path string, frame gopi.MediaFrame) error {
return err
}

this.Printf("Saved frame:", frame, "=>", path)
this.Print("Saved frame:", frame, " => ", path)
return nil
}
83 changes: 56 additions & 27 deletions media.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import (
/*
This file contains definitions for media devices:
* Video and Audio decoding
* Video and Audio encoding and decoding
* Input and output media devices
* DVB tuning and decoding
* DVB tuning and decoding (experimental)
There are aditional interfaces for audio and graphics elsewhere
*/

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -27,7 +29,7 @@ type (
)

////////////////////////////////////////////////////////////////////////////////
// MEDIA FILE INTERFACES
// MEDIA MANAGER

// MediaManager for media file management
type MediaManager interface {
Expand All @@ -47,8 +49,14 @@ type MediaManager interface {
// audio, video, encode and decode. By default (empty name and
// MediaFlag) lists all codecs
ListCodecs(string, MediaFlag) []MediaCodec

// Create an audio profile with format, sample rate, channels and layout
AudioProfile(AudioFormat, uint, AudioChannelLayout) MediaProfile
}

////////////////////////////////////////////////////////////////////////////////
// MEDIA OBJECTS

// Media is an input or output
type Media interface {
URL() *url.URL // Return URL for the media location
Expand All @@ -58,6 +66,7 @@ type Media interface {
StreamForIndex(int) MediaStream // Return stream by index
}

// MediaInput represents a source of media
type MediaInput interface {
Media

Expand All @@ -73,26 +82,42 @@ type MediaInput interface {
DecodeFrameIterator(MediaDecodeContext, MediaPacket, DecodeFrameIteratorFunc) error
}

// MediaOutput represents a sink for media
type MediaOutput interface {
Media

// Write packets to output
Write(MediaDecodeContext, MediaPacket) error
}

////////////////////////////////////////////////////////////////////////////////
// MEDIA PROFILES

type MediaProfile interface {
Flags() MediaFlag // Return audio or video profile
}

type MediaAudioProfile interface {
MediaProfile

Format() AudioFormat
SampleRate() uint
Layout() AudioChannelLayout
}

type MediaVideoProfile interface {
MediaProfile
}

////////////////////////////////////////////////////////////////////////////////
// MEDIA METADATA AND CODECS

// MediaMetadata are key value pairs for a media object
type MediaMetadata interface {
Keys() []MediaKey // Return all existing keys
Value(MediaKey) interface{} // Return value for key, or nil
}

// MediaStream is a stream of packets from a media object
type MediaStream interface {
Index() int // Stream index
Flags() MediaFlag // Flags for the stream (Audio, Video, etc)
Codec() MediaCodec // Return codec and parameters
}

// MediaCodec is the codec and parameters
type MediaCodec interface {
// Name returns the unique name for the codec
Expand All @@ -105,6 +130,16 @@ type MediaCodec interface {
Flags() MediaFlag
}

////////////////////////////////////////////////////////////////////////////////
// MEDIA STREAMS, PACKETS AND FRAMES

// MediaStream is a stream of packets from a media object
type MediaStream interface {
Index() int // Stream index
Flags() MediaFlag // Flags for the stream (Audio, Video, etc)
Codec() MediaCodec // Return codec and parameters
}

// MediaPacket is a packet of data from a stream
type MediaPacket interface {
Size() int
Expand All @@ -114,9 +149,19 @@ type MediaPacket interface {

// MediaFrame is a decoded audio or video frame
type MediaFrame interface {
// Implements image interface which can be saved to save frame as bitmap
image.Image

// Resample a frame to a specific profile
Resample(MediaProfile) (MediaFrame, error)

// Flags for the frame (Audio, Video)
Flags() MediaFlag
}

////////////////////////////////////////////////////////////////////////////////
// MEDIA ENCODING AND DECODING

// MediaDecodeContext provides packet data and streams for decoding
// frames of data
type MediaDecodeContext interface {
Expand All @@ -125,23 +170,7 @@ type MediaDecodeContext interface {
}

////////////////////////////////////////////////////////////////////////////////
// AUDIO INTERFACES

type AudioManager interface {
// OpenDefaultSink opens default output device
OpenDefaultSink() (AudioContext, error)

// Close audio stream
Close(AudioContext) error
}

type AudioContext interface {
// Write data to audio output device
Write(MediaFrame) error
}

////////////////////////////////////////////////////////////////////////////////
// DVB INTERFACES
// DVB INTERFACES - EXPERIMENTAL

// DVBManager encapsulates methods for DVB reception
type DVBManager interface {
Expand Down
Loading

0 comments on commit 55d359d

Please sign in to comment.