| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License along with FFmpeg; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @file | 
					
						
							|  |  |  |  * audio conversion routines | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-05 01:28:22 +02:00
										 |  |  | #include "avstring.h"
 | 
					
						
							|  |  |  | #include "avutil.h"
 | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | #include "audioconvert.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char * const channel_names[] = { | 
					
						
							| 
									
										
										
										
											2011-09-11 01:07:08 +02:00
										 |  |  |     [0]  = "FL",        /* front left */ | 
					
						
							|  |  |  |     [1]  = "FR",        /* front right */ | 
					
						
							|  |  |  |     [2]  = "FC",        /* front center */ | 
					
						
							|  |  |  |     [3]  = "LFE",       /* low frequency */ | 
					
						
							|  |  |  |     [4]  = "BL",        /* back left */ | 
					
						
							|  |  |  |     [5]  = "BR",        /* back right */ | 
					
						
							|  |  |  |     [6]  = "FLC",       /* front left-of-center  */ | 
					
						
							|  |  |  |     [7]  = "FRC",       /* front right-of-center */ | 
					
						
							|  |  |  |     [8]  = "BC",        /* back-center */ | 
					
						
							|  |  |  |     [9]  = "SL",        /* side left */ | 
					
						
							|  |  |  |     [10] = "SR",        /* side right */ | 
					
						
							|  |  |  |     [11] = "TC",        /* top center */ | 
					
						
							|  |  |  |     [12] = "TFL",       /* top front left */ | 
					
						
							|  |  |  |     [13] = "TFC",       /* top front center */ | 
					
						
							|  |  |  |     [14] = "TFR",       /* top front right */ | 
					
						
							|  |  |  |     [15] = "TBL",       /* top back left */ | 
					
						
							|  |  |  |     [16] = "TBC",       /* top back center */ | 
					
						
							|  |  |  |     [17] = "TBR",       /* top back right */ | 
					
						
							|  |  |  |     [29] = "DL",        /* downmix left */ | 
					
						
							|  |  |  |     [30] = "DR",        /* downmix right */ | 
					
						
							| 
									
										
										
										
											2012-02-22 15:43:22 +01:00
										 |  |  |     [31] = "WL",        /* wide left */ | 
					
						
							|  |  |  |     [32] = "WR",        /* wide right */ | 
					
						
							|  |  |  |     [33] = "SDL",       /* surround direct left */ | 
					
						
							|  |  |  |     [34] = "SDR",       /* surround direct right */ | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *get_channel_name(int channel_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names)) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     return channel_names[channel_id]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct { | 
					
						
							|  |  |  |     const char *name; | 
					
						
							|  |  |  |     int         nb_channels; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:51:57 +00:00
										 |  |  |     uint64_t     layout; | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | } channel_layout_map[] = { | 
					
						
							|  |  |  |     { "mono",        1,  AV_CH_LAYOUT_MONO }, | 
					
						
							|  |  |  |     { "stereo",      2,  AV_CH_LAYOUT_STEREO }, | 
					
						
							| 
									
										
										
										
											2012-01-11 10:09:37 +01:00
										 |  |  |     { "2.1",         3,  AV_CH_LAYOUT_2POINT1 }, | 
					
						
							| 
									
										
										
										
											2012-02-21 21:27:03 +01:00
										 |  |  |     { "3.0",         3,  AV_CH_LAYOUT_SURROUND }, | 
					
						
							|  |  |  |     { "3.0(back)",   3,  AV_CH_LAYOUT_2_1 }, | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |     { "4.0",         4,  AV_CH_LAYOUT_4POINT0 }, | 
					
						
							|  |  |  |     { "quad",        4,  AV_CH_LAYOUT_QUAD }, | 
					
						
							| 
									
										
										
										
											2012-02-21 21:27:03 +01:00
										 |  |  |     { "quad(side)",  4,  AV_CH_LAYOUT_2_2 }, | 
					
						
							| 
									
										
										
										
											2012-02-22 01:35:41 +01:00
										 |  |  |     { "3.1",         4,  AV_CH_LAYOUT_3POINT1 }, | 
					
						
							| 
									
										
										
										
											2011-08-28 22:37:11 +02:00
										 |  |  |     { "5.0",         5,  AV_CH_LAYOUT_5POINT0_BACK }, | 
					
						
							| 
									
										
										
										
											2011-11-06 17:05:08 +01:00
										 |  |  |     { "5.0(side)",   5,  AV_CH_LAYOUT_5POINT0 }, | 
					
						
							| 
									
										
										
										
											2012-02-22 01:35:41 +01:00
										 |  |  |     { "4.1",         5,  AV_CH_LAYOUT_4POINT1 }, | 
					
						
							| 
									
										
										
										
											2011-08-28 22:37:11 +02:00
										 |  |  |     { "5.1",         6,  AV_CH_LAYOUT_5POINT1_BACK }, | 
					
						
							| 
									
										
										
										
											2011-11-06 17:05:08 +01:00
										 |  |  |     { "5.1(side)",   6,  AV_CH_LAYOUT_5POINT1 }, | 
					
						
							| 
									
										
										
										
											2012-02-21 21:27:03 +01:00
										 |  |  |     { "6.0",         6,  AV_CH_LAYOUT_6POINT0 }, | 
					
						
							|  |  |  |     { "6.0(front)",  6,  AV_CH_LAYOUT_6POINT0_FRONT }, | 
					
						
							|  |  |  |     { "hexagonal",   6,  AV_CH_LAYOUT_HEXAGONAL }, | 
					
						
							|  |  |  |     { "6.1",         7,  AV_CH_LAYOUT_6POINT1 }, | 
					
						
							|  |  |  |     { "6.1",         7,  AV_CH_LAYOUT_6POINT1_BACK }, | 
					
						
							|  |  |  |     { "6.1(front)",  7,  AV_CH_LAYOUT_6POINT1_FRONT }, | 
					
						
							|  |  |  |     { "7.0",         7,  AV_CH_LAYOUT_7POINT0 }, | 
					
						
							|  |  |  |     { "7.0(front)",  7,  AV_CH_LAYOUT_7POINT0_FRONT }, | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |     { "7.1",         8,  AV_CH_LAYOUT_7POINT1 }, | 
					
						
							|  |  |  |     { "7.1(wide)",   8,  AV_CH_LAYOUT_7POINT1_WIDE }, | 
					
						
							| 
									
										
										
										
											2012-02-21 21:27:03 +01:00
										 |  |  |     { "octagonal",   8,  AV_CH_LAYOUT_OCTAGONAL }, | 
					
						
							| 
									
										
										
										
											2011-11-08 16:32:50 +01:00
										 |  |  |     { "downmix",     2,  AV_CH_LAYOUT_STEREO_DOWNMIX, }, | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-26 01:12:08 +01:00
										 |  |  | static uint64_t get_channel_layout_single(const char *name, int name_len) | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-08 16:32:50 +01:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     char *end; | 
					
						
							|  |  |  |     int64_t layout; | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-14 12:07:31 +01:00
										 |  |  |     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) { | 
					
						
							| 
									
										
										
										
											2011-11-08 16:32:50 +01:00
										 |  |  |         if (strlen(channel_layout_map[i].name) == name_len && | 
					
						
							|  |  |  |             !memcmp(channel_layout_map[i].name, name, name_len)) | 
					
						
							|  |  |  |             return channel_layout_map[i].layout; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) | 
					
						
							|  |  |  |         if (channel_names[i] && | 
					
						
							|  |  |  |             strlen(channel_names[i]) == name_len && | 
					
						
							|  |  |  |             !memcmp(channel_names[i], name, name_len)) | 
					
						
							|  |  |  |             return (int64_t)1 << i; | 
					
						
							|  |  |  |     i = strtol(name, &end, 10); | 
					
						
							|  |  |  |     if (end - name == name_len || | 
					
						
							|  |  |  |         (end + 1 - name == name_len && *end  == 'c')) | 
					
						
							|  |  |  |         return av_get_default_channel_layout(i); | 
					
						
							|  |  |  |     layout = strtoll(name, &end, 0); | 
					
						
							|  |  |  |     if (end - name == name_len) | 
					
						
							|  |  |  |         return FFMAX(layout, 0); | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-26 01:12:08 +01:00
										 |  |  | uint64_t av_get_channel_layout(const char *name) | 
					
						
							| 
									
										
										
										
											2011-11-08 16:32:50 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     const char *n, *e; | 
					
						
							|  |  |  |     const char *name_end = name + strlen(name); | 
					
						
							|  |  |  |     int64_t layout = 0, layout_single; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (n = name; n < name_end; n = e + 1) { | 
					
						
							|  |  |  |         for (e = n; e < name_end && *e != '+' && *e != '|'; e++); | 
					
						
							|  |  |  |         layout_single = get_channel_layout_single(n, e - n); | 
					
						
							|  |  |  |         if (!layout_single) | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         layout |= layout_single; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return layout; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | void av_get_channel_layout_string(char *buf, int buf_size, | 
					
						
							| 
									
										
										
										
											2011-11-25 12:51:57 +00:00
										 |  |  |                                   int nb_channels, uint64_t channel_layout) | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-13 01:00:31 +00:00
										 |  |  |     if (nb_channels <= 0) | 
					
						
							|  |  |  |         nb_channels = av_get_channel_layout_nb_channels(channel_layout); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-14 12:07:31 +01:00
										 |  |  |     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |         if (nb_channels    == channel_layout_map[i].nb_channels && | 
					
						
							|  |  |  |             channel_layout == channel_layout_map[i].layout) { | 
					
						
							|  |  |  |             av_strlcpy(buf, channel_layout_map[i].name, buf_size); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     snprintf(buf, buf_size, "%d channels", nb_channels); | 
					
						
							|  |  |  |     if (channel_layout) { | 
					
						
							| 
									
										
										
										
											2011-09-11 01:06:57 +02:00
										 |  |  |         int i, ch; | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |         av_strlcat(buf, " (", buf_size); | 
					
						
							| 
									
										
										
										
											2011-09-11 01:06:57 +02:00
										 |  |  |         for (i = 0, ch = 0; i < 64; i++) { | 
					
						
							| 
									
										
										
										
											2011-11-25 14:58:50 +00:00
										 |  |  |             if ((channel_layout & (UINT64_C(1) << i))) { | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |                 const char *name = get_channel_name(i); | 
					
						
							|  |  |  |                 if (name) { | 
					
						
							| 
									
										
										
										
											2011-09-11 01:06:57 +02:00
										 |  |  |                     if (ch > 0) | 
					
						
							| 
									
										
										
										
											2011-11-05 21:21:50 +01:00
										 |  |  |                         av_strlcat(buf, "+", buf_size); | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  |                     av_strlcat(buf, name, buf_size); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 ch++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         av_strlcat(buf, ")", buf_size); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-25 12:51:57 +00:00
										 |  |  | int av_get_channel_layout_nb_channels(uint64_t channel_layout) | 
					
						
							| 
									
										
										
										
											2010-11-21 19:28:52 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int count; | 
					
						
							|  |  |  |     uint64_t x = channel_layout; | 
					
						
							|  |  |  |     for (count = 0; x; count++) | 
					
						
							|  |  |  |         x &= x-1; // unset lowest set bit
 | 
					
						
							|  |  |  |     return count; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-10-02 16:28:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-06 23:44:48 +02:00
										 |  |  | int64_t av_get_default_channel_layout(int nb_channels) { | 
					
						
							| 
									
										
										
										
											2011-10-02 16:28:36 +02:00
										 |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2012-02-14 12:07:31 +01:00
										 |  |  |     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) | 
					
						
							| 
									
										
										
										
											2011-10-02 16:28:36 +02:00
										 |  |  |         if (nb_channels == channel_layout_map[i].nb_channels) | 
					
						
							|  |  |  |             return channel_layout_map[i].layout; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } |