[Libav-user] avcodec_send_packet() gets blocked until decoding is complete (with H264 stream)

Kolominsky, Ilia ilia.kolominsky at intel.com
Thu Oct 25 19:26:56 EEST 2018


Dear ffmpeg devs,

I`ve been trying to solve my issue for some time, unfortunately in vain.
So I have to ask for your kind assistance:

The issue is with avcodec_send_packet() gets blocked until the
decoding is complete.
Pretty sure I am missing some setup steps, because when the
same stream is decoded with ffmpeg (linked with the same avcodec),
it clearly decodes using parallel threads -I have ensured it by logs and
via the fact that each decode() takes ~90ms, but ffmpeg decodes
30 fps at x1.74 speed.

Ive been following the examples for setup and this page:
https://blogs.gentoo.org/lu_zero/2016/03/29/new-avcodec-api/
but, obviously I am missing something.

Below is the code and its output for decoding of 3 frames.
Thanks in advance and BR
Ilia

void setUpDecoder(const char *decName)
{

	codec = avcodec_find_decoder_by_name(decName);
	if (!codec) {
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}

	c = avcodec_alloc_context3(codec);
	if (!c) {
		fprintf(stderr, "Could not allocate video codec context\n");
		exit(1);
	}

	//c->get_format = get_hw_format;
	if (avcodec_open2(c, codec, NULL) < 0) {
		fprintf(stderr, "Could not open codec\n");
		exit(1);
	}
}

void configCtx1(AVCodecContext *c)
{
	c->flags = AV_CODEC_FLAG_OUTPUT_CORRUPT | AV_CODEC_FLAG_LOW_DELAY;
	c->flags2 = AV_CODEC_FLAG2_SHOW_ALL | AV_CODEC_FLAG2_FAST;

	c->thread_count = 10;
	c->thread_type = FF_THREAD_FRAME | FF_THREAD_SLICE;
}

void DecodePar(const char *inputTmpl, int startFid, int endFid)
{
	for (int i = startFid; i <= endFid; i++)
	{
		char fnBuff[256];
		snprintf(fnBuff, 255, inputTmpl, i);

		fprintf(stderr, "Opening %s...\n", fnBuff);

		FILE *fileIn = fopen(fnBuff, "rb");
		if (!fileIn) {
			fprintf(stderr, "Could not open \n");
			exit(1);
		}

		AVPacket *pkt = av_packet_alloc();
		if (!pkt)
		{
			fprintf(stderr, "av_packet_alloc failed\n");
			exit(1);
		}


		fseek(fileIn, 0, SEEK_END);
		pkt->size = ftell(fileIn);
		pkt->data = (uint8_t *)malloc(pkt->size + AV_INPUT_BUFFER_PADDING_SIZE);
		fseek(fileIn, 0, SEEK_SET);

		size_t data_size = fread(pkt->data, 1, pkt->size, fileIn);
		if (data_size != pkt->size)
		{
			fprintf(stderr, "Could not read %s\n", fnBuff);
			exit(1);
		}
		fclose(fileIn);

		auto start = std::chrono::high_resolution_clock::now();
		int ret = avcodec_send_packet(c, pkt);
		if (ret < 0) {
			fprintf(stderr, "Error sending a packet for decoding\n");
			exit(1);
		}
		cout << "avcodec_send_packet took " <<
			chrono::duration_cast<std::chrono::milliseconds>(chrono::high_resolution_clock::now() - start).count()
			<< "ms" << endl;


		AVFrame *frame = av_frame_alloc();
		ret = avcodec_receive_frame(c, frame);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
		{
			if (ret == AVERROR(EAGAIN))
			{
				fprintf(stderr, "EAGAIN\n");
			}
			else
			{
				fprintf(stderr, "EOF\n");
			}
		}
		else if (ret < 0)
		{
			fprintf(stderr, "avcodec_receive_frame error\n");
			exit(1);
		}
		else
		{
			fprintf(stderr, "Frame decoded\n");
		}

		av_frame_free(&frame);
		free(pkt->data);
		av_packet_free(&pkt);
	}

	AVPacket *pkt = av_packet_alloc();
	pkt->size = 0;
	avcodec_send_packet(c, pkt);
	av_packet_free(&pkt);

	//drain
	int ret;
	AVFrame *frame = av_frame_alloc();
	while (!(ret = avcodec_receive_frame(c, frame)))
	{
		fprintf(stderr, "Frame decoded in draining\n");
	}
	av_frame_free(&frame);

	if (ret != AVERROR_EOF)
	{
		fprintf(stderr, "Failed to drain\n");
		exit(1);
	}
}

int main(int argc, char *argv[])
{
	if (argc != 5)
	{
		cerr << "Wrong params, usage: $INPUT_PATERN $START_FID $END_FID $DECODER" << endl;
		return 1;
	}

	const char *inputTmpl = argv[1];
	int startFid = stoi(argv[2]);
	int endFid = stoi(argv[3]);
	const char *decoderName = argv[4];

	setUpDecoder(decoderName);
	configCtx1(c);

	cout << "starting DecodePar()...";
	auto start = std::chrono::high_resolution_clock::now();
	//DecodeSeq(inputTmpl, startFid, endFid);

	DecodePar(inputTmpl, startFid, endFid);
	cout << chrono::duration_cast<std::chrono::milliseconds>(chrono::high_resolution_clock::now() - start).count() << "ms" << endl;
    return 0;
}


Output:

starting DecodePar()...Opening M:\encoded_cams_bp_30_200\1\1_0.h264...
[h264 @ 0000007D62963FC0] avcodec_send_packet 2945266
[h264 @ 0000007D62963FC0] h264_decode_frame() avpkt->size: 2945266
[h264 @ 0000007D62963FC0] returning at 8, TID: 15256, TS: 3574460658, dur: 882338 ns
avcodec_send_packet took 89ms
Frame decoded
Opening M:\encoded_cams_bp_30_200\1\1_1.h264...
[h264 @ 0000007D62963FC0] avcodec_send_packet 819304
[h264 @ 0000007D62963FC0] h264_decode_frame() avpkt->size: 819304
[h264 @ 0000007D62963FC0] returning at 8, TID: 15256, TS: 3575152502, dur: 641715 ns
avcodec_send_packet took 65ms
Frame decoded
Opening M:\encoded_cams_bp_30_200\1\1_2.h264...
[h264 @ 0000007D62963FC0] avcodec_send_packet 784883
[h264 @ 0000007D62963FC0] h264_decode_frame() avpkt->size: 784883
[h264 @ 0000007D62963FC0] returning at 8, TID: 15256, TS: 3575854354, dur: 661758 ns
avcodec_send_packet took 66ms


---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.



More information about the Libav-user mailing list