Files
Corebreaker 001779d032 Working tutorial; More hooks to libav API; removes debbuging print
Missing constants, additional functions, remove errors
2019-04-07 13:45:00 -04:00

212 lines
6.7 KiB
Go

// Use of this source code is governed by a MIT license that can be found in the LICENSE file.
// Giorgis (habtom@giorgis.io)
package avutil
/*
#cgo pkg-config: libavutil
#include <libavutil/frame.h>
#include <stdlib.h>
*/
import "C"
import (
"fmt"
"image"
"log"
"unsafe"
)
type (
AvBuffer C.struct_AVBuffer
AvBufferRef C.struct_AVBufferRef
AvBufferPool C.struct_AVBufferPool
Frame C.struct_AVFrame
AvFrameSideData C.struct_AVFrameSideData
AvFrameSideDataType C.enum_AVFrameSideDataType
)
func AvprivFrameGetMetadatap(f *Frame) *Dictionary {
return (*Dictionary)(unsafe.Pointer(f.metadata))
}
func AvFrameSetQpTable(f *Frame, b *AvBufferRef, s, q int) int {
return int(C.av_frame_set_qp_table((*C.struct_AVFrame)(unsafe.Pointer(f)), (*C.struct_AVBufferRef)(unsafe.Pointer(b)), C.int(s), C.int(q)))
}
func AvFrameGetQpTable(f *Frame, s, t *int) int8 {
return int8(*C.av_frame_get_qp_table((*C.struct_AVFrame)(unsafe.Pointer(f)), (*C.int)(unsafe.Pointer(s)), (*C.int)(unsafe.Pointer(t))))
}
//Allocate an Frame and set its fields to default values.
func AvFrameAlloc() *Frame {
return (*Frame)(unsafe.Pointer(C.av_frame_alloc()))
}
//Free the frame and any dynamically allocated objects in it, e.g.
func AvFrameFree(f *Frame) {
C.av_frame_free((**C.struct_AVFrame)(unsafe.Pointer(&f)))
}
//Allocate new buffer(s) for audio or video data.
func AvFrameGetBuffer(f *Frame, a int) int {
return int(C.av_frame_get_buffer((*C.struct_AVFrame)(unsafe.Pointer(f)), C.int(a)))
}
//Setup a new reference to the data described by an given frame.
func AvFrameRef(d, s *Frame) int {
return int(C.av_frame_ref((*C.struct_AVFrame)(unsafe.Pointer(d)), (*C.struct_AVFrame)(unsafe.Pointer(s))))
}
//Create a new frame that references the same data as src.
func AvFrameClone(f *Frame) *Frame {
return (*Frame)(C.av_frame_clone((*C.struct_AVFrame)(unsafe.Pointer(f))))
}
//Unreference all the buffers referenced by frame and reset the frame fields.
func AvFrameUnref(f *Frame) {
cf := (*C.struct_AVFrame)(unsafe.Pointer(f))
C.av_frame_unref(cf)
}
//Move everythnig contained in src to dst and reset src.
func AvFrameMoveRef(d, s *Frame) {
C.av_frame_move_ref((*C.struct_AVFrame)(unsafe.Pointer(d)), (*C.struct_AVFrame)(unsafe.Pointer(s)))
}
//Check if the frame data is writable.
func AvFrameIsWritable(f *Frame) int {
return int(C.av_frame_is_writable((*C.struct_AVFrame)(unsafe.Pointer(f))))
}
//Ensure that the frame data is writable, avoiding data copy if possible.
func AvFrameMakeWritable(f *Frame) int {
return int(C.av_frame_make_writable((*C.struct_AVFrame)(unsafe.Pointer(f))))
}
//Copy only "metadata" fields from src to dst.
func AvFrameCopyProps(d, s *Frame) int {
return int(C.av_frame_copy_props((*C.struct_AVFrame)(unsafe.Pointer(d)), (*C.struct_AVFrame)(unsafe.Pointer(s))))
}
//Get the buffer reference a given data plane is stored in.
func AvFrameGetPlaneBuffer(f *Frame, p int) *AvBufferRef {
return (*AvBufferRef)(C.av_frame_get_plane_buffer((*C.struct_AVFrame)(unsafe.Pointer(f)), C.int(p)))
}
//Add a new side data to a frame.
func AvFrameNewSideData(f *Frame, d AvFrameSideDataType, s int) *AvFrameSideData {
return (*AvFrameSideData)(C.av_frame_new_side_data((*C.struct_AVFrame)(unsafe.Pointer(f)), (C.enum_AVFrameSideDataType)(d), C.int(s)))
}
func AvFrameGetSideData(f *Frame, t AvFrameSideDataType) *AvFrameSideData {
return (*AvFrameSideData)(C.av_frame_get_side_data((*C.struct_AVFrame)(unsafe.Pointer(f)), (C.enum_AVFrameSideDataType)(t)))
}
func Data(f *Frame) (data [8]*uint8) {
for i := range data {
data[i] = (*uint8)(f.data[i])
}
return
}
func Linesize(f *Frame) (linesize [8]int32) {
for i := range linesize {
linesize[i] = int32(f.linesize[i])
}
return
}
//GetPicture creates a YCbCr image from the frame
func GetPicture(f *Frame) (img *image.YCbCr, err error) {
// For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
// For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
// For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
// For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
// For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
// For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
w := int(f.linesize[0])
h := int(f.height)
r := image.Rectangle{image.Point{0, 0}, image.Point{w, h}}
// TODO: Use the sub sample ratio from the input image 'f.format'
img = image.NewYCbCr(r, image.YCbCrSubsampleRatio420)
// convert the frame data data to a Go byte array
img.Y = C.GoBytes(unsafe.Pointer(f.data[0]), C.int(w*h))
wCb := int(f.linesize[1])
if unsafe.Pointer(f.data[1]) != nil {
img.Cb = C.GoBytes(unsafe.Pointer(f.data[1]), C.int(wCb*h/2))
}
wCr := int(f.linesize[2])
if unsafe.Pointer(f.data[2]) != nil {
img.Cr = C.GoBytes(unsafe.Pointer(f.data[2]), C.int(wCr*h/2))
}
return
}
// SetPicture sets the image pointer of |f| to the image pointers of |img|
func SetPicture(f *Frame, img *image.YCbCr) {
d := Data(f)
// l := Linesize(f)
// FIXME: Save the original pointers somewhere, this is a memory leak
d[0] = (*uint8)(unsafe.Pointer(&img.Y[0]))
// d[1] = (*uint8)(unsafe.Pointer(&img.Cb[0]))
}
func GetPictureRGB(f *Frame) (img *image.RGBA, err error) {
w := int(f.linesize[0])
h := int(f.height)
r := image.Rectangle{image.Point{0, 0}, image.Point{w, h}}
// TODO: Use the sub sample ratio from the input image 'f.format'
img = image.NewRGBA(r)
// convert the frame data data to a Go byte array
img.Pix = C.GoBytes(unsafe.Pointer(f.data[0]), C.int(w*h))
img.Stride = w
log.Println("w", w, "h", h)
return
}
func AvSetFrame(f *Frame, w int, h int, pixFmt int) (err error) {
f.width = C.int(w)
f.height = C.int(h)
f.format = C.int(pixFmt)
if ret := C.av_frame_get_buffer((*C.struct_AVFrame)(unsafe.Pointer(f)), 32 /*alignment*/); ret < 0 {
err = fmt.Errorf("Error allocating avframe buffer. Err: %v", ret)
return
}
return
}
func AvFrameGetInfo(f *Frame) (width int, height int, linesize [8]int32, data [8]*uint8) {
width = int(f.linesize[0])
height = int(f.height)
for i := range linesize {
linesize[i] = int32(f.linesize[i])
}
for i := range data {
data[i] = (*uint8)(f.data[i])
}
// log.Println("Linesize is ", f.linesize, "Data is", data)
return
}
func GetBestEffortTimestamp(f *Frame) int64 {
return int64(f.best_effort_timestamp)
}
// //static int get_video_buffer (Frame *frame, int align)
// func GetVideoBuffer(f *Frame, a int) int {
// return int(C.get_video_buffer(f, C.int(a)))
// }
// //static int get_audio_buffer (Frame *frame, int align)
// func GetAudioBuffer(f *Frame, a int) int {
// return C.get_audio_buffer(f, C.int(a))
// }
// //static void get_frame_defaults (Frame *frame)
// func GetFrameDefaults(f *Frame) {
// C.get_frame_defaults(*C.struct_AVFrame(f))
// }