mirror of
https://github.com/qrtc/ffmpeg-dev-go.git
synced 2025-10-06 16:19:38 +08:00
2023-10-31 09:16:44 CST W44D2
This commit is contained in:
15
avcodec.go
15
avcodec.go
@@ -3472,6 +3472,11 @@ func (avctx *AVCodecContext) GetPropertiesAddr() *uint32 {
|
|||||||
return (*uint32)(&avctx.properties)
|
return (*uint32)(&avctx.properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
FF_CODEC_PROPERTY_LOSSLESS = uint32(C.FF_CODEC_PROPERTY_LOSSLESS)
|
||||||
|
FF_CODEC_PROPERTY_CLOSED_CAPTIONS = uint32(C.FF_CODEC_PROPERTY_CLOSED_CAPTIONS)
|
||||||
|
)
|
||||||
|
|
||||||
// GetCodedSideData gets `AVCodecContext.coded_side_data` value.
|
// GetCodedSideData gets `AVCodecContext.coded_side_data` value.
|
||||||
func (avctx *AVCodecContext) GetCodedSideData() *AVPacketSideData {
|
func (avctx *AVCodecContext) GetCodedSideData() *AVPacketSideData {
|
||||||
return (*AVPacketSideData)(avctx.coded_side_data)
|
return (*AVPacketSideData)(avctx.coded_side_data)
|
||||||
@@ -3730,7 +3735,7 @@ func AvCodecGetLowres(avctx *AVCodecContext) int32 {
|
|||||||
//
|
//
|
||||||
// AvCodecSetLowres
|
// AvCodecSetLowres
|
||||||
func AvCodecSetLowres(avctx *AVCodecContext, i int32) {
|
func AvCodecSetLowres(avctx *AVCodecContext, i int32) {
|
||||||
C.av_codec_set_lowres((*C.struct_AVCodecContext)(avctx), C.int(i))
|
C.av_codec_set_lowres((*C.struct_AVCodecContext)(avctx), (C.int)(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: No use.
|
// Deprecated: No use.
|
||||||
@@ -3744,7 +3749,7 @@ func AvCodecGetSeekPreroll(avctx *AVCodecContext) int32 {
|
|||||||
//
|
//
|
||||||
// AvCodecSetSeekPreroll
|
// AvCodecSetSeekPreroll
|
||||||
func AvCodecSetSeekPreroll(avctx *AVCodecContext, i int32) {
|
func AvCodecSetSeekPreroll(avctx *AVCodecContext, i int32) {
|
||||||
C.av_codec_set_seek_preroll((*C.struct_AVCodecContext)(avctx), C.int(i))
|
C.av_codec_set_seek_preroll((*C.struct_AVCodecContext)(avctx), (C.int)(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: No use.
|
// Deprecated: No use.
|
||||||
@@ -4290,13 +4295,13 @@ func AvSubtitleFree(s *AVSubtitle) {
|
|||||||
// The default callback for AVCodecContext.get_buffer2().
|
// The default callback for AVCodecContext.get_buffer2().
|
||||||
func AvCodecDefaultGetBuffer2(avctx *AVCodecContext, frame *AVFrame, flags int32) int32 {
|
func AvCodecDefaultGetBuffer2(avctx *AVCodecContext, frame *AVFrame, flags int32) int32 {
|
||||||
return (int32)(C.avcodec_default_get_buffer2((*C.struct_AVCodecContext)(avctx),
|
return (int32)(C.avcodec_default_get_buffer2((*C.struct_AVCodecContext)(avctx),
|
||||||
(*C.struct_AVFrame)(frame), C.int(flags)))
|
(*C.struct_AVFrame)(frame), (C.int)(flags)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default callback for AVCodecContext.get_encode_buffer().
|
// The default callback for AVCodecContext.get_encode_buffer().
|
||||||
func AvCodecDefaultGetEncodeBuffer(avctx *AVCodecContext, pkt *AVPacket, flags int32) int32 {
|
func AvCodecDefaultGetEncodeBuffer(avctx *AVCodecContext, pkt *AVPacket, flags int32) int32 {
|
||||||
return (int32)(C.avcodec_default_get_encode_buffer((*C.struct_AVCodecContext)(avctx),
|
return (int32)(C.avcodec_default_get_encode_buffer((*C.struct_AVCodecContext)(avctx),
|
||||||
(*C.struct_AVPacket)(pkt), C.int(flags)))
|
(*C.struct_AVPacket)(pkt), (C.int)(flags)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvCodecAlignDimensions modifies width and height values so that they will result in a memory
|
// AvCodecAlignDimensions modifies width and height values so that they will result in a memory
|
||||||
@@ -4321,7 +4326,7 @@ func AvCodecEnumToChromaPos(xpos, ypos *int32, pos AVChromaLocation) int32 {
|
|||||||
|
|
||||||
// AvCodecChromaPosToEnum converts swscale x/y chroma position to AVChromaLocation.
|
// AvCodecChromaPosToEnum converts swscale x/y chroma position to AVChromaLocation.
|
||||||
func AvCodecChromaPosToEnum(xpos, ypos int32) AVChromaLocation {
|
func AvCodecChromaPosToEnum(xpos, ypos int32) AVChromaLocation {
|
||||||
return (AVChromaLocation)(C.avcodec_chroma_pos_to_enum(C.int(xpos), C.int(ypos)))
|
return (AVChromaLocation)(C.avcodec_chroma_pos_to_enum((C.int)(xpos), (C.int)(ypos)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Use AVCodecSendPacket() and AVCodecReceiveFrame().
|
// Deprecated: Use AVCodecSendPacket() and AVCodecReceiveFrame().
|
||||||
|
@@ -20,10 +20,16 @@ func AvDisplayRotationGet(matrix []int32) float64 {
|
|||||||
// AvDisplayRotationSet initializes a transformation matrix describing a pure counterclockwise
|
// AvDisplayRotationSet initializes a transformation matrix describing a pure counterclockwise
|
||||||
// rotation by the specified angle (in degrees).
|
// rotation by the specified angle (in degrees).
|
||||||
func AvDisplayRotationSet(matrix []int32, angle float64) {
|
func AvDisplayRotationSet(matrix []int32, angle float64) {
|
||||||
|
if len(matrix) < 9 {
|
||||||
|
panic("matrix len < 9")
|
||||||
|
}
|
||||||
C.av_display_rotation_set((*C.int32_t)(&matrix[0]), (C.double)(angle))
|
C.av_display_rotation_set((*C.int32_t)(&matrix[0]), (C.double)(angle))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvDisplayMatrixFlip flips the input matrix horizontally and/or vertically.
|
// AvDisplayMatrixFlip flips the input matrix horizontally and/or vertically.
|
||||||
func AvDisplayMatrixFlip(matrix []int32, hflip, vflip int32) {
|
func AvDisplayMatrixFlip(matrix []int32, hflip, vflip int32) {
|
||||||
|
if len(matrix) < 9 {
|
||||||
|
panic("matrix len < 9")
|
||||||
|
}
|
||||||
C.av_display_matrix_flip((*C.int32_t)(&matrix[0]), (C.int)(hflip), (C.int)(vflip))
|
C.av_display_matrix_flip((*C.int32_t)(&matrix[0]), (C.int)(hflip), (C.int)(vflip))
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
package ffmpeg
|
package ffmpeg
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
#include <libavutil/file.h>
|
#include <libavutil/file.h>
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
@@ -16,3 +16,18 @@ type AVQSVDeviceContext C.struct_AVQSVDeviceContext
|
|||||||
|
|
||||||
// AVQSVFramesContext
|
// AVQSVFramesContext
|
||||||
type AVQSVFramesContext C.struct_AVQSVFramesContext
|
type AVQSVFramesContext C.struct_AVQSVFramesContext
|
||||||
|
|
||||||
|
// GetFrameType gets `AVQSVFramesContext.frame_type` value.
|
||||||
|
func (ctx *AVQSVFramesContext) GetFrameType() int32 {
|
||||||
|
return (int32)(ctx.frame_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFrameType sets `AVQSVFramesContext.frame_type` value.
|
||||||
|
func (ctx *AVQSVFramesContext) SetFrameType(v int32) {
|
||||||
|
ctx.frame_type = (C.int)(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFrameTypeAddr gets `AVQSVFramesContext.frame_type` address.
|
||||||
|
func (ctx *AVQSVFramesContext) GetFrameTypeAddr() *int32 {
|
||||||
|
return (*int32)(&ctx.frame_type)
|
||||||
|
}
|
||||||
|
@@ -206,7 +206,7 @@ func AvLogGetLevel() int32 {
|
|||||||
|
|
||||||
// AvLogSetLevel sets the log level
|
// AvLogSetLevel sets the log level
|
||||||
func AvLogSetLevel(level int32) {
|
func AvLogSetLevel(level int32) {
|
||||||
C.av_log_set_level(C.int(level))
|
C.av_log_set_level((C.int)(level))
|
||||||
}
|
}
|
||||||
|
|
||||||
// typedef void (*av_log_callback_func)(void*, int, const char*, va_list);
|
// typedef void (*av_log_callback_func)(void*, int, const char*, va_list);
|
||||||
|
@@ -49,7 +49,7 @@ func AvGetSampleFmt(name string) AVSampleFormat {
|
|||||||
// requested planar/packed format, the format returned is the same as the
|
// requested planar/packed format, the format returned is the same as the
|
||||||
// input.
|
// input.
|
||||||
func AvGetAltSampleFmt(sampleFmt AVSampleFormat, planar int32) AVSampleFormat {
|
func AvGetAltSampleFmt(sampleFmt AVSampleFormat, planar int32) AVSampleFormat {
|
||||||
return (AVSampleFormat)(C.av_get_alt_sample_fmt((C.enum_AVSampleFormat)(sampleFmt), C.int(planar)))
|
return (AVSampleFormat)(C.av_get_alt_sample_fmt((C.enum_AVSampleFormat)(sampleFmt), (C.int)(planar)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AvGetPackedSampleFmt gets the packed alternative form of the given sample format.
|
// AvGetPackedSampleFmt gets the packed alternative form of the given sample format.
|
||||||
|
@@ -1,5 +1,192 @@
|
|||||||
|
//go:build ffmpeg_hw_qsv
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct AVCodecContext;
|
||||||
|
|
||||||
|
int get_format(struct AVCodecContext *avctx, int *pix_fmts) {
|
||||||
|
// TODO.
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
ffmpeg "github.com/qrtc/ffmpeg-dev-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type decodeContext struct {
|
||||||
|
hwDeviceRef *ffmpeg.AVBufferRef
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodePacket(decode *decodeContext, decoderCtx *ffmpeg.AVCodecContext,
|
||||||
|
frame *ffmpeg.AVFrame, swFrame *ffmpeg.AVFrame,
|
||||||
|
pkt *ffmpeg.AVPacket, outputCtx *ffmpeg.AVIOContext) (ret int32) {
|
||||||
|
var (
|
||||||
|
data [][]uint8
|
||||||
|
)
|
||||||
|
if ret = ffmpeg.AvCodecSendPacket(decoderCtx, pkt); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error during decoding\n")
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
for ret >= 0 {
|
||||||
|
ret = ffmpeg.AvCodecReceiveFrame(decoderCtx, frame)
|
||||||
|
if ret == ffmpeg.AVERROR(syscall.EAGAIN) || ret == ffmpeg.AVERROR_EOF {
|
||||||
|
break
|
||||||
|
} else if ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error while decoding.\n")
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// A real program would do something useful with the decoded frame here.
|
||||||
|
// We just retrieve the raw data and write it to a file, which is rather
|
||||||
|
// useless but pedagogic.
|
||||||
|
if ret = ffmpeg.AvHWFrameTransferData(swFrame, frame, 0); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error transferring the data to system memory\n")
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
data = ffmpeg.SliceSlice(&swFrame.GetData()[0], len(swFrame.GetData()),
|
||||||
|
swFrame.GetWidth()*swFrame.GetHeight())
|
||||||
|
for i := 0; i < len(swFrame.GetData()) && data[i] != nil; i++ {
|
||||||
|
for j := 0; j < int(swFrame.GetHeight()>>ffmpeg.CondExpr(i > 0, 1, 0)); j++ {
|
||||||
|
ffmpeg.AvIOWrite(outputCtx, &data[i][j*int(swFrame.GetLinesize()[i])], swFrame.GetWidth())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fail:
|
||||||
|
ffmpeg.AvFrameUnref(swFrame)
|
||||||
|
ffmpeg.AvFrameUnref(frame)
|
||||||
|
|
||||||
|
if ret < 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
intputCtx *ffmpeg.AVFormatContext
|
||||||
|
videoSt *ffmpeg.AVStream
|
||||||
|
decoderCtx *ffmpeg.AVCodecContext
|
||||||
|
decoder *ffmpeg.AVCodec
|
||||||
|
pkt ffmpeg.AVPacket
|
||||||
|
frame, swFrame *ffmpeg.AVFrame
|
||||||
|
decode = &decodeContext{}
|
||||||
|
outputCtx *ffmpeg.AVIOContext
|
||||||
|
ret int32
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(os.Args) < 3 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage: %s <input file> <output file>\n", os.Args[0])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the input file
|
||||||
|
if ret = ffmpeg.AvFormatOpenInput(&intputCtx, os.Args[1], nil, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Cannot open input file '%s': ", os.Args[1])
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the first H.264 video stream
|
||||||
|
for i := 0; i < int(intputCtx.GetNbStreams()); i++ {
|
||||||
|
st := intputCtx.GetStreams()[i]
|
||||||
|
if st.GetCodecpar().GetCodecId() == ffmpeg.AV_CODEC_ID_H264 && videoSt == nil {
|
||||||
|
videoSt = st
|
||||||
|
} else {
|
||||||
|
st.SetDiscard(ffmpeg.AVDISCARD_ALL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if videoSt == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "No H.264 video stream in the input file\n")
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the hardware device
|
||||||
|
if ret = ffmpeg.AvHWDeviceCtxCreate(&decode.hwDeviceRef, ffmpeg.AV_HWDEVICE_TYPE_QSV,
|
||||||
|
"auto", nil, 0); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Cannot open the hardware device\n")
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the decoder
|
||||||
|
if decoder = ffmpeg.AvCodecFindDecoderByName("h264_qsv"); decoder == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "The QSV decoder is not present in libavcodec\n")
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
decoderCtx.SetCodecId(ffmpeg.AV_CODEC_ID_H264)
|
||||||
|
if videoSt.GetCodecpar().GetExtradataSize() != 0 {
|
||||||
|
decoderCtx.SetExtradata((*uint8)(ffmpeg.AvMallocz(videoSt.GetCodecpar().GetExtradataSize() +
|
||||||
|
ffmpeg.AV_INPUT_BUFFER_PADDING_SIZE)))
|
||||||
|
if decoderCtx.GetExtradata() == nil {
|
||||||
|
ret = ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
copy(unsafe.Slice(decoderCtx.GetExtradata(), videoSt.GetCodecpar().GetExtradataSize()),
|
||||||
|
unsafe.Slice(videoSt.GetCodecpar().GetExtradata(), videoSt.GetCodecpar().GetExtradataSize()))
|
||||||
|
}
|
||||||
|
|
||||||
|
decoderCtx.SetOpaque(decode.hwDeviceRef)
|
||||||
|
decoderCtx.SetGetFormat((ffmpeg.AVCodecContextGetFormatFunc)(C.get_format))
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvCodecOpen2(decoderCtx, nil, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error opening the decoder: ")
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the output stream
|
||||||
|
if ret = ffmpeg.AvIOOpen(&outputCtx, os.Args[2], ffmpeg.AVIO_FLAG_WRITE); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error opening the output context: ")
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = ffmpeg.AvFrameAlloc()
|
||||||
|
swFrame = ffmpeg.AvFrameAlloc()
|
||||||
|
if frame == nil || swFrame == nil {
|
||||||
|
ret = ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
goto finish
|
||||||
|
}
|
||||||
|
|
||||||
|
// actual decoding
|
||||||
|
for ret >= 0 {
|
||||||
|
if ret = ffmpeg.AvReadFrame(intputCtx, &pkt); ret < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkt.GetStreamIndex() == videoSt.GetIndex() {
|
||||||
|
ret = decodePacket(decode, decoderCtx, frame, swFrame, &pkt, outputCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ffmpeg.AvPacketUnref(&pkt)
|
||||||
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
ffmpeg.AvFormatCloseInput(&intputCtx)
|
||||||
|
|
||||||
|
ffmpeg.AvFrameFree(&frame)
|
||||||
|
ffmpeg.AvFrameFree(&swFrame)
|
||||||
|
|
||||||
|
ffmpeg.AvCodecFreeContext(&decoderCtx)
|
||||||
|
|
||||||
|
ffmpeg.AvBufferUnref(&decode.hwDeviceRef)
|
||||||
|
|
||||||
|
ffmpeg.AvIOClose(outputCtx)
|
||||||
|
|
||||||
|
os.Exit(int(ret))
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,302 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
func main() {
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
struct AVCodecContext;
|
||||||
|
|
||||||
|
static int av_pix_fmt_none;
|
||||||
|
static int av_pix_fmt_vaapi;
|
||||||
|
|
||||||
|
static inline void initial_pix_fmt(int x, int y)
|
||||||
|
{
|
||||||
|
av_pix_fmt_none = x;
|
||||||
|
av_pix_fmt_vaapi = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_vaapi_format(struct AVCodecContext *ctx, int *pix_fmts)
|
||||||
|
{
|
||||||
|
const int *p;
|
||||||
|
|
||||||
|
for (p = pix_fmts; *p != av_pix_fmt_none; p++) {
|
||||||
|
if (*p == av_pix_fmt_vaapi)
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Unable to decode this file using VA-API.\n");
|
||||||
|
return av_pix_fmt_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
ffmpeg "github.com/qrtc/ffmpeg-dev-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type streamContext struct {
|
||||||
|
ifmtCtx *ffmpeg.AVFormatContext
|
||||||
|
ofmtCtx *ffmpeg.AVFormatContext
|
||||||
|
|
||||||
|
hwDeviceCtx *ffmpeg.AVBufferRef
|
||||||
|
|
||||||
|
decoderCtx *ffmpeg.AVCodecContext
|
||||||
|
encoderCtx *ffmpeg.AVCodecContext
|
||||||
|
|
||||||
|
videoStream int32
|
||||||
|
ost *ffmpeg.AVStream
|
||||||
|
initialized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func openInputFile(filename string, sc *streamContext) (ret int32) {
|
||||||
|
var (
|
||||||
|
decoder *ffmpeg.AVCodec
|
||||||
|
video *ffmpeg.AVStream
|
||||||
|
)
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvFormatOpenInput(&sc.ifmtCtx, filename, nil, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Cannot open input file '%s', Error code: %s\n",
|
||||||
|
filename, ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvFormatFindStreamInfo(sc.ifmtCtx, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Cannot find input stream information. Error code: %s\n",
|
||||||
|
ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvFindBestStream(sc.ifmtCtx, ffmpeg.AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Cannot find a video stream in the input file."+
|
||||||
|
" Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
sc.videoStream = ret
|
||||||
|
|
||||||
|
if sc.decoderCtx = ffmpeg.AvCodecAllocContext3(decoder); sc.decoderCtx == nil {
|
||||||
|
return ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
}
|
||||||
|
|
||||||
|
video = sc.ifmtCtx.GetStreams()[sc.videoStream]
|
||||||
|
if ret = ffmpeg.AvCodecParametersToContext(sc.decoderCtx, video.GetCodecpar()); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "avcodec_parameters_to_context error. Error code: %s\n",
|
||||||
|
ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.decoderCtx.SetHwDeviceCtx(ffmpeg.AvBufferRef(sc.hwDeviceCtx))
|
||||||
|
if sc.decoderCtx.GetHwDeviceCtx() == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "A hardware device reference create failed.\n")
|
||||||
|
return ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
}
|
||||||
|
C.initial_pix_fmt((C.int)(ffmpeg.AV_PIX_FMT_NONE), (C.int)(ffmpeg.AV_PIX_FMT_VAAPI))
|
||||||
|
sc.decoderCtx.SetGetFormat((ffmpeg.AVCodecContextGetFormatFunc)(C.get_vaapi_format))
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvCodecOpen2(sc.decoderCtx, decoder, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to open codec for decoding. Error code: %s\n",
|
||||||
|
ffmpeg.AvErr2str(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeWrite(encPkt *ffmpeg.AVPacket, frame *ffmpeg.AVFrame, sc *streamContext) (ret int32) {
|
||||||
|
|
||||||
|
ffmpeg.AvPacketUnref(encPkt)
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvCodecSendFrame(sc.encoderCtx, frame); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error during encoding. Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if ret = ffmpeg.AvCodecReceivePacket(sc.encoderCtx, encPkt); ret != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
encPkt.SetStreamIndex(0)
|
||||||
|
ffmpeg.AvPacketRescaleTs(encPkt, sc.ifmtCtx.GetStreams()[sc.videoStream].GetTimeBase(),
|
||||||
|
sc.ofmtCtx.GetStreams()[0].GetTimeBase())
|
||||||
|
if ret = ffmpeg.AvInterleavedWriteFrame(sc.ofmtCtx, encPkt); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error during writing data to output file. "+
|
||||||
|
"Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
if ret == ffmpeg.AVERROR_EOF {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return ffmpeg.CondExpr(ret == ffmpeg.AVERROR(syscall.EAGAIN), 0, int32(-1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func initialEncCodecCtx(encCodec *ffmpeg.AVCodec, sc *streamContext) (ret int32) {
|
||||||
|
|
||||||
|
// we need to ref hw_frames_ctx of decoder to initialize encoder's codec.
|
||||||
|
// Only after we get a decoded frame, can we obtain its hw_frames_ctx
|
||||||
|
sc.encoderCtx.SetHwFramesCtx(ffmpeg.AvBufferRef(sc.decoderCtx.GetHwFramesCtx()))
|
||||||
|
if sc.encoderCtx.GetHwFramesCtx() == nil {
|
||||||
|
return ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
}
|
||||||
|
// set AVCodecContext Parameters for encoder, here we keep them stay
|
||||||
|
// the same as decoder.
|
||||||
|
// xxx: now the sample can't handle resolution change case.
|
||||||
|
sc.encoderCtx.SetTimeBase(ffmpeg.AvInvQ(sc.decoderCtx.GetFramerate()))
|
||||||
|
sc.encoderCtx.SetPixFmt(ffmpeg.AV_PIX_FMT_VAAPI)
|
||||||
|
sc.encoderCtx.SetWidth(sc.decoderCtx.GetWidth())
|
||||||
|
sc.encoderCtx.SetHeight(sc.decoderCtx.GetHeight())
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvCodecOpen2(sc.encoderCtx, encCodec, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to open encode codec. Error code: %s\n",
|
||||||
|
ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
sc.ost.SetTimeBase(sc.encoderCtx.GetTimeBase())
|
||||||
|
if ret = ffmpeg.AvCodecParametersFromContext(sc.ost.GetCodecpar(), sc.encoderCtx); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to copy the stream parameters. "+
|
||||||
|
"Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the stream header
|
||||||
|
if ret = ffmpeg.AvFormatWriteHeader(sc.ofmtCtx, nil); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error while writing stream header. "+
|
||||||
|
"Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func decEnc(pkt *ffmpeg.AVPacket, encCodec *ffmpeg.AVCodec, sc *streamContext) (ret int32) {
|
||||||
|
var (
|
||||||
|
frame *ffmpeg.AVFrame
|
||||||
|
)
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvCodecSendPacket(sc.decoderCtx, pkt); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error during decoding. Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
for ret >= 0 {
|
||||||
|
if frame = ffmpeg.AvFrameAlloc(); frame == nil {
|
||||||
|
return ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ffmpeg.AvCodecReceiveFrame(sc.decoderCtx, frame)
|
||||||
|
if ret == ffmpeg.AVERROR(syscall.EAGAIN) || ret == ffmpeg.AVERROR_EOF {
|
||||||
|
ffmpeg.AvFrameFree(&frame)
|
||||||
|
} else if ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error while decoding. Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sc.initialized {
|
||||||
|
if ret = initialEncCodecCtx(encCodec, sc); ret != 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Initial EncodeCtx failed.\n")
|
||||||
|
goto fail
|
||||||
|
}
|
||||||
|
sc.initialized = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = encodeWrite(pkt, frame, sc); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error during encoding and writing.\n")
|
||||||
|
}
|
||||||
|
fail:
|
||||||
|
ffmpeg.AvFrameFree(&frame)
|
||||||
|
if ret < 0 {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
ret int32
|
||||||
|
decPkt *ffmpeg.AVPacket
|
||||||
|
encCodec *ffmpeg.AVCodec
|
||||||
|
sc = &streamContext{}
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(os.Args) != 4 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage: %s <input file> <encode codec> <output file>\n"+
|
||||||
|
"The output format is guessed according to the file extension.\n"+
|
||||||
|
"\n", os.Args[0])
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvHWDeviceCtxCreate(&sc.hwDeviceCtx, ffmpeg.AV_HWDEVICE_TYPE_VAAPI,
|
||||||
|
ffmpeg.NIL, nil, 0); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to create a VAAPI device. Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if decPkt = ffmpeg.AvPacketAlloc(); decPkt == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to allocate decode packet\n")
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = openInputFile(os.Args[1], sc); ret < 0 {
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
|
||||||
|
if encCodec = ffmpeg.AvCodecFindEncoderByName(os.Args[2]); encCodec == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Could not find encoder '%s'\n", os.Args[2])
|
||||||
|
ret = -1
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvFormatAllocOutputContext2(&sc.ofmtCtx, nil, ffmpeg.NIL, os.Args[3]); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to deduce output format from file extension. Error code: "+
|
||||||
|
"%s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc.encoderCtx = ffmpeg.AvCodecAllocContext3(encCodec); sc.encoderCtx == nil {
|
||||||
|
ret = ffmpeg.AVERROR(syscall.ENOMEM)
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret = ffmpeg.AvIOOpen(sc.ofmtCtx.GetPbAddr(), os.Args[3], ffmpeg.AVIO_FLAG_WRITE); ret < 0 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Cannot open output file. "+
|
||||||
|
"Error code: %s\n", ffmpeg.AvErr2str(ret))
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
|
||||||
|
// read all packets and only transcoding video
|
||||||
|
for ret >= 0 {
|
||||||
|
if ret = ffmpeg.AvReadFrame(sc.ifmtCtx, decPkt); ret < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc.videoStream == decPkt.GetStreamIndex() {
|
||||||
|
ret = decEnc(decPkt, encCodec, sc)
|
||||||
|
}
|
||||||
|
|
||||||
|
ffmpeg.AvPacketUnref(decPkt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush decoder
|
||||||
|
ffmpeg.AvPacketUnref(decPkt)
|
||||||
|
decEnc(decPkt, encCodec, sc)
|
||||||
|
|
||||||
|
// flush encoder
|
||||||
|
encodeWrite(decPkt, nil, sc)
|
||||||
|
|
||||||
|
// write the trailer for output stream
|
||||||
|
ffmpeg.AvWriteTrailer(sc.ofmtCtx)
|
||||||
|
|
||||||
|
end:
|
||||||
|
ffmpeg.AvFormatCloseInput(&sc.ifmtCtx)
|
||||||
|
ffmpeg.AvFormatCloseInput(&sc.ofmtCtx)
|
||||||
|
ffmpeg.AvCodecFreeContext(&sc.decoderCtx)
|
||||||
|
ffmpeg.AvCodecFreeContext(&sc.encoderCtx)
|
||||||
|
ffmpeg.AvBufferUnref(&sc.hwDeviceCtx)
|
||||||
|
ffmpeg.AvPacketFree(&decPkt)
|
||||||
|
os.Exit(int(ret))
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user