mirror of
				https://github.com/nyanmisaka/ffmpeg-rockchip.git
				synced 2025-10-28 03:13:08 +08:00 
			
		
		
		
	 d1262262de
			
		
	
	d1262262de
	
	
	
		
			
			* commit 'cc4c24208159200b7aff5b5c313903c7f23fa345': avresample: Mark avresample_buffer() as pointer to const Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>
		
			
				
	
	
		
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			382 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
 | |
|  *
 | |
|  * 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
 | |
|  */
 | |
| 
 | |
| #include <stdint.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "libavutil/mem.h"
 | |
| #include "audio_data.h"
 | |
| 
 | |
| static const AVClass audio_data_class = {
 | |
|     .class_name = "AudioData",
 | |
|     .item_name  = av_default_item_name,
 | |
|     .version    = LIBAVUTIL_VERSION_INT,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Calculate alignment for data pointers.
 | |
|  */
 | |
| static void calc_ptr_alignment(AudioData *a)
 | |
| {
 | |
|     int p;
 | |
|     int min_align = 128;
 | |
| 
 | |
|     for (p = 0; p < a->planes; p++) {
 | |
|         int cur_align = 128;
 | |
|         while ((intptr_t)a->data[p] % cur_align)
 | |
|             cur_align >>= 1;
 | |
|         if (cur_align < min_align)
 | |
|             min_align = cur_align;
 | |
|     }
 | |
|     a->ptr_align = min_align;
 | |
| }
 | |
| 
 | |
| int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels)
 | |
| {
 | |
|     if (channels == 1)
 | |
|         return 1;
 | |
|     else
 | |
|         return av_sample_fmt_is_planar(sample_fmt);
 | |
| }
 | |
| 
 | |
| int ff_audio_data_set_channels(AudioData *a, int channels)
 | |
| {
 | |
|     if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS ||
 | |
|         channels > a->allocated_channels)
 | |
|         return AVERROR(EINVAL);
 | |
| 
 | |
|     a->channels  = channels;
 | |
|     a->planes    = a->is_planar ? channels : 1;
 | |
| 
 | |
|     calc_ptr_alignment(a);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size,
 | |
|                        int channels, int nb_samples,
 | |
|                        enum AVSampleFormat sample_fmt, int read_only,
 | |
|                        const char *name)
 | |
| {
 | |
|     int p;
 | |
| 
 | |
|     memset(a, 0, sizeof(*a));
 | |
|     a->class = &audio_data_class;
 | |
| 
 | |
|     if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) {
 | |
|         av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels);
 | |
|         return AVERROR(EINVAL);
 | |
|     }
 | |
| 
 | |
|     a->sample_size = av_get_bytes_per_sample(sample_fmt);
 | |
|     if (!a->sample_size) {
 | |
|         av_log(a, AV_LOG_ERROR, "invalid sample format\n");
 | |
|         return AVERROR(EINVAL);
 | |
|     }
 | |
|     a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
 | |
|     a->planes    = a->is_planar ? channels : 1;
 | |
|     a->stride    = a->sample_size * (a->is_planar ? 1 : channels);
 | |
| 
 | |
|     for (p = 0; p < (a->is_planar ? channels : 1); p++) {
 | |
|         if (!src[p]) {
 | |
|             av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p);
 | |
|             return AVERROR(EINVAL);
 | |
|         }
 | |
|         a->data[p] = src[p];
 | |
|     }
 | |
|     a->allocated_samples  = nb_samples * !read_only;
 | |
|     a->nb_samples         = nb_samples;
 | |
|     a->sample_fmt         = sample_fmt;
 | |
|     a->channels           = channels;
 | |
|     a->allocated_channels = channels;
 | |
|     a->read_only          = read_only;
 | |
|     a->allow_realloc      = 0;
 | |
|     a->name               = name ? name : "{no name}";
 | |
| 
 | |
|     calc_ptr_alignment(a);
 | |
|     a->samples_align = plane_size / a->stride;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| AudioData *ff_audio_data_alloc(int channels, int nb_samples,
 | |
|                                enum AVSampleFormat sample_fmt, const char *name)
 | |
| {
 | |
|     AudioData *a;
 | |
|     int ret;
 | |
| 
 | |
|     if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS)
 | |
|         return NULL;
 | |
| 
 | |
|     a = av_mallocz(sizeof(*a));
 | |
|     if (!a)
 | |
|         return NULL;
 | |
| 
 | |
|     a->sample_size = av_get_bytes_per_sample(sample_fmt);
 | |
|     if (!a->sample_size) {
 | |
|         av_free(a);
 | |
|         return NULL;
 | |
|     }
 | |
|     a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels);
 | |
|     a->planes    = a->is_planar ? channels : 1;
 | |
|     a->stride    = a->sample_size * (a->is_planar ? 1 : channels);
 | |
| 
 | |
|     a->class              = &audio_data_class;
 | |
|     a->sample_fmt         = sample_fmt;
 | |
|     a->channels           = channels;
 | |
|     a->allocated_channels = channels;
 | |
|     a->read_only          = 0;
 | |
|     a->allow_realloc      = 1;
 | |
|     a->name               = name ? name : "{no name}";
 | |
| 
 | |
|     if (nb_samples > 0) {
 | |
|         ret = ff_audio_data_realloc(a, nb_samples);
 | |
|         if (ret < 0) {
 | |
|             av_free(a);
 | |
|             return NULL;
 | |
|         }
 | |
|         return a;
 | |
|     } else {
 | |
|         calc_ptr_alignment(a);
 | |
|         return a;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int ff_audio_data_realloc(AudioData *a, int nb_samples)
 | |
| {
 | |
|     int ret, new_buf_size, plane_size, p;
 | |
| 
 | |
|     /* check if buffer is already large enough */
 | |
|     if (a->allocated_samples >= nb_samples)
 | |
|         return 0;
 | |
| 
 | |
|     /* validate that the output is not read-only and realloc is allowed */
 | |
|     if (a->read_only || !a->allow_realloc)
 | |
|         return AVERROR(EINVAL);
 | |
| 
 | |
|     new_buf_size = av_samples_get_buffer_size(&plane_size,
 | |
|                                               a->allocated_channels, nb_samples,
 | |
|                                               a->sample_fmt, 0);
 | |
|     if (new_buf_size < 0)
 | |
|         return new_buf_size;
 | |
| 
 | |
|     /* if there is already data in the buffer and the sample format is planar,
 | |
|        allocate a new buffer and copy the data, otherwise just realloc the
 | |
|        internal buffer and set new data pointers */
 | |
|     if (a->nb_samples > 0 && a->is_planar) {
 | |
|         uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL };
 | |
| 
 | |
|         ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels,
 | |
|                                nb_samples, a->sample_fmt, 0);
 | |
|         if (ret < 0)
 | |
|             return ret;
 | |
| 
 | |
|         for (p = 0; p < a->planes; p++)
 | |
|             memcpy(new_data[p], a->data[p], a->nb_samples * a->stride);
 | |
| 
 | |
|         av_freep(&a->buffer);
 | |
|         memcpy(a->data, new_data, sizeof(new_data));
 | |
|         a->buffer = a->data[0];
 | |
|     } else {
 | |
|         av_freep(&a->buffer);
 | |
|         a->buffer = av_malloc(new_buf_size);
 | |
|         if (!a->buffer)
 | |
|             return AVERROR(ENOMEM);
 | |
|         ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer,
 | |
|                                      a->allocated_channels, nb_samples,
 | |
|                                      a->sample_fmt, 0);
 | |
|         if (ret < 0)
 | |
|             return ret;
 | |
|     }
 | |
|     a->buffer_size       = new_buf_size;
 | |
|     a->allocated_samples = nb_samples;
 | |
| 
 | |
|     calc_ptr_alignment(a);
 | |
|     a->samples_align = plane_size / a->stride;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| void ff_audio_data_free(AudioData **a)
 | |
| {
 | |
|     if (!*a)
 | |
|         return;
 | |
|     av_free((*a)->buffer);
 | |
|     av_freep(a);
 | |
| }
 | |
| 
 | |
| int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map)
 | |
| {
 | |
|     int ret, p;
 | |
| 
 | |
|     /* validate input/output compatibility */
 | |
|     if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels)
 | |
|         return AVERROR(EINVAL);
 | |
| 
 | |
|     if (map && !src->is_planar) {
 | |
|         av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n");
 | |
|         return AVERROR(EINVAL);
 | |
|     }
 | |
| 
 | |
|     /* if the input is empty, just empty the output */
 | |
|     if (!src->nb_samples) {
 | |
|         dst->nb_samples = 0;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     /* reallocate output if necessary */
 | |
|     ret = ff_audio_data_realloc(dst, src->nb_samples);
 | |
|     if (ret < 0)
 | |
|         return ret;
 | |
| 
 | |
|     /* copy data */
 | |
|     if (map) {
 | |
|         if (map->do_remap) {
 | |
|             for (p = 0; p < src->planes; p++) {
 | |
|                 if (map->channel_map[p] >= 0)
 | |
|                     memcpy(dst->data[p], src->data[map->channel_map[p]],
 | |
|                            src->nb_samples * src->stride);
 | |
|             }
 | |
|         }
 | |
|         if (map->do_copy || map->do_zero) {
 | |
|             for (p = 0; p < src->planes; p++) {
 | |
|                 if (map->channel_copy[p])
 | |
|                     memcpy(dst->data[p], dst->data[map->channel_copy[p]],
 | |
|                            src->nb_samples * src->stride);
 | |
|                 else if (map->channel_zero[p])
 | |
|                     av_samples_set_silence(&dst->data[p], 0, src->nb_samples,
 | |
|                                            1, dst->sample_fmt);
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         for (p = 0; p < src->planes; p++)
 | |
|             memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride);
 | |
|     }
 | |
| 
 | |
|     dst->nb_samples = src->nb_samples;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src,
 | |
|                           int src_offset, int nb_samples)
 | |
| {
 | |
|     int ret, p, dst_offset2, dst_move_size;
 | |
| 
 | |
|     /* validate input/output compatibility */
 | |
|     if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) {
 | |
|         av_log(src, AV_LOG_ERROR, "sample format mismatch\n");
 | |
|         return AVERROR(EINVAL);
 | |
|     }
 | |
| 
 | |
|     /* validate offsets are within the buffer bounds */
 | |
|     if (dst_offset < 0 || dst_offset > dst->nb_samples ||
 | |
|         src_offset < 0 || src_offset > src->nb_samples) {
 | |
|         av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n",
 | |
|                src_offset, dst_offset);
 | |
|         return AVERROR(EINVAL);
 | |
|     }
 | |
| 
 | |
|     /* check offsets and sizes to see if we can just do nothing and return */
 | |
|     if (nb_samples > src->nb_samples - src_offset)
 | |
|         nb_samples = src->nb_samples - src_offset;
 | |
|     if (nb_samples <= 0)
 | |
|         return 0;
 | |
| 
 | |
|     /* validate that the output is not read-only */
 | |
|     if (dst->read_only) {
 | |
|         av_log(dst, AV_LOG_ERROR, "dst is read-only\n");
 | |
|         return AVERROR(EINVAL);
 | |
|     }
 | |
| 
 | |
|     /* reallocate output if necessary */
 | |
|     ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples);
 | |
|     if (ret < 0) {
 | |
|         av_log(dst, AV_LOG_ERROR, "error reallocating dst\n");
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     dst_offset2   = dst_offset + nb_samples;
 | |
|     dst_move_size = dst->nb_samples - dst_offset;
 | |
| 
 | |
|     for (p = 0; p < src->planes; p++) {
 | |
|         if (dst_move_size > 0) {
 | |
|             memmove(dst->data[p] + dst_offset2 * dst->stride,
 | |
|                     dst->data[p] + dst_offset  * dst->stride,
 | |
|                     dst_move_size * dst->stride);
 | |
|         }
 | |
|         memcpy(dst->data[p] + dst_offset * dst->stride,
 | |
|                src->data[p] + src_offset * src->stride,
 | |
|                nb_samples * src->stride);
 | |
|     }
 | |
|     dst->nb_samples += nb_samples;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| void ff_audio_data_drain(AudioData *a, int nb_samples)
 | |
| {
 | |
|     if (a->nb_samples <= nb_samples) {
 | |
|         /* drain the whole buffer */
 | |
|         a->nb_samples = 0;
 | |
|     } else {
 | |
|         int p;
 | |
|         int move_offset = a->stride * nb_samples;
 | |
|         int move_size   = a->stride * (a->nb_samples - nb_samples);
 | |
| 
 | |
|         for (p = 0; p < a->planes; p++)
 | |
|             memmove(a->data[p], a->data[p] + move_offset, move_size);
 | |
| 
 | |
|         a->nb_samples -= nb_samples;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset,
 | |
|                               int nb_samples)
 | |
| {
 | |
|     uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS];
 | |
|     int offset_size, p;
 | |
| 
 | |
|     if (offset >= a->nb_samples)
 | |
|         return 0;
 | |
|     offset_size = offset * a->stride;
 | |
|     for (p = 0; p < a->planes; p++)
 | |
|         offset_data[p] = a->data[p] + offset_size;
 | |
| 
 | |
|     return av_audio_fifo_write(af, (void **)offset_data, nb_samples);
 | |
| }
 | |
| 
 | |
| int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples)
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     if (a->read_only)
 | |
|         return AVERROR(EINVAL);
 | |
| 
 | |
|     ret = ff_audio_data_realloc(a, nb_samples);
 | |
|     if (ret < 0)
 | |
|         return ret;
 | |
| 
 | |
|     ret = av_audio_fifo_read(af, (void **)a->data, nb_samples);
 | |
|     if (ret >= 0)
 | |
|         a->nb_samples = ret;
 | |
|     return ret;
 | |
| }
 |