Что не так при предоставлении аргументов для sws_scale? - PullRequest
0 голосов
/ 30 апреля 2019

В следующем коде я не могу понять, что не так:

uint8_t *dstData[4];
int dstLinesize[4];
AVPixelFormat convertToPixFmt = AV_PIX_FMT_RGBA;
int ret;

// ...

printf("tmp_frame format: %d (%s) %dx%d\n", tmp_frame->format, av_get_pix_fmt_name((AVPixelFormat)tmp_frame->format), tmp_frame->width, tmp_frame->height);
// The above line prints: tmp_frame format: 23 (nv12) 480x480

int size = av_image_get_buffer_size(convertToPixFmt, tmp_frame->width, tmp_frame->height, 1);
uint8_t *buffer = (uint8_t *) av_malloc(size);

ret = av_image_copy_to_buffer(buffer, size,
    (const uint8_t * const *)&tmp_frame->data[i],
    (const int *)&tmp_frame->linesize[i], (AVPixelFormat)tmp_frame->format,
    tmp_frame->width, tmp_frame->height, 1);
ASSERT(ret >= 0);

ret = av_image_fill_arrays(dstData, dstLinesize, buffer, convertToPixFmt, dest_width, dest_height, 1);
ASSERT(ret >= 0);

ret = sws_scale(
    convertContext,
    dstData,
    dstLinesize,
    0,
    dest_width,
    convertedFrame->data,
    convertedFrame->linesize);
printf("sws_scale returns %d\n", ret);  // prints: sws_scale returns 0
ASSERT(ret == tmp_frame->height);

// ...

Это часть кода, которая использует dxva2 для получения tmp_frame.Я вдохновил код из hw_decode.c и уверен, что в коде нет ошибок.Tmp_frame правильно выполнен в формате NV12.Ошибка возникает, когда я вызываю sws_scale, и это:

bad src image pointers

Так что я не знаю, как предоставить указатели, чтобы не получать эту ошибку, и sws_scale может работать правильно.Любая идея?

Я обновляю вопрос, чтобы включить весь мой код:

static AVBufferRef *hw_device_ctx = NULL;
static enum AVPixelFormat hw_pix_fmt;
static FILE *output_file = NULL;

int main(int argc, char *argv[])
{
    AVFormatContext *input_ctx = NULL;
    int video_stream, ret;
    AVStream *video = NULL;
    AVCodecContext *decoder_ctx = NULL;
    AVCodec *decoder = NULL;
    AVPacket packet;
    enum AVHWDeviceType type;
    int i;

    if (argc < 2)
    {
        fprintf(stderr, "Usage: %s <input file>\n", argv[0]);
        return -1;
    }

    type = av_hwdevice_find_type_by_name("dxva2");
    ASSERT(type != AV_HWDEVICE_TYPE_NONE);
    ASSERT(avformat_open_input(&input_ctx, argv[1], NULL, NULL) == 0);
    ASSERT(avformat_find_stream_info(input_ctx, NULL) >= 0);
    video_stream = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
    ASSERT(video_stream >= 0);
    decoder_ctx = avcodec_alloc_context3(decoder);
    ASSERT(decoder_ctx);
    video = input_ctx->streams[video_stream];
    ASSERT(avcodec_parameters_to_context(decoder_ctx, video->codecpar) >= 0);
    ASSERT(av_hwdevice_ctx_create(&hw_device_ctx, type, NULL, NULL, 0) >= 0);
    decoder_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    ASSERT(avcodec_open2(decoder_ctx, decoder, NULL) >= 0);
    printf("video info: %dx%d\n", decoder_ctx->width, decoder_ctx->height);

    AVFrame *frame = av_frame_alloc();
    ASSERT(frame);
    AVFrame *sw_frame = av_frame_alloc();
    ASSERT(sw_frame);
    AVFrame* convertedFrame = av_frame_alloc();
    ASSERT(convertedFrame);

    AVPixelFormat convertToPixFmt = AV_PIX_FMT_RGBA;
    //int dest_width = 320, dest_height = 200;
    int dest_width = decoder_ctx->width, dest_height = decoder_ctx->height;
    SwsContext* convertContext = sws_getContext(decoder_ctx->width, decoder_ctx->height, AV_PIX_FMT_YUV420P,
        dest_width, dest_height, convertToPixFmt,
        SWS_FAST_BILINEAR, NULL, NULL, NULL);
    ASSERT(convertContext);
    int convertedFrameAspectBufferSize = avpicture_get_size(convertToPixFmt, dest_width, dest_height);
    void *convertedFrameBuffer = av_malloc(convertedFrameAspectBufferSize);
    avpicture_fill((AVPicture*)convertedFrame, (uint8_t *)convertedFrameBuffer, convertToPixFmt, dest_width, dest_height);
    output_file = fopen("1.out", "w+");

    for (int i = 0; /*i < 20*/; i++)
    {
        ret = av_read_frame(input_ctx, &packet);
        if (ret == AVERROR_EOF)
            break;
        ASSERT(ret >= 0);
        if (video_stream != packet.stream_index)
            continue;
        int ret = avcodec_send_packet(decoder_ctx, &packet);
        ASSERT(ret >= 0);
        //printf("%p", decoder->hw_configs->hwaccel);
        ret = avcodec_receive_frame(decoder_ctx, frame);
        if (ret < 0)
            printf("%d\t%d\n", i, ret);
        AVFrame *tmp_frame;
        if (frame->format > 0)  // hw enabled
        {
            ASSERT(av_hwframe_transfer_data(sw_frame, frame, 0) >= 0);
            tmp_frame = sw_frame;
        }
        else
        {
            tmp_frame = frame;
        }
        printf("frame format: %d (%s) %dx%d\n", frame->format, av_get_pix_fmt_name((AVPixelFormat)frame->format), frame->width, frame->height);
        printf("sw_frame format: %d (%s) %dx%d\n", sw_frame->format, av_get_pix_fmt_name((AVPixelFormat)sw_frame->format), sw_frame->width, sw_frame->height);
        printf("tmp_frame format: %d (%s) %dx%d\n", tmp_frame->format, av_get_pix_fmt_name((AVPixelFormat)tmp_frame->format), tmp_frame->width, tmp_frame->height);
        /*
        video info: 480x480
        frame format: 53 (dxva2_vld) 480x480
        sw_frame format: 23 (nv12) 480x480
        [swscaler @ 004cb2c0] bad src image pointers
        */

        int size = av_image_get_buffer_size(convertToPixFmt, tmp_frame->width, tmp_frame->height, 1);
        uint8_t *buffer = (uint8_t *) av_malloc(size);

        ret = av_image_copy_to_buffer(buffer, size,
            (const uint8_t * const *)&tmp_frame->data[i],
            (const int *)&tmp_frame->linesize[i], (AVPixelFormat)tmp_frame->format,
            tmp_frame->width, tmp_frame->height, 1);
        ASSERT(ret > 0);

        ret = av_image_fill_arrays(dstData, dstLinesize, buffer, convertToPixFmt, dest_width, dest_height, 1);
        ASSERT(ret > 0);

        ret = sws_scale(
            convertContext,
            tmp_frame->data,
            tmp_frame->linesize,
            0,
            dest_width,
            convertedFrame->data,
            convertedFrame->linesize);
        printf("sws_scale returns %d\n", ret);
        ASSERT(ret == tmp_frame->height);
        ret = fwrite(convertedFrame->data, tmp_frame->height * tmp_frame->width, 1, output_file);
        ASSERT(ret == 1);
        break;
    }
    av_frame_free(&frame);
    av_packet_unref(&packet);
    avcodec_free_context(&decoder_ctx);
    avformat_close_input(&input_ctx);
    av_buffer_unref(&hw_device_ctx);

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...