You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
joy4/av/avconv/avconv.go

256 lines
4.4 KiB
Go

3 years ago
package avconv
import (
"fmt"
"io"
"time"
"gitlab.com/ics_cinnamon/joy4/av"
"gitlab.com/ics_cinnamon/joy4/av/avutil"
"gitlab.com/ics_cinnamon/joy4/av/pktque"
"gitlab.com/ics_cinnamon/joy4/av/transcode"
3 years ago
)
var Debug bool
type Option struct {
Transcode bool
Args []string
3 years ago
}
type Options struct {
OutputCodecTypes []av.CodecType
}
type Demuxer struct {
transdemux *transcode.Demuxer
streams []av.CodecData
3 years ago
Options
Demuxer av.Demuxer
}
func (self *Demuxer) Close() (err error) {
if self.transdemux != nil {
return self.transdemux.Close()
}
return
}
func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
if err = self.prepare(); err != nil {
return
}
streams = self.streams
return
}
func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
if err = self.prepare(); err != nil {
return
}
return self.transdemux.ReadPacket()
}
func (self *Demuxer) prepare() (err error) {
if self.transdemux != nil {
return
}
/*
var streams []av.CodecData
if streams, err = self.Demuxer.Streams(); err != nil {
return
}
3 years ago
*/
supports := self.Options.OutputCodecTypes
transopts := transcode.Options{}
transopts.FindAudioDecoderEncoder = func(codec av.AudioCodecData, i int) (ok bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) {
if len(supports) == 0 {
return
}
support := false
for _, typ := range supports {
if typ == codec.Type() {
support = true
}
}
if support {
return
}
ok = true
var enctype av.CodecType
for _, typ := range supports {
3 years ago
if typ.IsAudio() {
if enc, _ = avutil.DefaultHandlers.NewAudioEncoder(typ); enc != nil {
enctype = typ
break
}
}
}
if enc == nil {
err = fmt.Errorf("avconv: convert %s->%s failed", codec.Type(), enctype)
return
}
// TODO: support per stream option
// enc.SetSampleRate ...
if dec, err = avutil.DefaultHandlers.NewAudioDecoder(codec); err != nil {
err = fmt.Errorf("avconv: decode %s failed", codec.Type())
return
}
return
}
self.transdemux = &transcode.Demuxer{
Options: transopts,
Demuxer: self.Demuxer,
}
if self.streams, err = self.transdemux.Streams(); err != nil {
return
}
return
}
func ConvertCmdline(args []string) (err error) {
output := ""
input := ""
flagi := false
flagv := false
flagt := false
flagre := false
duration := time.Duration(0)
options := Options{}
for _, arg := range args {
switch arg {
case "-i":
flagi = true
case "-v":
flagv = true
case "-t":
flagt = true
case "-re":
flagre = true
default:
switch {
case flagi:
flagi = false
input = arg
case flagt:
flagt = false
var f float64
fmt.Sscanf(arg, "%f", &f)
duration = time.Duration(f * float64(time.Second))
3 years ago
default:
output = arg
}
}
}
if input == "" {
err = fmt.Errorf("avconv: input file not specified")
return
}
if output == "" {
err = fmt.Errorf("avconv: output file not specified")
return
}
var demuxer av.DemuxCloser
var muxer av.MuxCloser
if demuxer, err = avutil.Open(input); err != nil {
return
}
defer demuxer.Close()
var handler avutil.RegisterHandler
if handler, muxer, err = avutil.DefaultHandlers.FindCreate(output); err != nil {
return
}
defer muxer.Close()
options.OutputCodecTypes = handler.CodecTypes
convdemux := &Demuxer{
Options: options,
Demuxer: demuxer,
}
defer convdemux.Close()
var streams []av.CodecData
if streams, err = demuxer.Streams(); err != nil {
return
}
var convstreams []av.CodecData
if convstreams, err = convdemux.Streams(); err != nil {
return
}
if flagv {
for _, stream := range streams {
fmt.Print(stream.Type(), " ")
}
fmt.Print("-> ")
for _, stream := range convstreams {
fmt.Print(stream.Type(), " ")
}
fmt.Println()
}
if err = muxer.WriteHeader(convstreams); err != nil {
return
}
filters := pktque.Filters{}
if flagre {
filters = append(filters, &pktque.Walltime{})
}
filterdemux := &pktque.FilterDemuxer{
Demuxer: convdemux,
Filter: filters,
3 years ago
}
for {
var pkt av.Packet
if pkt, err = filterdemux.ReadPacket(); err != nil {
if err == io.EOF {
err = nil
break
}
return
}
if flagv {
fmt.Println(pkt.Idx, pkt.Time, len(pkt.Data), pkt.IsKeyFrame)
}
if duration != 0 && pkt.Time > duration {
break
}
if err = muxer.WritePacket(pkt); err != nil {
return
}
}
if err = muxer.WriteTrailer(); err != nil {
return
}
return
}