Search code examples
c++videoffmpegyuvrgba

ffmpeg sws_scale YUV420p to RGBA not giving correct scaling result (c++)


I am trying to scale a decoded YUV420p frame(1018x700) via sws_scale to RGBA, I am saving data to a raw video file and then playing the raw video using ffplay to see the result.

Here is my code:

sws_ctx = sws_getContext(video_dec_ctx->width, video_dec_ctx->height,AV_PIX_FMT_YUV420P, video_dec_ctx->width, video_dec_ctx->height, AV_PIX_FMT_BGR32, SWS_LANCZOS | SWS_ACCURATE_RND, 0, 0, 0);
ret = avcodec_decode_video2(video_dec_ctx, yuvframe, got_frame, &pkt);
    if (ret < 0) {
        std::cout<<"Error in decoding"<<std::endl;
        return ret;
    }else{
        //the source and destination heights and widths are the same
        int sourceX = video_dec_ctx->width;
        int sourceY = video_dec_ctx->height;
        int destX = video_dec_ctx->width;
        int destY = video_dec_ctx->height;

        //declare destination frame
        AVFrame avFrameRGB;
        avFrameRGB.linesize[0] = destX * 4;
        avFrameRGB.data[0] = (uint8_t*)malloc(avFrameRGB.linesize[0] * destY);

        //scale the frame to avFrameRGB
        sws_scale(sws_ctx, yuvframe->data, yuvframe->linesize, 0, yuvframe->height, avFrameRGB.data, avFrameRGB.linesize);

        //write to file
        fwrite(avFrameRGB.data[0], 1, video_dst_bufsize, video_dst_file);
 }

Here is the result without scaling (i.e. in YUV420p Format) Here is the result without scaling (i.e. in YUV420p Format)

Here is the after scaling while playing using ffplay (i.e. in RGBA format) enter image description here

I run the ffplay using the following command ('video' is the raw video file)

ffplay -f rawvideo -pix_fmt bgr32 -video_size 1018x700 video

What should I fix to make the correct scaling happen to RGB32?


Solution

  • I found the solution, the problem here was that I was not using the correct buffer size to write to the file.

    fwrite(avFrameRGB.data[0], 1, video_dst_bufsize, video_dst_file);
    

    The variable video_dst_file was being taken from the return value of

    video_dst_bufsize = av_image_alloc(yuvframe.data, yuvframe.linesize, destX, destY, AV_PIX_FMT_YUV420P, 1);
    

    The solution is to get the return value from and use this in the fwrite statement:

    video_dst_bufsize_RGB = av_image_alloc(avFrameRGB.data, avFrameRGB.linesize, destX, destY, AV_PIX_FMT_BGR32, 1);
    
    fwrite(avFrameRGB.data[0], 1, video_dst_bufsize_RGB, video_dst_file);