-
Notifications
You must be signed in to change notification settings - Fork 0
LibAV Playback initialization
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.)
// 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;
}
// 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;
}
// 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.