I am trying to scale a video from 1080p to 480p. For that, I have setup swscaler context as:
encoder_sc->sws_ctx = sws_getContext(1920, 1080,
AV_PIX_FMT_YUV420P,
854, 480, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL );
However, when I am calling the scale frame function as
sws_scale_frame(encoder->sws_ctx, input_frame, input_frame);
However, when I do that I am getting the error Slice parameter 0, 1080 are in valid. I am very new to FFMPEG and video processing in general. I could not find any solution while searching. Any help is greatly appreciated.
EDIT: I am including the entire source code because I cannot seem to solve the issue.
typedef struct StreamingContext{
AVFormatContext* avfc;
AVCodec *video_avc;
AVCodec *audio_avc;
AVStream *video_avs;
AVStream *audio_avs;
AVCodecContext *video_avcc;
AVCodecContext *audio_avcc;
int video_index;
int audio_index;
char* filename;
struct SwsContext *sws_ctx;
}StreamingContext;
typedef struct StreamingParams{
char copy_video;
char copy_audio;
char *output_extension;
char *muxer_opt_key;
char *muxer_opt_value;
char *video_codec;
char *audio_codec;
char *codec_priv_key;
char *codec_priv_value;
}StreamingParams;
int prepare_video_encoder(StreamingContext *encoder_sc, AVCodecContext *decoder_ctx, AVRational input_framerate,
StreamingParams sp)
{
encoder_sc->video_avs = avformat_new_stream(encoder_sc->avfc, NULL);
encoder_sc->video_avc = avcodec_find_encoder_by_name(sp.video_codec);
if (!encoder_sc->video_avc)
{
logging("Cannot find the Codec.");
return -1;
}
encoder_sc->video_avcc = avcodec_alloc_context3(encoder_sc->video_avc);
if (!encoder_sc->video_avcc)
{
logging("Could not allocate memory for Codec Context.");
return -1;
}
av_opt_set(encoder_sc->video_avcc->priv_data, "preset", "fast", 0);
if (sp.codec_priv_key && sp.codec_priv_value)
av_opt_set(encoder_sc->video_avcc->priv_data, sp.codec_priv_key, sp.codec_priv_value, 0);
encoder_sc->video_avcc->height = decoder_ctx->height;
encoder_sc->video_avcc->width = decoder_ctx->width;
encoder_sc->video_avcc->sample_aspect_ratio = decoder_ctx->sample_aspect_ratio;
if (encoder_sc->video_avc->pix_fmts)
encoder_sc->video_avcc->pix_fmt = encoder_sc->video_avc->pix_fmts[0];
else
encoder_sc->video_avcc->pix_fmt = decoder_ctx->pix_fmt;
encoder_sc->video_avcc->bit_rate = 2 * 1000 * 1000;
encoder_sc->video_avcc->rc_buffer_size = 4 * 1000 * 1000;
encoder_sc->video_avcc->rc_max_rate = 2 * 1000 * 1000;
encoder_sc->video_avcc->rc_min_rate = 2.5 * 1000 * 1000;
encoder_sc->video_avcc->time_base = av_inv_q(input_framerate);
encoder_sc->video_avs->time_base = encoder_sc->video_avcc->time_base;
//Creating Scaling Context
encoder_sc->sws_ctx = sws_getContext(1920, 1080,
decoder_ctx->pix_fmt,
854, 480, encoder_sc->video_avcc->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
if (!encoder_sc->sws_ctx){logging("Cannot Create Scaling Context."); return -1;}
if (avcodec_open2(encoder_sc->video_avcc, encoder_sc->video_avc, NULL) < 0)
{
logging("Could not open the Codec.");
return -1;
}
avcodec_parameters_from_context(encoder_sc->video_avs->codecpar, encoder_sc->video_avcc);
return 0;
}
int transcode_video(StreamingContext *decoder, StreamingContext *encoder, AVPacket *input_packet, AVFrame *input_frame, AVFrame *scaled_frame)
{
int response = avcodec_send_packet(decoder->video_avcc, input_packet);
if (response < 0)
{
logging("Error while sending the Packet to Decoder: %s", av_err2str(response));
return response;
}
while (response >= 0)
{
response = avcodec_receive_frame(decoder->video_avcc, input_frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
{
break;
}
else if (response < 0)
{
logging("Error while receiving frame from Decoder: %s", av_err2str(response));
return response;
}
if (response >= 0)
{
scaled_frame->format = encoder->video_avcc->pix_fmt;
scaled_frame->width = 854;
scaled_frame->height = 480;
sws_scale_frame(encoder->sws_ctx, scaled_frame, input_frame);
//ERROR is in the scaled_frame
if (encode_video(decoder, encoder, scaled_frame))
return -1;
}
av_frame_unref(input_frame);
}
return 0;
}
In the small piece of code you have posted we can see that there is an issue.
Using
input_frame, input_frameinstead ofoutput_frame, input_frameis the issue.Replace
sws_scale_frame(encoder->sws_ctx, input_frame, input_frame);with:When executing
sws_scale_frame, the function verifies that the dimensions and format of the input and the output matches the dimensions and format defined insws_getContext.In our case:
The width and height input must be 1920 and 1080.
The width and height output must be 854 and 480.
When the dimensions doesn't match, the function fails and return an error (return a negative value).
In our case, the expected height of the output is
854, but the given height of the frame is1080.I don't know if this is the only issue...
I created a complete reproducible example that demonstrate the usage of
sws_scale_frame- scaling a single frame.Code sample:
Output image after converting from YUV420p to PNG image (downscaled):
