Files
goav/example/tutorial01.go
T

247 lines
5.6 KiB
Go

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()
}