I'm trying to follow a tutorial to display ffmpeg AVFrame output in SDL. The tutorial(and all examples I'm seeing online) are still using 'sws_getContext', which has been deprecated and removed from the newest version of ffmpeg. Trying to change current pixel format from whatever it currently is to PIX_FMT_YUV420P, so I can display it. I believe I need the sws_scale function to accomplish this.
However, sws_scale is the function that causes a command line error of: Slice parameters 0, 2160 are invalid
Here is all my code associate with swsContext:
struct SwsContext* av_sws_ctx = NULL;
av_sws_ctx = sws_alloc_context();
sws_init_context(av_sws_ctx, NULL, NULL);
sws_scale(av_sws_ctx, (uint8_t const* const*)av_frame->data,
av_frame->linesize, 0, av_codec_context->height,
av_frame->data, av_frame->linesize);
Further complicating the matter, SwsContext is only defined internal to ffmpeg, externally I can't set/get any variables or even view them in the debugger.
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[] )
The vales of other parameters, other than av_sws_ctx:
srcSlice: av_frame->data =
8 arrays, first is filled with "\x10\x10\x10\x10\x10..."
second and third are "€€€€€€€€€€€€€€€€€..."
rest are NULL
linesize(av_frame->linesize) is an array:
3840,1920,1920,0,0,0,0,0
srcSliceY:0
srcSliceH:2160
dest: same as second parameter (av_frame->data)
dstStride: av_frame->linesize again
If I drill into sws_scale source code, I find that this error is thrown by this chunk of code:
if ((srcSliceY & (macro_height-1)) ||
((srcSliceH& (macro_height-1)) && srcSliceY + srcSliceH != c->srcH) ||
srcSliceY + srcSliceH > c->srcH) {
av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", srcSliceY, srcSliceH);
return AVERROR(EINVAL);
}
I assume that the issue therefore is that the height of my video is bigger than sws_context(4k video). But can't figure out how to tell sws_context what it's height should be using sws_alloc_context or sws_init_context or any other function.
See something I'm missing? Thank you.
Yes something missing.
Forget sws_init_context(av_sws_ctx, NULL, NULL);
1) Init sws_context (once) with one of these:
// for UPSCALE
av_sws_ctx = sws_getContext(src_width, src_height, src_pixfmt,
dst_width, dst_height, dst_pixfmt,
SWS_BILINEAR, NULL, NULL, NULL);
// for DOWNSCALE
av_sws_ctx = sws_getContext(src_width, src_height, src_pixfmt,
dst_width, dst_height, dst_pixfmt,
SWS_BICUBIC, NULL, NULL, NULL);
2) Then call for the conversion:
int ret = sws_scale(swsContext,
srcframe->data, /* srcSlice[] */
srcframe->linesize, /* srcStride[] */
0, /* srcSliceY */
src_height, /* srcSliceH */
dstframe->data, /* dst[] */
dstframe->linesize); /* dstStride[] */
Notice that, src and dst frames are different AVFrame instances.
Upscale and downscale lines above are suggestions, for I prefer different algorithm (bilinear vs bicubic).
Hope that helps.