LCOV - code coverage report
Current view: top level - libavfilter - fifo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 36 126 28.6 %
Date: 2017-12-11 04:34:20 Functions: 5 8 62.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2007 Bobby Bingham
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : /**
      22             :  * @file
      23             :  * FIFO buffering filter
      24             :  */
      25             : 
      26             : #include "libavutil/avassert.h"
      27             : #include "libavutil/channel_layout.h"
      28             : #include "libavutil/common.h"
      29             : #include "libavutil/mathematics.h"
      30             : #include "libavutil/samplefmt.h"
      31             : 
      32             : #include "audio.h"
      33             : #include "avfilter.h"
      34             : #include "internal.h"
      35             : #include "video.h"
      36             : 
      37             : typedef struct Buf {
      38             :     AVFrame *frame;
      39             :     struct Buf        *next;
      40             : } Buf;
      41             : 
      42             : typedef struct FifoContext {
      43             :     Buf  root;
      44             :     Buf *last;   ///< last buffered frame
      45             : 
      46             :     /**
      47             :      * When a specific number of output samples is requested, the partial
      48             :      * buffer is stored here
      49             :      */
      50             :     AVFrame *out;
      51             :     int allocated_samples;      ///< number of samples out was allocated for
      52             : } FifoContext;
      53             : 
      54          10 : static av_cold int init(AVFilterContext *ctx)
      55             : {
      56          10 :     FifoContext *fifo = ctx->priv;
      57          10 :     fifo->last = &fifo->root;
      58             : 
      59          10 :     return 0;
      60             : }
      61             : 
      62          10 : static av_cold void uninit(AVFilterContext *ctx)
      63             : {
      64          10 :     FifoContext *fifo = ctx->priv;
      65             :     Buf *buf, *tmp;
      66             : 
      67          10 :     for (buf = fifo->root.next; buf; buf = tmp) {
      68           0 :         tmp = buf->next;
      69           0 :         av_frame_free(&buf->frame);
      70           0 :         av_free(buf);
      71             :     }
      72             : 
      73          10 :     av_frame_free(&fifo->out);
      74          10 : }
      75             : 
      76         136 : static int add_to_queue(AVFilterLink *inlink, AVFrame *frame)
      77             : {
      78         136 :     FifoContext *fifo = inlink->dst->priv;
      79             : 
      80         136 :     fifo->last->next = av_mallocz(sizeof(Buf));
      81         136 :     if (!fifo->last->next) {
      82           0 :         av_frame_free(&frame);
      83           0 :         return AVERROR(ENOMEM);
      84             :     }
      85             : 
      86         136 :     fifo->last = fifo->last->next;
      87         136 :     fifo->last->frame = frame;
      88             : 
      89         136 :     return 0;
      90             : }
      91             : 
      92         136 : static void queue_pop(FifoContext *s)
      93             : {
      94         136 :     Buf *tmp = s->root.next->next;
      95         136 :     if (s->last == s->root.next)
      96         136 :         s->last = &s->root;
      97         136 :     av_freep(&s->root.next);
      98         136 :     s->root.next = tmp;
      99         136 : }
     100             : 
     101             : /**
     102             :  * Move data pointers and pts offset samples forward.
     103             :  */
     104           0 : static void buffer_offset(AVFilterLink *link, AVFrame *frame,
     105             :                           int offset)
     106             : {
     107           0 :     int nb_channels = link->channels;
     108           0 :     int planar = av_sample_fmt_is_planar(link->format);
     109           0 :     int planes = planar ? nb_channels : 1;
     110           0 :     int block_align = av_get_bytes_per_sample(link->format) * (planar ? 1 : nb_channels);
     111             :     int i;
     112             : 
     113           0 :     av_assert0(frame->nb_samples > offset);
     114             : 
     115           0 :     for (i = 0; i < planes; i++)
     116           0 :         frame->extended_data[i] += block_align * offset;
     117           0 :     if (frame->data != frame->extended_data)
     118           0 :         memcpy(frame->data, frame->extended_data,
     119           0 :                FFMIN(planes, FF_ARRAY_ELEMS(frame->data)) * sizeof(*frame->data));
     120           0 :     frame->linesize[0] -= block_align*offset;
     121           0 :     frame->nb_samples -= offset;
     122             : 
     123           0 :     if (frame->pts != AV_NOPTS_VALUE) {
     124           0 :         frame->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate},
     125             :                                    link->time_base);
     126             :     }
     127           0 : }
     128             : 
     129           0 : static int calc_ptr_alignment(AVFrame *frame)
     130             : {
     131           0 :     int planes = av_sample_fmt_is_planar(frame->format) ?
     132           0 :                  frame->channels : 1;
     133           0 :     int min_align = 128;
     134             :     int p;
     135             : 
     136           0 :     for (p = 0; p < planes; p++) {
     137           0 :         int cur_align = 128;
     138           0 :         while ((intptr_t)frame->extended_data[p] % cur_align)
     139           0 :             cur_align >>= 1;
     140           0 :         if (cur_align < min_align)
     141           0 :             min_align = cur_align;
     142             :     }
     143           0 :     return min_align;
     144             : }
     145             : 
     146           0 : static int return_audio_frame(AVFilterContext *ctx)
     147             : {
     148           0 :     AVFilterLink *link = ctx->outputs[0];
     149           0 :     FifoContext *s = ctx->priv;
     150           0 :     AVFrame *head = s->root.next ? s->root.next->frame : NULL;
     151             :     AVFrame *out;
     152             :     int ret;
     153             : 
     154             :     /* if head is NULL then we're flushing the remaining samples in out */
     155           0 :     if (!head && !s->out)
     156           0 :         return AVERROR_EOF;
     157             : 
     158           0 :     if (!s->out &&
     159           0 :         head->nb_samples >= link->request_samples &&
     160           0 :         calc_ptr_alignment(head) >= 32) {
     161           0 :         if (head->nb_samples == link->request_samples) {
     162           0 :             out = head;
     163           0 :             queue_pop(s);
     164             :         } else {
     165           0 :             out = av_frame_clone(head);
     166           0 :             if (!out)
     167           0 :                 return AVERROR(ENOMEM);
     168             : 
     169           0 :             out->nb_samples = link->request_samples;
     170           0 :             buffer_offset(link, head, link->request_samples);
     171             :         }
     172             :     } else {
     173           0 :         int nb_channels = link->channels;
     174             : 
     175           0 :         if (!s->out) {
     176           0 :             s->out = ff_get_audio_buffer(link, link->request_samples);
     177           0 :             if (!s->out)
     178           0 :                 return AVERROR(ENOMEM);
     179             : 
     180           0 :             s->out->nb_samples = 0;
     181           0 :             s->out->pts                   = head->pts;
     182           0 :             s->allocated_samples          = link->request_samples;
     183           0 :         } else if (link->request_samples != s->allocated_samples) {
     184           0 :             av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
     185             :                    "buffer was returned.\n");
     186           0 :             return AVERROR(EINVAL);
     187             :         }
     188             : 
     189           0 :         while (s->out->nb_samples < s->allocated_samples) {
     190             :             int len;
     191             : 
     192           0 :             if (!s->root.next) {
     193           0 :                 ret = ff_request_frame(ctx->inputs[0]);
     194           0 :                 if (ret == AVERROR_EOF) {
     195           0 :                     av_samples_set_silence(s->out->extended_data,
     196           0 :                                            s->out->nb_samples,
     197           0 :                                            s->allocated_samples -
     198           0 :                                            s->out->nb_samples,
     199           0 :                                            nb_channels, link->format);
     200           0 :                     s->out->nb_samples = s->allocated_samples;
     201           0 :                     break;
     202           0 :                 } else if (ret < 0)
     203           0 :                     return ret;
     204           0 :                 if (!s->root.next)
     205           0 :                     return 0;
     206             :             }
     207           0 :             head = s->root.next->frame;
     208             : 
     209           0 :             len = FFMIN(s->allocated_samples - s->out->nb_samples,
     210             :                         head->nb_samples);
     211             : 
     212           0 :             av_samples_copy(s->out->extended_data, head->extended_data,
     213           0 :                             s->out->nb_samples, 0, len, nb_channels,
     214           0 :                             link->format);
     215           0 :             s->out->nb_samples += len;
     216             : 
     217           0 :             if (len == head->nb_samples) {
     218           0 :                 av_frame_free(&head);
     219           0 :                 queue_pop(s);
     220             :             } else {
     221           0 :                 buffer_offset(link, head, len);
     222             :             }
     223             :         }
     224           0 :         out = s->out;
     225           0 :         s->out = NULL;
     226             :     }
     227           0 :     return ff_filter_frame(link, out);
     228             : }
     229             : 
     230         272 : static int request_frame(AVFilterLink *outlink)
     231             : {
     232         272 :     FifoContext *fifo = outlink->src->priv;
     233         272 :     int ret = 0;
     234             : 
     235         272 :     if (!fifo->root.next) {
     236         136 :         if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0) {
     237          10 :             if (ret == AVERROR_EOF && outlink->request_samples)
     238           0 :                 return return_audio_frame(outlink->src);
     239          10 :             return ret;
     240             :         }
     241         126 :         if (!fifo->root.next)
     242         126 :             return 0;
     243             :     }
     244             : 
     245         136 :     if (outlink->request_samples) {
     246           0 :         return return_audio_frame(outlink->src);
     247             :     } else {
     248         136 :         ret = ff_filter_frame(outlink, fifo->root.next->frame);
     249         136 :         queue_pop(fifo);
     250             :     }
     251             : 
     252         136 :     return ret;
     253             : }
     254             : 
     255             : static const AVFilterPad avfilter_vf_fifo_inputs[] = {
     256             :     {
     257             :         .name             = "default",
     258             :         .type             = AVMEDIA_TYPE_VIDEO,
     259             :         .filter_frame     = add_to_queue,
     260             :     },
     261             :     { NULL }
     262             : };
     263             : 
     264             : static const AVFilterPad avfilter_vf_fifo_outputs[] = {
     265             :     {
     266             :         .name          = "default",
     267             :         .type          = AVMEDIA_TYPE_VIDEO,
     268             :         .request_frame = request_frame,
     269             :     },
     270             :     { NULL }
     271             : };
     272             : 
     273             : AVFilter ff_vf_fifo = {
     274             :     .name      = "fifo",
     275             :     .description = NULL_IF_CONFIG_SMALL("Buffer input images and send them when they are requested."),
     276             : 
     277             :     .init      = init,
     278             :     .uninit    = uninit,
     279             : 
     280             :     .priv_size = sizeof(FifoContext),
     281             : 
     282             :     .inputs    = avfilter_vf_fifo_inputs,
     283             :     .outputs   = avfilter_vf_fifo_outputs,
     284             : };
     285             : 
     286             : static const AVFilterPad avfilter_af_afifo_inputs[] = {
     287             :     {
     288             :         .name             = "default",
     289             :         .type             = AVMEDIA_TYPE_AUDIO,
     290             :         .filter_frame     = add_to_queue,
     291             :     },
     292             :     { NULL }
     293             : };
     294             : 
     295             : static const AVFilterPad avfilter_af_afifo_outputs[] = {
     296             :     {
     297             :         .name          = "default",
     298             :         .type          = AVMEDIA_TYPE_AUDIO,
     299             :         .request_frame = request_frame,
     300             :     },
     301             :     { NULL }
     302             : };
     303             : 
     304             : AVFilter ff_af_afifo = {
     305             :     .name        = "afifo",
     306             :     .description = NULL_IF_CONFIG_SMALL("Buffer input frames and send them when they are requested."),
     307             : 
     308             :     .init      = init,
     309             :     .uninit    = uninit,
     310             : 
     311             :     .priv_size = sizeof(FifoContext),
     312             : 
     313             :     .inputs    = avfilter_af_afifo_inputs,
     314             :     .outputs   = avfilter_af_afifo_outputs,
     315             : };

Generated by: LCOV version 1.13