The following code works perfectly as long as I only move the crop rectangle, however as soon as I change its size I no longer get frames out of my filter (av_buffersink_get_frame
returns -11
). It’s crazy, even after the size changes, if it eventually changes to the original size that frame will go through, then it will go back to no longer providing frames.
Would anyone happen to know what I’m doing wrong?
My filter setup (note the crop
& scale
combination, it should (I think?) scale whatever I crop to the output video size):
// buffer source -> buffer sink setup
auto args = std::format("video_size={}x{}:pix_fmt={}:time_base={}/{}:pixel_aspect={}/{}",
inputCodecContext->width, inputCodecContext->height, (int)inputCodecContext->pix_fmt,
inputCodecContext->pkt_timebase.num, inputCodecContext->pkt_timebase.den,
inputCodecContext->sample_aspect_ratio.num, inputCodecContext->sample_aspect_ratio.den);
AVFilterContext* buffersrc_ctx = nullptr, * buffersink_ctx = nullptr;
check_av_result(avfilter_graph_create_filter(&buffersrc_ctx, bufferSource, "in",
args.c_str(), nullptr, &*filterGraph));
check_av_result(avfilter_graph_create_filter(&buffersink_ctx, bufferSink, "out",
nullptr, nullptr, &*filterGraph));
check_av_result(av_opt_set_bin(buffersink_ctx, "pix_fmts",
(uint8_t*)&outputCodecContext->pix_fmt, sizeof(outputCodecContext->pix_fmt), AV_OPT_SEARCH_CHILDREN));
// filter command setup
auto filterSpec = std::format("crop,scale={}:{},setsar=1:1", outputCodecContext->width, outputCodecContext->height);
check_av_result(avfilter_graph_parse_ptr(&*filterGraph, filterSpec.c_str(), &filterInputs, &filterOutputs, nullptr));
check_av_result(avfilter_graph_config(&*filterGraph, nullptr));
Frame cropping:
check_av_result(avfilter_graph_send_command(&*filterGraph, "crop", "x", std::to_string(cropRectangle.CenterX() - cropRectangle.Width() / 2).c_str(), nullptr, 0, 0));
check_av_result(avfilter_graph_send_command(&*filterGraph, "crop", "y", std::to_string(cropRectangle.CenterY() - cropRectangle.Height() / 2).c_str(), nullptr, 0, 0));
check_av_result(avfilter_graph_send_command(&*filterGraph, "crop", "w", std::to_string(cropRectangle.Width()).c_str(), nullptr, 0, 0));
check_av_result(avfilter_graph_send_command(&*filterGraph, "crop", "h", std::to_string(cropRectangle.Height()).c_str(), nullptr, 0, 0));
// push the decoded frame into the filter graph
check_av_result(av_buffersrc_add_frame_flags(buffersrc_ctx, &*inputFrame, 0));
// pull filtered frames from the filter graph
while (1)
{
ret = av_buffersink_get_frame(buffersink_ctx, &*filteredFrame);
if (ret < 0)
{
// if no more frames, rewrite the code to 0 to show it as normal completion
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
ret = 0;
break;
}
// write the filtered frame to the output file
// [...]
}
I also set the output video size before creating the file, and it is obeyed as expected:
outputCodecContext->width = (int)output.PixelSize().Width;
outputCodecContext->height = (int)output.PixelSize().Height;