You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	lavfi: use a video frame pool for each link of the filtergraph
This commit is contained in:
		| @@ -17,6 +17,7 @@ OBJS = allfilters.o                                                     \ | ||||
|        drawutils.o                                                      \ | ||||
|        fifo.o                                                           \ | ||||
|        formats.o                                                        \ | ||||
|        framepool.o                                                      \ | ||||
|        graphdump.o                                                      \ | ||||
|        graphparser.o                                                    \ | ||||
|        opencl_allkernels.o                                              \ | ||||
|   | ||||
| @@ -168,6 +168,7 @@ void avfilter_link_free(AVFilterLink **link) | ||||
|         return; | ||||
|  | ||||
|     av_frame_free(&(*link)->partial_buf); | ||||
|     ff_video_frame_pool_uninit((FFVideoFramePool**)&(*link)->video_frame_pool); | ||||
|  | ||||
|     av_freep(link); | ||||
| } | ||||
|   | ||||
| @@ -509,6 +509,11 @@ struct AVFilterLink { | ||||
|      * Number of past frames sent through the link. | ||||
|      */ | ||||
|     int64_t frame_count; | ||||
|  | ||||
|     /** | ||||
|      * A pointer to a FFVideoFramePool struct. | ||||
|      */ | ||||
|     void *video_frame_pool; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|   | ||||
							
								
								
									
										189
									
								
								libavfilter/framepool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								libavfilter/framepool.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| /* | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com> | ||||
|  * | ||||
|  * 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 "framepool.h" | ||||
| #include "libavutil/avassert.h" | ||||
| #include "libavutil/buffer.h" | ||||
| #include "libavutil/frame.h" | ||||
| #include "libavutil/imgutils.h" | ||||
| #include "libavutil/mem.h" | ||||
| #include "libavutil/pixfmt.h" | ||||
|  | ||||
| struct FFVideoFramePool { | ||||
|  | ||||
|     int width; | ||||
|     int height; | ||||
|     int format; | ||||
|     int align; | ||||
|     int linesize[4]; | ||||
|     AVBufferPool *pools[4]; | ||||
|  | ||||
| }; | ||||
|  | ||||
| FFVideoFramePool *ff_video_frame_pool_init(AVBufferRef* (*alloc)(int size), | ||||
|                                            int width, | ||||
|                                            int height, | ||||
|                                            enum AVPixelFormat format, | ||||
|                                            int align) | ||||
| { | ||||
|     int i, ret; | ||||
|     FFVideoFramePool *pool; | ||||
|     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); | ||||
|  | ||||
|     if (!desc) | ||||
|         return NULL; | ||||
|  | ||||
|     pool = av_mallocz(sizeof(FFVideoFramePool)); | ||||
|     if (!pool) | ||||
|         return NULL; | ||||
|  | ||||
|     pool->width = width; | ||||
|     pool->height = height; | ||||
|     pool->format = format; | ||||
|     pool->align = align; | ||||
|  | ||||
|     if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) { | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     if (!pool->linesize[0]) { | ||||
|         for(i = 1; i <= align; i += i) { | ||||
|             ret = av_image_fill_linesizes(pool->linesize, pool->format, | ||||
|                                           FFALIGN(pool->width, i)); | ||||
|             if (ret < 0) { | ||||
|                 goto fail; | ||||
|             } | ||||
|             if (!(pool->linesize[0] & (pool->align - 1))) | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         for (i = 0; i < 4 && pool->linesize[i]; i++) { | ||||
|             pool->linesize[i] = FFALIGN(pool->linesize[i], pool->align); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     for (i = 0; i < 4 && pool->linesize[i]; i++) { | ||||
|         int h = FFALIGN(pool->height, 32); | ||||
|         if (i == 1 || i == 2) | ||||
|             h = FF_CEIL_RSHIFT(h, desc->log2_chroma_h); | ||||
|  | ||||
|         pool->pools[i] = av_buffer_pool_init(pool->linesize[i] * h + 16 + 16 - 1, | ||||
|                                              alloc); | ||||
|         if (!pool->pools[i]) | ||||
|             goto fail; | ||||
|     } | ||||
|  | ||||
|     if (desc->flags & AV_PIX_FMT_FLAG_PAL || | ||||
|         desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { | ||||
|         pool->pools[1] = av_buffer_pool_init(AVPALETTE_SIZE, alloc); | ||||
|         if (!pool->pools[1]) | ||||
|             goto fail; | ||||
|     } | ||||
|  | ||||
|     return pool; | ||||
|  | ||||
| fail: | ||||
|     ff_video_frame_pool_uninit(&pool); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| int ff_video_frame_pool_get_config(FFVideoFramePool *pool, | ||||
|                                    int *width, | ||||
|                                    int *height, | ||||
|                                    enum AVPixelFormat *format, | ||||
|                                    int *align) | ||||
| { | ||||
|     if (!pool) | ||||
|         return AVERROR(EINVAL); | ||||
|  | ||||
|     *width = pool->width; | ||||
|     *height = pool->height; | ||||
|     *format = pool->format; | ||||
|     *align = pool->align; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| AVFrame *ff_video_frame_pool_get(FFVideoFramePool *pool) | ||||
| { | ||||
|     int i; | ||||
|     AVFrame *frame; | ||||
|     const AVPixFmtDescriptor *desc; | ||||
|  | ||||
|     frame = av_frame_alloc(); | ||||
|     if (!frame) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     desc = av_pix_fmt_desc_get(pool->format); | ||||
|     if (!desc) { | ||||
|         goto fail; | ||||
|     } | ||||
|  | ||||
|     frame->width = pool->width; | ||||
|     frame->height = pool->height; | ||||
|     frame->format = pool->format; | ||||
|  | ||||
|     for (i = 0; i < 4; i++) { | ||||
|         frame->linesize[i] = pool->linesize[i]; | ||||
|         if (!pool->pools[i]) | ||||
|             break; | ||||
|  | ||||
|         frame->buf[i] = av_buffer_pool_get(pool->pools[i]); | ||||
|         if (!frame->buf[i]) { | ||||
|             goto fail; | ||||
|         } | ||||
|  | ||||
|         frame->data[i] = frame->buf[i]->data; | ||||
|     } | ||||
|  | ||||
|     if (desc->flags & AV_PIX_FMT_FLAG_PAL || | ||||
|         desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { | ||||
|         enum AVPixelFormat format = | ||||
|             pool->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : pool->format; | ||||
|  | ||||
|         av_assert0(frame->data[1] != NULL); | ||||
|         if (avpriv_set_systematic_pal2((uint32_t *)frame->data[1], format) < 0) { | ||||
|             goto fail; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     frame->extended_data = frame->data; | ||||
|  | ||||
|     return frame; | ||||
| fail: | ||||
|     av_frame_free(&frame); | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| void ff_video_frame_pool_uninit(FFVideoFramePool **pool) | ||||
| { | ||||
|     int i; | ||||
|  | ||||
|     if (!pool || !*pool) | ||||
|         return; | ||||
|  | ||||
|     for (i = 0; i < 4; i++) { | ||||
|         av_buffer_pool_uninit(&(*pool)->pools[i]); | ||||
|     } | ||||
|  | ||||
|     av_freep(pool); | ||||
| } | ||||
							
								
								
									
										84
									
								
								libavfilter/framepool.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								libavfilter/framepool.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com> | ||||
|  * | ||||
|  * 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 | ||||
|  */ | ||||
|  | ||||
| #ifndef AVUTIL_FRAME_POOL_H | ||||
| #define AVUTIL_FRAME_POOL_H | ||||
|  | ||||
| #include "libavutil/buffer.h" | ||||
| #include "libavutil/frame.h" | ||||
|  | ||||
| /** | ||||
|  * Video frame pool. This structure is opaque and not meant to be accessed | ||||
|  * directly. It is allocated with ff_video_frame_pool_init() and freed with | ||||
|  * ff_video_frame_pool_uninit(). | ||||
|  */ | ||||
| typedef struct FFVideoFramePool FFVideoFramePool; | ||||
|  | ||||
| /** | ||||
|  * Allocate and initialize a video frame pool. | ||||
|  * | ||||
|  * @param alloc a function that will be used to allocate new frame buffers when | ||||
|  * the pool is empty. May be NULL, then the default allocator will be used | ||||
|  * (av_buffer_alloc()). | ||||
|  * @param width width of each frame in this pool | ||||
|  * @param height height of each frame in this pool | ||||
|  * @param format format of each frame in this pool | ||||
|  * @param align buffers alignement of each frame in this pool | ||||
|  * @return newly created video frame pool on success, NULL on error. | ||||
|  */ | ||||
| FFVideoFramePool *ff_video_frame_pool_init(AVBufferRef* (*alloc)(int size), | ||||
|                                            int width, | ||||
|                                            int height, | ||||
|                                            enum AVPixelFormat format, | ||||
|                                            int align); | ||||
|  | ||||
| /** | ||||
|  * Deallocate the video frame pool. It is safe to call this function while | ||||
|  * some of the allocated video frame are still in use. | ||||
|  * | ||||
|  * @param pool pointer to the video frame pool to be freed. It will be set to NULL. | ||||
|  */ | ||||
| void ff_video_frame_pool_uninit(FFVideoFramePool **pool); | ||||
|  | ||||
| /** | ||||
|  * Get the video frame pool configuration. | ||||
|  * | ||||
|  * @param width width of each frame in this pool | ||||
|  * @param height height of each frame in this pool | ||||
|  * @param format format of each frame in this pool | ||||
|  * @param align buffers alignement of each frame in this pool | ||||
|  * @return 0 on success, a negative AVERROR otherwise. | ||||
|  */ | ||||
| int ff_video_frame_pool_get_config(FFVideoFramePool *pool, | ||||
|                                    int *width, | ||||
|                                    int *height, | ||||
|                                    enum AVPixelFormat *format, | ||||
|                                    int *align); | ||||
|  | ||||
| /** | ||||
|  * Allocate a new AVFrame, reussing old buffers from the pool when available. | ||||
|  * This function may be called simultaneously from multiple threads. | ||||
|  * | ||||
|  * @return a new AVFrame on success, NULL on error. | ||||
|  */ | ||||
| AVFrame *ff_video_frame_pool_get(FFVideoFramePool *pool); | ||||
|  | ||||
|  | ||||
| #endif /* AVUTIL_FRAME_POOL_H */ | ||||
| @@ -28,6 +28,7 @@ | ||||
| #include "avfilter.h" | ||||
| #include "avfiltergraph.h" | ||||
| #include "formats.h" | ||||
| #include "framepool.h" | ||||
| #include "thread.h" | ||||
| #include "version.h" | ||||
| #include "video.h" | ||||
|   | ||||
| @@ -32,31 +32,45 @@ | ||||
| #include "internal.h" | ||||
| #include "video.h" | ||||
|  | ||||
| #define BUFFER_ALIGN 32 | ||||
|  | ||||
|  | ||||
| AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h) | ||||
| { | ||||
|     return ff_get_video_buffer(link->dst->outputs[0], w, h); | ||||
| } | ||||
|  | ||||
| /* TODO: set the buffer's priv member to a context structure for the whole | ||||
|  * filter chain.  This will allow for a buffer pool instead of the constant | ||||
|  * alloc & free cycle currently implemented. */ | ||||
| AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h) | ||||
| { | ||||
|     AVFrame *frame = av_frame_alloc(); | ||||
|     int ret; | ||||
|     int pool_width = 0; | ||||
|     int pool_height = 0; | ||||
|     int pool_align = 0; | ||||
|     enum AVPixelFormat pool_format = AV_PIX_FMT_NONE; | ||||
|  | ||||
|     if (!frame) | ||||
|         return NULL; | ||||
|     if (!link->video_frame_pool) { | ||||
|         link->video_frame_pool = ff_video_frame_pool_init(av_buffer_allocz, w, h, | ||||
|                                                           link->format, BUFFER_ALIGN); | ||||
|         if (!link->video_frame_pool) | ||||
|             return NULL; | ||||
|     } else { | ||||
|         if (ff_video_frame_pool_get_config(link->video_frame_pool, | ||||
|                                            &pool_width, &pool_height, | ||||
|                                            &pool_format, &pool_align) < 0) { | ||||
|             return NULL; | ||||
|         } | ||||
|  | ||||
|     frame->width  = w; | ||||
|     frame->height = h; | ||||
|     frame->format = link->format; | ||||
|         if (pool_width != w || pool_height != h || | ||||
|             pool_format != link->format || pool_align != BUFFER_ALIGN) { | ||||
|  | ||||
|     ret = av_frame_get_buffer(frame, 32); | ||||
|     if (ret < 0) | ||||
|         av_frame_free(&frame); | ||||
|             ff_video_frame_pool_uninit((FFVideoFramePool **)&link->video_frame_pool); | ||||
|             link->video_frame_pool = ff_video_frame_pool_init(av_buffer_allocz, w, h, | ||||
|                                                               link->format, BUFFER_ALIGN); | ||||
|             if (!link->video_frame_pool) | ||||
|                 return NULL; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return frame; | ||||
|     return ff_video_frame_pool_get(link->video_frame_pool); | ||||
| } | ||||
|  | ||||
| AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user