Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2015 Derek Buitenhuis
  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. #include "libavutil/opt.h"
  22. #include "avfilter.h"
  23. #include "formats.h"
  24. #include "internal.h"
  25. #include "video.h"
  26.  
  27. #define DEFAULT_LENGTH 300
  28.  
  29. typedef struct ReverseContext {
  30.     int nb_frames;
  31.     AVFrame **frames;
  32.     unsigned int frames_size;
  33.     unsigned int pts_size;
  34.     int64_t *pts;
  35.     int flush_idx;
  36. } ReverseContext;
  37.  
  38. static av_cold int init(AVFilterContext *ctx)
  39. {
  40.     ReverseContext *s = ctx->priv;
  41.  
  42.     s->pts = av_fast_realloc(NULL, &s->pts_size,
  43.                              DEFAULT_LENGTH * sizeof(*(s->pts)));
  44.     if (!s->pts)
  45.         return AVERROR(ENOMEM);
  46.  
  47.     s->frames = av_fast_realloc(NULL, &s->frames_size,
  48.                                 DEFAULT_LENGTH * sizeof(*(s->frames)));
  49.     if (!s->frames) {
  50.         av_freep(&s->pts);
  51.         return AVERROR(ENOMEM);
  52.     }
  53.  
  54.     return 0;
  55. }
  56.  
  57. static av_cold void uninit(AVFilterContext *ctx)
  58. {
  59.     ReverseContext *s = ctx->priv;
  60.  
  61.     av_freep(&s->pts);
  62.     av_freep(&s->frames);
  63. }
  64.  
  65. static int config_output(AVFilterLink *outlink)
  66. {
  67.     outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
  68.     return 0;
  69. }
  70.  
  71. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  72. {
  73.     AVFilterContext *ctx = inlink->dst;
  74.     ReverseContext *s    = ctx->priv;
  75.     void *ptr;
  76.  
  77.     if (s->nb_frames + 1 > s->pts_size / sizeof(*(s->pts))) {
  78.         ptr = av_fast_realloc(s->pts, &s->pts_size, s->pts_size * 2);
  79.         if (!ptr)
  80.             return AVERROR(ENOMEM);
  81.         s->pts = ptr;
  82.     }
  83.  
  84.     if (s->nb_frames + 1 > s->frames_size / sizeof(*(s->frames))) {
  85.         ptr = av_fast_realloc(s->frames, &s->frames_size, s->frames_size * 2);
  86.         if (!ptr)
  87.             return AVERROR(ENOMEM);
  88.         s->frames = ptr;
  89.     }
  90.  
  91.     s->frames[s->nb_frames] = in;
  92.     s->pts[s->nb_frames]    = in->pts;
  93.     s->nb_frames++;
  94.  
  95.     return 0;
  96. }
  97.  
  98. #if CONFIG_REVERSE_FILTER
  99.  
  100. static int request_frame(AVFilterLink *outlink)
  101. {
  102.     AVFilterContext *ctx = outlink->src;
  103.     ReverseContext *s = ctx->priv;
  104.     int ret;
  105.  
  106.     ret = ff_request_frame(ctx->inputs[0]);
  107.  
  108.     if (ret == AVERROR_EOF && s->nb_frames > 0) {
  109.         AVFrame *out = s->frames[s->nb_frames - 1];
  110.         out->pts     = s->pts[s->flush_idx++];
  111.         ret          = ff_filter_frame(outlink, out);
  112.         s->nb_frames--;
  113.     }
  114.  
  115.     return ret;
  116. }
  117.  
  118. static const AVFilterPad reverse_inputs[] = {
  119.     {
  120.         .name         = "default",
  121.         .type         = AVMEDIA_TYPE_VIDEO,
  122.         .filter_frame = filter_frame,
  123.     },
  124.     { NULL }
  125. };
  126.  
  127. static const AVFilterPad reverse_outputs[] = {
  128.     {
  129.         .name          = "default",
  130.         .type          = AVMEDIA_TYPE_VIDEO,
  131.         .request_frame = request_frame,
  132.         .config_props  = config_output,
  133.     },
  134.     { NULL }
  135. };
  136.  
  137. AVFilter ff_vf_reverse = {
  138.     .name        = "reverse",
  139.     .description = NULL_IF_CONFIG_SMALL("Reverse a clip."),
  140.     .priv_size   = sizeof(ReverseContext),
  141.     .init        = init,
  142.     .uninit      = uninit,
  143.     .inputs      = reverse_inputs,
  144.     .outputs     = reverse_outputs,
  145. };
  146.  
  147. #endif /* CONFIG_REVERSE_FILTER */
  148.  
  149. #if CONFIG_AREVERSE_FILTER
  150.  
  151. static int query_formats(AVFilterContext *ctx)
  152. {
  153.     AVFilterFormats *formats;
  154.     AVFilterChannelLayouts *layouts;
  155.     int ret;
  156.  
  157.     layouts = ff_all_channel_layouts();
  158.     if (!layouts)
  159.         return AVERROR(ENOMEM);
  160.     ret = ff_set_common_channel_layouts(ctx, layouts);
  161.     if (ret < 0)
  162.         return ret;
  163.  
  164.     ret = ff_set_common_formats(ctx, ff_planar_sample_fmts());
  165.     if (ret < 0)
  166.         return ret;
  167.  
  168.     formats = ff_all_samplerates();
  169.     if (!formats)
  170.         return AVERROR(ENOMEM);
  171.     return ff_set_common_samplerates(ctx, formats);
  172. }
  173.  
  174. static int areverse_request_frame(AVFilterLink *outlink)
  175. {
  176.     AVFilterContext *ctx = outlink->src;
  177.     ReverseContext *s = ctx->priv;
  178.     int ret, p, i, j;
  179.  
  180.     ret = ff_request_frame(ctx->inputs[0]);
  181.  
  182.     if (ret == AVERROR_EOF && s->nb_frames > 0) {
  183.         AVFrame *out = s->frames[s->nb_frames - 1];
  184.         out->pts     = s->pts[s->flush_idx++];
  185.  
  186.         for (p = 0; p < outlink->channels; p++) {
  187.             switch (outlink->format) {
  188.             case AV_SAMPLE_FMT_U8P: {
  189.                 uint8_t *dst = (uint8_t *)out->extended_data[p];
  190.                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
  191.                     FFSWAP(uint8_t, dst[i], dst[j]);
  192.             }
  193.                 break;
  194.             case AV_SAMPLE_FMT_S16P: {
  195.                 int16_t *dst = (int16_t *)out->extended_data[p];
  196.                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
  197.                     FFSWAP(int16_t, dst[i], dst[j]);
  198.             }
  199.                 break;
  200.             case AV_SAMPLE_FMT_S32P: {
  201.                 int32_t *dst = (int32_t *)out->extended_data[p];
  202.                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
  203.                     FFSWAP(int32_t, dst[i], dst[j]);
  204.             }
  205.                 break;
  206.             case AV_SAMPLE_FMT_FLTP: {
  207.                 float *dst = (float *)out->extended_data[p];
  208.                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
  209.                     FFSWAP(float, dst[i], dst[j]);
  210.             }
  211.                 break;
  212.             case AV_SAMPLE_FMT_DBLP: {
  213.                 double *dst = (double *)out->extended_data[p];
  214.                 for (i = 0, j = out->nb_samples - 1; i < j; i++, j--)
  215.                     FFSWAP(double, dst[i], dst[j]);
  216.             }
  217.                 break;
  218.             }
  219.         }
  220.  
  221.         ret = ff_filter_frame(outlink, out);
  222.         s->nb_frames--;
  223.     }
  224.  
  225.     return ret;
  226. }
  227.  
  228. static const AVFilterPad areverse_inputs[] = {
  229.     {
  230.         .name           = "default",
  231.         .type           = AVMEDIA_TYPE_AUDIO,
  232.         .filter_frame   = filter_frame,
  233.         .needs_writable = 1,
  234.     },
  235.     { NULL }
  236. };
  237.  
  238. static const AVFilterPad areverse_outputs[] = {
  239.     {
  240.         .name          = "default",
  241.         .type          = AVMEDIA_TYPE_AUDIO,
  242.         .request_frame = areverse_request_frame,
  243.         .config_props  = config_output,
  244.     },
  245.     { NULL }
  246. };
  247.  
  248. AVFilter ff_af_areverse = {
  249.     .name          = "areverse",
  250.     .description   = NULL_IF_CONFIG_SMALL("Reverse an audio clip."),
  251.     .query_formats = query_formats,
  252.     .priv_size     = sizeof(ReverseContext),
  253.     .init          = init,
  254.     .uninit        = uninit,
  255.     .inputs        = areverse_inputs,
  256.     .outputs       = areverse_outputs,
  257. };
  258.  
  259. #endif /* CONFIG_AREVERSE_FILTER */
  260.