问题
I'm using the C API for ffmpeg/libav to rotate a vertically filmed iphone video during the encoding step. There are other questions asking to do a similar thing but they are all using the CLI tool to do so.
So far I was able to figure out how to use the AVFilter
to rotate the video, base off this example https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/filtering_video.c
The problem is that half the output file is corrupt.
Here is the code for my encoding logic. Its written with GOLANG using CGO to interface with the C API.
// Encode encode an AVFrame and return it
func Encode(enc Encoder, frame *C.AVFrame) (*EncodedFrame, error) {
ctx := enc.Context()
if ctx.buffersrcctx == nil {
// initialize filter
outputs := C.avfilter_inout_alloc()
inputs := C.avfilter_inout_alloc()
m_pFilterGraph := C.avfilter_graph_alloc()
buffersrc := C.avfilter_get_by_name(C.CString("buffer"))
argsStr := fmt.Sprintf("video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", ctx.avctx.width, ctx.avctx.height, ctx.avctx.pix_fmt, ctx.avctx.time_base.num, ctx.avctx.time_base.den, ctx.avctx.sample_aspect_ratio.num, ctx.avctx.sample_aspect_ratio.den)
Log.Info.Println("yakotest")
Log.Info.Println(argsStr)
args := C.CString(argsStr)
ret := C.avfilter_graph_create_filter(&ctx.buffersrcctx, buffersrc, C.CString("my_buffersrc"), args, nil, m_pFilterGraph)
if ret < 0 {
Log.Info.Printf("\n problem creating filter %v\n", AVError(ret).Error())
}
buffersink := C.avfilter_get_by_name(C.CString("buffersink"))
ret = C.avfilter_graph_create_filter(&ctx.buffersinkctx, buffersink, C.CString("my_buffersink"), nil, nil, m_pFilterGraph)
if ret < 0 {
Log.Info.Printf("\n problem creating filter %v\n", AVError(ret).Error())
}
/*
* Set the endpoints for the filter graph. The filter_graph will
* be linked to the graph described by filters_descr.
*/
/*
* The buffer source output must be connected to the input pad of
* the first filter described by filters_descr; since the first
* filter input label is not specified, it is set to "in" by
* default.
*/
outputs.name = C.av_strdup(C.CString("in"))
outputs.filter_ctx = ctx.buffersrcctx
outputs.pad_idx = 0
outputs.next = nil
/*
* The buffer sink input must be connected to the output pad of
* the last filter described by filters_descr; since the last
* filter output label is not specified, it is set to "out" by
* default.
*/
inputs.name = C.av_strdup(C.CString("out"))
inputs.filter_ctx = ctx.buffersinkctx
inputs.pad_idx = 0
inputs.next = nil
ret = C.avfilter_graph_parse_ptr(m_pFilterGraph, C.CString("transpose=clock,scale=-2:1080"),
&inputs, &outputs, nil)
if ret < 0 {
Log.Info.Printf("\n problem with avfilter_graph_parse %v\n", AVError(ret).Error())
}
ret = C.avfilter_graph_config(m_pFilterGraph, nil)
if ret < 0 {
Log.Info.Printf("\n problem with graph config %v\n", AVError(ret).Error())
}
}
filteredFrame := C.av_frame_alloc()
/* push the decoded frame into the filtergraph */
ret := C.av_buffersrc_add_frame_flags(ctx.buffersrcctx, frame, C.AV_BUFFERSRC_FLAG_KEEP_REF)
if ret < 0 {
Log.Error.Printf("\nError while feeding the filter greaph, err = %v\n", AVError(ret).Error())
return nil, errors.New(ErrorFFmpegCodecFailure)
}
/* pull filtered frames from the filtergraph */
for {
ret = C.av_buffersink_get_frame(ctx.buffersinkctx, filteredFrame)
if ret == C.AVERROR_EAGAIN || ret == C.AVERROR_EOF {
break
}
if ret < 0 {
Log.Error.Printf("\nCouldnt find a frame, err = %v\n", AVError(ret).Error())
return nil, errors.New(ErrorFFmpegCodecFailure)
}
filteredFrame.pts = frame.pts
frame = filteredFrame
defer C.av_frame_free(&filteredFrame)
}
if frame != nil {
frame.pict_type = 0 // reset pict type for the encoder
if C.avcodec_send_frame(ctx.avctx, frame) != 0 {
Log.Error.Printf("%+v\n", StackErrorf("codec error, could not send frame"))
return nil, errors.New(ErrorFFmpegCodecFailure)
}
}
for {
ret := C.avcodec_receive_packet(ctx.avctx, ctx.pkt)
if ret == C.AVERROR_EAGAIN {
break
}
if ret == C.AVERROR_EOF {
return nil, fmt.Errorf("EOF")
}
if ret < 0 {
Log.Error.Printf("%+v\n", StackErrorf("codec error, receiving packet"))
return nil, errors.New(ErrorFFmpegCodecFailure)
}
data := C.GoBytes(unsafe.Pointer(ctx.pkt.data), ctx.pkt.size)
return &EncodedFrame{data, int64(ctx.pkt.pts), int64(ctx.pkt.dts),
(ctx.pkt.flags & C.AV_PKT_FLAG_KEY) != 0}, nil
}
return nil, nil
}
It seems like I need to do something with the scaling here but I'm struggling to find helpful information online.
来源:https://stackoverflow.com/questions/61719959/rotating-a-video-during-encoding-with-ffmpeg-and-libav-api-results-in-half-of-vi