func NewCapture(driver, device string) (*Capture, error) { id := Capture{index: -1} id.context = C.avformat_alloc_context() if id.context == (*C.AVFormatContext)(null) { return nil, fmt.Errorf("allocate output format context failed") } _driver := C.CString(driver) defer C.free(unsafe.Pointer(_driver)) ifmt := C.av_find_input_format(_driver) if ifmt == (*C.AVInputFormat)(null) { return nil, fmt.Errorf("cannot find input driver: %s", driver) } dev := C.CString(device) defer C.free(unsafe.Pointer(dev)) if C.avformat_open_input(&(id.context), dev, ifmt, (**C.AVDictionary)(null)) < 0 { return nil, fmt.Errorf("cannot open device %s", device) } if C.avformat_find_stream_info(id.context, (**C.AVDictionary)(null)) < 0 { return nil, fmt.Errorf("cannot find stream information") } num := int(id.context.nb_streams) streams := (*[1 << 30]*C.AVStream)(unsafe.Pointer(id.context.streams)) var deCtx *C.AVCodecContext for i := 0; i < num; i++ { if streams[i].codec.codec_type == C.AVMEDIA_TYPE_VIDEO { deCtx = streams[i].codec id.index = i break } } if id.index == -1 { return nil, fmt.Errorf("cannot find video stream") } codec := C.avcodec_find_decoder(deCtx.codec_id) if codec == (*C.AVCodec)(null) { return nil, fmt.Errorf("cannot find decode codec") } id.codec = C.avcodec_alloc_context3(codec) if C.avcodec_copy_context(id.codec, deCtx) != 0 { return nil, fmt.Errorf("cannot copy codec context") } if C.avcodec_open2(id.codec, codec, (**C.struct_AVDictionary)(null)) < 0 { return nil, fmt.Errorf("cannot open decode codec") } id.sws = C.sws_getContext(id.codec.width, id.codec.height, id.codec.pix_fmt, id.codec.width, id.codec.height, C.AV_PIX_FMT_YUV420P, C.SWS_BILINEAR, (*C.struct_SwsFilter)(null), (*C.struct_SwsFilter)(null), (*C.double)(null)) id.frame = C.av_frame_alloc() return &id, nil }
func avcodec_open(cctx _CodecContext, codec _Codec) int { avcodec_mutex.Lock() res := C.avcodec_open2(cctx.ctx, codec.codec, nil) avcodec_mutex.Unlock() return int(res) }
func (m *Muxer) AddVideoStream(codecId uint32, width, height int) bool { codec := C.avcodec_find_encoder(codecId) if codec == (*C.AVCodec)(null) { return false } m.context.oformat.video_codec = codecId stream := C.avformat_new_stream(m.context, codec) if stream == (*C.AVStream)(null) { return false } m.videoStream = Stream{stream, 0} c := m.videoStream.stream.codec c.codec_id = codecId c.codec_type = C.AVMEDIA_TYPE_VIDEO c.bit_rate = 400000 c.width = C.int(width) c.height = C.int(height) m.videoStream.stream.time_base = C.AVRational{1, 30} c.time_base = m.videoStream.stream.time_base c.gop_size = 12 c.pix_fmt = C.AV_PIX_FMT_YUV420P if m.context.oformat.flags&C.AVFMT_GLOBALHEADER != 0 { c.flags |= C.CODEC_FLAG_GLOBAL_HEADER } if C.avcodec_open2(c, (*C.AVCodec)(null), (**C.AVDictionary)(null)) < 0 { return false } m.recl = append(m.recl, func() { C.avcodec_close(c) }) return true }
func (stream *Stream) init() error { // need to allocate this first so that it can be closed on error stream.Frames = make(chan *Frame) if stream.avstream == nil { close(stream.Frames) return errors.New("nil avstream") } if stream.cdcctx != nil { stream.freeCodecContext() } stream.cdcctx = stream.avstream.codec if decoder := C.avcodec_find_decoder(stream.cdcctx.codec_id); decoder == nil || C.avcodec_open2(stream.cdcctx, decoder, nil) < 0 { stream.cdcctx = nil close(stream.Frames) return errors.New("Cannot find decoder for " + C.GoString(C.avcodec_get_name(stream.cdcctx.codec_id))) } stream.packets = make(chan *C.AVPacket) stream.frame = &Frame{} switch stream.avstream.codec.codec_type { case C.AVMEDIA_TYPE_AUDIO: stream.decodeF = avcodec_decode_audio case C.AVMEDIA_TYPE_VIDEO: stream.decodeF = avcodec_decode_video default: stream.freeCodecContext() close(stream.Frames) return errors.New("unsupported codec") } return nil }
func (codecContext *CodecContext) Codec() *Codec { if codecContext.CodecIsOpen() == false { codec := C.avcodec_find_decoder(codecContext.codec_id) if codec == nil { panic("Codec not found") } C.avcodec_open2((*C.struct_AVCodecContext)(codecContext), codec, nil) } return (*Codec)(codecContext.codec) }
func NewDecoder(filename string) (*Decoder, error) { self := new(Decoder) // format context var formatContext *C.AVFormatContext if C.avformat_open_input(&formatContext, C.CString(filename), nil, nil) != C.int(0) { return nil, errors.New(fmt.Sprintf("can't open %d", filename)) } if C.avformat_find_stream_info(formatContext, nil) < 0 { return nil, errors.New("find stream info error") } C.av_dump_format(formatContext, 0, C.CString(filename), 0) self.FormatContext = formatContext // streams var streams []*C.AVStream header := (*reflect.SliceHeader)(unsafe.Pointer(&streams)) header.Cap = int(formatContext.nb_streams) header.Len = int(formatContext.nb_streams) header.Data = uintptr(unsafe.Pointer(formatContext.streams)) self.Streams = streams for _, stream := range streams { switch stream.codec.codec_type { case C.AVMEDIA_TYPE_VIDEO: self.VideoStreams = append(self.VideoStreams, stream) case C.AVMEDIA_TYPE_AUDIO: self.AudioStreams = append(self.AudioStreams, stream) default: //TODO other stream } } // codecs for _, stream := range self.Streams { codec := C.avcodec_find_decoder(stream.codec.codec_id) if codec == nil { continue } var options *C.AVDictionary if C.avcodec_open2(stream.codec, codec, &options) < 0 { return nil, errors.New(fmt.Sprintf("open codec error %v", stream.codec)) } self.openedCodecs = append(self.openedCodecs, stream.codec) } // output channels self.audioFrames = make(chan *AudioFrame, 1024) self.timedFrames = make(chan *C.AVFrame) return self, nil }
func (this *CodecCtx) Open(dict *Dict) error { if this.IsOpen() { return nil } var avDict *C.struct_AVDictionary if dict != nil { avDict = dict.avDict } if averr := C.avcodec_open2(this.avCodecCtx, this.codec.avCodec, &avDict); averr < 0 { return errors.New(fmt.Sprintf("Error opening codec '%s:%s', averror: %s", this.codec.Name(), this.codec.LongName(), AvError(int(averr)))) } return nil }
func (m *Muxer) AddAudioStream(codecId uint32) bool { codec := C.avcodec_find_encoder(codecId) if codec == (*C.AVCodec)(null) { return false } m.context.oformat.audio_codec = codecId stream := C.avformat_new_stream(m.context, codec) if stream == (*C.AVStream)(null) { return false } m.audioStream = Stream{stream, 0} c := m.audioStream.stream.codec c.bit_rate = 48000 c.sample_fmt = C.AV_SAMPLE_FMT_S16 if C.check_sample_fmt(codec, c.sample_fmt) == 0 { return false } c.channels = 1 c.channel_layout = C.uint64_t(C.av_get_default_channel_layout(c.channels)) c.sample_rate = 44100 m.audioStream.stream.time_base = C.AVRational{1, c.sample_rate} c.time_base = m.audioStream.stream.time_base if m.context.oformat.flags&C.AVFMT_GLOBALHEADER != 0 { c.flags |= C.CODEC_FLAG_GLOBAL_HEADER } if codecId == C.AV_CODEC_ID_AAC { m.fifo = C.av_audio_fifo_alloc(c.sample_fmt, c.channels, 1) if m.fifo == (*C.AVAudioFifo)(null) { return false } m.recl = append(m.recl, func() { C.av_audio_fifo_free(m.fifo) }) } if C.avcodec_open2(c, (*C.AVCodec)(null), (**C.AVDictionary)(null)) < 0 { return false } m.recl = append(m.recl, func() { C.avcodec_close(c) }) if c.codec.capabilities&C.CODEC_CAP_VARIABLE_FRAME_SIZE != 0 { c.frame_size = 10000 } return true }
func NewEncoder(codec uint32, in image.Image, out io.Writer) (*Encoder, error) { _codec := C.avcodec_find_encoder(codec) if _codec == nil { return nil, fmt.Errorf("could not find codec") } c := C.avcodec_alloc_context3(_codec) f := C.avcodec_alloc_frame() c.bit_rate = 400000 // resolution must be a multiple of two w, h := C.int(in.Bounds().Dx()), C.int(in.Bounds().Dy()) if w%2 == 1 || h%2 == 1 { return nil, fmt.Errorf("Bad image dimensions (%d, %d), must be even", w, h) } log.Printf("Encoder dimensions: %d, %d", w, h) c.width = w c.height = h c.time_base = C.AVRational{1, 25} // FPS c.gop_size = 10 // emit one intra frame every ten frames c.max_b_frames = 1 underlying_im := image.NewYCbCr(in.Bounds(), image.YCbCrSubsampleRatio420) c.pix_fmt = C.PIX_FMT_YUV420P f.data[0] = ptr(underlying_im.Y) f.data[1] = ptr(underlying_im.Cb) f.data[2] = ptr(underlying_im.Cr) f.linesize[0] = w f.linesize[1] = w / 2 f.linesize[2] = w / 2 if C.avcodec_open2(c, _codec, nil) < 0 { return nil, fmt.Errorf("could not open codec") } _swscontext := C.sws_getContext(w, h, C.PIX_FMT_RGB0, w, h, C.PIX_FMT_YUV420P, C.SWS_BICUBIC, nil, nil, nil) e := &Encoder{codec, in, underlying_im, out, _codec, c, _swscontext, f, make([]byte, 16*1024)} return e, nil }
//Initialize the Context to use the given Codec func (ctxt *Context) AvcodecOpen2(c *Codec, d **Dictionary) int { return int(C.avcodec_open2((*C.struct_AVCodecContext)(ctxt), (*C.struct_AVCodec)(c), (**C.struct_AVDictionary)(unsafe.Pointer(d)))) }
// NewGenerator returns new generator of screenshots for the video file fn. func NewGenerator(fn string) (_ *Generator, err error) { avfCtx := C.avformat_alloc_context() cfn := C.CString(fn) defer C.free(unsafe.Pointer(cfn)) if C.avformat_open_input(&avfCtx, cfn, nil, nil) != 0 { return nil, errors.New("can't open input stream") } defer func() { if err != nil { C.avformat_close_input(&avfCtx) } }() if C.avformat_find_stream_info(avfCtx, nil) < 0 { return nil, errors.New("can't get stream info") } duration := int64(avfCtx.duration) / 1000 bitrate := int(avfCtx.bit_rate) / 1000 numberOfStreams := int(avfCtx.nb_streams) hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(avfCtx.streams)), Len: numberOfStreams, Cap: numberOfStreams, } streams := *(*[]*C.struct_AVStream)(unsafe.Pointer(&hdr)) vStreamIndex := -1 aStreamIndex := -1 for i := 0; i < numberOfStreams; i++ { if streams[i].codec.codec_type == C.AVMEDIA_TYPE_VIDEO { vStreamIndex = i } else if streams[i].codec.codec_type == C.AVMEDIA_TYPE_AUDIO { aStreamIndex = i } } if vStreamIndex == -1 { return nil, errors.New("no video stream") } avcCtx := streams[vStreamIndex].codec vCodec := C.avcodec_find_decoder(avcCtx.codec_id) if vCodec == nil { return nil, errors.New("can't find decoder") } if C.avcodec_open2(avcCtx, vCodec, nil) != 0 { return nil, errors.New("can't initialize codec context") } width := int(avcCtx.width) height := int(avcCtx.height) fps := (float64(streams[vStreamIndex].r_frame_rate.num) / float64(streams[vStreamIndex].r_frame_rate.den)) vCodecName := strings.ToUpper(C.GoString(vCodec.name)) vCodecHuman := C.GoString(vCodec.long_name) aCodecName := "" aCodecHuman := "" if aStreamIndex != -1 { aacCtx := streams[aStreamIndex].codec aCodec := C.avcodec_find_decoder(aacCtx.codec_id) if aCodec != nil { aCodecName = strings.ToUpper(C.GoString(aCodec.name)) aCodecHuman = C.GoString(aCodec.long_name) } } return &Generator{ Width: width, Height: height, Duration: duration, VideoCodec: vCodecName, VideoCodecLongName: vCodecHuman, AudioCodec: aCodecName, AudioCodecLongName: aCodecHuman, numberOfStreams: numberOfStreams, vStreamIndex: vStreamIndex, aStreamIndex: aStreamIndex, FPS: fps, Bitrate: bitrate, streams: streams, avfContext: avfCtx, avcContext: avcCtx, }, nil }