c++visual-c++ffmpegswscale

FFMPEG: sws_scale returns error: Slice parameters 0, 2160 are invalid


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.


Solution

  • 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.