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 Open(name string) (*MediaFile, error) { file := &MediaFile{ Name: name, packets: make(chan *C.AVPacket, 8), } cName := C.CString(name) defer C.free(unsafe.Pointer(cName)) if C.avformat_open_input(&file.fmtctx, cName, nil, nil) < 0 { return nil, errors.New("cannot open file " + name) } runtime.SetFinalizer(file, (*MediaFile).Close) if C.avformat_find_stream_info(file.fmtctx, nil) < 0 { return nil, errors.New("cannot find stream info for file " + name) } file.Streams = make([]Stream, file.fmtctx.nb_streams) for i := range file.Streams { file.Streams[i] = Stream{ avstream: C.AVFormatContext_GetStream(file.fmtctx, C.int(i)), } } return file, nil }
func av_open_input_file(ctx *FormatContext, filename string, format *InputFormat, bufsize int, params *FormatParameters) int { cfilename := C.CString(filename) //defer C.free(unsafe.Pointer(cfilename)) return int(C.avformat_open_input( &ctx.ctx, cfilename, /*(*C.AVInputFormat)(unsafe.Pointer(&format))*/ nil, nil)) }
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 *FmtCtx) OpenInput(filename string) error { cfilename := C.CString(filename) defer C.free(unsafe.Pointer(cfilename)) if averr := C.avformat_open_input(&this.avCtx, cfilename, nil, nil); averr < 0 { return errors.New(fmt.Sprintf("Error opening input '%s': %s", filename, AvError(int(averr)))) } if averr := C.avformat_find_stream_info(this.avCtx, nil); averr < 0 { return errors.New(fmt.Sprintf("Unable to find stream info: %s", AvError(int(averr)))) } // C.av_opt_set_int(this.avCtx.codec, "refcounted_frames", 1, 0) return nil }
func (ctx *Context) OpenInput(fileName string, input *Input, options *avutil.Dictionary) error { cFileName := C.CString(fileName) defer C.free(unsafe.Pointer(cFileName)) var cInput *C.AVInputFormat if input != nil { cInput = input.CAVInputFormat } var cOptions **C.AVDictionary if options != nil { cOptions = (**C.AVDictionary)(unsafe.Pointer(&options.CAVDictionary)) } code := C.avformat_open_input(&ctx.CAVFormatContext, cFileName, cInput, cOptions) if code < 0 { return avutil.NewErrorFromCode(avutil.ErrorCode(code)) } return nil }
func main() { var ( fmt_ctx *C.AVFormatContext video_stream_idx C.int pkt C.AVPacket fn string ) flag.StringVar(&fn, "i", fn, "Input filename") flag.Parse() if fn == "" { flag.PrintDefaults() os.Exit(1) } cfn := C.CString(fn) defer C.free(unsafe.Pointer(cfn)) C.av_register_all() if err := C.avformat_open_input(&fmt_ctx, cfn, nil, nil); err < 0 { log.Fatalf("Could not open source file %s, %d\n", fn, err) } // The smd codecs aren't too happy with missing PTS fmt_ctx.flags |= C.AVFMT_FLAG_GENPTS defer C.avformat_close_input(&fmt_ctx) if err := C.avformat_find_stream_info(fmt_ctx, nil); err < 0 { log.Fatalf("Could not find stream information: %d", err) } if err := open_codec_context(&video_stream_idx, fmt_ctx, C.AVMEDIA_TYPE_VIDEO); err < 0 { log.Fatalf("Could not open codec context: %d", err) } log.Printf("fmt_ctx: %+v", fmt_ctx) streams := (*[32]*C.AVStream)(unsafe.Pointer(fmt_ctx.streams)) log.Printf("video stream codec: %+v", streams[video_stream_idx].codec.codec_id) log.Printf("time_base: %+v", streams[video_stream_idx].time_base) num := 1000000 * float64(streams[video_stream_idx].time_base.num) den := float64(streams[video_stream_idx].time_base.den) var codec C.ismd_codec_type_t switch vc := streams[video_stream_idx].codec.codec_id; vc { case C.AV_CODEC_ID_H264: codec = C.ISMD_CODEC_TYPE_H264 case C.AV_CODEC_ID_MPEG1VIDEO: fallthrough case C.AV_CODEC_ID_MPEG2VIDEO: codec = C.ISMD_CODEC_TYPE_MPEG2 case C.AV_CODEC_ID_MPEG4: codec = C.ISMD_CODEC_TYPE_MPEG4 default: log.Fatalf("Unhandled video codec: %d", vc) } Init(codec, C.GDL_PLANE_ID_UPP_C) defer Destroy() C.av_init_packet(&pkt) pkt.data = nil pkt.size = 0 running := true go func() { os.Stdin.Read(make([]byte, 1)) running = false }() frame := 0 for running && C.av_read_frame(fmt_ctx, &pkt) >= 0 { orig_pkt := pkt wrote := false for pkt.stream_index == video_stream_idx && (pkt.size > 0) { pts := num * float64(pkt.pts) / den WriteToInputPort(uintptr(unsafe.Pointer(pkt.data)), C.size_t(pkt.size), pts, 32*1024) wrote = true break } if wrote { frame++ if frame%100 == 0 { var stat C.ismd_vidrend_stats_t C.ismd_vidrend_get_stats(m_video_render, &stat) log.Printf("%+v", stat) } } C.av_free_packet(&orig_pkt) } }
//Open an input stream and read the header. func AvformatOpenInput(ps **Context, fi string, fmt *InputFormat, d **Dictionary) int { return int(C.avformat_open_input((**C.struct_AVFormatContext)(unsafe.Pointer(ps)), C.CString(fi), (*C.struct_AVInputFormat)(fmt), (**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 }