libswscale error Slice Parameters 0, 1080 are invalid

问题描述 投票:0回答:1

我正在尝试将视频从 1080p 缩放到 480p。为此,我将 swscaler 上下文设置为:

encoder_sc->sws_ctx = sws_getContext(1920, 1080,
                            AV_PIX_FMT_YUV420P, 
                           854, 480, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL );

但是,当我调用比例框架函数时

sws_scale_frame(encoder->sws_ctx, input_frame, input_frame);

但是,当我这样做时,我得到了错误

Slice parameter 0, 1080 are in valid
。总的来说,我对 FFMPEG 和视频处理还很陌生。搜索时我找不到任何解决方案。非常感谢任何帮助。

c ffmpeg video-processing swscale
1个回答
0
投票

在您发布的一小段代码中,我们可以看到存在问题。
使用

input_frame, input_frame
而不是
output_frame, input_frame
是问题所在。

sws_scale_frame(encoder->sws_ctx, input_frame, input_frame);
替换为:

sws_scale_frame(encoder->sws_ctx, output_frame, input_frame);

执行

sws_scale_frame
时,函数验证输入和输出的维度和格式是否与
sws_getContext
中定义的维度和格式匹配。
在我们的例子中:
输入的宽度和高度必须是 1920 和 1080。
宽高输出必须是854和480。
当尺寸不匹配时,函数失败并返回错误(返回负值)。
在我们的例子中,输出的预期高度是
854
,但框架的给定高度是
1080
.


我不知道这是不是唯一的问题...

我创建了一个完整的可重现示例,演示了

sws_scale_frame
的用法 - 缩放单个帧。

代码示例:

extern "C"  //extern "C" is required because we are using C++ code.
{
    #include <libswscale/swscale.h>
}

#include <cassert>


int main()
{
    //Allocate buffer for input frame
    ////////////////////////////////////////////////////////////////////////////
    const int in_width = 1920;
    const int in_height = 1080;
    AVFrame *input_frame = av_frame_alloc();
    input_frame->format = AV_PIX_FMT_YUV420P;
    input_frame->width = in_width;
    input_frame->height = in_height;
    int sts = av_frame_get_buffer(input_frame, 0);
    assert(sts >= 0);

    //Make sure Y,U,V buffers are continuous in memory (this is not part of the solution, we need it only due to the way we are reading the frame from file).
    assert((input_frame->linesize[0] == in_width) && (input_frame->linesize[1] == in_width/2) && (input_frame->linesize[2] == in_width/2));
    ////////////////////////////////////////////////////////////////////////////

    //Read input_frame from binary file: input_frame.bin
    //The binary file was created using FFmpeg CLI (for testing):
    //ffmpeg -y -f lavfi -i testsrc=size=1920x1080:rate=1 -vcodec rawvideo -pix_fmt yuv420p -frames 1 -f rawvideo input_frame.bin
    ////////////////////////////////////////////////////////////////////////////
    FILE *f = fopen("input_frame.bin", "rb");
    assert(f != nullptr);
    fread(input_frame->data[0], 1, in_width*in_height, f);      //Read Y channel
    fread(input_frame->data[1], 1, in_width*in_height/4, f);    //Read U channel
    fread(input_frame->data[2], 1, in_width*in_height/4, f);    //Read V channel
    fclose(f);
    ////////////////////////////////////////////////////////////////////////////


    //Allocate buffer for output frame
    ////////////////////////////////////////////////////////////////////////////
    const int out_width = 854;
    const int out_height = 480;
    AVFrame *output_frame = av_frame_alloc();
    output_frame->format = AV_PIX_FMT_YUV420P;
    output_frame->width = out_width;
    output_frame->height = out_height;
    sts = av_frame_get_buffer(output_frame, 0);
    assert(sts >= 0);

    //Make sure Y,U,V buffers are continuous in memory (this is not part of the solution, we need it only due to the way we are writing the frame to file).
    //assert((output_frame->linesize[0] == out_width) && (output_frame->linesize[1] == out_width/2) && (output_frame->linesize[2] == out_width/2));
    ////////////////////////////////////////////////////////////////////////////


    //Allocate SwsContext
    ////////////////////////////////////////////////////////////////////////////
    SwsContext *sws_ctx = sws_getContext(input_frame->width,
                                         input_frame->height,
                                         (AVPixelFormat)input_frame->format,
                                         output_frame->width,
                                         output_frame->height,
                                         (AVPixelFormat)output_frame->format,
                                         SWS_BICUBIC,
                                         nullptr,
                                         nullptr,
                                         nullptr);
    assert(sws_ctx != nullptr);
    ////////////////////////////////////////////////////////////////////////////

    //Scale 1920x1080 input_frame and store the result in 854x480 output_frame.
    ////////////////////////////////////////////////////////////////////////////
    //sts = sws_scale_frame(sws_ctx, input_frame, input_frame);  //Return error code -22 "Slice parameters 0, 1080 are invalid" (input_frame, input_frame is a bug).
    sts = sws_scale_frame(sws_ctx, output_frame, input_frame);
    
    if (sts < 0)
    {
        char errbuf[AV_ERROR_MAX_STRING_SIZE];
        av_strerror(sts, errbuf, sizeof(errbuf));
        fprintf(stderr, "sws_scale_frame error: %s\n", errbuf);
        return -1;
    }
    ////////////////////////////////////////////////////////////////////////////


    //Write output_frame to binary file - write line by line because output_frame channels are not continuous in memory
    //After saving the output, we may convert it to PNG image using FFmpeg CLI (for testing):
    //ffmpeg -y -f rawvideo -video_size 854x480 -pixel_format yuv420p -i output_frame.bin output_frame.png
    ////////////////////////////////////////////////////////////////////////////
    f = fopen("output_frame.bin", "wb");
    assert(f != nullptr);

    // Writing line by line
    for (int y = 0; y < output_frame->height; y++)
    {
        fwrite(output_frame->data[0] + (size_t)y * output_frame->linesize[0], 1, output_frame->width, f);  //Write Y channel (line by line).
    }
    for (int y = 0; y < output_frame->height/2; y++)
    {
        fwrite(output_frame->data[1] + (size_t)y * output_frame->linesize[1], 1, output_frame->width/2, f);  //Write U channel (line by line).
    }
    for (int y = 0; y < output_frame->height/2; y++)
    {
        fwrite(output_frame->data[2] + (size_t)y * output_frame->linesize[2], 1, output_frame->width/2, f);  //Write V channel (line by line).
    }
    fclose(f);
    ////////////////////////////////////////////////////////////////////////////


    //Free allocated resources.
    ////////////////////////////////////////////////////////////////////////////
    sws_freeContext(sws_ctx);
    av_frame_free(&input_frame);
    av_frame_free(&output_frame);
    ////////////////////////////////////////////////////////////////////////////

    return 0;
}

从YUV420p转换为PNG图像后的输出图像(缩小):

© www.soinside.com 2019 - 2024. All rights reserved.