From 12b407d5e4a1e835c9cc6c6cafb45d712de359d1 Mon Sep 17 00:00:00 2001 From: nareix Date: Tue, 12 Jul 2016 13:15:54 +0800 Subject: [PATCH] add avconv.go --- av/avconv/avconv.go | 249 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 av/avconv/avconv.go diff --git a/av/avconv/avconv.go b/av/avconv/avconv.go new file mode 100644 index 0000000..96a0588 --- /dev/null +++ b/av/avconv/avconv.go @@ -0,0 +1,249 @@ +package avconv + +import ( + "fmt" + "io" + "time" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/av" + "github.com/nareix/joy4/av/transcode" +) + +var Debug bool + +func Open(filename string) (demuxer av.DemuxCloser, err error) { + if demuxer, err = avutil.Open(filename); err != nil { + err = fmt.Errorf("avconv: open input `%s` failed: %s", filename, err) + return + } + return +} + +func Create(filename string) (muxer av.MuxCloser, err error) { + if muxer, err = avutil.Create(filename); err != nil { + err = fmt.Errorf("avconv: create output `%s` failed: %s", filename, err) + return + } + return +} + +type Option struct { + Transcode bool + Args []string +} + +type Options struct { +} + +type Demuxer struct { + transdemux *transcode.Demuxer + streams []av.CodecData + Options + Demuxer av.Demuxer + Muxer av.Muxer +} + +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 + } + */ + + supports := self.Muxer.SupportedCodecTypes() + + transopts := transcode.Options{} + transopts.FindAudioDecoderEncoder = func(codec av.AudioCodecData, i int) (ok bool, err error, dec av.AudioDecoder, enc av.AudioEncoder) { + support := false + for _, typ := range supports { + if typ == codec.Type() { + support = true + } + } + + if support { + return + } + ok = true + + for _, typ:= range supports { + if typ.IsAudio() { + if enc, _ = avutil.DefaultHandlers.NewAudioEncoder(typ); dec != nil { + break + } + } + } + if enc == nil { + err = fmt.Errorf("avconv: convert %s failed", codec.Type()) + 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 + duration := time.Duration(0) + options := Options{} + + for _, arg := range args { + switch arg { + case "-i": + flagi = true + + case "-v": + flagv = true + + case "-t": + flagt = 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)) + + 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 = Open(input); err != nil { + return + } + defer demuxer.Close() + + if muxer, err = Create(output); err != nil { + return + } + defer muxer.Close() + + convdemux := &Demuxer{ + Options: options, + Demuxer: demuxer, + Muxer: muxer, + } + 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 + } + + for { + var pkt av.Packet + if pkt, err = convdemux.ReadPacket(); err != nil { + if err == io.EOF { + err = nil + break + } + return + } + if flagv { + fmt.Println(pkt.Idx, pkt.Time, len(pkt.Data)) + } + if duration != 0 && pkt.Time > duration { + break + } + if err = muxer.WritePacket(pkt); err != nil { + return + } + } + + if err = muxer.WriteTrailer(); err != nil { + return + } + + return +} +