mirror of
https://github.com/zergon321/reisen.git
synced 2025-09-26 20:01:14 +08:00
162 lines
3.8 KiB
Go
Executable File
162 lines
3.8 KiB
Go
Executable File
package reisen
|
|
|
|
// #cgo pkg-config: libavutil libavformat libavcodec libswscale
|
|
// #include <libavcodec/avcodec.h>
|
|
// #include <libavformat/avformat.h>
|
|
// #include <libavutil/avutil.h>
|
|
// #include <libavutil/imgutils.h>
|
|
// #include <libswscale/swscale.h>
|
|
// #include <inttypes.h>
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
// VideoStream is a streaming holding
|
|
// video frames.
|
|
type VideoStream struct {
|
|
baseStream
|
|
swsCtx *C.struct_SwsContext
|
|
rgbaFrame *C.AVFrame
|
|
bufSize C.int
|
|
}
|
|
|
|
// AspectRatio returns the fraction of the video
|
|
// stream frame aspect ratio (1/0 if unknown).
|
|
func (video *VideoStream) AspectRatio() (int, int) {
|
|
return int(video.codecParams.sample_aspect_ratio.num),
|
|
int(video.codecParams.sample_aspect_ratio.den)
|
|
}
|
|
|
|
// Width returns the width of the video
|
|
// stream frame.
|
|
func (video *VideoStream) Width() int {
|
|
return int(video.codecParams.width)
|
|
}
|
|
|
|
// Height returns the height of the video
|
|
// stream frame.
|
|
func (video *VideoStream) Height() int {
|
|
return int(video.codecParams.height)
|
|
}
|
|
|
|
// OpenDecode opens the video stream for
|
|
// decoding with default parameters.
|
|
func (video *VideoStream) Open() error {
|
|
return video.OpenDecode(
|
|
int(video.codecParams.width),
|
|
int(video.codecParams.height),
|
|
InterpolationBicubic)
|
|
}
|
|
|
|
// OpenDecode opens the video stream for
|
|
// decoding with the specified parameters.
|
|
func (video *VideoStream) OpenDecode(width, height int, alg InterpolationAlgorithm) error {
|
|
err := video.open()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
video.rgbaFrame = C.av_frame_alloc()
|
|
|
|
if video.rgbaFrame == nil {
|
|
return fmt.Errorf(
|
|
"couldn't allocate a new RGBA frame")
|
|
}
|
|
|
|
video.bufSize = C.av_image_get_buffer_size(
|
|
C.AV_PIX_FMT_RGBA, C.int(width), C.int(height), 1)
|
|
|
|
if video.bufSize < 0 {
|
|
return fmt.Errorf(
|
|
"%d: couldn't get the buffer size", video.bufSize)
|
|
}
|
|
|
|
buf := (*C.uint8_t)(unsafe.Pointer(
|
|
C.av_malloc(bufferSize(video.bufSize))))
|
|
|
|
if buf == nil {
|
|
return fmt.Errorf(
|
|
"couldn't allocate an AV buffer")
|
|
}
|
|
|
|
status := C.av_image_fill_arrays(&video.rgbaFrame.data[0],
|
|
&video.rgbaFrame.linesize[0], buf, C.AV_PIX_FMT_RGBA,
|
|
C.int(width), C.int(height), 1)
|
|
|
|
if status < 0 {
|
|
return fmt.Errorf(
|
|
"%d: couldn't fill the image arrays", status)
|
|
}
|
|
|
|
video.swsCtx = C.sws_getContext(video.codecCtx.width,
|
|
video.codecCtx.height, video.codecCtx.pix_fmt,
|
|
C.int(width), C.int(height),
|
|
C.AV_PIX_FMT_RGBA, C.int(alg), nil, nil, nil)
|
|
|
|
if video.swsCtx == nil {
|
|
return fmt.Errorf(
|
|
"couldn't create an SWS context")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReadFrame reads the next frame from the stream.
|
|
func (video *VideoStream) ReadFrame() (Frame, bool, error) {
|
|
return video.ReadVideoFrame()
|
|
}
|
|
|
|
// ReadVideoFrame reads the next video frame
|
|
// from the video stream.
|
|
func (video *VideoStream) ReadVideoFrame() (*VideoFrame, bool, error) {
|
|
ok, err := video.read()
|
|
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
if ok && video.skip {
|
|
return nil, true, nil
|
|
}
|
|
|
|
// No more data.
|
|
if !ok {
|
|
return nil, false, nil
|
|
}
|
|
|
|
C.sws_scale(video.swsCtx, &video.frame.data[0],
|
|
&video.frame.linesize[0], 0,
|
|
video.codecCtx.height,
|
|
&video.rgbaFrame.data[0],
|
|
&video.rgbaFrame.linesize[0])
|
|
|
|
data := C.GoBytes(unsafe.
|
|
Pointer(video.rgbaFrame.data[0]),
|
|
video.bufSize)
|
|
frame := newVideoFrame(video, int64(video.frame.pts),
|
|
int(video.frame.coded_picture_number),
|
|
int(video.frame.display_picture_number),
|
|
int(video.codecCtx.width), int(video.codecCtx.height), data)
|
|
|
|
return frame, true, nil
|
|
}
|
|
|
|
// Close closes the video stream for decoding.
|
|
func (video *VideoStream) Close() error {
|
|
err := video.close()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
C.av_free(unsafe.Pointer(video.rgbaFrame))
|
|
video.rgbaFrame = nil
|
|
C.sws_freeContext(video.swsCtx)
|
|
video.swsCtx = nil
|
|
|
|
return nil
|
|
}
|