void vlc_audio_replay_gain_MergeFromMeta( audio_replay_gain_t *p_dst, const vlc_meta_t *p_meta ) { const char * psz_value; if( !p_meta ) return; if( (psz_value = vlc_meta_GetExtra(p_meta, "REPLAYGAIN_TRACK_GAIN")) || (psz_value = vlc_meta_GetExtra(p_meta, "RG_RADIO")) ) { p_dst->pb_gain[AUDIO_REPLAY_GAIN_TRACK] = true; p_dst->pf_gain[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_value ); } if( (psz_value = vlc_meta_GetExtra(p_meta, "REPLAYGAIN_TRACK_PEAK" )) || (psz_value = vlc_meta_GetExtra(p_meta, "RG_PEAK" )) ) { p_dst->pb_peak[AUDIO_REPLAY_GAIN_TRACK] = true; p_dst->pf_peak[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_value ); } if( (psz_value = vlc_meta_GetExtra(p_meta, "REPLAYGAIN_ALBUM_GAIN" )) || (psz_value = vlc_meta_GetExtra(p_meta, "RG_AUDIOPHILE" )) ) { p_dst->pb_gain[AUDIO_REPLAY_GAIN_ALBUM] = true; p_dst->pf_gain[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_value ); } if( (psz_value = vlc_meta_GetExtra(p_meta, "REPLAYGAIN_ALBUM_PEAK" )) ) { p_dst->pb_peak[AUDIO_REPLAY_GAIN_ALBUM] = true; p_dst->pf_peak[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_value ); } }
/********************************************************************** * Execute a var command on an object identified by its name **********************************************************************/ int var_Command( vlc_object_t *p_this, const char *psz_name, const char *psz_cmd, const char *psz_arg, char **psz_msg ) { vlc_object_t *p_obj = vlc_object_find_name( p_this->p_libvlc, psz_name ); int i_type, i_ret; if( !p_obj ) { if( psz_msg ) *psz_msg = strdup( "Unknown destination object." ); return VLC_ENOOBJ; } i_type = var_Type( p_obj, psz_cmd ); if( !( i_type&VLC_VAR_ISCOMMAND ) ) { vlc_object_release( p_obj ); if( psz_msg ) *psz_msg = strdup( "Variable doesn't exist or isn't a command." ); return VLC_EGENERIC; } i_type &= VLC_VAR_CLASS; switch( i_type ) { case VLC_VAR_INTEGER: i_ret = var_SetInteger( p_obj, psz_cmd, atoi( psz_arg ) ); break; case VLC_VAR_FLOAT: i_ret = var_SetFloat( p_obj, psz_cmd, us_atof( psz_arg ) ); break; case VLC_VAR_STRING: i_ret = var_SetString( p_obj, psz_cmd, psz_arg ); break; case VLC_VAR_BOOL: i_ret = var_SetBool( p_obj, psz_cmd, atoi( psz_arg ) ); break; default: i_ret = VLC_EGENERIC; break; } vlc_object_release( p_obj ); if( psz_msg ) { if( asprintf( psz_msg, "%s on object %s returned %i (%s)", psz_cmd, psz_name, i_ret, vlc_error( i_ret ) ) == -1) *psz_msg = NULL; } return i_ret; }
/** * It inherits a string as an unsigned rational number (it also accepts basic * float number). * * It returns an error if the rational number cannot be parsed (0/0 is valid). * The rational is already reduced. */ int (var_InheritURational)(vlc_object_t *object, unsigned *num, unsigned *den, const char *var) { /* */ *num = 0; *den = 0; /* */ char *tmp = var_InheritString(object, var); if (!tmp) goto error; char *next; unsigned n = strtol(tmp, &next, 0); unsigned d = strtol(*next ? &next[1] : "0", NULL, 0); if (*next == '.') { /* Interpret as a float number */ double r = us_atof(tmp); double c = ceil(r); if (c >= UINT_MAX) goto error; unsigned m = c; if (m > 0) { d = UINT_MAX / m; n = r * d; } else { n = 0; d = 0; } } else if ( *next == '\0' ) { /* plain integer given */ *num = n; *den = 1; } if (n > 0 && d > 0) vlc_ureduce(num, den, n, d, 0); free(tmp); return VLC_SUCCESS; error: free(tmp); return VLC_EGENERIC; }
/***************************************************************************** * OpenDemux: initialize the target, ie. parse the command *****************************************************************************/ int OpenDemux ( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; char * psz_name = p_demux->psz_path; p_demux->pf_control = DemuxControl; p_demux->p_sys = NULL; /* Check for a "vlc://nop" command */ if( !strcasecmp( psz_name, "nop" ) ) { msg_Info( p_demux, "command `nop'" ); p_demux->pf_demux = DemuxNoOp; return VLC_SUCCESS; } /* Check for a "vlc://quit" command */ if( !strcasecmp( psz_name, "quit" ) ) { msg_Info( p_demux, "command `quit'" ); p_demux->pf_demux = DemuxNoOp; libvlc_Quit( p_demux->p_libvlc ); return VLC_SUCCESS; } /* Check for a "vlc://pause:***" command */ if( !strncasecmp( psz_name, "pause:", 6 ) ) { double f = us_atof( psz_name + 6 ); mtime_t end = mdate() + f * (mtime_t)1000000; msg_Info( p_demux, "command `pause %f'", f ); p_demux->pf_demux = DemuxPause; p_demux->p_sys = malloc( sizeof( end ) ); if( p_demux->p_sys == NULL ) return VLC_ENOMEM; memcpy( p_demux->p_sys, &end, sizeof( end ) ); return VLC_SUCCESS; } msg_Err( p_demux, "unknown command `%s'", psz_name ); return VLC_EGENERIC; }
/***************************************************************************** * Open: probe the encoder *****************************************************************************/ static int Open ( vlc_object_t *p_this ) { encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys; int i_val; char *psz_val; int i_qmin = 0, i_qmax = 0; x264_nal_t *nal; int i, i_nal; if( p_enc->fmt_out.i_codec != VLC_CODEC_H264 && !p_enc->b_force ) { return VLC_EGENERIC; } /* X264_POINTVER or X264_VERSION are not available */ msg_Dbg ( p_enc, "version x264 0.%d.X", X264_BUILD ); config_ChainParse( p_enc, SOUT_CFG_PREFIX, ppsz_sout_options, p_enc->p_cfg ); p_enc->fmt_out.i_cat = VIDEO_ES; p_enc->fmt_out.i_codec = VLC_CODEC_H264; p_enc->fmt_in.i_codec = VLC_CODEC_I420; p_enc->pf_encode_video = Encode; p_enc->pf_encode_audio = NULL; p_enc->p_sys = p_sys = malloc( sizeof( encoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->i_interpolated_dts = 0; p_sys->psz_stat_name = NULL; p_sys->p_buffer = NULL; x264_param_default( &p_sys->param ); p_sys->param.i_width = p_enc->fmt_in.video.i_width; p_sys->param.i_height = p_enc->fmt_in.video.i_height; p_sys->param.rc.f_qcompress = var_GetFloat( p_enc, SOUT_CFG_PREFIX "qcomp" ); /* transcode-default bitrate is 0, * set more to ABR if user specifies bitrate */ if( p_enc->fmt_out.i_bitrate > 0 ) { p_sys->param.rc.i_bitrate = p_enc->fmt_out.i_bitrate / 1000; p_sys->param.rc.i_rc_method = X264_RC_ABR; } else /* Set default to CRF */ { i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "crf" ); if( i_val > 0 && i_val <= 51 ) { p_sys->param.rc.f_rf_constant = i_val; p_sys->param.rc.i_rc_method = X264_RC_CRF; } } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpstep" ); if( i_val >= 0 && i_val <= 51 ) p_sys->param.rc.i_qp_step = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpmin" ); if( i_val >= 0 && i_val <= 51 ) { i_qmin = i_val; p_sys->param.rc.i_qp_min = i_qmin; } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qpmax" ); if( i_val >= 0 && i_val <= 51 ) { i_qmax = i_val; p_sys->param.rc.i_qp_max = i_qmax; } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "qp" ); if( i_val >= 0 && i_val <= 51 ) { if( i_qmin > i_val ) i_qmin = i_val; if( i_qmax < i_val ) i_qmax = i_val; /* User defined QP-value, so change ratecontrol method */ p_sys->param.rc.i_rc_method = X264_RC_CQP; p_sys->param.rc.i_qp_constant = i_val; p_sys->param.rc.i_qp_min = i_qmin; p_sys->param.rc.i_qp_max = i_qmax; } p_sys->param.rc.f_rate_tolerance = var_GetFloat( p_enc, SOUT_CFG_PREFIX "ratetol" ); p_sys->param.rc.f_vbv_buffer_init = var_GetFloat( p_enc, SOUT_CFG_PREFIX "vbv-init" ); p_sys->param.rc.i_vbv_buffer_size = var_GetInteger( p_enc, SOUT_CFG_PREFIX "vbv-bufsize" ); /* max bitrate = average bitrate -> CBR */ i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "vbv-maxrate" ); if( !i_val && p_sys->param.rc.i_rc_method == X264_RC_ABR ) p_sys->param.rc.i_vbv_max_bitrate = p_sys->param.rc.i_bitrate; else if ( i_val ) p_sys->param.rc.i_vbv_max_bitrate = i_val; p_sys->param.b_cabac = var_GetBool( p_enc, SOUT_CFG_PREFIX "cabac" ); /* disable deblocking when nf (no loop filter) is enabled */ p_sys->param.b_deblocking_filter = !var_GetBool( p_enc, SOUT_CFG_PREFIX "nf" ); psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "deblock" ); if( psz_val ) { char *p = strchr( psz_val, ':' ); p_sys->param.i_deblocking_filter_alphac0 = atoi( psz_val ); p_sys->param.i_deblocking_filter_beta = p ? atoi( p+1 ) : p_sys->param.i_deblocking_filter_alphac0; free( psz_val ); } psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "psy-rd" ); if( psz_val ) { char *p = strchr( psz_val, ':' ); p_sys->param.analyse.f_psy_rd = us_atof( psz_val ); p_sys->param.analyse.f_psy_trellis = p ? us_atof( p+1 ) : 0; free( psz_val ); } psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "level" ); if( psz_val ) { if( us_atof (psz_val) < 6 ) p_sys->param.i_level_idc = (int) (10 * us_atof (psz_val) + .5); else p_sys->param.i_level_idc = atoi (psz_val); free( psz_val ); } p_sys->param.b_interlaced = var_GetBool( p_enc, SOUT_CFG_PREFIX "interlaced" ); p_sys->param.rc.f_ip_factor = var_GetFloat( p_enc, SOUT_CFG_PREFIX "ipratio" ); p_sys->param.rc.f_pb_factor = var_GetFloat( p_enc, SOUT_CFG_PREFIX "pbratio" ); p_sys->param.rc.f_complexity_blur = var_GetFloat( p_enc, SOUT_CFG_PREFIX "cplxblur" ); p_sys->param.rc.f_qblur = var_GetFloat( p_enc, SOUT_CFG_PREFIX "qblur" ); p_sys->param.rc.i_aq_mode = var_GetInteger( p_enc, SOUT_CFG_PREFIX "aq-mode" ); p_sys->param.rc.f_aq_strength = var_GetFloat( p_enc, SOUT_CFG_PREFIX "aq-strength" ); if( var_GetBool( p_enc, SOUT_CFG_PREFIX "verbose" ) ) p_sys->param.i_log_level = X264_LOG_DEBUG; if( var_GetBool( p_enc, SOUT_CFG_PREFIX "quiet" ) ) p_sys->param.i_log_level = X264_LOG_NONE; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "sps-id" ); if( i_val >= 0 ) p_sys->param.i_sps_id = i_val; if( var_GetBool( p_enc, SOUT_CFG_PREFIX "aud" ) ) p_sys->param.b_aud = true; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "keyint" ); if( i_val > 0 ) p_sys->param.i_keyint_max = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "min-keyint" ); if( i_val > 0 ) p_sys->param.i_keyint_min = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "bframes" ); if( i_val >= 0 && i_val <= 16 ) p_sys->param.i_bframe = i_val; #if X264_BUILD >= 78 psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "bpyramid" ); p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; if( !strcmp( psz_val, "none" ) ) { p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_NONE; } else if ( !strcmp( psz_val, "strict" ) ) { p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_STRICT; } else if ( !strcmp( psz_val, "normal" ) ) { p_sys->param.i_bframe_pyramid = X264_B_PYRAMID_NORMAL; } free( psz_val ); #else p_sys->param.b_bframe_pyramid = var_GetBool( p_enc, SOUT_CFG_PREFIX "bpyramid" ); #endif i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "ref" ); if( i_val > 0 && i_val <= 15 ) p_sys->param.i_frame_reference = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "scenecut" ); if( i_val >= -1 && i_val <= 100 ) p_sys->param.i_scenecut_threshold = i_val; p_sys->param.b_deterministic = var_GetBool( p_enc, SOUT_CFG_PREFIX "non-deterministic" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "subme" ); if( i_val >= 1 && i_val <= SUBME_MAX ) p_sys->param.analyse.i_subpel_refine = i_val; //TODO: psz_val == NULL ? psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "me" ); if( !strcmp( psz_val, "dia" ) ) { p_sys->param.analyse.i_me_method = X264_ME_DIA; } else if( !strcmp( psz_val, "hex" ) ) { p_sys->param.analyse.i_me_method = X264_ME_HEX; } else if( !strcmp( psz_val, "umh" ) ) { p_sys->param.analyse.i_me_method = X264_ME_UMH; } else if( !strcmp( psz_val, "esa" ) ) { p_sys->param.analyse.i_me_method = X264_ME_ESA; } else if( !strcmp( psz_val, "tesa" ) ) { p_sys->param.analyse.i_me_method = X264_ME_TESA; } free( psz_val ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "merange" ); if( i_val >= 0 && i_val <= 64 ) p_sys->param.analyse.i_me_range = i_val; p_sys->param.analyse.i_mv_range = var_GetInteger( p_enc, SOUT_CFG_PREFIX "mvrange" ); p_sys->param.analyse.i_mv_range_thread = var_GetInteger( p_enc, SOUT_CFG_PREFIX "mvrange-thread" ); psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "direct" ); if( !strcmp( psz_val, "none" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_NONE; } else if( !strcmp( psz_val, "spatial" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; } else if( !strcmp( psz_val, "temporal" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; } else if( !strcmp( psz_val, "auto" ) ) { p_sys->param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; } free( psz_val ); p_sys->param.analyse.b_psnr = var_GetBool( p_enc, SOUT_CFG_PREFIX "psnr" ); p_sys->param.analyse.b_ssim = var_GetBool( p_enc, SOUT_CFG_PREFIX "ssim" ); p_sys->param.analyse.b_weighted_bipred = var_GetBool( p_enc, SOUT_CFG_PREFIX "weightb" ); p_sys->param.i_bframe_adaptive = var_GetInteger( p_enc, SOUT_CFG_PREFIX "b-adapt" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "b-bias" ); if( i_val >= -100 && i_val <= 100 ) p_sys->param.i_bframe_bias = i_val; p_sys->param.analyse.b_chroma_me = var_GetBool( p_enc, SOUT_CFG_PREFIX "chroma-me" ); p_sys->param.analyse.i_chroma_qp_offset = var_GetInteger( p_enc, SOUT_CFG_PREFIX "chroma-qp-offset" ); p_sys->param.analyse.b_mixed_references = var_GetBool( p_enc, SOUT_CFG_PREFIX "mixed-refs" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "trellis" ); if( i_val >= 0 && i_val <= 2 ) p_sys->param.analyse.i_trellis = i_val; p_sys->param.analyse.b_fast_pskip = var_GetBool( p_enc, SOUT_CFG_PREFIX "fast-pskip" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "nr" ); if( i_val >= 0 && i_val <= 1000 ) p_sys->param.analyse.i_noise_reduction = i_val; p_sys->param.analyse.b_dct_decimate = var_GetBool( p_enc, SOUT_CFG_PREFIX "dct-decimate" ); i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "deadzone-inter" ); if( i_val >= 0 && i_val <= 32 ) p_sys->param.analyse.i_luma_deadzone[0] = i_val; i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "deadzone-intra" ); if( i_val >= 0 && i_val <= 32 ) p_sys->param.analyse.i_luma_deadzone[1] = i_val; if( !var_GetBool( p_enc, SOUT_CFG_PREFIX "asm" ) ) p_sys->param.cpu = 0; #ifndef X264_ANALYSE_BSUB16x16 # define X264_ANALYSE_BSUB16x16 0 #endif psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "partitions" ); if( !strcmp( psz_val, "none" ) ) { p_sys->param.analyse.inter = 0; } else if( !strcmp( psz_val, "fast" ) ) { p_sys->param.analyse.inter = X264_ANALYSE_I4x4; } else if( !strcmp( psz_val, "normal" ) ) { p_sys->param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16; #ifdef X264_ANALYSE_I8x8 p_sys->param.analyse.inter |= X264_ANALYSE_I8x8; #endif } else if( !strcmp( psz_val, "slow" ) ) { p_sys->param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16; #ifdef X264_ANALYSE_I8x8 p_sys->param.analyse.inter |= X264_ANALYSE_I8x8; #endif } else if( !strcmp( psz_val, "all" ) ) { p_sys->param.analyse.inter = ~0; } free( psz_val ); p_sys->param.analyse.b_transform_8x8 = var_GetBool( p_enc, SOUT_CFG_PREFIX "8x8dct" ); if( p_enc->fmt_in.video.i_aspect > 0 ) { int64_t i_num, i_den; unsigned int i_dst_num, i_dst_den; i_num = p_enc->fmt_in.video.i_aspect * (int64_t)p_enc->fmt_in.video.i_height; i_den = VOUT_ASPECT_FACTOR * p_enc->fmt_in.video.i_width; vlc_ureduce( &i_dst_num, &i_dst_den, i_num, i_den, 0 ); p_sys->param.vui.i_sar_width = i_dst_num; p_sys->param.vui.i_sar_height = i_dst_den; } if( p_enc->fmt_in.video.i_frame_rate_base > 0 ) { p_sys->param.i_fps_num = p_enc->fmt_in.video.i_frame_rate; p_sys->param.i_fps_den = p_enc->fmt_in.video.i_frame_rate_base; } /* x264 vbv-bufsize = 0 (default). if not provided set period in seconds for local maximum bitrate (cache/bufsize) based on average bitrate when use has told bitrate. vbv-buffer size is set to bitrate * secods between keyframes */ if( !p_sys->param.rc.i_vbv_buffer_size && p_sys->param.rc.i_rc_method == X264_RC_ABR && p_sys->param.i_fps_num ) { p_sys->param.rc.i_vbv_buffer_size = p_sys->param.rc.i_bitrate * p_sys->param.i_fps_den; p_sys->param.rc.i_vbv_buffer_size *= p_sys->param.i_keyint_max; p_sys->param.rc.i_vbv_buffer_size /= p_sys->param.i_fps_num; } /* Check if user has given some profile (baseline,main,high) to limit * settings, and apply those*/ psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "profile" ); if( psz_val ) { if( !strcasecmp( psz_val, "baseline" ) ) { msg_Dbg( p_enc, "Limiting to baseline profile"); p_sys->param.analyse.b_transform_8x8 = 0; p_sys->param.b_cabac = 0; p_sys->param.i_bframe = 0; } else if (!strcasecmp( psz_val, "main" ) ) { msg_Dbg( p_enc, "Limiting to main-profile"); p_sys->param.analyse.b_transform_8x8 = 0; } /* high profile don't restrict stuff*/ } free( psz_val ); unsigned i_cpu = vlc_CPU(); if( !(i_cpu & CPU_CAPABILITY_MMX) ) { p_sys->param.cpu &= ~X264_CPU_MMX; } if( !(i_cpu & CPU_CAPABILITY_MMXEXT) ) { p_sys->param.cpu &= ~X264_CPU_MMXEXT; } if( !(i_cpu & CPU_CAPABILITY_SSE) ) { p_sys->param.cpu &= ~X264_CPU_SSE; } if( !(i_cpu & CPU_CAPABILITY_SSE2) ) { p_sys->param.cpu &= ~X264_CPU_SSE2; } /* BUILD 29 adds support for multi-threaded encoding while BUILD 49 (r543) also adds support for threads = 0 for automatically selecting an optimal value (cores * 1.5) based on detected CPUs. Default behavior for x264 is threads = 1, however VLC usage differs and uses threads = 0 (auto) by default unless ofcourse transcode threads is explicitly specified.. */ p_sys->param.i_threads = p_enc->i_threads; psz_val = var_GetString( p_enc, SOUT_CFG_PREFIX "stats" ); if( psz_val ) { p_sys->param.rc.psz_stat_in = p_sys->param.rc.psz_stat_out = p_sys->psz_stat_name = psz_val; } i_val = var_GetInteger( p_enc, SOUT_CFG_PREFIX "pass" ); if( i_val > 0 && i_val <= 3 ) { p_sys->param.rc.b_stat_write = i_val & 1; p_sys->param.rc.b_stat_read = i_val & 2; } /* We need to initialize pthreadw32 before we open the encoder, but only once for the whole application. Since pthreadw32 doesn't keep a refcount, do it ourselves. */ #ifdef PTW32_STATIC_LIB vlc_value_t lock, count; var_Create( p_enc->p_libvlc, "pthread_win32_mutex", VLC_VAR_MUTEX ); var_Get( p_enc->p_libvlc, "pthread_win32_mutex", &lock ); vlc_mutex_lock( lock.p_address ); var_Create( p_enc->p_libvlc, "pthread_win32_count", VLC_VAR_INTEGER ); var_Get( p_enc->p_libvlc, "pthread_win32_count", &count ); if( count.i_int == 0 ) { msg_Dbg( p_enc, "initializing pthread-win32" ); if( !pthread_win32_process_attach_np() || !pthread_win32_thread_attach_np() ) { msg_Warn( p_enc, "pthread Win32 Initialization failed" ); vlc_mutex_unlock( lock.p_address ); return VLC_EGENERIC; } } count.i_int++; var_Set( p_enc->p_libvlc, "pthread_win32_count", count ); vlc_mutex_unlock( lock.p_address ); #endif /* Set lookahead value to lower than default, * as rtp-output without mux doesn't handle * difference that well yet*/ p_sys->param.rc.i_lookahead=5; /* Open the encoder */ p_sys->h = x264_encoder_open( &p_sys->param ); if( p_sys->h == NULL ) { msg_Err( p_enc, "cannot open x264 encoder" ); Close( VLC_OBJECT(p_enc) ); return VLC_EGENERIC; } /* alloc mem */ p_sys->i_buffer = 4 * p_enc->fmt_in.video.i_width * p_enc->fmt_in.video.i_height + 1000; p_sys->p_buffer = malloc( p_sys->i_buffer ); if( !p_sys->p_buffer ) { Close( VLC_OBJECT(p_enc) ); return VLC_ENOMEM; } /* get the globals headers */ p_enc->fmt_out.i_extra = 0; p_enc->fmt_out.p_extra = NULL; p_enc->fmt_out.i_extra = x264_encoder_headers( p_sys->h, &nal, &i_nal ); p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra ); if( !p_enc->fmt_out.p_extra ) { Close( VLC_OBJECT(p_enc) ); return VLC_ENOMEM; } void *p_tmp = p_enc->fmt_out.p_extra; for( i = 0; i < i_nal; i++ ) { memcpy( p_tmp, nal[i].p_payload, nal[i].i_payload ); p_tmp += nal[i].i_payload; } return VLC_SUCCESS; }
/** * Parse command line for configuration options. * * Now that the module_bank has been initialized, we can dynamically * generate the longopts structure used by getops. We have to do it this way * because we don't know (and don't want to know) in advance the configuration * options used (ie. exported) by each module. * * @param p_this object to write command line options as variables to * @param i_argc number of command line arguments * @param ppsz_args commandl ine arguments [IN/OUT] * @param pindex NULL to ignore unknown options, * otherwise index of the first non-option argument [OUT] * @return 0 on success, -1 on error. */ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, const char *ppsz_argv[], int *pindex ) { int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0; module_t *p_parser; struct vlc_option *p_longopts; const char **argv_copy = NULL; #define b_ignore_errors (pindex == NULL) /* Short options */ module_config_t *pp_shortopts[256]; char *psz_shortopts; /* List all modules */ module_t **list = module_list_get (NULL); /* * Generate the longopts and shortopts structures used by getopt_long */ i_opts = 0; for (size_t i = 0; (p_parser = list[i]) != NULL; i++) /* count the number of exported configuration options (to allocate * longopts). We also need to allocate space for two options when * dealing with boolean to allow for --foo and --no-foo */ i_opts += p_parser->i_config_items + 2 * p_parser->i_bool_items; p_longopts = malloc( sizeof(*p_longopts) * (i_opts + 1) ); if( p_longopts == NULL ) { module_list_free (list); return -1; } psz_shortopts = malloc( 2 * i_opts + 1 ); if( psz_shortopts == NULL ) { free( p_longopts ); module_list_free (list); return -1; } /* If we are requested to ignore errors, then we must work on a copy * of the ppsz_argv array, otherwise getopt_long will reorder it for * us, ignoring the arity of the options */ if( b_ignore_errors ) { argv_copy = (const char**)malloc( i_argc * sizeof(char *) ); if( argv_copy == NULL ) { free( psz_shortopts ); free( p_longopts ); module_list_free (list); return -1; } memcpy( argv_copy, ppsz_argv, i_argc * sizeof(char *) ); ppsz_argv = argv_copy; } i_shortopts = 0; for( i_index = 0; i_index < 256; i_index++ ) { pp_shortopts[i_index] = NULL; } /* Fill the p_longopts and psz_shortopts structures */ i_index = 0; for (size_t i = 0; (p_parser = list[i]) != NULL; i++) { module_config_t *p_item, *p_end; if( !p_parser->i_config_items ) continue; for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize; p_item < p_end; p_item++ ) { /* Ignore hints */ if( p_item->i_type & CONFIG_HINT ) continue; /* Add item to long options */ p_longopts[i_index].name = strdup( p_item->psz_name ); if( p_longopts[i_index].name == NULL ) continue; p_longopts[i_index].has_arg = (p_item->i_type != CONFIG_ITEM_BOOL); p_longopts[i_index].flag = &flag; p_longopts[i_index].val = 0; i_index++; /* When dealing with bools we also need to add the --no-foo * option */ if( p_item->i_type == CONFIG_ITEM_BOOL ) { char *psz_name = malloc( strlen(p_item->psz_name) + 3 ); if( psz_name == NULL ) continue; strcpy( psz_name, "no" ); strcat( psz_name, p_item->psz_name ); p_longopts[i_index].name = psz_name; p_longopts[i_index].has_arg = false; p_longopts[i_index].flag = &flag; p_longopts[i_index].val = 1; i_index++; psz_name = malloc( strlen(p_item->psz_name) + 4 ); if( psz_name == NULL ) continue; strcpy( psz_name, "no-" ); strcat( psz_name, p_item->psz_name ); p_longopts[i_index].name = psz_name; p_longopts[i_index].has_arg = false; p_longopts[i_index].flag = &flag; p_longopts[i_index].val = 1; i_index++; } /* If item also has a short option, add it */ if( p_item->i_short ) { pp_shortopts[(int)p_item->i_short] = p_item; psz_shortopts[i_shortopts] = p_item->i_short; i_shortopts++; if( p_item->i_type != CONFIG_ITEM_BOOL && p_item->i_short != 'v' ) { psz_shortopts[i_shortopts] = ':'; i_shortopts++; } } } } /* We don't need the module list anymore */ module_list_free( list ); /* Close the longopts and shortopts structures */ memset( &p_longopts[i_index], 0, sizeof(*p_longopts) ); psz_shortopts[i_shortopts] = '\0'; int ret = -1; /* * Parse the command line options */ vlc_getopt_t state; state.optind = 0 ; /* set to 0 to tell GNU getopt to reinitialize */ while( ( i_cmd = vlc_getopt_long( i_argc, (char **)ppsz_argv, psz_shortopts, p_longopts, &i_index, &state ) ) != -1 ) { /* A long option has been recognized */ if( i_cmd == 0 ) { module_config_t *p_conf; const char *psz_name = p_longopts[i_index].name; /* Check if we deal with a --nofoo or --no-foo long option */ if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2; /* Store the configuration option */ p_conf = config_FindConfig( p_this, psz_name ); if( p_conf ) { /* Check if the option is deprecated */ if( p_conf->b_removed ) { fprintf(stderr, "Warning: option --%s no longer exists.\n", psz_name); continue; } if( p_conf->psz_oldname && !strcmp( p_conf->psz_oldname, psz_name) ) { if( !b_ignore_errors ) { fprintf( stderr, "Error: option --%s is deprecated. " "Use --%s instead.\n", psz_name, p_conf->psz_name ); goto out; } psz_name = p_conf->psz_name; } switch( p_conf->i_type ) { case CONFIG_ITEM_STRING: case CONFIG_ITEM_PASSWORD: case CONFIG_ITEM_FILE: case CONFIG_ITEM_DIRECTORY: case CONFIG_ITEM_MODULE: case CONFIG_ITEM_MODULE_LIST: case CONFIG_ITEM_MODULE_LIST_CAT: case CONFIG_ITEM_MODULE_CAT: var_Create( p_this, psz_name, VLC_VAR_STRING ); var_SetString( p_this, psz_name, state.optarg ); break; case CONFIG_ITEM_INTEGER: var_Create( p_this, psz_name, VLC_VAR_INTEGER ); var_SetInteger( p_this, psz_name, strtol(state.optarg, NULL, 0)); break; case CONFIG_ITEM_FLOAT: var_Create( p_this, psz_name, VLC_VAR_FLOAT ); var_SetFloat( p_this, psz_name, us_atof(state.optarg) ); break; case CONFIG_ITEM_KEY: var_Create( p_this, psz_name, VLC_VAR_INTEGER ); var_SetInteger( p_this, psz_name, ConfigStringToKey( state.optarg ) ); break; case CONFIG_ITEM_BOOL: var_Create( p_this, psz_name, VLC_VAR_BOOL ); var_SetBool( p_this, psz_name, !flag ); break; } continue; } } /* A short option has been recognized */ if( pp_shortopts[i_cmd] != NULL ) { const char *name = pp_shortopts[i_cmd]->psz_name; switch( pp_shortopts[i_cmd]->i_type ) { case CONFIG_ITEM_STRING: case CONFIG_ITEM_PASSWORD: case CONFIG_ITEM_FILE: case CONFIG_ITEM_DIRECTORY: case CONFIG_ITEM_MODULE: case CONFIG_ITEM_MODULE_CAT: case CONFIG_ITEM_MODULE_LIST: case CONFIG_ITEM_MODULE_LIST_CAT: var_Create( p_this, name, VLC_VAR_STRING ); var_SetString( p_this, name, state.optarg ); break; case CONFIG_ITEM_INTEGER: var_Create( p_this, name, VLC_VAR_INTEGER ); if( i_cmd == 'v' ) { i_verbose++; /* -v */ var_SetInteger( p_this, name, i_verbose ); } else { var_SetInteger( p_this, name, strtol(state.optarg, NULL, 0) ); } break; case CONFIG_ITEM_BOOL: var_Create( p_this, name, VLC_VAR_BOOL ); var_SetBool( p_this, name, true ); break; } continue; } /* Internal error: unknown option */ if( !b_ignore_errors ) { fputs( "vlc: unknown option" " or missing mandatory argument ", stderr ); if( state.optopt ) { fprintf( stderr, "`-%c'\n", state.optopt ); } else { fprintf( stderr, "`%s'\n", ppsz_argv[state.optind-1] ); } fputs( "Try `vlc --help' for more information.\n", stderr ); goto out; } } ret = 0; if( pindex != NULL ) *pindex = state.optind; out: /* Free allocated resources */ for( i_index = 0; p_longopts[i_index].name; i_index++ ) free( (char *)p_longopts[i_index].name ); free( p_longopts ); free( psz_shortopts ); free( argv_copy ); return ret; }
/***************************************************************************** * ParseVorbisComments *****************************************************************************/ static void ParseVorbisComments( decoder_t *p_dec ) { char *psz_name, *psz_value, *psz_comment; int i = 0; while( i < p_dec->p_sys->vc.comments ) { psz_comment = strdup( p_dec->p_sys->vc.user_comments[i] ); if( !psz_comment ) break; psz_name = psz_comment; psz_value = strchr( psz_comment, '=' ); /* Don't add empty values */ if( psz_value && psz_value[1] != '\0') { *psz_value = '\0'; psz_value++; if( !strcasecmp( psz_name, "REPLAYGAIN_TRACK_GAIN" ) || !strcasecmp( psz_name, "RG_RADIO" ) ) { audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain; r->pb_gain[AUDIO_REPLAY_GAIN_TRACK] = true; r->pf_gain[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_value ); } else if( !strcasecmp( psz_name, "REPLAYGAIN_TRACK_PEAK" ) || !strcasecmp( psz_name, "RG_PEAK" ) ) { audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain; r->pb_peak[AUDIO_REPLAY_GAIN_TRACK] = true; r->pf_peak[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_value ); } else if( !strcasecmp( psz_name, "REPLAYGAIN_ALBUM_GAIN" ) || !strcasecmp( psz_name, "RG_AUDIOPHILE" ) ) { audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain; r->pb_gain[AUDIO_REPLAY_GAIN_ALBUM] = true; r->pf_gain[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_value ); } else if( !strcasecmp( psz_name, "REPLAYGAIN_ALBUM_PEAK" ) ) { audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain; r->pb_peak[AUDIO_REPLAY_GAIN_ALBUM] = true; r->pf_peak[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_value ); } else if( !strcasecmp( psz_name, "METADATA_BLOCK_PICTURE" ) ) { /* Do nothing, for now */ } else { if( !p_dec->p_description ) p_dec->p_description = vlc_meta_New(); if( p_dec->p_description ) vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value ); } } free( psz_comment ); i++; } }
/** Parse a stringified option * This function parse a string option and create the associated object * variable * The option must be of the form "[no[-]]foo[=bar]" where foo is the * option name and bar is the value of the option. * \param p_obj the object in which the variable must be created * \param psz_option the option to parse * \param trusted whether the option is set by a trusted input or not * \return nothing */ void var_OptionParse( vlc_object_t *p_obj, const char *psz_option, bool trusted ) { char *psz_name, *psz_value; int i_type; bool b_isno = false; vlc_value_t val; val.psz_string = NULL; /* It's too much of a hassle to remove the ':' when we parse * the cmd line :) */ if( psz_option[0] == ':' ) psz_option++; if( !psz_option[0] ) return; psz_name = strdup( psz_option ); if( psz_name == NULL ) return; psz_value = strchr( psz_name, '=' ); if( psz_value != NULL ) *psz_value++ = '\0'; i_type = config_GetType( p_obj, psz_name ); if( !i_type && !psz_value ) { /* check for "no-foo" or "nofoo" */ if( !strncmp( psz_name, "no-", 3 ) ) { memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 ); } else if( !strncmp( psz_name, "no", 2 ) ) { memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 ); } else goto cleanup; /* Option doesn't exist */ b_isno = true; i_type = config_GetType( p_obj, psz_name ); } if( !i_type ) goto cleanup; /* Option doesn't exist */ if( ( i_type != VLC_VAR_BOOL ) && ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */ /* check if option is unsafe */ if( !trusted && !config_IsSafe( psz_name ) ) { msg_Err( p_obj, "unsafe option \"%s\" has been ignored for " "security reasons", psz_name ); free( psz_name ); return; } /* Create the variable in the input object. * Children of the input object will be able to retrieve this value * thanks to the inheritance property of the object variables. */ var_Create( p_obj, psz_name, i_type ); switch( i_type ) { case VLC_VAR_BOOL: val.b_bool = !b_isno; break; case VLC_VAR_INTEGER: val.i_int = strtoll( psz_value, NULL, 0 ); break; case VLC_VAR_FLOAT: val.f_float = us_atof( psz_value ); break; case VLC_VAR_STRING: val.psz_string = psz_value; break; default: goto cleanup; } var_Set( p_obj, psz_name, val ); cleanup: free( psz_name ); }
/***************************************************************************** * OpenDemux: initialize the target, ie. parse the command *****************************************************************************/ static int OpenDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; char * psz_name = p_demux->psz_location; p_demux->p_sys = NULL; /* Check for a "vlc://nop" command */ if( !strcasecmp( psz_name, "nop" ) ) { nop: msg_Info( p_demux, "command `nop'" ); p_demux->pf_demux = DemuxNoOp; p_demux->pf_control = DemuxControl; return VLC_SUCCESS; } /* Check for a "vlc://quit" command */ if( !strcasecmp( psz_name, "quit" ) ) { msg_Info( p_demux, "command `quit'" ); p_demux->pf_demux = DemuxNoOp; p_demux->pf_control = DemuxControl; libvlc_Quit( p_demux->p_libvlc ); return VLC_SUCCESS; } if( !strcasecmp( psz_name, "pause" ) ) { msg_Info( p_demux, "command `pause'" ); p_demux->pf_demux = DemuxHold; p_demux->pf_control = DemuxControl; return VLC_SUCCESS; } /* Check for a "vlc://pause:***" command */ if( !strncasecmp( psz_name, "pause:", 6 ) ) { double f = us_atof( psz_name + 6 ); mtime_t length = f * CLOCK_FREQ; msg_Info( p_demux, "command `pause %f'", f ); if( length == 0 ) goto nop; /* avoid division by zero */ demux_sys_t *p_sys = malloc( sizeof( *p_sys ) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->end = mdate() + length; p_sys->length = length; p_demux->p_sys = p_sys; p_demux->pf_demux = DemuxPause; p_demux->pf_control = ControlPause; return VLC_SUCCESS; } msg_Err( p_demux, "unknown command `%s'", psz_name ); return VLC_EGENERIC; }
void config_ChainParse( vlc_object_t *p_this, const char *psz_prefix, const char *const *ppsz_options, config_chain_t *cfg ) { if( psz_prefix == NULL ) psz_prefix = ""; size_t plen = 1 + strlen( psz_prefix ); /* First, var_Create all variables */ for( size_t i = 0; ppsz_options[i] != NULL; i++ ) { const char *optname = ppsz_options[i]; if (optname[0] == '*') optname++; char name[plen + strlen( optname )]; snprintf( name, sizeof (name), "%s%s", psz_prefix, optname ); if( var_Create( p_this, name, config_GetType( p_this, name ) | VLC_VAR_DOINHERIT ) ) return /* VLC_xxx */; } /* Now parse options and set value */ for(; cfg; cfg = cfg->p_next ) { vlc_value_t val; bool b_yes = true; bool b_once = false; module_config_t *p_conf; int i_type; size_t i; if( cfg->psz_name == NULL || *cfg->psz_name == '\0' ) continue; for( i = 0; ppsz_options[i] != NULL; i++ ) { if( !strcmp( ppsz_options[i], cfg->psz_name ) ) { break; } if( ( !strncmp( cfg->psz_name, "no-", 3 ) && !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) || ( !strncmp( cfg->psz_name, "no", 2 ) && !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) ) { b_yes = false; break; } if( *ppsz_options[i] == '*' && !strcmp( &ppsz_options[i][1], cfg->psz_name ) ) { b_once = true; break; } } if( ppsz_options[i] == NULL ) { msg_Warn( p_this, "option %s is unknown", cfg->psz_name ); continue; } /* create name */ char name[plen + strlen( ppsz_options[i] )]; const char *psz_name = name; snprintf( name, sizeof (name), "%s%s", psz_prefix, b_once ? (ppsz_options[i] + 1) : ppsz_options[i] ); /* Check if the option is deprecated */ p_conf = config_FindConfig( p_this, name ); /* This is basically cut and paste from src/misc/configuration.c * with slight changes */ if( p_conf ) { if( p_conf->b_removed ) { msg_Err( p_this, "Option %s is not supported anymore.", name ); /* TODO: this should return an error and end option parsing * ... but doing this would change the VLC API and all the * modules so i'll do it later */ continue; } } /* </Check if the option is deprecated> */ /* get the type of the variable */ i_type = config_GetType( p_this, psz_name ); if( !i_type ) { msg_Warn( p_this, "unknown option %s (value=%s)", cfg->psz_name, cfg->psz_value ); continue; } if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL ) { msg_Warn( p_this, "missing value for option %s", cfg->psz_name ); continue; } if( i_type != VLC_VAR_STRING && b_once ) { msg_Warn( p_this, "*option_name need to be a string option" ); continue; } switch( i_type ) { case VLC_VAR_BOOL: val.b_bool = b_yes; break; case VLC_VAR_INTEGER: val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0", NULL, 0 ); break; case VLC_VAR_FLOAT: val.f_float = us_atof( cfg->psz_value ? cfg->psz_value : "0" ); break; case VLC_VAR_STRING: val.psz_string = cfg->psz_value; break; default: msg_Warn( p_this, "unhandled config var type (%d)", i_type ); memset( &val, 0, sizeof( vlc_value_t ) ); break; } if( b_once ) { vlc_value_t val2; var_Get( p_this, psz_name, &val2 ); if( *val2.psz_string ) { free( val2.psz_string ); msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name ); continue; } free( val2.psz_string ); } var_Set( p_this, psz_name, val ); msg_Dbg( p_this, "set config option: %s to %s", psz_name, cfg->psz_value ? cfg->psz_value : "(null)" ); } }
void vorbis_ParseComment( es_format_t *p_fmt, vlc_meta_t **pp_meta, const uint8_t *p_data, int i_data, int *i_attachments, input_attachment_t ***attachments, int *i_cover_score, int *i_cover_idx, int *i_seekpoint, seekpoint_t ***ppp_seekpoint, float (* ppf_replay_gain)[AUDIO_REPLAY_GAIN_MAX], float (* ppf_replay_peak)[AUDIO_REPLAY_GAIN_MAX] ) { int n; int i_comment; if( i_data < 8 ) return; n = GetDWLE(p_data); RM(4); if( n < 0 || n > i_data ) return; #if 0 if( n > 0 ) { /* TODO report vendor string ? */ char *psz_vendor = psz_vendor = strndup( p_data, n ); free( psz_vendor ); } #endif RM(n); if( i_data < 4 ) return; i_comment = GetDWLE(p_data); RM(4); if( i_comment <= 0 ) return; /* */ vlc_meta_t *p_meta = *pp_meta; if( !p_meta ) *pp_meta = p_meta = vlc_meta_New(); if( !p_meta ) return; /* */ bool hasTitle = false; bool hasArtist = false; bool hasGenre = false; bool hasCopyright = false; bool hasAlbum = false; bool hasTrackNum = false; bool hasDescription = false; bool hasRating = false; bool hasDate = false; bool hasLanguage = false; bool hasPublisher = false; bool hasEncodedBy = false; bool hasTrackTotal = false; chapters_array_t chapters_array = { 0, NULL }; for( ; i_comment > 0; i_comment-- ) { char *psz_comment; if( i_data < 4 ) break; n = GetDWLE(p_data); RM(4); if( n > i_data ) break; if( n <= 0 ) continue; psz_comment = strndup( (const char*)p_data, n ); RM(n); EnsureUTF8( psz_comment ); #define IF_EXTRACT(txt,var) \ if( !strncasecmp(psz_comment, txt, strlen(txt)) ) \ { \ const char *oldval = vlc_meta_Get( p_meta, vlc_meta_ ## var ); \ if( oldval && has##var) \ { \ char * newval; \ if( asprintf( &newval, "%s,%s", oldval, &psz_comment[strlen(txt)] ) == -1 ) \ newval = NULL; \ vlc_meta_Set( p_meta, vlc_meta_ ## var, newval ); \ free( newval ); \ } \ else \ vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \ has##var = true; \ } #define IF_EXTRACT_ONCE(txt,var) \ if( !strncasecmp(psz_comment, txt, strlen(txt)) && !has##var ) \ { \ vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \ has##var = true; \ } #define IF_EXTRACT_FMT(txt,var,fmt,target) \ IF_EXTRACT(txt,var)\ if( fmt && !strncasecmp(psz_comment, txt, strlen(txt)) )\ {\ if ( fmt->target ) free( fmt->target );\ fmt->target = strdup(&psz_comment[strlen(txt)]);\ } IF_EXTRACT("TITLE=", Title ) else IF_EXTRACT("ARTIST=", Artist ) else IF_EXTRACT("GENRE=", Genre ) else IF_EXTRACT("COPYRIGHT=", Copyright ) else IF_EXTRACT("ALBUM=", Album ) else if( !hasTrackNum && !strncasecmp(psz_comment, "TRACKNUMBER=", strlen("TRACKNUMBER=" ) ) ) { /* Yeah yeah, such a clever idea, let's put xx/xx inside TRACKNUMBER * Oh, and let's not use TRACKTOTAL or TOTALTRACKS... */ short unsigned u_track, u_total; if( sscanf( &psz_comment[strlen("TRACKNUMBER=")], "%hu/%hu", &u_track, &u_total ) == 2 ) { char str[6]; snprintf(str, 6, "%u", u_track); vlc_meta_Set( p_meta, vlc_meta_TrackNumber, str ); hasTrackNum = true; snprintf(str, 6, "%u", u_total); vlc_meta_Set( p_meta, vlc_meta_TrackTotal, str ); hasTrackTotal = true; } else { vlc_meta_Set( p_meta, vlc_meta_TrackNumber, &psz_comment[strlen("TRACKNUMBER=")] ); hasTrackNum = true; } } else IF_EXTRACT_ONCE("TRACKTOTAL=", TrackTotal ) else IF_EXTRACT_ONCE("TOTALTRACKS=", TrackTotal ) else IF_EXTRACT("DESCRIPTION=", Description ) else IF_EXTRACT("COMMENT=", Description ) else IF_EXTRACT("COMMENTS=", Description ) else IF_EXTRACT("RATING=", Rating ) else IF_EXTRACT("DATE=", Date ) else IF_EXTRACT_FMT("LANGUAGE=", Language, p_fmt, psz_language ) else IF_EXTRACT("ORGANIZATION=", Publisher ) else IF_EXTRACT("ENCODER=", EncodedBy ) else if( !strncasecmp( psz_comment, "METADATA_BLOCK_PICTURE=", strlen("METADATA_BLOCK_PICTURE="))) { if( attachments == NULL ) continue; uint8_t *p_picture; size_t i_size = vlc_b64_decode_binary( &p_picture, &psz_comment[strlen("METADATA_BLOCK_PICTURE=")]); input_attachment_t *p_attachment = ParseFlacPicture( p_picture, i_size, *i_attachments, i_cover_score, i_cover_idx ); free( p_picture ); if( p_attachment ) { TAB_APPEND_CAST( (input_attachment_t**), *i_attachments, *attachments, p_attachment ); } } else if ( ppf_replay_gain && ppf_replay_peak && !strncmp(psz_comment, "REPLAYGAIN_", 11) ) { char *p = strchr( psz_comment, '=' ); if (!p) continue; if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_GAIN=", 22) ) { (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p ); } else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_GAIN=", 22) ) { (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p ); } else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_PEAK=", 22) ) { (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p ); } else if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_PEAK=", 22) ) { (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p ); } } else if( !strncasecmp(psz_comment, "CHAPTER", 7) ) { unsigned int i_chapt; seekpoint_t *p_seekpoint = NULL; for( int i = 0; psz_comment[i] && psz_comment[i] != '='; i++ ) if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' ) psz_comment[i] -= 'a' - 'A'; if( strstr( psz_comment, "NAME=" ) && sscanf( psz_comment, "CHAPTER%uNAME=", &i_chapt ) == 1 ) { char *p = strchr( psz_comment, '=' ); p_seekpoint = getChapterEntry( i_chapt, &chapters_array ); if ( !p || ! p_seekpoint ) continue; if ( ! p_seekpoint->psz_name ) p_seekpoint->psz_name = strdup( ++p ); } else if( sscanf( psz_comment, "CHAPTER%u=", &i_chapt ) == 1 ) { unsigned int h, m, s, ms; char *p = strchr( psz_comment, '=' ); if( p && sscanf( ++p, "%u:%u:%u.%u", &h, &m, &s, &ms ) == 4 ) { p_seekpoint = getChapterEntry( i_chapt, &chapters_array ); if ( ! p_seekpoint ) continue; p_seekpoint->i_time_offset = (((int64_t)h * 3600 + (int64_t)m * 60 + (int64_t)s) * 1000 + ms) * 1000; } } } else if( strchr( psz_comment, '=' ) ) { /* generic (PERFORMER/LICENSE/ORGANIZATION/LOCATION/CONTACT/ISRC, * undocumented tags and replay gain ) */ char *p = strchr( psz_comment, '=' ); *p++ = '\0'; for( int i = 0; psz_comment[i]; i++ ) if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' ) psz_comment[i] -= 'a' - 'A'; vlc_meta_AddExtra( p_meta, psz_comment, p ); } #undef IF_EXTRACT free( psz_comment ); }