In the following code, I can't figure out what's wrong:
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);
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);
ASSERT(ret == tmp_frame->height);
It's part of a code which uses dxva2 to obtain tmp_frame. I inspired the code from hw_decode.c and am sure that there's no mistake in the code. The tmp_frame is properly made in NV12 format. The error occurs just when I call sws_scale and it's:
bad src image pointers
So I don't know how to provide pointers not to get this error and sws_scale may work properly. Any idea?
I updated the question for giving the complete code:
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 = 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++)
{
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);
ret = avcodec_receive_frame(decoder_ctx, frame);
if (ret < 0)
printf("%d\t%d\n", i, ret);
AVFrame *tmp_frame;
if (frame->format > 0)
{
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);
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 = 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;
}
What I have tried:
I tried using a larger allocated block as buffer. I also tried other formats and changing arguments. But I couldn't succeed.