Files
gmf/utils.go

255 lines
6.0 KiB
Go

package gmf
/*
#cgo pkg-config: libavcodec libavutil
#include "libavutil/avutil.h"
#include "libavutil/error.h"
#include "libavutil/mathematics.h"
#include "libavutil/rational.h"
#include "libavutil/samplefmt.h"
#include "libavcodec/avcodec.h"
#include "libavutil/imgutils.h"
uint32_t return_int (int num) {
return (uint32_t)(num);
}
uint8_t * gmf_alloc_buffer(int32_t fmt, int width, int height) {
int numBytes = av_image_get_buffer_size(fmt, width, height, 0);
return (uint8_t *) av_malloc(numBytes*sizeof(uint8_t));
}
*/
import "C"
import (
"bytes"
"errors"
"fmt"
"strconv"
"strings"
"syscall"
"unsafe"
)
type AVRational C.struct_AVRational
type AVR struct {
Num int
Den int
}
const (
AVERROR_EOF = -541478725
// AV_ROUND_PASS_MINMAX = 8192
)
var (
AV_TIME_BASE int = C.AV_TIME_BASE
AV_TIME_BASE_Q AVRational = AVRational{1, C.int(AV_TIME_BASE)}
)
func (a AVR) AVRational() AVRational {
return AVRational{C.int(a.Num), C.int(a.Den)}
}
func (a AVR) String() string {
return fmt.Sprintf("%d/%d", a.Num, a.Den)
}
func (a AVR) Av2qd() float64 {
return float64(a.Num) / float64(a.Den)
}
func (a AVR) Invert() AVR {
return AVR{Num: a.Den, Den: a.Num}
}
func (a AVRational) AVR() AVR {
return AVR{Num: int(a.num), Den: int(a.den)}
}
func AvError(averr int) error {
errlen := 1024
b := make([]byte, errlen)
C.av_strerror(C.int(averr), (*C.char)(unsafe.Pointer(&b[0])), C.size_t(errlen))
return errors.New(string(b[:bytes.Index(b, []byte{0})]))
}
func AvErrno(ret int) syscall.Errno {
if ret < 0 {
ret = -ret
}
return syscall.Errno(ret)
}
func RescaleQ(a int64, encBase AVRational, stBase AVRational) int64 {
return int64(C.av_rescale_q(C.int64_t(a), C.struct_AVRational(encBase), C.struct_AVRational(stBase)))
}
func RescaleQRnd(a int64, encBase AVRational, stBase AVRational) int64 {
return int64(C.av_rescale_q_rnd(C.int64_t(a), C.struct_AVRational(encBase), C.struct_AVRational(stBase), C.AV_ROUND_NEAR_INF|C.AV_ROUND_PASS_MINMAX))
}
func CompareTimeStamp(aTimestamp int, aTimebase AVRational, bTimestamp int, bTimebase AVRational) int {
return int(C.av_compare_ts(C.int64_t(aTimestamp), C.struct_AVRational(aTimebase),
C.int64_t(bTimestamp), C.struct_AVRational(bTimebase)))
}
func RescaleDelta(inTb AVRational, inTs int64, fsTb AVRational, duration int, last *int64, outTb AVRational) int64 {
return int64(C.av_rescale_delta(C.struct_AVRational(inTb), C.int64_t(inTs), C.struct_AVRational(fsTb), C.int(duration), (*C.int64_t)(unsafe.Pointer(&last)), C.struct_AVRational(outTb)))
}
func Rescale(a, b, c int64) int64 {
return int64(C.av_rescale(C.int64_t(a), C.int64_t(b), C.int64_t(c)))
}
func RescaleTs(pkt *Packet, encBase AVRational, stBase AVRational) {
C.av_packet_rescale_ts(&pkt.avPacket, C.struct_AVRational(encBase), C.struct_AVRational(stBase))
}
func GetSampleFmtName(fmt int32) string {
return C.GoString(C.av_get_sample_fmt_name(fmt))
}
func AvInvQ(q AVRational) AVRational {
avr := q.AVR()
return AVRational{C.int(avr.Den), C.int(avr.Num)}
}
// Synthetic video generator. It produces 25 iteratable frames.
// Used for tests.
func GenSyntVideoNewFrame(w, h int, fmt int32) chan *Frame {
yield := make(chan *Frame)
go func() {
defer close(yield)
for i := 0; i < 25; i++ {
frame := NewFrame().SetWidth(w).SetHeight(h).SetFormat(fmt)
if err := frame.ImgAlloc(); err != nil {
return
}
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
frame.SetData(0, y*frame.LineSize(0)+x, x+y+i*3)
}
}
// Cb and Cr
for y := 0; y < h/2; y++ {
for x := 0; x < w/2; x++ {
frame.SetData(1, y*frame.LineSize(1)+x, 128+y+i*2)
frame.SetData(2, y*frame.LineSize(2)+x, 64+x+i*5)
}
}
yield <- frame
}
}()
return yield
}
// tmp
func GenSyntVideoN(N, w, h int, fmt int32) chan *Frame {
yield := make(chan *Frame)
go func() {
defer close(yield)
for i := 0; i < N; i++ {
frame := NewFrame().SetWidth(w).SetHeight(h).SetFormat(fmt)
if err := frame.ImgAlloc(); err != nil {
return
}
for y := 0; y < h; y++ {
for x := 0; x < w; x++ {
frame.SetData(0, y*frame.LineSize(0)+x, x+y+i*3)
}
}
// Cb and Cr
for y := 0; y < h/2; y++ {
for x := 0; x < w/2; x++ {
frame.SetData(1, y*frame.LineSize(1)+x, 128+y+i*2)
frame.SetData(2, y*frame.LineSize(2)+x, 64+x+i*5)
}
}
yield <- frame
}
}()
return yield
}
func TimeCodeToComparable(timeCodeToTest, timeCodeStart, timeCodeEnd string) (hhToTest int, hhStart int, hhEnd int, err error) {
hhStart, err = TimeCodeToHundredths(timeCodeStart)
if err != nil {
return
}
hhEnd, err = TimeCodeToHundredths(timeCodeEnd)
if err != nil {
return
}
hhToTest, err = TimeCodeToHundredths(timeCodeToTest)
if err != nil {
return
}
if hhEnd < hhStart {
hhStart -= hhEnd
hhToTest -= hhEnd
if hhToTest <= 0 {
hhToTest += 24 * 60 * 60 * 100
}
hhEnd = 24 * 60 * 60 * 100
}
return
}
func IsTimeCodeBetween(timeCodeToTest, timeCodeStart, timeCodeEnd string) (bool, error) {
hhToTest, hhStart, hhEnd, err := TimeCodeToComparable(timeCodeToTest, timeCodeStart, timeCodeEnd)
if err != nil {
return false, err
}
return hhToTest >= hhStart && hhToTest <= hhEnd, nil
}
// TimeCodeToHHMMSS splits a timeCode = "20:15:31:00" to return 20, 15, 31
func TimeCodeToHHMMSS(timeCode string) (int, int, int, int, error) {
parts := strings.Split(timeCode, ":")
if len(parts) != 4 {
return -1, -1, -1, -1, errors.New("invalid timecode")
}
hh, err := strconv.Atoi(parts[0])
if err != nil {
return -1, -1, -1, -1, errors.New("invalid timecode")
}
mm, err := strconv.Atoi(parts[1])
if err != nil {
return -1, -1, -1, -1, errors.New("invalid timecode")
}
ss, err := strconv.Atoi(parts[2])
if err != nil {
return -1, -1, -1, -1, errors.New("invalid timecode")
}
hs, err := strconv.Atoi(parts[3])
if err != nil {
return -1, -1, -1, -1, errors.New("invalid timecode")
}
return hh, mm, ss, hs, nil
}
func TimeCodeToHundredths(timeCode string) (int, error) {
hh, mm, ss, hs, err := TimeCodeToHHMMSS(timeCode)
if err != nil {
return -1, err
}
return (hh * 60 * 60 * 100) + (mm * 60 * 100) + (ss * 100) + hs, nil
}