@ -98,7 +98,7 @@ static int frame_topBand = 0;
static int frame_bottomBand = 0 ;
static int frame_leftBand = 0 ;
static int frame_rightBand = 0 ;
static int max_frames [ 3 ] = { INT_MAX , INT_MAX , INT_MAX } ;
static int max_frames [ 4 ] = { INT_MAX , INT_MAX , INT_MAX , INT_MAX } ;
static int frame_rate = 25 ;
static int frame_rate_base = 1 ;
static int video_bit_rate = 200 * 1000 ;
@ -219,6 +219,10 @@ static int audio_disable = 0;
static int audio_channels = 1 ;
static int audio_codec_id = CODEC_ID_NONE ;
static int audio_codec_tag = 0 ;
static char * audio_language = NULL ;
static int subtitle_codec_id = CODEC_ID_NONE ;
static char * subtitle_language = NULL ;
static int mux_rate = 0 ;
static int mux_packet_size = 0 ;
@ -244,6 +248,7 @@ static int bitexact = 0;
static char * pass_logfilename = NULL ;
static int audio_stream_copy = 0 ;
static int video_stream_copy = 0 ;
static int subtitle_stream_copy = 0 ;
static int video_sync_method = 1 ;
static int audio_sync_method = 0 ;
static int copy_ts = 0 ;
@ -693,6 +698,58 @@ static void fill_pad_region(AVPicture* img, int height, int width,
}
}
static void do_subtitle_out ( AVFormatContext * s ,
AVOutputStream * ost ,
AVInputStream * ist ,
AVSubtitle * sub ,
int64_t pts )
{
static uint8_t * subtitle_out = NULL ;
int subtitle_out_max_size = 65536 ;
int subtitle_out_size , nb , i ;
AVCodecContext * enc ;
AVPacket pkt ;
if ( pts = = AV_NOPTS_VALUE ) {
fprintf ( stderr , " Subtitle packets must have a pts \n " ) ;
return ;
}
enc = & ost - > st - > codec ;
if ( ! subtitle_out ) {
subtitle_out = av_malloc ( subtitle_out_max_size ) ;
}
/* Note: DVB subtitle need one packet to draw them and one other
packet to clear them */
/* XXX: signal it in the codec context ? */
if ( enc - > codec_id = = CODEC_ID_DVB_SUBTITLE )
nb = 2 ;
else
nb = 1 ;
for ( i = 0 ; i < nb ; i + + ) {
subtitle_out_size = avcodec_encode_subtitle ( enc , subtitle_out ,
subtitle_out_max_size , sub ) ;
av_init_packet ( & pkt ) ;
pkt . stream_index = ost - > index ;
pkt . data = subtitle_out ;
pkt . size = subtitle_out_size ;
pkt . pts = av_rescale_q ( av_rescale_q ( pts , ist - > st - > time_base , AV_TIME_BASE_Q ) + input_files_ts_offset [ ist - > file_index ] , AV_TIME_BASE_Q , ost - > st - > time_base ) ;
if ( enc - > codec_id = = CODEC_ID_DVB_SUBTITLE ) {
/* XXX: the pts correction is handled here. Maybe handling
it in the codec would be better */
if ( i = = 0 )
pkt . pts + = 90 * sub - > start_display_time ;
else
pkt . pts + = 90 * sub - > end_display_time ;
}
av_interleaved_write_frame ( s , & pkt ) ;
}
}
static int bit_buffer_size = 1024 * 256 ;
static uint8_t * bit_buffer = NULL ;
@ -1130,6 +1187,8 @@ static int output_packet(AVInputStream *ist, int ist_index,
void * buffer_to_free ;
static int samples_size = 0 ;
static short * samples = NULL ;
AVSubtitle subtitle , * subtitle_to_free ;
int got_subtitle ;
if ( ! pkt ) {
ist - > pts = ist - > next_pts ; // needed for last packet if vsync=0
@ -1153,6 +1212,7 @@ static int output_packet(AVInputStream *ist, int ist_index,
/* decode the packet if needed */
data_buf = NULL ; /* fail safe */
data_size = 0 ;
subtitle_to_free = NULL ;
if ( ist - > decoding_needed ) {
switch ( ist - > st - > codec . codec_type ) {
case CODEC_TYPE_AUDIO : {
@ -1197,6 +1257,17 @@ static int output_packet(AVInputStream *ist, int ist_index,
}
len = 0 ;
break ;
case CODEC_TYPE_SUBTITLE :
ret = avcodec_decode_subtitle ( & ist - > st - > codec ,
& subtitle , & got_subtitle , ptr , len ) ;
if ( ret < 0 )
goto fail_decode ;
if ( ! got_subtitle ) {
goto discard_packet ;
}
subtitle_to_free = & subtitle ;
len = 0 ;
break ;
default :
goto fail_decode ;
}
@ -1293,6 +1364,10 @@ static int output_packet(AVInputStream *ist, int ist_index,
if ( do_vstats & & frame_size )
do_video_stats ( os , ost , frame_size ) ;
break ;
case CODEC_TYPE_SUBTITLE :
do_subtitle_out ( os , ost , ist , & subtitle ,
pkt - > pts ) ;
break ;
default :
av_abort ( ) ;
}
@ -1322,9 +1397,16 @@ static int output_packet(AVInputStream *ist, int ist_index,
opkt . pts = av_rescale_q ( av_rescale_q ( pkt - > pts , ist - > st - > time_base , AV_TIME_BASE_Q ) + input_files_ts_offset [ ist - > file_index ] , AV_TIME_BASE_Q , ost - > st - > time_base ) ;
else
opkt . pts = AV_NOPTS_VALUE ;
opkt . dts = av_rescale_q ( av_rescale_q ( pkt - > dts , ist - > st - > time_base , AV_TIME_BASE_Q ) + input_files_ts_offset [ ist - > file_index ] , AV_TIME_BASE_Q , ost - > st - > time_base ) ;
opkt . flags = pkt - > flags ;
{
int64_t dts ;
if ( pkt - > dts = = AV_NOPTS_VALUE )
dts = ist - > next_pts ;
else
dts = av_rescale_q ( pkt - > dts , ist - > st - > time_base , AV_TIME_BASE_Q ) ;
opkt . dts = av_rescale_q ( dts + input_files_ts_offset [ ist - > file_index ] , AV_TIME_BASE_Q , ost - > st - > time_base ) ;
}
opkt . flags = pkt - > flags ;
av_interleaved_write_frame ( os , & opkt ) ;
ost - > st - > codec . frame_number + + ;
ost - > frame_number + + ;
@ -1332,6 +1414,12 @@ static int output_packet(AVInputStream *ist, int ist_index,
}
}
av_free ( buffer_to_free ) ;
/* XXX: allocate the subtitles in the codec ? */
if ( subtitle_to_free ) {
av_free ( subtitle_to_free - > bitmap ) ;
av_free ( subtitle_to_free - > rgba_palette ) ;
subtitle_to_free = NULL ;
}
}
discard_packet :
if ( pkt = = NULL ) {
@ -1579,6 +1667,8 @@ static int av_encode(AVFormatContext **output_files,
codec - > height = icodec - > height ;
codec - > has_b_frames = icodec - > has_b_frames ;
break ;
case CODEC_TYPE_SUBTITLE :
break ;
default :
av_abort ( ) ;
}
@ -1686,8 +1776,13 @@ static int av_encode(AVFormatContext **output_files,
ost - > encoding_needed = 1 ;
ist - > decoding_needed = 1 ;
break ;
case CODEC_TYPE_SUBTITLE :
ost - > encoding_needed = 1 ;
ist - > decoding_needed = 1 ;
break ;
default :
av_abort ( ) ;
break ;
}
/* two pass mode */
if ( ost - > encoding_needed & &
@ -2722,28 +2817,34 @@ static void opt_audio_device(const char *arg)
audio_device = av_strdup ( arg ) ;
}
static void opt_audio_codec ( const char * arg )
static void opt_codec ( int * pstream_copy , int * pcodec_id ,
int codec_type , const char * arg )
{
AVCodec * p ;
if ( ! strcmp ( arg , " copy " ) ) {
audio_ stream_copy = 1 ;
* p stream_copy = 1 ;
} else {
p = first_avcodec ;
while ( p ) {
if ( ! strcmp ( p - > name , arg ) & & p - > type = = CODEC_TYPE_AUDIO )
if ( ! strcmp ( p - > name , arg ) & & p - > type = = codec_type )
break ;
p = p - > next ;
}
if ( p = = NULL ) {
fprintf ( stderr , " Unknown audio codec '%s' \n " , arg ) ;
fprintf ( stderr , " Unknown codec '%s' \n " , arg ) ;
exit ( 1 ) ;
} else {
audio_ codec_id = p - > id ;
* p codec_id = p - > id ;
}
}
}
static void opt_audio_codec ( const char * arg )
{
opt_codec ( & audio_stream_copy , & audio_codec_id , CODEC_TYPE_AUDIO , arg ) ;
}
static void opt_audio_tag ( const char * arg )
{
char * tail ;
@ -2811,24 +2912,12 @@ static void opt_motion_estimation(const char *arg)
static void opt_video_codec ( const char * arg )
{
AVCodec * p ;
opt_codec ( & video_stream_copy , & video_codec_id , CODEC_TYPE_VIDEO , arg ) ;
}
if ( ! strcmp ( arg , " copy " ) ) {
video_stream_copy = 1 ;
} else {
p = first_avcodec ;
while ( p ) {
if ( ! strcmp ( p - > name , arg ) & & p - > type = = CODEC_TYPE_VIDEO )
break ;
p = p - > next ;
}
if ( p = = NULL ) {
fprintf ( stderr , " Unknown video codec '%s' \n " , arg ) ;
exit ( 1 ) ;
} else {
video_codec_id = p - > id ;
}
}
static void opt_subtitle_codec ( const char * arg )
{
opt_codec ( & subtitle_stream_copy , & subtitle_codec_id , CODEC_TYPE_SUBTITLE , arg ) ;
}
static void opt_map ( const char * arg )
@ -3011,6 +3100,8 @@ static void opt_input_file(const char *filename)
break ;
case CODEC_TYPE_DATA :
break ;
case CODEC_TYPE_SUBTITLE :
break ;
default :
av_abort ( ) ;
}
@ -3058,6 +3149,7 @@ static void check_audio_video_inputs(int *has_video_ptr, int *has_audio_ptr)
has_video = 1 ;
break ;
case CODEC_TYPE_DATA :
case CODEC_TYPE_SUBTITLE :
break ;
default :
av_abort ( ) ;
@ -3068,65 +3160,13 @@ static void check_audio_video_inputs(int *has_video_ptr, int *has_audio_ptr)
* has_audio_ptr = has_audio ;
}
static void opt_output_file ( const char * filename )
static void new_video_stream ( AVFormatContext * oc )
{
AVStream * st ;
AVFormatContext * oc ;
int use_video , use_audio , nb_streams , input_has_video , input_has_audio ;
int codec_id ;
AVFormatParameters params , * ap = & params ;
if ( ! strcmp ( filename , " - " ) )
filename = " pipe: " ;
oc = av_alloc_format_context ( ) ;
if ( ! file_oformat ) {
file_oformat = guess_format ( NULL , filename , NULL ) ;
if ( ! file_oformat ) {
fprintf ( stderr , " Unable for find a suitable output format for '%s' \n " ,
filename ) ;
exit ( 1 ) ;
}
}
oc - > oformat = file_oformat ;
if ( ! strcmp ( file_oformat - > name , " ffm " ) & &
strstart ( filename , " http: " , NULL ) ) {
/* special case for files sent to ffserver: we get the stream
parameters from ffserver */
if ( read_ffserver_streams ( oc , filename ) < 0 ) {
fprintf ( stderr , " Could not read stream parameters from '%s' \n " , filename ) ;
exit ( 1 ) ;
}
} else {
use_video = file_oformat - > video_codec ! = CODEC_ID_NONE | | video_stream_copy ;
use_audio = file_oformat - > audio_codec ! = CODEC_ID_NONE | | audio_stream_copy ;
/* disable if no corresponding type found and at least one
input file */
if ( nb_input_files > 0 ) {
check_audio_video_inputs ( & input_has_video , & input_has_audio ) ;
if ( ! input_has_video )
use_video = 0 ;
if ( ! input_has_audio )
use_audio = 0 ;
}
/* manual disable */
if ( audio_disable ) {
use_audio = 0 ;
}
if ( video_disable ) {
use_video = 0 ;
}
nb_streams = 0 ;
if ( use_video ) {
AVCodecContext * video_enc ;
int codec_id ;
st = av_new_stream ( oc , nb_streams + + ) ;
st = av_new_stream ( oc , oc - > nb_streams ) ;
if ( ! st ) {
fprintf ( stderr , " Could not alloc stream \n " ) ;
exit ( 1 ) ;
@ -3141,7 +3181,7 @@ static void opt_output_file(const char *filename)
if ( video_codec_tag )
video_enc - > codec_tag = video_codec_tag ;
if ( file_ oformat- > flags & AVFMT_GLOBALHEADER )
if ( oc - > oformat - > flags & AVFMT_GLOBALHEADER )
video_enc - > flags | = CODEC_FLAG_GLOBAL_HEADER ;
if ( video_stream_copy ) {
st - > stream_copy = 1 ;
@ -3151,7 +3191,7 @@ static void opt_output_file(const char *filename)
int i ;
AVCodec * codec ;
codec_id = av_guess_codec ( file_ oformat, NULL , filename , NULL , CODEC_TYPE_VIDEO ) ;
codec_id = av_guess_codec ( oc - > oformat , NULL , oc - > filename , NULL , CODEC_TYPE_VIDEO ) ;
if ( video_codec_id ! = CODEC_ID_NONE )
codec_id = video_codec_id ;
@ -3395,12 +3435,20 @@ static void opt_output_file(const char *filename)
}
}
}
}
if ( use_audio ) {
/* reset some key parameters */
video_disable = 0 ;
video_codec_id = CODEC_ID_NONE ;
video_stream_copy = 0 ;
}
static void new_audio_stream ( AVFormatContext * oc )
{
AVStream * st ;
AVCodecContext * audio_enc ;
int codec_id ;
st = av_new_stream ( oc , nb_streams + + ) ;
st = av_new_stream ( oc , oc - > nb_streams ) ;
if ( ! st ) {
fprintf ( stderr , " Could not alloc stream \n " ) ;
exit ( 1 ) ;
@ -3416,13 +3464,13 @@ static void opt_output_file(const char *filename)
if ( audio_codec_tag )
audio_enc - > codec_tag = audio_codec_tag ;
if ( file_ oformat- > flags & AVFMT_GLOBALHEADER )
if ( oc - > oformat - > flags & AVFMT_GLOBALHEADER )
audio_enc - > flags | = CODEC_FLAG_GLOBAL_HEADER ;
if ( audio_stream_copy ) {
st - > stream_copy = 1 ;
audio_enc - > channels = audio_channels ;
} else {
codec_id = av_guess_codec ( file_ oformat, NULL , filename , NULL , CODEC_TYPE_AUDIO ) ;
codec_id = av_guess_codec ( oc - > oformat , NULL , oc - > filename , NULL , CODEC_TYPE_AUDIO ) ;
if ( audio_codec_id ! = CODEC_ID_NONE )
codec_id = audio_codec_id ;
audio_enc - > codec_id = codec_id ;
@ -3439,11 +3487,138 @@ static void opt_output_file(const char *filename)
audio_enc - > channels = audio_channels ;
}
audio_enc - > sample_rate = audio_sample_rate ;
if ( audio_language ) {
pstrcpy ( st - > language , sizeof ( st - > language ) , audio_language ) ;
av_free ( audio_language ) ;
audio_language = NULL ;
}
/* reset some key parameters */
audio_disable = 0 ;
audio_codec_id = CODEC_ID_NONE ;
audio_stream_copy = 0 ;
}
static void opt_new_subtitle_stream ( void )
{
AVFormatContext * oc ;
AVStream * st ;
AVCodecContext * subtitle_enc ;
if ( nb_output_files < = 0 ) {
fprintf ( stderr , " At least one output file must be specified \n " ) ;
exit ( 1 ) ;
}
oc = output_files [ nb_output_files - 1 ] ;
st = av_new_stream ( oc , oc - > nb_streams ) ;
if ( ! st ) {
fprintf ( stderr , " Could not alloc stream \n " ) ;
exit ( 1 ) ;
}
subtitle_enc = & st - > codec ;
subtitle_enc - > codec_type = CODEC_TYPE_SUBTITLE ;
if ( subtitle_stream_copy ) {
st - > stream_copy = 1 ;
} else {
subtitle_enc - > codec_id = subtitle_codec_id ;
}
if ( subtitle_language ) {
pstrcpy ( st - > language , sizeof ( st - > language ) , subtitle_language ) ;
av_free ( subtitle_language ) ;
subtitle_language = NULL ;
}
subtitle_codec_id = CODEC_ID_NONE ;
subtitle_stream_copy = 0 ;
}
static void opt_new_audio_stream ( void )
{
AVFormatContext * oc ;
if ( nb_output_files < = 0 ) {
fprintf ( stderr , " At least one output file must be specified \n " ) ;
exit ( 1 ) ;
}
oc = output_files [ nb_output_files - 1 ] ;
new_audio_stream ( oc ) ;
}
static void opt_new_video_stream ( void )
{
AVFormatContext * oc ;
if ( nb_output_files < = 0 ) {
fprintf ( stderr , " At least one output file must be specified \n " ) ;
exit ( 1 ) ;
}
oc = output_files [ nb_output_files - 1 ] ;
new_video_stream ( oc ) ;
}
static void opt_output_file ( const char * filename )
{
AVFormatContext * oc ;
int use_video , use_audio , input_has_video , input_has_audio ;
AVFormatParameters params , * ap = & params ;
if ( ! strcmp ( filename , " - " ) )
filename = " pipe: " ;
oc = av_alloc_format_context ( ) ;
if ( ! file_oformat ) {
file_oformat = guess_format ( NULL , filename , NULL ) ;
if ( ! file_oformat ) {
fprintf ( stderr , " Unable for find a suitable output format for '%s' \n " ,
filename ) ;
exit ( 1 ) ;
}
}
oc - > oformat = file_oformat ;
pstrcpy ( oc - > filename , sizeof ( oc - > filename ) , filename ) ;
if ( ! strcmp ( file_oformat - > name , " ffm " ) & &
strstart ( filename , " http: " , NULL ) ) {
/* special case for files sent to ffserver: we get the stream
parameters from ffserver */
if ( read_ffserver_streams ( oc , filename ) < 0 ) {
fprintf ( stderr , " Could not read stream parameters from '%s' \n " , filename ) ;
exit ( 1 ) ;
}
} else {
use_video = file_oformat - > video_codec ! = CODEC_ID_NONE | | video_stream_copy ;
use_audio = file_oformat - > audio_codec ! = CODEC_ID_NONE | | audio_stream_copy ;
/* disable if no corresponding type found and at least one
input file */
if ( nb_input_files > 0 ) {
check_audio_video_inputs ( & input_has_video , & input_has_audio ) ;
if ( ! input_has_video )
use_video = 0 ;
if ( ! input_has_audio )
use_audio = 0 ;
}
oc - > nb_streams = nb_streams ;
/* manual disable */
if ( audio_disable ) {
use_audio = 0 ;
}
if ( video_disable ) {
use_video = 0 ;
}
if ( ! nb_streams ) {
if ( use_video ) {
new_video_stream ( oc ) ;
}
if ( use_audio ) {
new_audio_stream ( oc ) ;
}
if ( ! oc - > nb_streams ) {
fprintf ( stderr , " No audio or video streams available \n " ) ;
exit ( 1 ) ;
}
@ -3462,8 +3637,6 @@ static void opt_output_file(const char *filename)
output_files [ nb_output_files + + ] = oc ;
pstrcpy ( oc - > filename , sizeof ( oc - > filename ) , filename ) ;
/* check filename in case of an image number is expected */
if ( oc - > oformat - > flags & AVFMT_NEEDNUMBER ) {
if ( filename_number_test ( oc - > filename ) < 0 ) {
@ -3520,12 +3693,6 @@ static void opt_output_file(const char *filename)
file_oformat = NULL ;
file_iformat = NULL ;
image_format = NULL ;
audio_disable = 0 ;
video_disable = 0 ;
audio_codec_id = CODEC_ID_NONE ;
video_codec_id = CODEC_ID_NONE ;
audio_stream_copy = 0 ;
video_stream_copy = 0 ;
}
/* prepare dummy protocols for grab */
@ -3722,6 +3889,7 @@ static void show_formats(void)
int decode = 0 ;
int encode = 0 ;
int cap = 0 ;
const char * type_str ;
p2 = NULL ;
for ( p = first_avcodec ; p ! = NULL ; p = p - > next ) {
@ -3740,11 +3908,25 @@ static void show_formats(void)
break ;
last_name = p2 - > name ;
switch ( p2 - > type ) {
case CODEC_TYPE_VIDEO :
type_str = " V " ;
break ;
case CODEC_TYPE_AUDIO :
type_str = " A " ;
break ;
case CODEC_TYPE_SUBTITLE :
type_str = " S " ;
break ;
default :
type_str = " ? " ;
break ;
}
printf (
" %s%s%s%s%s%s %s " ,
decode ? " D " : ( /*p2->decoder ? "d":*/ " " ) ,
encode ? " E " : " " ,
p2 - > type = = CODEC_TYPE_AUDIO ? " A " : " V " ,
type_str ,
cap & CODEC_CAP_DRAW_HORIZ_BAND ? " S " : " " ,
cap & CODEC_CAP_DR1 ? " D " : " " ,
cap & CODEC_CAP_TRUNCATED ? " T " : " " ,
@ -4132,7 +4314,8 @@ const OptionDef options[] = {
{ " skip_factor " , OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO , { ( void * ) & frame_skip_factor } , " frame skip factor " , " factor " } ,
{ " skip_exp " , OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO , { ( void * ) & frame_skip_exp } , " frame skip exponent " , " exponent " } ,
{ " skip_cmp " , OPT_INT | HAS_ARG | OPT_EXPERT | OPT_VIDEO , { ( void * ) & frame_skip_cmp } , " frame skip compare function " , " compare function " } ,
{ " gray " , OPT_BOOL | OPT_EXPERT | OPT_VIDEO , { & gray_only } , " encode/decode grayscale " } ,
{ " gray " , OPT_BOOL | OPT_EXPERT | OPT_VIDEO , { ( void * ) & gray_only } , " encode/decode grayscale " } ,
{ " newvideo " , OPT_VIDEO , { ( void * ) opt_new_video_stream } , " add a new video stream to the current output stream " } ,
/* audio options */
{ " ab " , HAS_ARG | OPT_AUDIO , { ( void * ) opt_audio_bitrate } , " set audio bitrate (in kbit/s) " , " bitrate " , } ,
@ -4142,6 +4325,13 @@ const OptionDef options[] = {
{ " acodec " , HAS_ARG | OPT_AUDIO , { ( void * ) opt_audio_codec } , " force audio codec ('copy' to copy stream) " , " codec " } ,
{ " atag " , HAS_ARG | OPT_EXPERT | OPT_AUDIO , { ( void * ) opt_audio_tag } , " force audio tag/fourcc " , " fourcc/tag " } ,
{ " vol " , OPT_INT | HAS_ARG | OPT_AUDIO , { ( void * ) & audio_volume } , " change audio volume (256=normal) " , " volume " } , //
{ " newaudio " , OPT_AUDIO , { ( void * ) opt_new_audio_stream } , " add a new audio stream to the current output stream " } ,
{ " alang " , HAS_ARG | OPT_STRING | OPT_AUDIO , { ( void * ) & audio_language } , " set the ISO 639 language code (3 letters) of the current audio stream " , " code " } ,
/* subtitle options */
{ " scodec " , HAS_ARG | OPT_SUBTITLE , { ( void * ) opt_subtitle_codec } , " force subtitle codec ('copy' to copy stream) " , " codec " } ,
{ " newsubtitle " , OPT_SUBTITLE , { ( void * ) opt_new_subtitle_stream } , " add a new subtitle stream to the current output stream " } ,
{ " slang " , HAS_ARG | OPT_STRING | OPT_SUBTITLE , { ( void * ) & subtitle_language } , " set the ISO 639 language code (3 letters) of the current subtitle stream " , " code " } ,
/* grab options */
{ " vd " , HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB , { ( void * ) opt_video_device } , " set video grab device " , " device " } ,
@ -4233,6 +4423,9 @@ static void show_help(void)
show_help_options ( options , " \n Advanced Audio options: \n " ,
OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_GRAB ,
OPT_AUDIO | OPT_EXPERT ) ;
show_help_options ( options , " \n Subtitle options: \n " ,
OPT_SUBTITLE | OPT_GRAB ,
OPT_SUBTITLE ) ;
show_help_options ( options , " \n Audio/Video grab options: \n " ,
OPT_GRAB ,
OPT_GRAB ) ;