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" ) var Debug bool type Option struct { Transcode bool Args []string } type Options struct { OutputCodecTypes []av.CodecType } type Demuxer struct { transdemux *transcode.Demuxer streams []av.CodecData 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 } */ 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 { 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)) 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, } 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 }