1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * The default get_buffer2() implementation
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include <stdint.h>
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
24cabdff1aSopenharmony_ci#include "libavutil/avutil.h"
25cabdff1aSopenharmony_ci#include "libavutil/buffer.h"
26cabdff1aSopenharmony_ci#include "libavutil/frame.h"
27cabdff1aSopenharmony_ci#include "libavutil/hwcontext.h"
28cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
29cabdff1aSopenharmony_ci#include "libavutil/mem.h"
30cabdff1aSopenharmony_ci#include "libavutil/samplefmt.h"
31cabdff1aSopenharmony_ci#include "libavutil/version.h"
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_ci#include "avcodec.h"
34cabdff1aSopenharmony_ci#include "internal.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_citypedef struct FramePool {
37cabdff1aSopenharmony_ci    /**
38cabdff1aSopenharmony_ci     * Pools for each data plane. For audio all the planes have the same size,
39cabdff1aSopenharmony_ci     * so only pools[0] is used.
40cabdff1aSopenharmony_ci     */
41cabdff1aSopenharmony_ci    AVBufferPool *pools[4];
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_ci    /*
44cabdff1aSopenharmony_ci     * Pool parameters
45cabdff1aSopenharmony_ci     */
46cabdff1aSopenharmony_ci    int format;
47cabdff1aSopenharmony_ci    int width, height;
48cabdff1aSopenharmony_ci    int stride_align[AV_NUM_DATA_POINTERS];
49cabdff1aSopenharmony_ci    int linesize[4];
50cabdff1aSopenharmony_ci    int planes;
51cabdff1aSopenharmony_ci    int channels;
52cabdff1aSopenharmony_ci    int samples;
53cabdff1aSopenharmony_ci} FramePool;
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_cistatic void frame_pool_free(void *opaque, uint8_t *data)
56cabdff1aSopenharmony_ci{
57cabdff1aSopenharmony_ci    FramePool *pool = (FramePool*)data;
58cabdff1aSopenharmony_ci    int i;
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
61cabdff1aSopenharmony_ci        av_buffer_pool_uninit(&pool->pools[i]);
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_ci    av_freep(&data);
64cabdff1aSopenharmony_ci}
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_cistatic AVBufferRef *frame_pool_alloc(void)
67cabdff1aSopenharmony_ci{
68cabdff1aSopenharmony_ci    FramePool *pool = av_mallocz(sizeof(*pool));
69cabdff1aSopenharmony_ci    AVBufferRef *buf;
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    if (!pool)
72cabdff1aSopenharmony_ci        return NULL;
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    buf = av_buffer_create((uint8_t*)pool, sizeof(*pool),
75cabdff1aSopenharmony_ci                           frame_pool_free, NULL, 0);
76cabdff1aSopenharmony_ci    if (!buf) {
77cabdff1aSopenharmony_ci        av_freep(&pool);
78cabdff1aSopenharmony_ci        return NULL;
79cabdff1aSopenharmony_ci    }
80cabdff1aSopenharmony_ci
81cabdff1aSopenharmony_ci    return buf;
82cabdff1aSopenharmony_ci}
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_cistatic int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
85cabdff1aSopenharmony_ci{
86cabdff1aSopenharmony_ci    FramePool *pool = avctx->internal->pool ?
87cabdff1aSopenharmony_ci                      (FramePool*)avctx->internal->pool->data : NULL;
88cabdff1aSopenharmony_ci    AVBufferRef *pool_buf;
89cabdff1aSopenharmony_ci    int i, ret, ch, planes;
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
92cabdff1aSopenharmony_ci        int planar = av_sample_fmt_is_planar(frame->format);
93cabdff1aSopenharmony_ci        ch     = frame->ch_layout.nb_channels;
94cabdff1aSopenharmony_ci#if FF_API_OLD_CHANNEL_LAYOUT
95cabdff1aSopenharmony_ciFF_DISABLE_DEPRECATION_WARNINGS
96cabdff1aSopenharmony_ci        if (!ch)
97cabdff1aSopenharmony_ci            ch = frame->channels;
98cabdff1aSopenharmony_ciFF_ENABLE_DEPRECATION_WARNINGS
99cabdff1aSopenharmony_ci#endif
100cabdff1aSopenharmony_ci        planes = planar ? ch : 1;
101cabdff1aSopenharmony_ci    }
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_ci    if (pool && pool->format == frame->format) {
104cabdff1aSopenharmony_ci        if (avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
105cabdff1aSopenharmony_ci            pool->width == frame->width && pool->height == frame->height)
106cabdff1aSopenharmony_ci            return 0;
107cabdff1aSopenharmony_ci        if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && pool->planes == planes &&
108cabdff1aSopenharmony_ci            pool->channels == ch && frame->nb_samples == pool->samples)
109cabdff1aSopenharmony_ci            return 0;
110cabdff1aSopenharmony_ci    }
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    pool_buf = frame_pool_alloc();
113cabdff1aSopenharmony_ci    if (!pool_buf)
114cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
115cabdff1aSopenharmony_ci    pool = (FramePool*)pool_buf->data;
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    switch (avctx->codec_type) {
118cabdff1aSopenharmony_ci    case AVMEDIA_TYPE_VIDEO: {
119cabdff1aSopenharmony_ci        int linesize[4];
120cabdff1aSopenharmony_ci        int w = frame->width;
121cabdff1aSopenharmony_ci        int h = frame->height;
122cabdff1aSopenharmony_ci        int unaligned;
123cabdff1aSopenharmony_ci        ptrdiff_t linesize1[4];
124cabdff1aSopenharmony_ci        size_t size[4];
125cabdff1aSopenharmony_ci
126cabdff1aSopenharmony_ci        avcodec_align_dimensions2(avctx, &w, &h, pool->stride_align);
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci        do {
129cabdff1aSopenharmony_ci            // NOTE: do not align linesizes individually, this breaks e.g. assumptions
130cabdff1aSopenharmony_ci            // that linesize[0] == 2*linesize[1] in the MPEG-encoder for 4:2:2
131cabdff1aSopenharmony_ci            ret = av_image_fill_linesizes(linesize, avctx->pix_fmt, w);
132cabdff1aSopenharmony_ci            if (ret < 0)
133cabdff1aSopenharmony_ci                goto fail;
134cabdff1aSopenharmony_ci            // increase alignment of w for next try (rhs gives the lowest bit set in w)
135cabdff1aSopenharmony_ci            w += w & ~(w - 1);
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_ci            unaligned = 0;
138cabdff1aSopenharmony_ci            for (i = 0; i < 4; i++)
139cabdff1aSopenharmony_ci                unaligned |= linesize[i] % pool->stride_align[i];
140cabdff1aSopenharmony_ci        } while (unaligned);
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci        for (i = 0; i < 4; i++)
143cabdff1aSopenharmony_ci            linesize1[i] = linesize[i];
144cabdff1aSopenharmony_ci        ret = av_image_fill_plane_sizes(size, avctx->pix_fmt, h, linesize1);
145cabdff1aSopenharmony_ci        if (ret < 0)
146cabdff1aSopenharmony_ci            goto fail;
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci        for (i = 0; i < 4; i++) {
149cabdff1aSopenharmony_ci            pool->linesize[i] = linesize[i];
150cabdff1aSopenharmony_ci            if (size[i]) {
151cabdff1aSopenharmony_ci                if (size[i] > INT_MAX - (16 + STRIDE_ALIGN - 1)) {
152cabdff1aSopenharmony_ci                    ret = AVERROR(EINVAL);
153cabdff1aSopenharmony_ci                    goto fail;
154cabdff1aSopenharmony_ci                }
155cabdff1aSopenharmony_ci                pool->pools[i] = av_buffer_pool_init(size[i] + 16 + STRIDE_ALIGN - 1,
156cabdff1aSopenharmony_ci                                                     CONFIG_MEMORY_POISONING ?
157cabdff1aSopenharmony_ci                                                        NULL :
158cabdff1aSopenharmony_ci                                                        av_buffer_allocz);
159cabdff1aSopenharmony_ci                if (!pool->pools[i]) {
160cabdff1aSopenharmony_ci                    ret = AVERROR(ENOMEM);
161cabdff1aSopenharmony_ci                    goto fail;
162cabdff1aSopenharmony_ci                }
163cabdff1aSopenharmony_ci            }
164cabdff1aSopenharmony_ci        }
165cabdff1aSopenharmony_ci        pool->format = frame->format;
166cabdff1aSopenharmony_ci        pool->width  = frame->width;
167cabdff1aSopenharmony_ci        pool->height = frame->height;
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci        break;
170cabdff1aSopenharmony_ci        }
171cabdff1aSopenharmony_ci    case AVMEDIA_TYPE_AUDIO: {
172cabdff1aSopenharmony_ci        ret = av_samples_get_buffer_size(&pool->linesize[0], ch,
173cabdff1aSopenharmony_ci                                         frame->nb_samples, frame->format, 0);
174cabdff1aSopenharmony_ci        if (ret < 0)
175cabdff1aSopenharmony_ci            goto fail;
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci        pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL);
178cabdff1aSopenharmony_ci        if (!pool->pools[0]) {
179cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
180cabdff1aSopenharmony_ci            goto fail;
181cabdff1aSopenharmony_ci        }
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci        pool->format     = frame->format;
184cabdff1aSopenharmony_ci        pool->planes     = planes;
185cabdff1aSopenharmony_ci        pool->channels   = ch;
186cabdff1aSopenharmony_ci        pool->samples = frame->nb_samples;
187cabdff1aSopenharmony_ci        break;
188cabdff1aSopenharmony_ci        }
189cabdff1aSopenharmony_ci    default: av_assert0(0);
190cabdff1aSopenharmony_ci    }
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci    av_buffer_unref(&avctx->internal->pool);
193cabdff1aSopenharmony_ci    avctx->internal->pool = pool_buf;
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    return 0;
196cabdff1aSopenharmony_cifail:
197cabdff1aSopenharmony_ci    av_buffer_unref(&pool_buf);
198cabdff1aSopenharmony_ci    return ret;
199cabdff1aSopenharmony_ci}
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_cistatic int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
202cabdff1aSopenharmony_ci{
203cabdff1aSopenharmony_ci    FramePool *pool = (FramePool*)avctx->internal->pool->data;
204cabdff1aSopenharmony_ci    int planes = pool->planes;
205cabdff1aSopenharmony_ci    int i;
206cabdff1aSopenharmony_ci
207cabdff1aSopenharmony_ci    frame->linesize[0] = pool->linesize[0];
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    if (planes > AV_NUM_DATA_POINTERS) {
210cabdff1aSopenharmony_ci        frame->extended_data = av_calloc(planes, sizeof(*frame->extended_data));
211cabdff1aSopenharmony_ci        frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS;
212cabdff1aSopenharmony_ci        frame->extended_buf  = av_calloc(frame->nb_extended_buf,
213cabdff1aSopenharmony_ci                                          sizeof(*frame->extended_buf));
214cabdff1aSopenharmony_ci        if (!frame->extended_data || !frame->extended_buf) {
215cabdff1aSopenharmony_ci            av_freep(&frame->extended_data);
216cabdff1aSopenharmony_ci            av_freep(&frame->extended_buf);
217cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
218cabdff1aSopenharmony_ci        }
219cabdff1aSopenharmony_ci    } else {
220cabdff1aSopenharmony_ci        frame->extended_data = frame->data;
221cabdff1aSopenharmony_ci        av_assert0(frame->nb_extended_buf == 0);
222cabdff1aSopenharmony_ci    }
223cabdff1aSopenharmony_ci
224cabdff1aSopenharmony_ci    for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) {
225cabdff1aSopenharmony_ci        frame->buf[i] = av_buffer_pool_get(pool->pools[0]);
226cabdff1aSopenharmony_ci        if (!frame->buf[i])
227cabdff1aSopenharmony_ci            goto fail;
228cabdff1aSopenharmony_ci        frame->extended_data[i] = frame->data[i] = frame->buf[i]->data;
229cabdff1aSopenharmony_ci    }
230cabdff1aSopenharmony_ci    for (i = 0; i < frame->nb_extended_buf; i++) {
231cabdff1aSopenharmony_ci        frame->extended_buf[i] = av_buffer_pool_get(pool->pools[0]);
232cabdff1aSopenharmony_ci        if (!frame->extended_buf[i])
233cabdff1aSopenharmony_ci            goto fail;
234cabdff1aSopenharmony_ci        frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data;
235cabdff1aSopenharmony_ci    }
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci    if (avctx->debug & FF_DEBUG_BUFFERS)
238cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "default_get_buffer called on frame %p", frame);
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci    return 0;
241cabdff1aSopenharmony_cifail:
242cabdff1aSopenharmony_ci    av_frame_unref(frame);
243cabdff1aSopenharmony_ci    return AVERROR(ENOMEM);
244cabdff1aSopenharmony_ci}
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_cistatic int video_get_buffer(AVCodecContext *s, AVFrame *pic)
247cabdff1aSopenharmony_ci{
248cabdff1aSopenharmony_ci    FramePool *pool = (FramePool*)s->internal->pool->data;
249cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format);
250cabdff1aSopenharmony_ci    int i;
251cabdff1aSopenharmony_ci
252cabdff1aSopenharmony_ci    if (pic->data[0] || pic->data[1] || pic->data[2] || pic->data[3]) {
253cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "pic->data[*]!=NULL in avcodec_default_get_buffer\n");
254cabdff1aSopenharmony_ci        return -1;
255cabdff1aSopenharmony_ci    }
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    if (!desc) {
258cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR,
259cabdff1aSopenharmony_ci            "Unable to get pixel format descriptor for format %s\n",
260cabdff1aSopenharmony_ci            av_get_pix_fmt_name(pic->format));
261cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
262cabdff1aSopenharmony_ci    }
263cabdff1aSopenharmony_ci
264cabdff1aSopenharmony_ci    memset(pic->data, 0, sizeof(pic->data));
265cabdff1aSopenharmony_ci    pic->extended_data = pic->data;
266cabdff1aSopenharmony_ci
267cabdff1aSopenharmony_ci    for (i = 0; i < 4 && pool->pools[i]; i++) {
268cabdff1aSopenharmony_ci        pic->linesize[i] = pool->linesize[i];
269cabdff1aSopenharmony_ci
270cabdff1aSopenharmony_ci        pic->buf[i] = av_buffer_pool_get(pool->pools[i]);
271cabdff1aSopenharmony_ci        if (!pic->buf[i])
272cabdff1aSopenharmony_ci            goto fail;
273cabdff1aSopenharmony_ci
274cabdff1aSopenharmony_ci        pic->data[i] = pic->buf[i]->data;
275cabdff1aSopenharmony_ci    }
276cabdff1aSopenharmony_ci    for (; i < AV_NUM_DATA_POINTERS; i++) {
277cabdff1aSopenharmony_ci        pic->data[i] = NULL;
278cabdff1aSopenharmony_ci        pic->linesize[i] = 0;
279cabdff1aSopenharmony_ci    }
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_ci    if (s->debug & FF_DEBUG_BUFFERS)
282cabdff1aSopenharmony_ci        av_log(s, AV_LOG_DEBUG, "default_get_buffer called on pic %p\n", pic);
283cabdff1aSopenharmony_ci
284cabdff1aSopenharmony_ci    return 0;
285cabdff1aSopenharmony_cifail:
286cabdff1aSopenharmony_ci    av_frame_unref(pic);
287cabdff1aSopenharmony_ci    return AVERROR(ENOMEM);
288cabdff1aSopenharmony_ci}
289cabdff1aSopenharmony_ci
290cabdff1aSopenharmony_ciint avcodec_default_get_buffer2(AVCodecContext *avctx, AVFrame *frame, int flags)
291cabdff1aSopenharmony_ci{
292cabdff1aSopenharmony_ci    int ret;
293cabdff1aSopenharmony_ci
294cabdff1aSopenharmony_ci    if (avctx->hw_frames_ctx) {
295cabdff1aSopenharmony_ci        ret = av_hwframe_get_buffer(avctx->hw_frames_ctx, frame, 0);
296cabdff1aSopenharmony_ci        frame->width  = avctx->coded_width;
297cabdff1aSopenharmony_ci        frame->height = avctx->coded_height;
298cabdff1aSopenharmony_ci        return ret;
299cabdff1aSopenharmony_ci    }
300cabdff1aSopenharmony_ci
301cabdff1aSopenharmony_ci    if ((ret = update_frame_pool(avctx, frame)) < 0)
302cabdff1aSopenharmony_ci        return ret;
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    switch (avctx->codec_type) {
305cabdff1aSopenharmony_ci    case AVMEDIA_TYPE_VIDEO:
306cabdff1aSopenharmony_ci        return video_get_buffer(avctx, frame);
307cabdff1aSopenharmony_ci    case AVMEDIA_TYPE_AUDIO:
308cabdff1aSopenharmony_ci        return audio_get_buffer(avctx, frame);
309cabdff1aSopenharmony_ci    default:
310cabdff1aSopenharmony_ci        return -1;
311cabdff1aSopenharmony_ci    }
312cabdff1aSopenharmony_ci}
313