Skip to content

LibAV Playback initialization

Blake Senftner edited this page Jun 11, 2020 · 2 revisions

As ffmpeg versions advance, the necessary settings to configure playback vary with each release. Here is a brief summary and description of the methods used by a LibAV based video player that ignores audio, featuring as fast as possible video frame decompression for display.

Note 3 types of video streams are supported: media files, USB cameras and IP video (from either an IP camera or an online video service.)

2018 setup, ffmpeg 3.1.4, player used 2 threads: packet reader & frame decompressor:

// options for all stream types:
av_dict_set(&mp_opts, "threads", "1", 0);              // if multi-threading is needed, do it
av_dict_set( &mp_opts, "refcounted_frames", "1", 0 );  // ffplay sets this
av_dict_set( &mp_opts, "max_delay", "500000", 0 );	
av_dict_set( &mp_opts, "sync", "video", 0 );	
av_dict_set( &mp_opts, "hwaccel", "none", 0 );	
av_dict_set( &mp_opts, "fflags", "discardcorrupt", 0 );	// works, sets flag in mp_format_context

switch (mp_av_player->m_stream_type)
{
case 0: // media file
	av_dict_set( &mp_opts, "framerate", "24", 0 );
	av_dict_set( &mp_opts, "scan_all_pmts", "1", 0 );		// ffplay uses this flag
	break;
case 1:	// usb cam
	// av_dict_set(&mp_opts,"show_video_device_dialog","true",0);
	if (usb_format)
	{
		av_dict_set( &mp_opts, "max_delay", "500000", 0 );	// half second
		av_dict_set( &mp_opts, "rtbufsize", "106M", 0 );	// a half second of 1280x720x4 

		char bsjnk[1024];
		sprintf( bsjnk, "%dx%d", usb_format->m_max_width, usb_format->m_max_height );
		av_dict_set( &mp_opts, "video_size", bsjnk, 0 );
		//
		sprintf( bsjnk, "%1.2f", usb_format->m_max_fps );
		av_dict_set( &mp_opts, "framerate", bsjnk, 0 );
		//
		if (usb_format->m_pixelFormat.size() > 0)
		{
			av_dict_set( &mp_opts, "pixel_format", usb_format->m_pixelFormat.c_str(), 0 );
		}
		else if (usb_format->m_pixelFormat.size() > 0)
		{
			av_dict_set( &mp_opts, "vcodec", usb_format->m_vcodec.c_str(), 0 );
		}
	} 
	else 
	{
		av_dict_set( &mp_opts, "video_size", "640x480", 0 );
		av_dict_set( &mp_opts, "framerate", "30", 0 );
	}
	break;
case 2: // ip cam
	av_dict_set( &mp_opts, "rtsp_transport", "tcp", 0 );
	av_dict_set( &mp_opts, "framerate", "29.97", 0 );
	av_dict_set( &mp_opts, "allowed_media_types", "video", 0 );
	break;
}

2019 setup, ffmpeg 3.2.2, player used 1 thread: packet reader, frame decompressor combined:

// options for all stream types:
av_dict_set(&mp_opts, "threads", "1", 0);                // if multi-threading is needed, do it
av_dict_set( &mp_opts, "refcounted_frames", "1", 0 );    // ffplay sets this
av_dict_set( &mp_opts, "sync", "video", 0 );	
av_dict_set( &mp_opts, "hwaccel", "none", 0 );	
av_dict_set( &mp_opts, "fflags", "discardcorrupt", 0 );	// works, sets flag in mp_format_context

char bsjnk[1024];
switch (mp_av_player->m_stream_type)
{
case 0: // media file
	av_dict_set( &mp_opts, "framerate", "24", 0 );
	av_dict_set( &mp_opts, "scan_all_pmts", "1", 0 );		// ffplay uses this flag
	break;
case 1:	// usb cam
	if (usb_format)
	{
		if (m_max_buffering_delay < 0.0f)
		{
		av_dict_set( &mp_opts, "max_delay", "100000", 0 );	// tenth of a second
		}
		else
		{
			ce_int m = (ce_int)(m_max_buffering_delay * 1000000.0f);
			sprintf( bsjnk, "%d", m );
			av_dict_set( &mp_opts, "max_delay", bsjnk, 0 );
		}

		sprintf( bsjnk, "%dx%d", usb_format->m_max_width, usb_format->m_max_height );
		av_dict_set( &mp_opts, "video_size", bsjnk, 0 );
		//
		sprintf( bsjnk, "%1.2f", usb_format->m_max_fps );
		av_dict_set( &mp_opts, "framerate", bsjnk, 0 );
		//
		if (usb_format->m_pixelFormat.size() > 0)
		{
			av_dict_set( &mp_opts, "pixel_format", usb_format->m_pixelFormat.c_str(), 0 );
		}
		else if (usb_format->m_vcodec.size() > 0)
		{
			av_dict_set( &mp_opts, "vcodec", usb_format->m_vcodec.c_str(), 0 );
		}
	} 
	else 
	{
		av_dict_set( &mp_opts, "video_size", "640x480", 0 );
		av_dict_set( &mp_opts, "framerate", "30", 0 );

		if (m_max_buffering_delay >= 0.0f)
		{
			ce_int m = (ce_int)(m_max_buffering_delay * 1000000.0f);
			sprintf( bsjnk, "%d", m );
			av_dict_set( &mp_opts, "max_delay", bsjnk, 0 );
		}
	}
	break;
case 2: // ip cam
	av_dict_set( &mp_opts, "rtsp_transport", "tcp", 0 );
	av_dict_set( &mp_opts, "framerate", "29.97", 0 );
	av_dict_set( &mp_opts, "allowed_media_types", "video", 0 );

	if (m_max_buffering_delay < 0.0f)
	{
		av_dict_set( &mp_opts, "max_delay", "0", 0 ); // no IP stream buffering
	}
	else // must have a m_max_buffering_delay set; recommended to use 0.1f for UDP IP streams
	{
		ce_int m = (ce_int)(m_max_buffering_delay * 1000000.0f);
		sprintf( bsjnk, "%d", m );
		av_dict_set( &mp_opts, "max_delay", bsjnk, 0 );
	}
	break;
}

2020 setup, ffmpeg 4.2.3, player still 1 thread

// options for all stream types:
av_dict_set(&mp_opts, "threads", "auto", 0);		// if multi-threading is needed, do it
av_dict_set( &mp_opts, "refcounted_frames", "1", 0 );	// ffplay sets this
av_dict_set( &mp_opts, "sync", "video", 0 );	
av_dict_set( &mp_opts, "fflags", "discardcorrupt", 0 );	// works, sets flag in mp_format_context

switch (mp_av_player->m_stream_type)
{
case 0: // media file
	av_dict_set( &mp_opts, "framerate", "24", 0 );
	av_dict_set( &mp_opts, "scan_all_pmts", "1", 0 ); // ffplay uses this flag
	break;
case 1:	// usb cam
	if (usb_format)
	{
		av_dict_set( &mp_opts, "fflags", "nobuffer", 0 );

		char bsjnk[1024];
		sprintf( bsjnk, "%dx%d", usb_format->m_max_width, usb_format->m_max_height );
		av_dict_set( &mp_opts, "video_size", bsjnk, 0 );
		//
		sprintf( bsjnk, "%1.2f", usb_format->m_max_fps );
		av_dict_set( &mp_opts, "framerate", bsjnk, 0 );
		//
		if (usb_format->m_pixelFormat.size() > 0)
		{
			av_dict_set( &mp_opts, "pixel_format", usb_format->m_pixelFormat.c_str(), 0 );
		}
		else if (usb_format->m_pixelFormat.size() > 0)
		{
			av_dict_set( &mp_opts, "vcodec", usb_format->m_vcodec.c_str(), 0 );
		}
	} 
	else 
	{
		av_dict_set( &mp_opts, "video_size", "640x480", 0 );
		av_dict_set( &mp_opts, "framerate", "30", 0 );
	}
	break;
case 2: // ip cam
	av_dict_set( &mp_opts, "max_delay", "100000", 0 );
	av_dict_set( &mp_opts, "flags", "low_delay", 0 );
	av_dict_set( &mp_opts, "rtsp_transport", "tcp", 0 );
	av_dict_set( &mp_opts, "framerate", "29.97", 0 );
	av_dict_set( &mp_opts, "allowed_media_types", "video", 0 );
	break;
}

An additional change in the 2020 ffmpeg 4.2.3 based player library is the removal of any delay/sleep between attempts to read the next stream packet. Previously two threads were used, one to read video packets and another to decompress them and send them to the library client. When changing to a single thread, it was realized allowing av_read_frame() to block is fine, because it is not blocking anything. The player library lives in its own thread, separate from the application.