cffmpegvideo-encodingswscale

Downscaling a video from 1080p to 480p using swscale and encoding to x265 gives a glitched output


I am basically first scaling a frame and then sending the frame to the encoder as below:

scaled_frame->pts = input_frame->pts;
scaled_frame->pkt_dts = input_frame->pkt_dts;
scaled_frame->pict_type = input_frame->pict_type;
sws_scale_frame(encoder->sws_ctx, scaled_frame, input_frame);
if (encode_video(decoder, encoder, scaled_frame))
     return -1;

The scaling context is configured as:

scaled_frame->width = 854;
scaled_frame->height=480; 
encoder->sws_ctx = sws_getContext(1920, 1080,
                            decoder->video_avcc->pix_fmt, 
                           scaled_frame->width, scaled_frame->height, decoder->video_avcc->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
    if (!encoder->sws_ctx){logging("Cannot Create Scaling Context."); return -1;}

The encoder is configured as:

    encoder_sc->video_avcc->height = decoder_ctx->height; //1080
    encoder_sc->video_avcc->width = decoder_ctx->width; //1920
    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;

When I get the output, the output video is 1080p and I have glitches like: enter image description here

I changed the encoder avcc resolution to 480p (854 x 480). However, that is causing the video to get sliced to the top quarter of the original frame. I am new to FFMPEG and video processing in general.

EDIT: I am adding the minimal reproducible code sample. However, it is really long because I need to include code for decoding, scaling and then encoding because the possible error is either in scaling or encoding:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/timestamp.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>

#include <string.h>
#include <inttypes.h>

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;

void logging(const char *fmt, ...)
{
    va_list args;
    fprintf(stderr, "LOG: ");
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n");
}

int fill_stream_info(AVStream *avs, AVCodec **avc, AVCodecContext **avcc)
{
    *avc = avcodec_find_decoder(avs->codecpar->codec_id);
    if (!*avc)
    {
        logging("Failed to find the codec.\n");
        return -1;
    }

    *avcc = avcodec_alloc_context3(*avc);
    if (!*avcc)
    {
        logging("Failed to alloc memory for codec context.");
        return -1;
    }

    if (avcodec_parameters_to_context(*avcc, avs->codecpar) < 0)
    {
        logging("Failed to fill Codec Context.");
        return -1;
    }

    if (avcodec_open2(*avcc, *avc, NULL) < 0)
    {
        logging("Failed to open Codec.");
        return -1;
    }

    return 0;
}

int open_media(const char *in_filename, AVFormatContext **avfc)
{
    *avfc = avformat_alloc_context();

    if (!*avfc)
    {
        logging("Failed to Allocate Memory for Format Context");
        return -1;
    }

    if (avformat_open_input(avfc, in_filename, NULL, NULL) != 0)
    {
        logging("Failed to open input file %s", in_filename);
        return -1;
    }

    if (avformat_find_stream_info(*avfc, NULL) < 0)
    {
        logging("Failed to get Stream Info.");
        return -1;
    }
}

int prepare_decoder(StreamingContext *sc)
{
    for (int i = 0; i < sc->avfc->nb_streams; i++)
    {
        if (sc->avfc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            sc->video_avs = sc->avfc->streams[i];
            sc->video_index = i;

            if (fill_stream_info(sc->video_avs, &sc->video_avc, &sc->video_avcc))
            {
                return -1;
            }
        }
        else
        {
            logging("Skipping Streams other than Video.");
        }
    }
    return 0;
}

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;

    

    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 encode_video(StreamingContext *decoder, StreamingContext *encoder, AVFrame *input_frame)
{
    if (input_frame)
        input_frame->pict_type = AV_PICTURE_TYPE_NONE;

    AVPacket *output_packet = av_packet_alloc();
    if (!output_packet)
    {
        logging("Could not allocate memory for Output Packet.");
        return -1;
    }

    int response = avcodec_send_frame(encoder->video_avcc, input_frame);

    while (response >= 0)
    {
        response = avcodec_receive_packet(encoder->video_avcc, output_packet);
        if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
        {
            break;
        }
        else if (response < 0)
        {
            logging("Error while receiving packet from encoder: %s", av_err2str(response));
            return -1;
        }

        output_packet->stream_index = decoder->video_index;
        output_packet->duration = encoder->video_avs->time_base.den / encoder->video_avs->time_base.num / decoder->video_avs->avg_frame_rate.num * decoder->video_avs->avg_frame_rate.den;

        av_packet_rescale_ts(output_packet, decoder->video_avs->time_base, encoder->video_avs->time_base);
        response = av_interleaved_write_frame(encoder->avfc, output_packet);
        if (response != 0)
        {
            logging("Error %d while receiving packet from decoder: %s", response, av_err2str(response));
            return -1;
        }
    }

    av_packet_unref(output_packet);
    av_packet_free(&output_packet);

    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->pts = input_frame->pts;
            scaled_frame->pkt_dts = input_frame->pkt_dts;
            scaled_frame->pict_type = input_frame->pict_type;
            sws_scale_frame(encoder->sws_ctx, scaled_frame, input_frame);
            if (encode_video(decoder, encoder, scaled_frame))
                return -1;
        }

        av_frame_unref(input_frame);
    }
    return 0;
}

int main(int argc, char *argv[])
{
    StreamingParams sp = {0};
    sp.copy_audio = 1;
    sp.copy_video = 0;
    sp.video_codec = "libx265";


    StreamingContext *decoder = (StreamingContext *)calloc(1, sizeof(StreamingContext));
    decoder->filename = argv[1];

    StreamingContext *encoder = (StreamingContext *)calloc(1, sizeof(StreamingContext));
    encoder->filename = argv[2];

    if (sp.output_extension)
    {
        strcat(encoder->filename, sp.output_extension);
    }

    if (open_media(decoder->filename, &decoder->avfc))
        return -1;
    if (prepare_decoder(decoder))
        return -1;

    avformat_alloc_output_context2(&encoder->avfc, NULL, NULL, encoder->filename);
    if (!encoder->avfc)
    {
        logging("Could not allocate memory for output Format Context.");
        return -1;
    }

        AVRational input_framerate = av_guess_frame_rate(decoder->avfc, decoder->video_avs, NULL);
        prepare_video_encoder(encoder, decoder->video_avcc, input_framerate, sp);


    if (encoder->avfc->oformat->flags & AVFMT_GLOBALHEADER)
        encoder->avfc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    if (!(encoder->avfc->oformat->flags & AVFMT_NOFILE))
    {
        if (avio_open(&encoder->avfc->pb, encoder->filename, AVIO_FLAG_WRITE) < 0)
        {
            logging("could not open the output file");
            return -1;
        }
    }

    AVDictionary *muxer_opts = NULL;

    if (sp.muxer_opt_key && sp.muxer_opt_value)
    {
        av_dict_set(&muxer_opts, sp.muxer_opt_key, sp.muxer_opt_value, 0);
    }

    if (avformat_write_header(encoder->avfc, &muxer_opts) < 0)
    {
        logging("an error occurred when opening output file");
        return -1;
    }

    AVFrame *input_frame = av_frame_alloc();
    AVFrame *scaled_frame = av_frame_alloc();
    if (!input_frame || !scaled_frame)
    {
        logging("Failed to allocate memory for AVFrame");
        return -1;
    }

    // scaled_frame->format = AV_PIX_FMT_YUV420P;
    scaled_frame->width = 854;
    scaled_frame->height=480;    

    //Creating Scaling Context
    encoder->sws_ctx = sws_getContext(1920, 1080,
                            decoder->video_avcc->pix_fmt, 
                           scaled_frame->width, scaled_frame->height, decoder->video_avcc->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
    if (!encoder->sws_ctx){logging("Cannot Create Scaling Context."); return -1;}


    AVPacket *input_packet = av_packet_alloc();
    if (!input_packet)
    {
        logging("Failed to allocate memory for AVPacket.");
        return -1;
    }

    while (av_read_frame(decoder->avfc, input_packet) >= 0)
    {
        if (decoder->avfc->streams[input_packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
                if (transcode_video(decoder, encoder, input_packet, input_frame, scaled_frame))
                    return -1;
                av_packet_unref(input_packet);
        }
        else
        {
            logging("Ignoring all nonvideo  packets.");
        }
    }

    if (encode_video(decoder, encoder, NULL))
        return -1;

    av_write_trailer(encoder->avfc);

    if (muxer_opts != NULL)
    {
        av_dict_free(&muxer_opts);
        muxer_opts = NULL;
    }

    if (input_frame != NULL)
    {
        av_frame_free(&input_frame);
        input_frame = NULL;
    }

    if (input_packet != NULL)
    {
        av_packet_free(&input_packet);
        input_packet = NULL;
    }

    avformat_close_input(&decoder->avfc);

    avformat_free_context(decoder->avfc);
    decoder->avfc = NULL;
    avformat_free_context(encoder->avfc);
    encoder->avfc = NULL;

    avcodec_free_context(&decoder->video_avcc);
    decoder->video_avcc = NULL;
    avcodec_free_context(&decoder->audio_avcc);
    decoder->audio_avcc = NULL;

    free(decoder);
    decoder = NULL;
    free(encoder);
    encoder = NULL;

    return 0;
}

The video I am using for testing is available at the repo: https://github.com/leandromoreira/ffmpeg-libav-tutorial

The file name is small_bunny_1080p_60fps.mp4


Solution

  • The current resolution of the output video is 1920x1080 instead of 854x480.
    The reason is that the width and height are copied from the decoder to the encoder:

    In the function prepare_video_encoder(...):

    encoder_sc->video_avcc->height = decoder_ctx->height;
    encoder_sc->video_avcc->width = decoder_ctx->width;
    

    We have to set width and height according to the scaled resolution:

    encoder_sc->video_avcc->height = 480;
    encoder_sc->video_avcc->width = 854;
    

    Updated code:

    extern "C"  //Building as C++
    {
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavutil/timestamp.h>
    #include <libavutil/opt.h>
    #include <libswscale/swscale.h>
    }
    
    #include <string.h>
    #include <inttypes.h>
    
    typedef struct StreamingContext{
        AVFormatContext* avfc;
        const AVCodec *video_avc;
        const AVCodec *audio_avc;
        AVStream *video_avs;
        AVStream *audio_avs;
        AVCodecContext *video_avcc;
        AVCodecContext *audio_avcc;
        int video_index;
        int audio_index;
        const 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;
        const char *video_codec;
        char *audio_codec;
        char *codec_priv_key;
        char *codec_priv_value;
    }StreamingParams;
    
    
    //C++ version of av_err2str_cpp function
    static char static_errbuf[AV_ERROR_MAX_STRING_SIZE];
    static const char *av_err2str_cpp(int sts)
    {
        av_make_error_string(static_errbuf, AV_ERROR_MAX_STRING_SIZE, sts);
        return static_errbuf;
    }
    
    
    void logging(const char *fmt, ...)
    {
        va_list args;
        fprintf(stderr, "LOG: ");
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        fprintf(stderr, "\n");
    }
    
    int fill_stream_info(AVStream *avs, const AVCodec **avc, AVCodecContext **avcc)
    {
        *avc = avcodec_find_decoder(avs->codecpar->codec_id);
        if (!*avc)
        {
            logging("Failed to find the codec.\n");
            return -1;
        }
    
        *avcc = avcodec_alloc_context3(*avc);
        if (!*avcc)
        {
            logging("Failed to alloc memory for codec context.");
            return -1;
        }
    
        if (avcodec_parameters_to_context(*avcc, avs->codecpar) < 0)
        {
            logging("Failed to fill Codec Context.");
            return -1;
        }
    
        if (avcodec_open2(*avcc, *avc, NULL) < 0)
        {
            logging("Failed to open Codec.");
            return -1;
        }
    
        return 0;
    }
    
    int open_media(const char *in_filename, AVFormatContext **avfc)
    {
        *avfc = avformat_alloc_context();
    
        if (!*avfc)
        {
            logging("Failed to Allocate Memory for Format Context");
            return -1;
        }
    
        if (avformat_open_input(avfc, in_filename, NULL, NULL) != 0)
        {
            logging("Failed to open input file %s", in_filename);
            return -1;
        }
    
        if (avformat_find_stream_info(*avfc, NULL) < 0)
        {
            logging("Failed to get Stream Info.");
            return -1;
        }
    
        return 0;
    }
    
    int prepare_decoder(StreamingContext *sc)
    {
        for (int i = 0; i < (int)sc->avfc->nb_streams; i++)
        {
            if (sc->avfc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
            {
                sc->video_avs = sc->avfc->streams[i];
                sc->video_index = i;
    
                if (fill_stream_info(sc->video_avs, &sc->video_avc, &sc->video_avcc))
                {
                    return -1;
                }
            }
            else
            {
                logging("Skipping Streams other than Video.");
            }
        }
        return 0;
    }
    
    //Adding arguments dst_width and dst_height
    int prepare_video_encoder(StreamingContext *encoder_sc, AVCodecContext *decoder_ctx, AVRational input_framerate,
                              StreamingParams sp, int dst_width, int dst_height)
    {
        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);
    
        //We have to set the scaled resolution (854x480) instead of copy the resolution from the decoder to the encoder.
        ////////////////////////////////////////////////////////////////////////////
        //encoder_sc->video_avcc->height = decoder_ctx->height;
        //encoder_sc->video_avcc->width = decoder_ctx->width;
        encoder_sc->video_avcc->width = dst_width;
        encoder_sc->video_avcc->height = dst_height;
        ////////////////////////////////////////////////////////////////////////////
    
        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 = (int64_t)(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;
    
        
    
        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 encode_video(StreamingContext *decoder, StreamingContext *encoder, AVFrame *input_frame)
    {
        if (input_frame)
            input_frame->pict_type = AV_PICTURE_TYPE_NONE;
    
        AVPacket *output_packet = av_packet_alloc();
        if (!output_packet)
        {
            logging("Could not allocate memory for Output Packet.");
            return -1;
        }
    
        int response = avcodec_send_frame(encoder->video_avcc, input_frame);
    
        while (response >= 0)
        {
            response = avcodec_receive_packet(encoder->video_avcc, output_packet);
            if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
            {
                break;
            }
            else if (response < 0)
            {
                logging("Error while receiving packet from encoder: %s", av_err2str_cpp(response));
                return -1;
            }
    
            output_packet->stream_index = decoder->video_index;
            output_packet->duration = encoder->video_avs->time_base.den / encoder->video_avs->time_base.num / decoder->video_avs->avg_frame_rate.num * decoder->video_avs->avg_frame_rate.den;
    
            av_packet_rescale_ts(output_packet, decoder->video_avs->time_base, encoder->video_avs->time_base);
            response = av_interleaved_write_frame(encoder->avfc, output_packet);
            if (response != 0)
            {
                logging("Error %d while receiving packet from decoder: %s", response, av_err2str_cpp(response));
                return -1;
            }
        }
    
        av_packet_unref(output_packet);
        av_packet_free(&output_packet);
    
        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_cpp(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_cpp(response));
                return response;
            }
            if (response >= 0)
            {
                scaled_frame->pts = input_frame->pts;
                scaled_frame->pkt_dts = input_frame->pkt_dts;
                scaled_frame->pict_type = input_frame->pict_type;
                sws_scale_frame(encoder->sws_ctx, scaled_frame, input_frame);
                if (encode_video(decoder, encoder, scaled_frame))
                    return -1;
            }
    
            av_frame_unref(input_frame);
        }
        return 0;
    }
    
    
    //Building input file using FFmpeg CLI:  
    //ffmpeg -y -ss 30 -i bunny_1080p_60fps.mp4 -c:v copy -c:a aac -map v:0 -map a:0 -t 5 short_bunny_streo.mp4
    int main(int argc, char *argv[])
    {
        const int scaled_frame_width = 854;
        const int scaled_frame_height = 480;
    
    
        StreamingParams sp = {0};
        sp.copy_audio = 1;
        sp.copy_video = 0;
        sp.video_codec = "libx265";
    
    
        StreamingContext *decoder = (StreamingContext *)calloc(1, sizeof(StreamingContext));
        //decoder->filename = argv[1];
        decoder->filename = "short_bunny_streo.mp4";
    
        StreamingContext *encoder = (StreamingContext *)calloc(1, sizeof(StreamingContext));
        //encoder->filename = argv[2];
        encoder->filename = "downscaled_short_bunny_streo.mp4";
    
        //if (sp.output_extension)
        //{
        //    strcat(encoder->filename, sp.output_extension);
        //}
    
        if (open_media(decoder->filename, &decoder->avfc))
            return -1;
        if (prepare_decoder(decoder))
            return -1;
    
        avformat_alloc_output_context2(&encoder->avfc, NULL, NULL, encoder->filename);
        if (!encoder->avfc)
        {
            logging("Could not allocate memory for output Format Context.");
            return -1;
        }
    
        AVRational input_framerate = av_guess_frame_rate(decoder->avfc, decoder->video_avs, NULL);
        prepare_video_encoder(encoder, decoder->video_avcc, input_framerate, sp, scaled_frame_width, scaled_frame_height);
    
    
        if (encoder->avfc->oformat->flags & AVFMT_GLOBALHEADER)
            encoder->avfc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    
        if (!(encoder->avfc->oformat->flags & AVFMT_NOFILE))
        {
            if (avio_open(&encoder->avfc->pb, encoder->filename, AVIO_FLAG_WRITE) < 0)
            {
                logging("could not open the output file");
                return -1;
            }
        }
    
        AVDictionary *muxer_opts = NULL;
    
        if (sp.muxer_opt_key && sp.muxer_opt_value)
        {
            av_dict_set(&muxer_opts, sp.muxer_opt_key, sp.muxer_opt_value, 0);
        }
    
        if (avformat_write_header(encoder->avfc, &muxer_opts) < 0)
        {
            logging("an error occurred when opening output file");
            return -1;
        }
    
        AVFrame *input_frame = av_frame_alloc();
        AVFrame *scaled_frame = av_frame_alloc();
        if (!input_frame || !scaled_frame)
        {
            logging("Failed to allocate memory for AVFrame");
            return -1;
        }
    
        // scaled_frame->format = AV_PIX_FMT_YUV420P;
        scaled_frame->width = scaled_frame_width;
        scaled_frame->height = scaled_frame_height;
    
        //Creating Scaling Context
        encoder->sws_ctx = sws_getContext(1920, 1080,
                                decoder->video_avcc->pix_fmt, 
                               scaled_frame->width, scaled_frame->height, decoder->video_avcc->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL );
        if (!encoder->sws_ctx){logging("Cannot Create Scaling Context."); return -1;}
    
    
        AVPacket *input_packet = av_packet_alloc();
        if (!input_packet)
        {
            logging("Failed to allocate memory for AVPacket.");
            return -1;
        }
    
        while (av_read_frame(decoder->avfc, input_packet) >= 0)
        {
            if (decoder->avfc->streams[input_packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
            {
                    if (transcode_video(decoder, encoder, input_packet, input_frame, scaled_frame))
                        return -1;
                    av_packet_unref(input_packet);
            }
            else
            {
                logging("Ignoring all nonvideo  packets.");
            }
        }
    
        if (encode_video(decoder, encoder, NULL))
            return -1;
    
        av_write_trailer(encoder->avfc);
    
        if (muxer_opts != NULL)
        {
            av_dict_free(&muxer_opts);
            muxer_opts = NULL;
        }
    
        if (input_frame != NULL)
        {
            av_frame_free(&input_frame);
            input_frame = NULL;
        }
    
        if (input_packet != NULL)
        {
            av_packet_free(&input_packet);
            input_packet = NULL;
        }
    
        avformat_close_input(&decoder->avfc);
    
        avformat_free_context(decoder->avfc);
        decoder->avfc = NULL;
        avformat_free_context(encoder->avfc);
        encoder->avfc = NULL;
    
        avcodec_free_context(&decoder->video_avcc);
        decoder->video_avcc = NULL;
        avcodec_free_context(&decoder->audio_avcc);
        decoder->audio_avcc = NULL;
    
        free(decoder);
        decoder = NULL;
        free(encoder);
        encoder = NULL;
    
        return 0;
    }