lavfi: better channel layout negotiation
Allow substitution of channel pairs in the input for nearby channel pairs in the output in order to get a closer match. Also weigh LFE channel mismatch differently to favor matching the same layout without LFE over one less channel with LFE.
This commit is contained in:
		
							parent
							
								
									81f548de57
								
							
						
					
					
						commit
						743f07062a
					
				| @ -424,11 +424,44 @@ static void swap_samplerates(AVFilterGraph *graph) | ||||
|         swap_samplerates_on_filter(graph->filters[i]); | ||||
| } | ||||
| 
 | ||||
| #define CH_CENTER_PAIR (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER) | ||||
| #define CH_FRONT_PAIR  (AV_CH_FRONT_LEFT           | AV_CH_FRONT_RIGHT) | ||||
| #define CH_STEREO_PAIR (AV_CH_STEREO_LEFT          | AV_CH_STEREO_RIGHT) | ||||
| #define CH_WIDE_PAIR   (AV_CH_WIDE_LEFT            | AV_CH_WIDE_RIGHT) | ||||
| #define CH_SIDE_PAIR   (AV_CH_SIDE_LEFT            | AV_CH_SIDE_RIGHT) | ||||
| #define CH_DIRECT_PAIR (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT) | ||||
| #define CH_BACK_PAIR   (AV_CH_BACK_LEFT            | AV_CH_BACK_RIGHT) | ||||
| 
 | ||||
| /* allowable substitutions for channel pairs when comparing layouts,
 | ||||
|  * ordered by priority for both values */ | ||||
| static const uint64_t ch_subst[][2] = { | ||||
|     { CH_FRONT_PAIR,      CH_CENTER_PAIR     }, | ||||
|     { CH_FRONT_PAIR,      CH_WIDE_PAIR       }, | ||||
|     { CH_FRONT_PAIR,      AV_CH_FRONT_CENTER }, | ||||
|     { CH_CENTER_PAIR,     CH_FRONT_PAIR      }, | ||||
|     { CH_CENTER_PAIR,     CH_WIDE_PAIR       }, | ||||
|     { CH_CENTER_PAIR,     AV_CH_FRONT_CENTER }, | ||||
|     { CH_WIDE_PAIR,       CH_FRONT_PAIR      }, | ||||
|     { CH_WIDE_PAIR,       CH_CENTER_PAIR     }, | ||||
|     { CH_WIDE_PAIR,       AV_CH_FRONT_CENTER }, | ||||
|     { AV_CH_FRONT_CENTER, CH_FRONT_PAIR      }, | ||||
|     { AV_CH_FRONT_CENTER, CH_CENTER_PAIR     }, | ||||
|     { AV_CH_FRONT_CENTER, CH_WIDE_PAIR       }, | ||||
|     { CH_SIDE_PAIR,       CH_DIRECT_PAIR     }, | ||||
|     { CH_SIDE_PAIR,       CH_BACK_PAIR       }, | ||||
|     { CH_SIDE_PAIR,       AV_CH_BACK_CENTER  }, | ||||
|     { CH_BACK_PAIR,       CH_DIRECT_PAIR     }, | ||||
|     { CH_BACK_PAIR,       CH_SIDE_PAIR       }, | ||||
|     { CH_BACK_PAIR,       AV_CH_BACK_CENTER  }, | ||||
|     { AV_CH_BACK_CENTER,  CH_BACK_PAIR       }, | ||||
|     { AV_CH_BACK_CENTER,  CH_DIRECT_PAIR     }, | ||||
|     { AV_CH_BACK_CENTER,  CH_SIDE_PAIR       }, | ||||
| }; | ||||
| 
 | ||||
| static void swap_channel_layouts_on_filter(AVFilterContext *filter) | ||||
| { | ||||
|     AVFilterLink *link = NULL; | ||||
|     uint64_t chlayout; | ||||
|     int i, j; | ||||
|     int i, j, k; | ||||
| 
 | ||||
|     for (i = 0; i < filter->nb_inputs; i++) { | ||||
|         link = filter->inputs[i]; | ||||
| @ -440,27 +473,55 @@ static void swap_channel_layouts_on_filter(AVFilterContext *filter) | ||||
|     if (i == filter->nb_inputs) | ||||
|         return; | ||||
| 
 | ||||
|     chlayout = link->out_channel_layouts->channel_layouts[0]; | ||||
| 
 | ||||
|     for (i = 0; i < filter->nb_outputs; i++) { | ||||
|         AVFilterLink *outlink = filter->outputs[i]; | ||||
|         int best_idx, best_score = INT_MIN; | ||||
|         int best_idx, best_score = INT_MIN, best_count_diff = INT_MAX; | ||||
| 
 | ||||
|         if (outlink->type != AVMEDIA_TYPE_AUDIO || | ||||
|             outlink->in_channel_layouts->nb_channel_layouts < 2) | ||||
|             continue; | ||||
| 
 | ||||
|         for (j = 0; j < outlink->in_channel_layouts->nb_channel_layouts; j++) { | ||||
|             uint64_t  in_chlayout = link->out_channel_layouts->channel_layouts[0]; | ||||
|             uint64_t out_chlayout = outlink->in_channel_layouts->channel_layouts[j]; | ||||
|             int matched_channels  = av_get_channel_layout_nb_channels(chlayout & | ||||
|                                                                       out_chlayout); | ||||
|             int extra_channels     = av_get_channel_layout_nb_channels(out_chlayout & | ||||
|                                                                        (~chlayout)); | ||||
|             int score = matched_channels - extra_channels; | ||||
|             int  in_channels      = av_get_channel_layout_nb_channels(in_chlayout); | ||||
|             int out_channels      = av_get_channel_layout_nb_channels(out_chlayout); | ||||
|             int count_diff        = out_channels - in_channels; | ||||
|             int matched_channels, extra_channels; | ||||
|             int score = 0; | ||||
| 
 | ||||
|             if (score > best_score) { | ||||
|             /* channel substitution */ | ||||
|             for (k = 0; k < FF_ARRAY_ELEMS(ch_subst); k++) { | ||||
|                 uint64_t cmp0 = ch_subst[k][0]; | ||||
|                 uint64_t cmp1 = ch_subst[k][1]; | ||||
|                 if (( in_chlayout & cmp0) && (!(out_chlayout & cmp0)) && | ||||
|                     (out_chlayout & cmp1) && (!( in_chlayout & cmp1))) { | ||||
|                     in_chlayout  &= ~cmp0; | ||||
|                     out_chlayout &= ~cmp1; | ||||
|                     /* add score for channel match, minus a deduction for
 | ||||
|                        having to do the substitution */ | ||||
|                     score += 10 * av_get_channel_layout_nb_channels(cmp1) - 2; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             /* no penalty for LFE channel mismatch */ | ||||
|             if ( (in_chlayout & AV_CH_LOW_FREQUENCY) && | ||||
|                 (out_chlayout & AV_CH_LOW_FREQUENCY)) | ||||
|                 score += 10; | ||||
|             in_chlayout  &= ~AV_CH_LOW_FREQUENCY; | ||||
|             out_chlayout &= ~AV_CH_LOW_FREQUENCY; | ||||
| 
 | ||||
|             matched_channels = av_get_channel_layout_nb_channels(in_chlayout & | ||||
|                                                                  out_chlayout); | ||||
|             extra_channels   = av_get_channel_layout_nb_channels(out_chlayout & | ||||
|                                                                  (~in_chlayout)); | ||||
|             score += 10 * matched_channels - 5 * extra_channels; | ||||
| 
 | ||||
|             if (score > best_score || | ||||
|                 (count_diff < best_count_diff && score == best_score)) { | ||||
|                 best_score = score; | ||||
|                 best_idx   = j; | ||||
|                 best_count_diff = count_diff; | ||||
|             } | ||||
|         } | ||||
|         FFSWAP(uint64_t, outlink->in_channel_layouts->channel_layouts[0], | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user