Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. /**
  22.  * @file
  23.  * audio channel layout utility functions
  24.  */
  25.  
  26. #include <stdint.h>
  27.  
  28. #include "avstring.h"
  29. #include "avutil.h"
  30. #include "channel_layout.h"
  31. #include "bprint.h"
  32. #include "common.h"
  33.  
  34. struct channel_name {
  35.     const char *name;
  36.     const char *description;
  37. };
  38.  
  39. static const struct channel_name channel_names[] = {
  40.      [0] = { "FL",        "front left"            },
  41.      [1] = { "FR",        "front right"           },
  42.      [2] = { "FC",        "front center"          },
  43.      [3] = { "LFE",       "low frequency"         },
  44.      [4] = { "BL",        "back left"             },
  45.      [5] = { "BR",        "back right"            },
  46.      [6] = { "FLC",       "front left-of-center"  },
  47.      [7] = { "FRC",       "front right-of-center" },
  48.      [8] = { "BC",        "back center"           },
  49.      [9] = { "SL",        "side left"             },
  50.     [10] = { "SR",        "side right"            },
  51.     [11] = { "TC",        "top center"            },
  52.     [12] = { "TFL",       "top front left"        },
  53.     [13] = { "TFC",       "top front center"      },
  54.     [14] = { "TFR",       "top front right"       },
  55.     [15] = { "TBL",       "top back left"         },
  56.     [16] = { "TBC",       "top back center"       },
  57.     [17] = { "TBR",       "top back right"        },
  58.     [29] = { "DL",        "downmix left"          },
  59.     [30] = { "DR",        "downmix right"         },
  60.     [31] = { "WL",        "wide left"             },
  61.     [32] = { "WR",        "wide right"            },
  62.     [33] = { "SDL",       "surround direct left"  },
  63.     [34] = { "SDR",       "surround direct right" },
  64.     [35] = { "LFE2",      "low frequency 2"       },
  65. };
  66.  
  67. static const char *get_channel_name(int channel_id)
  68. {
  69.     if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names))
  70.         return NULL;
  71.     return channel_names[channel_id].name;
  72. }
  73.  
  74. static const struct {
  75.     const char *name;
  76.     int         nb_channels;
  77.     uint64_t     layout;
  78. } channel_layout_map[] = {
  79.     { "mono",        1,  AV_CH_LAYOUT_MONO },
  80.     { "stereo",      2,  AV_CH_LAYOUT_STEREO },
  81.     { "2.1",         3,  AV_CH_LAYOUT_2POINT1 },
  82.     { "3.0",         3,  AV_CH_LAYOUT_SURROUND },
  83.     { "3.0(back)",   3,  AV_CH_LAYOUT_2_1 },
  84.     { "4.0",         4,  AV_CH_LAYOUT_4POINT0 },
  85.     { "quad",        4,  AV_CH_LAYOUT_QUAD },
  86.     { "quad(side)",  4,  AV_CH_LAYOUT_2_2 },
  87.     { "3.1",         4,  AV_CH_LAYOUT_3POINT1 },
  88.     { "5.0",         5,  AV_CH_LAYOUT_5POINT0_BACK },
  89.     { "5.0(side)",   5,  AV_CH_LAYOUT_5POINT0 },
  90.     { "4.1",         5,  AV_CH_LAYOUT_4POINT1 },
  91.     { "5.1",         6,  AV_CH_LAYOUT_5POINT1_BACK },
  92.     { "5.1(side)",   6,  AV_CH_LAYOUT_5POINT1 },
  93.     { "6.0",         6,  AV_CH_LAYOUT_6POINT0 },
  94.     { "6.0(front)",  6,  AV_CH_LAYOUT_6POINT0_FRONT },
  95.     { "hexagonal",   6,  AV_CH_LAYOUT_HEXAGONAL },
  96.     { "6.1",         7,  AV_CH_LAYOUT_6POINT1 },
  97.     { "6.1",         7,  AV_CH_LAYOUT_6POINT1_BACK },
  98.     { "6.1(front)",  7,  AV_CH_LAYOUT_6POINT1_FRONT },
  99.     { "7.0",         7,  AV_CH_LAYOUT_7POINT0 },
  100.     { "7.0(front)",  7,  AV_CH_LAYOUT_7POINT0_FRONT },
  101.     { "7.1",         8,  AV_CH_LAYOUT_7POINT1 },
  102.     { "7.1(wide)",   8,  AV_CH_LAYOUT_7POINT1_WIDE_BACK },
  103.     { "7.1(wide-side)",   8,  AV_CH_LAYOUT_7POINT1_WIDE },
  104.     { "octagonal",   8,  AV_CH_LAYOUT_OCTAGONAL },
  105.     { "hexadecagonal", 16, AV_CH_LAYOUT_HEXADECAGONAL },
  106.     { "downmix",     2,  AV_CH_LAYOUT_STEREO_DOWNMIX, },
  107. };
  108.  
  109. #if FF_API_GET_CHANNEL_LAYOUT_COMPAT
  110. static uint64_t get_channel_layout_single(const char *name, int name_len, int compat)
  111. #else
  112. static uint64_t get_channel_layout_single(const char *name, int name_len)
  113. #endif
  114. {
  115.     int i;
  116.     char *end;
  117.     int64_t layout;
  118.  
  119.     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) {
  120.         if (strlen(channel_layout_map[i].name) == name_len &&
  121.             !memcmp(channel_layout_map[i].name, name, name_len))
  122.             return channel_layout_map[i].layout;
  123.     }
  124.     for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
  125.         if (channel_names[i].name &&
  126.             strlen(channel_names[i].name) == name_len &&
  127.             !memcmp(channel_names[i].name, name, name_len))
  128.             return (int64_t)1 << i;
  129.  
  130.     errno = 0;
  131.     i = strtol(name, &end, 10);
  132.  
  133. #if FF_API_GET_CHANNEL_LAYOUT_COMPAT
  134.     if (compat) {
  135.         if (end - name == name_len ||
  136.             (end + 1 - name == name_len && *end  == 'c')) {
  137.             layout = av_get_default_channel_layout(i);
  138.             if (end - name == name_len) {
  139.                 av_log(NULL, AV_LOG_WARNING,
  140.                        "Single channel layout '%.*s' is interpreted as a number of channels, "
  141.                        "switch to the syntax '%.*sc' otherwise it will be interpreted as a "
  142.                        "channel layout number in a later version\n",
  143.                        name_len, name, name_len, name);
  144.             }
  145.             return layout;
  146.         }
  147.     } else {
  148. #endif
  149.     if (!errno && (end + 1 - name == name_len && *end  == 'c'))
  150.         return av_get_default_channel_layout(i);
  151. #if FF_API_GET_CHANNEL_LAYOUT_COMPAT
  152.     }
  153. #endif
  154.  
  155.     errno = 0;
  156.     layout = strtoll(name, &end, 0);
  157.     if (!errno && end - name == name_len)
  158.         return FFMAX(layout, 0);
  159.     return 0;
  160. }
  161.  
  162. #if FF_API_GET_CHANNEL_LAYOUT_COMPAT
  163. uint64_t ff_get_channel_layout(const char *name, int compat)
  164. #else
  165. uint64_t av_get_channel_layout(const char *name)
  166. #endif
  167. {
  168.     const char *n, *e;
  169.     const char *name_end = name + strlen(name);
  170.     int64_t layout = 0, layout_single;
  171.  
  172.     for (n = name; n < name_end; n = e + 1) {
  173.         for (e = n; e < name_end && *e != '+' && *e != '|'; e++);
  174. #if FF_API_GET_CHANNEL_LAYOUT_COMPAT
  175.         layout_single = get_channel_layout_single(n, e - n, compat);
  176. #else
  177.         layout_single = get_channel_layout_single(n, e - n);
  178. #endif
  179.         if (!layout_single)
  180.             return 0;
  181.         layout |= layout_single;
  182.     }
  183.     return layout;
  184. }
  185.  
  186. #if FF_API_GET_CHANNEL_LAYOUT_COMPAT
  187. uint64_t av_get_channel_layout(const char *name)
  188. {
  189.     return ff_get_channel_layout(name, 1);
  190. }
  191. #endif
  192.  
  193. void av_bprint_channel_layout(struct AVBPrint *bp,
  194.                               int nb_channels, uint64_t channel_layout)
  195. {
  196.     int i;
  197.  
  198.     if (nb_channels <= 0)
  199.         nb_channels = av_get_channel_layout_nb_channels(channel_layout);
  200.  
  201.     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
  202.         if (nb_channels    == channel_layout_map[i].nb_channels &&
  203.             channel_layout == channel_layout_map[i].layout) {
  204.             av_bprintf(bp, "%s", channel_layout_map[i].name);
  205.             return;
  206.         }
  207.  
  208.     av_bprintf(bp, "%d channels", nb_channels);
  209.     if (channel_layout) {
  210.         int i, ch;
  211.         av_bprintf(bp, " (");
  212.         for (i = 0, ch = 0; i < 64; i++) {
  213.             if ((channel_layout & (UINT64_C(1) << i))) {
  214.                 const char *name = get_channel_name(i);
  215.                 if (name) {
  216.                     if (ch > 0)
  217.                         av_bprintf(bp, "+");
  218.                     av_bprintf(bp, "%s", name);
  219.                 }
  220.                 ch++;
  221.             }
  222.         }
  223.         av_bprintf(bp, ")");
  224.     }
  225. }
  226.  
  227. void av_get_channel_layout_string(char *buf, int buf_size,
  228.                                   int nb_channels, uint64_t channel_layout)
  229. {
  230.     AVBPrint bp;
  231.  
  232.     av_bprint_init_for_buffer(&bp, buf, buf_size);
  233.     av_bprint_channel_layout(&bp, nb_channels, channel_layout);
  234. }
  235.  
  236. int av_get_channel_layout_nb_channels(uint64_t channel_layout)
  237. {
  238.     return av_popcount64(channel_layout);
  239. }
  240.  
  241. int64_t av_get_default_channel_layout(int nb_channels) {
  242.     int i;
  243.     for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++)
  244.         if (nb_channels == channel_layout_map[i].nb_channels)
  245.             return channel_layout_map[i].layout;
  246.     return 0;
  247. }
  248.  
  249. int av_get_channel_layout_channel_index(uint64_t channel_layout,
  250.                                         uint64_t channel)
  251. {
  252.     if (!(channel_layout & channel) ||
  253.         av_get_channel_layout_nb_channels(channel) != 1)
  254.         return AVERROR(EINVAL);
  255.     channel_layout &= channel - 1;
  256.     return av_get_channel_layout_nb_channels(channel_layout);
  257. }
  258.  
  259. const char *av_get_channel_name(uint64_t channel)
  260. {
  261.     int i;
  262.     if (av_get_channel_layout_nb_channels(channel) != 1)
  263.         return NULL;
  264.     for (i = 0; i < 64; i++)
  265.         if ((1ULL<<i) & channel)
  266.             return get_channel_name(i);
  267.     return NULL;
  268. }
  269.  
  270. const char *av_get_channel_description(uint64_t channel)
  271. {
  272.     int i;
  273.     if (av_get_channel_layout_nb_channels(channel) != 1)
  274.         return NULL;
  275.     for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++)
  276.         if ((1ULL<<i) & channel)
  277.             return channel_names[i].description;
  278.     return NULL;
  279. }
  280.  
  281. uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index)
  282. {
  283.     int i;
  284.  
  285.     if (av_get_channel_layout_nb_channels(channel_layout) <= index)
  286.         return 0;
  287.  
  288.     for (i = 0; i < 64; i++) {
  289.         if ((1ULL << i) & channel_layout && !index--)
  290.             return 1ULL << i;
  291.     }
  292.     return 0;
  293. }
  294.  
  295. int av_get_standard_channel_layout(unsigned index, uint64_t *layout,
  296.                                    const char **name)
  297. {
  298.     if (index >= FF_ARRAY_ELEMS(channel_layout_map))
  299.         return AVERROR_EOF;
  300.     if (layout) *layout = channel_layout_map[index].layout;
  301.     if (name)   *name   = channel_layout_map[index].name;
  302.     return 0;
  303. }
  304.