zoukankan      html  css  js  c++  java
  • ffmpeg之samplefmt

    音频量化格式和相关的工具函数

    类型说明

    AVSampleFormat

    /**
     * Audio sample formats
     *
     * - The data described by the sample format is always in native-endian order.
     *   Sample values can be expressed by native C types, hence the lack of a signed
     *   24-bit sample format even though it is a common raw audio data format.
     *
     * - The floating-point formats are based on full volume being in the range
     *   [-1.0, 1.0]. Any values outside this range are beyond full volume level.
     *
     * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg
     *   (such as AVFrame in libavcodec) is as follows:
     *
     * @par
     * For planar sample formats, each audio channel is in a separate data plane,
     * and linesize is the buffer size, in bytes, for a single plane. All data
     * planes must be the same size. For packed sample formats, only the first data
     * plane is used, and samples for each channel are interleaved. In this case,
     * linesize is the buffer size, in bytes, for the 1 plane.
     *
     */
    /*
    *planar:每个音频数据通道位于不同的plane,且所有plane的数据长度是一致的, data[0] = LLL..., data[1] = RRR...。
    *	linesize表示单个plane的buffer size(以字节为单位)。
    *packed:仅使用了第一个plane,且数据是交错存储的,data[0] = LRLRLR...。
    *	linesize表示单个plane的buffer size(以字节为单位)。。。(仅使用了一个plane == 单个plane)
    */
    enum AVSampleFormat {
        AV_SAMPLE_FMT_NONE = -1,
        AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits
        AV_SAMPLE_FMT_S16,         ///< signed 16 bits
        AV_SAMPLE_FMT_S32,         ///< signed 32 bits
        AV_SAMPLE_FMT_FLT,         ///< float
        AV_SAMPLE_FMT_DBL,         ///< double
    
        AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar
        AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar
        AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar
        AV_SAMPLE_FMT_FLTP,        ///< float, planar
        AV_SAMPLE_FMT_DBLP,        ///< double, planar
        AV_SAMPLE_FMT_S64,         ///< signed 64 bits
        AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar
    
        AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically
    };
    
    

    SampleFmtInfo

    // 量化格式信息
    typedef struct SampleFmtInfo {
        char name[8];       // 量化格式名称
        int bits;                    // bits >> 3 占据字节数量(1byte = 8bit ( 8 == 2 ** 3))
        int planar;              // 是否为planar格式,1是,0不是
        enum AVSampleFormat altform; ///< planar<->packed alternative form,相反的格式
    } SampleFmtInfo;
    
    /** this table gives more information about formats */
    // 量化格式参照表
    static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = {
        [AV_SAMPLE_FMT_U8]   = { .name =   "u8", .bits =  8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P  },
        [AV_SAMPLE_FMT_S16]  = { .name =  "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P },
        [AV_SAMPLE_FMT_S32]  = { .name =  "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P },
        [AV_SAMPLE_FMT_S64]  = { .name =  "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P },
        [AV_SAMPLE_FMT_FLT]  = { .name =  "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP },
        [AV_SAMPLE_FMT_DBL]  = { .name =  "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP },
        [AV_SAMPLE_FMT_U8P]  = { .name =  "u8p", .bits =  8, .planar = 1, .altform = AV_SAMPLE_FMT_U8   },
        [AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16  },
        [AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32  },
        [AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64  },
        [AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT  },
        [AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL  },
    };
    
    

    便捷的工具函数

    av_get_sample_fmt_name

    • brief:获取量化格式对应的字符串名称
    • parameter: 量化格式
    • return: 成功返回量化格式的字符串名称,失败返回NULL
    /**
     * Return the name of sample_fmt, or NULL if sample_fmt is not recognized.
     */
    const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt)
    {
        if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
            return NULL;
        return sample_fmt_info[sample_fmt].name;
    }
    

    av_get_sample_fmt

    • 获取字符串名称对应的量化格式
    • parameter: 量化格式的字符串名称
    • return:成功返回对应的量化格式,失败返回AV_SAMPLE_FMT_NONE
    /**
     * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE
     * on error.
     */
    enum AVSampleFormat av_get_sample_fmt(const char *name)
    {
        int i;
    
        for (i = 0; i < AV_SAMPLE_FMT_NB; i++)
            if (!strcmp(sample_fmt_info[i].name, name))
                return i;
        return AV_SAMPLE_FMT_NONE;
    }
    
    

    av_get_alt_sample_fmt

    • brief:获取相反的量化格式

    • parameter:sample_fmt:量化格式,planar:是否为planar格式

    • return:失败是返回AV_SAMPLE_FMT_NONE。

      ​ 如果传递的sample_fmt已经采用请求的量化格式,则返回自己sample_fmt,比如 AV_SAMPLE_FMT_S16 = av_get_alt_sample_fmt(AV_SAMPLE_FMT_S16, 0);

      ​ 否则返回对应的量化格式,比如AV_SAMPLE_FMT_S16P = av_get_alt_sample_fmt(AV_SAMPLE_FMT_S16, 1)。

    /**
     * Return the planar<->packed alternative form of the given sample format, or
     * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the
     * requested planar/packed format, the format returned is the same as the
     * input.
     */
    enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar)
    {
        if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
            return AV_SAMPLE_FMT_NONE;
        if (sample_fmt_info[sample_fmt].planar == planar)
            return sample_fmt;
        return sample_fmt_info[sample_fmt].altform;
    }
    
    

    av_get_packed_sample_fmt

    • brief:返回packed格式的量化格式

    • parameter:sample_fmt请求的量化格式

    • return:失败返回AV_SAMPLE_FMT_NONE;

      ​ 如果输入的已经是packed的格式,则返回自己sample_fmt。

      ​ 否则返回对应的的packed格式的量化格式

    /**
     * Get the packed alternative form of the given sample format.
     *
     * If the passed sample_fmt is already in packed format, the format returned is
     * the same as the input.
     *
     * @return  the packed alternative form of the given sample format or
                AV_SAMPLE_FMT_NONE on error.
    */
    enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt)
    {
        if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
            return AV_SAMPLE_FMT_NONE;
        if (sample_fmt_info[sample_fmt].planar)
            return sample_fmt_info[sample_fmt].altform;
        return sample_fmt;
    }
    
    

    av_get_planar_sample_fmt

    • brief:返回planar格式的量化格式

    • parameter:sample_fmt请求的量化格式

    • return:失败返回AV_SAMPLE_FMT_NONE;

      ​ 如果输入的已经是planar的格式,则返回自己sample_fmt。

      ​ 否则返回对应的的planar格式的量化格式

    /**
     * Get the planar alternative form of the given sample format.
     *
     * If the passed sample_fmt is already in planar format, the format returned is
     * the same as the input.
     *
     * @return  the planar alternative form of the given sample format or
                AV_SAMPLE_FMT_NONE on error.
     */
    enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt)
    {
        if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
            return AV_SAMPLE_FMT_NONE;
        if (sample_fmt_info[sample_fmt].planar)
            return sample_fmt;
        return sample_fmt_info[sample_fmt].altform;
    }
    
    

    av_get_sample_fmt_string

    • brief:获取指定量化格式的表示字符串,如果sample_fmt小于0,这返回描述信息头
    • parameter:buf:描述字符串,buf_size, sample_fmt
    • return:量化格式的对应字符串描述
    /**
     * Generate a string corresponding to the sample format with
     * sample_fmt, or a header if sample_fmt is negative.
     *
     * @param buf the buffer where to write the string
     * @param buf_size the size of buf
     * @param sample_fmt the number of the sample format to print the
     * corresponding info string, or a negative value to print the
     * corresponding header.
     * @return the pointer to the filled buffer or NULL if sample_fmt is
     * unknown or in case of other errors
     */
    char *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt)
    {
        /* print header */
        if (sample_fmt < 0)
            snprintf(buf, buf_size, "name  " " depth");
        else if (sample_fmt < AV_SAMPLE_FMT_NB) {
            SampleFmtInfo info = sample_fmt_info[sample_fmt];
            snprintf (buf, buf_size, "%-6s" "   %2d ", info.name, info.bits);
        }
    
        return buf;
    }
    
    

    av_get_bytes_per_sample

    • brief:获取指定量化格式的单个样本使用的字节数量
    • parameter
    • return:如果sample_fmt非法,返回0,成功返回占据字节数量
    /**
     * Return number of bytes per sample.
     *
     * @param sample_fmt the sample format
     * @return number of bytes per sample or zero if unknown for the given
     * sample format
     */
    int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt)
    {
         return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ?
            0 : sample_fmt_info[sample_fmt].bits >> 3;
    }
    
    

    av_sample_fmt_is_planar

    • brief:判断指定量化格式释放为planar格式
    • parameter
    • return:如果是planar格式则返回1,否则返回0
    /**
     * Check if the sample format is planar.
     *
     * @param sample_fmt the sample format to inspect
     * @return 1 if the sample format is planar, 0 if it is interleaved
     */
    int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt)
    {
         if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
             return 0;
         return sample_fmt_info[sample_fmt].planar;
    }
    
    

    av_sample_get_buffer_size

    • brief:获取指定样本格式的缓冲区大小
    • parameter:linesize单个plane的大小,nb_channels声音通道个数,nb_samples:帧率,sample_fmt, align对齐
    • return:失败返回负数标示故障码,否则返回缓冲区大小
    /**
     * Get the required buffer size for the given audio parameters.
     *
     * @param[out] linesize calculated linesize, may be NULL
     * @param nb_channels   the number of channels
     * @param nb_samples    the number of samples in a single channel
     * @param sample_fmt    the sample format
     * @param align         buffer size alignment (0 = default, 1 = no alignment)
     * @return              required buffer size, or negative error code on failure
     */
    int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
                                   enum AVSampleFormat sample_fmt, int align)
    {
        int line_size;
        int sample_size = av_get_bytes_per_sample(sample_fmt);
        int planar      = av_sample_fmt_is_planar(sample_fmt);
    
        /* validate parameter ranges */
        if (!sample_size || nb_samples <= 0 || nb_channels <= 0)
            return AVERROR(EINVAL);
    
        /* auto-select alignment if not specified */
        if (!align) {
            if (nb_samples > INT_MAX - 31)
                return AVERROR(EINVAL);
            align = 1;
            nb_samples = FFALIGN(nb_samples, 32);
        }
    
        /* check for integer overflow */
        if (nb_channels > INT_MAX / align ||
            (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size)
            return AVERROR(EINVAL);
    
        line_size = planar ? FFALIGN(nb_samples * sample_size,               align) :
                             FFALIGN(nb_samples * sample_size * nb_channels, align);
        if (linesize)
            *linesize = line_size;
    
        return planar ? line_size * nb_channels : line_size;
    }
    
    

    av_samples_fill_array

    • brief:为指定sample_fmt格式的样本填充plane data和linesize

      ​ 使用char **audio_data接受被填充的样本数据,对于packed数据,仅需要设置audio_data起始点即可,

      ​ 对于planar数据,*audio_data表示不同的通道数据的起点

      ​ linesize:对于planar数据,linesize标示单个plane对齐后的数据大小

      ​ 对于packed数据,linesize标示说有plane对齐后的数据大小总和

      ​ buf的buf_size必须足够大用来存储所有样本,否则audio_data会指向无效数据,可以通过av_samples_get_buffer_size()来计算

    • return:指定量化格式需要buf_size

    /**
     * Fill plane data pointers and linesize for samples with sample
     * format sample_fmt.
     *
     * The audio_data array is filled with the pointers to the samples data planes:
     * for planar, set the start point of each channel's data within the buffer,
     * for packed, set the start point of the entire buffer only.
     *
     * The value pointed to by linesize is set to the aligned size of each
     * channel's data buffer for planar layout, or to the aligned size of the
     * buffer for all channels for packed layout.
     *
     * The buffer in buf must be big enough to contain all the samples
     * (use av_samples_get_buffer_size() to compute its minimum size),
     * otherwise the audio_data pointers will point to invalid data.
     *
     * @see enum AVSampleFormat
     * The documentation for AVSampleFormat describes the data layout.
     *
     * @param[out] audio_data  array to be filled with the pointer for each channel
     * @param[out] linesize    calculated linesize, may be NULL
     * @param buf              the pointer to a buffer containing the samples
     * @param nb_channels      the number of channels
     * @param nb_samples       the number of samples in a single channel
     * @param sample_fmt       the sample format
     * @param align            buffer size alignment (0 = default, 1 = no alignment)
     * @return                 >=0 on success or a negative error code on failure
     * @todo return minimum size in bytes required for the buffer in case
     * of success at the next bump
     */
    int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
                               const uint8_t *buf, int nb_channels, int nb_samples,
                               enum AVSampleFormat sample_fmt, int align)
    {
        int ch, planar, buf_size, line_size;
    
        planar   = av_sample_fmt_is_planar(sample_fmt);
        buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples,
                                              sample_fmt, align);
        if (buf_size < 0)
            return buf_size;
    
        // if planar to packed
        audio_data[0] = (uint8_t *)buf;
        for (ch = 1; planar && ch < nb_channels; ch++)
            audio_data[ch] = audio_data[ch-1] + line_size;
    
        if (linesize)
            *linesize = line_size;
    
        return buf_size;
    }
    
    

    av_sample_alloc

    • brief:为指定格式的量化格式分配样本buffer,并且填充静音音频数据
    • return:负数标示失败错误码,否则成功
    /**
     * Allocate a samples buffer for nb_samples samples, and fill data pointers and
     * linesize accordingly.
     * The allocated samples buffer can be freed by using av_freep(&audio_data[0])
     * Allocated data will be initialized to silence.
     *
     * @see enum AVSampleFormat
     * The documentation for AVSampleFormat describes the data layout.
     *
     * @param[out] audio_data  array to be filled with the pointer for each channel
     * @param[out] linesize    aligned size for audio buffer(s), may be NULL
     * @param nb_channels      number of audio channels
     * @param nb_samples       number of samples per channel
     * @param align            buffer size alignment (0 = default, 1 = no alignment)
     * @return                 >=0 on success or a negative error code on failure
     * @todo return the size of the allocated buffer in case of success at the next bump
     * @see av_samples_fill_arrays()
     * @see av_samples_alloc_array_and_samples()
     */
    int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
                         int nb_samples, enum AVSampleFormat sample_fmt, int align)
    {
        uint8_t *buf;
        int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples,
                                              sample_fmt, align);
        if (size < 0)
            return size;
    
        buf = av_malloc(size);
        if (!buf)
            return AVERROR(ENOMEM);
    
        size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels,
                                      nb_samples, sample_fmt, align);
        if (size < 0) {
            av_free(buf);
            return size;
        }
    
        av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt);
    
        return size;
    }
    
    

    av_samples_alloc_array_and_samples

    • av_sample_alloc()
    /**
     * Allocate a data pointers array, samples buffer for nb_samples
     * samples, and fill data pointers and linesize accordingly.
     *
     * This is the same as av_samples_alloc(), but also allocates the data
     * pointers array.
     *
     * @see av_samples_alloc()
     */
    int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
                                           int nb_samples, enum AVSampleFormat sample_fmt, int align)
    {
        int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1;
    
        *audio_data = av_calloc(nb_planes, sizeof(**audio_data));
        if (!*audio_data)
            return AVERROR(ENOMEM);
        ret = av_samples_alloc(*audio_data, linesize, nb_channels,
                               nb_samples, sample_fmt, align);
        if (ret < 0)
            av_freep(audio_data);
        return ret;
    }
    
    

    av_samples_copy

    /**
     * Copy samples from src to dst.
     *
     * @param dst destination array of pointers to data planes
     * @param src source array of pointers to data planes
     * @param dst_offset offset in samples at which the data will be written to dst
     * @param src_offset offset in samples at which the data will be read from src
     * @param nb_samples number of samples to be copied
     * @param nb_channels number of audio channels
     * @param sample_fmt audio sample format
     */
    int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset,
                        int src_offset, int nb_samples, int nb_channels,
                        enum AVSampleFormat sample_fmt)
    {
        int planar      = av_sample_fmt_is_planar(sample_fmt);
        int planes      = planar ? nb_channels : 1;
        int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels);
        int data_size   = nb_samples * block_align;
        int i;
    
        dst_offset *= block_align;
        src_offset *= block_align;
    
        if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) {
            for (i = 0; i < planes; i++)
                memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size);
        } else {
            for (i = 0; i < planes; i++)
                memmove(dst[i] + dst_offset, src[i] + src_offset, data_size);
        }
    
        return 0;
    }
    
    

    av_samples_set_slience

    /**
     * Fill an audio buffer with silence.
     *
     * @param audio_data  array of pointers to data planes
     * @param offset      offset in samples at which to start filling
     * @param nb_samples  number of samples to fill
     * @param nb_channels number of audio channels
     * @param sample_fmt  audio sample format
     */
    int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples,
                               int nb_channels, enum AVSampleFormat sample_fmt)
    {
        int planar      = av_sample_fmt_is_planar(sample_fmt);
        int planes      = planar ? nb_channels : 1;
        int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels);
        int data_size   = nb_samples * block_align;
        int fill_char   = (sample_fmt == AV_SAMPLE_FMT_U8 ||
                         sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00;
        int i;
    
        offset *= block_align;
    
        for (i = 0; i < planes; i++)
            memset(audio_data[i] + offset, fill_char, data_size);
    
        return 0;
    }
    
    

    本文来自博客园,作者:faithlocus,转载请注明原文链接:https://www.cnblogs.com/faithlocus/p/15640737.html

  • 相关阅读:
    RTX这种东西究竟有什么价值?
    为什么必须要有需求文档这种东西?
    如何理解环境光?
    文字校对应该怎么校对?
    绑定解绑钝化活化监听器
    ServletRequestLister
    HttpSessionListener
    ServletContextListener知识点
    案例8-站内搜索功能
    案例7-用户名异步校验
  • 原文地址:https://www.cnblogs.com/faithlocus/p/15640737.html
Copyright © 2011-2022 走看看