Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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);
// 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);

// ...

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 = 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 = 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.
Posted
Updated 30-Apr-19 3:39am
v3

1 solution

Normally the error message is more correct than the code written by some beginner. So I think you have mismatched some data or data types.

Here is some working code with sws_scale which may show you to get it work.

I think you should review the naming of your variables and their usage in the sws_scale call.
 
Share this answer
 
Comments
ilostmyid2 30-Apr-19 9:26am    
I've exactly did the same. The problem arises when I use dxva2 and I think it's because the format changes to nv12.
ilostmyid2 30-Apr-19 9:40am    
I updated the question to include my whole code.
KarstenK 1-May-19 14:00pm    
Try with some other data format to prove the code is correct or it is a bug in ffmpeg. You better try your luck in some ffmpeg forum for such special questions. ;-)
ilostmyid2 4-May-19 1:09am    
I couldn't find a proper and active enough forum for this purpose

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900