diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index f12ca3a097..5973e6b248 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -57,6 +57,7 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask) return NULL; } *ret->video = *ref->video; + ret->extended_data = ret->data; } else if (ref->type == AVMEDIA_TYPE_AUDIO) { ret->audio = av_malloc(sizeof(AVFilterBufferRefAudioProps)); if (!ret->audio) { @@ -64,6 +65,19 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask) return NULL; } *ret->audio = *ref->audio; + + if (ref->extended_data != ref->data) { + int nb_channels = av_get_channel_layout_nb_channels(ref->audio->channel_layout); + if (!(ret->extended_data = av_malloc(sizeof(*ret->extended_data) * + nb_channels))) { + av_freep(&ret->audio); + av_freep(&ret); + return NULL; + } + memcpy(ret->extended_data, ref->extended_data, + sizeof(*ret->extended_data) * nb_channels); + } else + ret->extended_data = ret->data; } ret->perms &= pmask; ret->buf->refcount ++; @@ -76,6 +90,8 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref) return; if (!(--ref->buf->refcount)) ref->buf->free(ref->buf); + if (ref->extended_data != ref->data) + av_freep(&ref->extended_data); av_free(ref->video); av_free(ref->audio); av_free(ref); @@ -338,6 +354,9 @@ avfilter_get_video_buffer_ref_from_arrays(uint8_t *data[4], int linesize[4], int memcpy(picref->data, pic->data, sizeof(picref->data)); memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize)); + pic-> extended_data = pic->data; + picref->extended_data = picref->data; + return picref; fail: @@ -710,6 +729,8 @@ int avfilter_copy_frame_props(AVFilterBufferRef *dst, const AVFrame *src) int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src) { + int planes, nb_channels; + memcpy(dst->data, src->data, sizeof(dst->data)); memcpy(dst->linesize, src->linesize, sizeof(dst->linesize)); @@ -727,6 +748,18 @@ int avfilter_copy_buf_props(AVFrame *dst, const AVFilterBufferRef *src) dst->pict_type = src->video->pict_type; break; case AVMEDIA_TYPE_AUDIO: + nb_channels = av_get_channel_layout_nb_channels(src->audio->channel_layout); + planes = av_sample_fmt_is_planar(src->format) ? nb_channels : 1; + + if (planes > FF_ARRAY_ELEMS(dst->data)) { + dst->extended_data = av_mallocz(planes * sizeof(*dst->extended_data)); + if (!dst->extended_data) + return AVERROR(ENOMEM); + memcpy(dst->extended_data, src->extended_data, + planes * sizeof(dst->extended_data)); + } else + dst->extended_data = dst->data; + dst->sample_rate = src->audio->sample_rate; dst->channel_layout = src->audio->channel_layout; dst->nb_samples = src->audio->nb_samples; diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index ef61a5da6a..8965094b19 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -76,6 +76,22 @@ typedef struct AVFilterBuffer { int format; ///< media format int w, h; ///< width and height of the allocated buffer + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data will always be set, but for planar + * audio with more channels that can fit in data, extended_data must be used + * in order to access all channels. + */ + uint8_t **extended_data; } AVFilterBuffer; #define AV_PERM_READ 0x01 ///< can read from the buffer @@ -140,6 +156,22 @@ typedef struct AVFilterBufferRef { enum AVMediaType type; ///< media type of buffer data AVFilterBufferRefVideoProps *video; ///< video buffer specific properties AVFilterBufferRefAudioProps *audio; ///< audio buffer specific properties + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data will always be set, but for planar + * audio with more channels that can fit in data, extended_data must be used + * in order to access all channels. + */ + uint8_t **extended_data; } AVFilterBufferRef; /** diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c index 6d9003de37..086fcc0b4c 100644 --- a/libavfilter/defaults.c +++ b/libavfilter/defaults.c @@ -28,6 +28,8 @@ /* TODO: buffer pool. see comment for avfilter_default_get_video_buffer() */ void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr) { + if (ptr->extended_data != ptr->data) + av_freep(&ptr->extended_data); av_free(ptr->data[0]); av_free(ptr); }