Проблема преобразования формата пикселей [FFMPEG]

Я написал небольшую программу, используя библиотеки ffmpeg. что делает следующее-

1) расшифровать кадр. 2) конвертировать кадр в rgb24 . 3) конвертировать кадр rgb24 обратно в yuv420p. 4) закодировать кадр yuv420p и упаковать его в видеофайл.

Но конец видео не совпадает с входным видео. в финальном видео есть некоторые артефакты (горизонтальные линии). Я также получаю предупреждение при вызове метода rgbToYuv - Предупреждение: данные не выровнены! Это может привести к потере скорости

Я подозреваю, что что-то не так с моими методами преобразования формата, потому что, когда я комментирую шаги покрытия из моей программы, выходное видео идентично входному видео.

следующие мои методы -

int VideoFileInstance::convertToRGBFrame(AVFrame **yuvframe,AVFrame **rgbPictInfo) {
    int ret;
    int width = ifmt_ctx->streams[VIDEO_STREAM_INDEX]->codec->width;
    int height = ifmt_ctx->streams[VIDEO_STREAM_INDEX]->codec->height;

    int m_bufferSize = avpicture_get_size(PIX_FMT_RGB24,width, height);

    uint8_t *buffer = (uint8_t *)av_malloc(m_bufferSize);

    //init context if not done already.
    if (imgConvertCtxYUVToRGB == NULL) {
        //init once
        imgConvertCtxYUVToRGB = sws_getContext(width, height, PIX_FMT_YUV420P, width, height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

        if(imgConvertCtxYUVToRGB == NULL) {
            av_log(NULL,AV_LOG_ERROR,"error creating img context");
            return -1;
        }

    }


    avpicture_fill((AVPicture*)(*rgbPictInfo), buffer,
                   PIX_FMT_RGB24,
                   width, height);

    uint8_t *inDate[3] = {
        (*yuvframe)->data[0] ,
        (*yuvframe)->data[1] ,
        (*yuvframe)->data[2]
    };

    int destLineSize[1] = {3*width};

    ret = sws_scale(imgConvertCtxYUVToRGB, inDate, (*yuvframe)->linesize, 0, height,
              (*rgbPictInfo)->data, destLineSize);

    av_free(buffer);


    return ret;
}

int VideoFileInstance::convertToYuvFrame (AVFrame **rgbFrame , AVFrame ** yuvFrame) {
    int ret = 0;
    int width = ifmt_ctx->streams[VIDEO_STREAM_INDEX]->codec->width;
    int height = ifmt_ctx->streams[VIDEO_STREAM_INDEX]->codec->height;
    int m_bufferSize = avpicture_get_size(PIX_FMT_YUV420P, width, height);

    uint8_t *buffer = (uint8_t *)av_malloc(m_bufferSize);

    avpicture_fill((AVPicture*)(*yuvFrame), buffer, PIX_FMT_YUV420P,
                   width, height);

    if(imgConvertCtxRGBToYUV == NULL) {
        imgConvertCtxRGBToYUV = sws_getContext(width, height, PIX_FMT_RGB24, width, height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

        if(imgConvertCtxRGBToYUV == NULL){
            av_log(NULL,AV_LOG_ERROR,"error creating img context");
            return -1;
        }
    }

    avpicture_fill((AVPicture*)(*yuvFrame), buffer,
                   PIX_FMT_YUV420P,
                   width, height);




    sws_scale(imgConvertCtxRGBToYUV,(*rgbFrame)->data , (*rgbFrame)->linesize, 0, height,
              (*yuvFrame)->data , (*yuvFrame)->linesize);

    av_free(buffer);

    return ret;
}

Размер входного видео 424 X 200. Что-то не так с моими функциями преобразования.

2 ответа

Решение

См. /questions/1490111/kak-vyi-izmenyaete-razmer-avframe/1490120#1490120 Вторая точка маркера, avpicture_ и связанные с ней функции не гарантируют выравнивание, необходимо использовать аналоги av_image_ с align=16 или align=32.

Использование Рональдсом предложения об использовании методов av_image* решило проблему для меня. Ниже приведен фиксированный код для одного из методов.

int VideoFileInstance::convertToRGBFrame(AVFrame **yuvframe,AVFrame **rgbPictInfo) {
    int ret;
    int width = ifmt_ctx->streams[VIDEO_STREAM_INDEX]->codec->width;
    int height = ifmt_ctx->streams[VIDEO_STREAM_INDEX]->codec->height;




    //init context if not done already.
    if (imgConvertCtxYUVToRGB == NULL) {
        //init once
        imgConvertCtxYUVToRGB = sws_getContext(width, height, PIX_FMT_YUV420P, width, height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, 0, 0, 0);

        if(imgConvertCtxYUVToRGB == NULL) {
            av_log(NULL,AV_LOG_ERROR,"error creating img context");
            return -1;
        }

    }


    // call av_freep(rgbPictInfo->data) to free memory

    av_image_alloc( (*rgbPictInfo)->data,   //data to be filled
                   (*rgbPictInfo)->linesize,//line sizes to be filled
                   width, height,
                   PIX_FMT_RGB24,           //pixel format
                   32                       //aling
                   );



    ret = sws_scale(imgConvertCtxYUVToRGB, (*yuvframe)->data, (*yuvframe)->linesize, 0, height,
              (*rgbPictInfo)->data, (*rgbPictInfo)->linesize);


    return ret;
}
Другие вопросы по тегам