package main import ( "fmt" "github.com/giorgisio/goav/avcodec" "github.com/giorgisio/goav/avformat" "github.com/giorgisio/goav/avutil" "github.com/giorgisio/goav/swscale" "log" "os" "unsafe" ) func main() { filename := "sample.mp4" var ( ctxtFormat *avformat.AvFormatContext ctxtSource *avcodec.AvCodecContext ctxtDest *avcodec.AvCodecContext videoCodec *avcodec.AvCodec videoFrame *avutil.AvFrame videoFrameRGB *avutil.AvFrame packet *avcodec.AvPacket ctxtSws *swscale.SwsContext videoStream int frameFinished int numBytes int url string ) //media_type *avutil.AvMediaType // Register all formats and codecs avformat.Av_register_all() // Open video file if avformat.Avformat_open_input(&ctxtFormat, filename, nil, nil) != 0 { log.Println("Error: Couldn't open file.") return } // Retrieve stream information if avformat.Avformat_find_stream_info(ctxtFormat, nil) < 0 { log.Println("Error: Couldn't find stream information.") return } // Dump information about file onto standard error avformat.Av_dump_format(ctxtFormat, 0, url, 0) // Find the first video stream videoStream = -1 //ctxtFormat->nb_streams n := ctxtFormat.Nb_streams() //ctxtFormat->streams[] s := ctxtFormat.Streams() //s2 := avformat.StreamsOne(ctxtFormat, 1) log.Print("Number of Streams:", n) for i := 0; i < int(n); i++ { // ctxtFormat->streams[i]->codec->codec_type log.Println("Stream Number:", i) //FIX: AvMEDIA_TYPE_VIDEO if (*avformat.AvCodecContext)(s.Codec()) != nil { videoStream = i break } } if videoStream == -1 { log.Println("Couldn't find a video stream") return } codec := s.Codec() // Get a pointer to the codec context for the video stream //ctxtSource = ctxtFormat.streams[videoStream].codec ctxtSource = (*avcodec.AvCodecContext)(unsafe.Pointer(&codec)) log.Println("Bit Rate:", ctxtSource.BitRate()) log.Println("Channels:", ctxtSource.Channels()) log.Println("Coded_height:", ctxtSource.CodedHeight()) log.Println("Coded_width:", ctxtSource.CodedWidth()) log.Println("Coder_type:", ctxtSource.CoderType()) log.Println("Height:", ctxtSource.Height()) log.Println("Profile:", ctxtSource.Profile()) log.Println("Width:", ctxtSource.Width()) log.Println("Codec ID:", ctxtSource.CodecId()) //C.enum_AVCodecID codec_id := ctxtSource.CodecId() // Find the decoder for the video stream videoCodec = avcodec.AvcodecFindDecoder(codec_id) if videoCodec == nil { log.Println("Error: Unsupported codec!") return // Codec not found } // Copy context ctxtDest = videoCodec.AvcodecAllocContext3() if ctxtDest.AvcodecCopyContext(ctxtSource) != 0 { log.Println("Error: Couldn't copy codec context") return // Error copying codec context } // Open codec if ctxtDest.AvcodecOpen2(videoCodec, nil) < 0 { return // Could not open codec } // Allocate video frame videoFrame = avutil.Av_frame_alloc() // Allocate an AvFrame structure if videoFrameRGB = avutil.Av_frame_alloc(); videoFrameRGB == nil { return } //##TODO var a swscale.AvPixelFormat var b int //avcodec.AvPixelFormat //avcodec.PIX_FMT_RGB24 //avcodec.SWS_BILINEAR w := ctxtDest.Width() h := ctxtDest.Height() pix_fmt := ctxtDest.PixFmt() // Determine required buffer size and allocate buffer numBytes = avcodec.AvpictureGetSize((avcodec.AvPixelFormat)(a), w, h) buffer := avutil.Av_malloc(uintptr(numBytes)) // Assign appropriate parts of buffer to image planes in videoFrameRGB // Note that videoFrameRGB is an AvFrame, but AvFrame is a superset // of AvPicture avp := (*avcodec.AvPicture)(unsafe.Pointer(videoFrameRGB)) avp.AvpictureFill((*uint8)(buffer), (avcodec.AvPixelFormat)(a), w, h) // initialize SWS context for software scaling ctxtSws = swscale.Sws_getContext(w, h, (swscale.AvPixelFormat)(pix_fmt), w, h, a, b, nil, nil, nil, ) // Read frames and save first five frames to disk i := 0 for avformat.Av_read_frame(ctxtFormat, packet) >= 0 { // Is this a packet from the video stream? s := packet.StreamIndex() if s == videoStream { // Decode video frame ctxtDest.AvcodecDecodeVideo2((*avcodec.AvFrame)(unsafe.Pointer(videoFrame)), &frameFinished, packet) // Did we get a video frame? if frameFinished > 0 { // Convert the image from its native format to RGB d := avutil.Data(videoFrame) l := avutil.Linesize(videoFrame) dr := avutil.Data(videoFrameRGB) lr := avutil.Linesize(videoFrameRGB) swscale.Sws_scale(ctxtSws, d, l, 0, h, dr, lr, ) // Save the frame to disk if i <= 5 { saveFrame(videoFrameRGB, w, h, i) } i++ } } // Free the packet that was allocated by av_read_frame packet.AvFreePacket() } // Free the RGB image avutil.Av_free(buffer) avutil.Av_frame_free(videoFrameRGB) // Free the YUV frame avutil.Av_frame_free(videoFrame) // Close the codecs ctxtDest.AvcodecClose() ctxtSource.AvcodecClose() // Close the video file avformat.Avformat_close_input(ctxtFormat) } func saveFrame(videoFrame *avutil.AvFrame, width int, height int, iFrame int) { var szFilename string var y int var file *os.File var err error szFilename = "" // Open file szFilename = fmt.Sprintf("frame%d.ppm", iFrame) if file, err = os.Open(szFilename); err != nil { log.Println("Error Reading") } // Write header fh := fmt.Sprintf("P6\n%d %d\n255\n", width, height) log.Println(fh) // Write pixel data for y = 0; y < height; y++ { // d := avutil.Data(videoFrame) // l := avutil.Linesize(videoFrame) //##TODO f := make([]byte, 100) file.Write(f) } file.Close() }