• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
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 <stdlib.h>
22 
23 #include "bsf.h"
24 #include "bsf_internal.h"
25 
26 #include "libavutil/log.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/eval.h"
29 
30 static const char *const var_names[] = {
31     "n",                           /// packet index, starting from zero
32     "tb",                          /// timebase
33     "pts",                         /// packet presentation timestamp
34     "dts",                         /// packet decoding timestamp
35     "nopts",                       /// AV_NOPTS_VALUE
36     "startpts",                    /// first seen non-AV_NOPTS_VALUE packet timestamp
37     "startdts",                    /// first seen non-AV_NOPTS_VALUE packet timestamp
38     "duration", "d",               /// packet duration
39     "pos",                         /// original position of packet in its source
40     "size",                        /// packet size
41     "key" ,                        /// packet keyframe flag
42     "state",                       /// random-ish state
43     NULL
44 };
45 
46 enum var_name {
47     VAR_N,
48     VAR_TB,
49     VAR_PTS,
50     VAR_DTS,
51     VAR_NOPTS,
52     VAR_STARTPTS,
53     VAR_STARTDTS,
54     VAR_DURATION, VAR_D,
55     VAR_POS,
56     VAR_SIZE,
57     VAR_KEY,
58     VAR_STATE,
59     VAR_VARS_NB
60 };
61 
62 typedef struct NoiseContext {
63     const AVClass *class;
64 
65     char *amount_str;
66     char *drop_str;
67     int dropamount;
68 
69     AVExpr *amount_pexpr;
70     AVExpr *drop_pexpr;
71 
72     double var_values[VAR_VARS_NB];
73 
74     unsigned int state;
75     unsigned int pkt_idx;
76 } NoiseContext;
77 
noise_init(AVBSFContext * ctx)78 static int noise_init(AVBSFContext *ctx)
79 {
80     NoiseContext *s = ctx->priv_data;
81     int ret;
82 
83     if (!s->amount_str) {
84         s->amount_str = (!s->drop_str && !s->dropamount) ? av_strdup("-1") : av_strdup("0");
85         if (!s->amount_str)
86             return AVERROR(ENOMEM);
87     }
88 
89     if (ctx->par_in->codec_id == AV_CODEC_ID_WRAPPED_AVFRAME &&
90         strcmp(s->amount_str, "0")) {
91         av_log(ctx, AV_LOG_ERROR, "Wrapped AVFrame noising is unsupported\n");
92         return AVERROR_PATCHWELCOME;
93     }
94 
95     ret = av_expr_parse(&s->amount_pexpr, s->amount_str,
96                         var_names, NULL, NULL, NULL, NULL, 0, ctx);
97     if (ret < 0) {
98         av_log(ctx, AV_LOG_ERROR, "Error in parsing expr for amount: %s\n", s->amount_str);
99         return ret;
100     }
101 
102     if (s->drop_str && s->dropamount) {
103         av_log(ctx, AV_LOG_WARNING, "Both drop '%s' and dropamount=%d set. Ignoring dropamount.\n",
104                s->drop_str, s->dropamount);
105         s->dropamount = 0;
106     }
107 
108     if (s->drop_str) {
109         ret = av_expr_parse(&s->drop_pexpr, s->drop_str,
110                             var_names, NULL, NULL, NULL, NULL, 0, ctx);
111         if (ret < 0) {
112             av_log(ctx, AV_LOG_ERROR, "Error in parsing expr for drop: %s\n", s->drop_str);
113             return ret;
114         }
115     }
116 
117     s->var_values[VAR_TB]       = ctx->time_base_out.den ? av_q2d(ctx->time_base_out) : 0;
118     s->var_values[VAR_NOPTS]    = AV_NOPTS_VALUE;
119     s->var_values[VAR_STARTPTS] = AV_NOPTS_VALUE;
120     s->var_values[VAR_STARTDTS] = AV_NOPTS_VALUE;
121     s->var_values[VAR_STATE] = 0;
122 
123     return 0;
124 }
125 
noise(AVBSFContext * ctx,AVPacket * pkt)126 static int noise(AVBSFContext *ctx, AVPacket *pkt)
127 {
128     NoiseContext *s = ctx->priv_data;
129     int i, ret, amount, drop = 0;
130     double res;
131 
132     ret = ff_bsf_get_packet_ref(ctx, pkt);
133     if (ret < 0)
134         return ret;
135 
136     s->var_values[VAR_N]           = s->pkt_idx++;
137     s->var_values[VAR_PTS]         = pkt->pts;
138     s->var_values[VAR_DTS]         = pkt->dts;
139     s->var_values[VAR_DURATION]    =
140     s->var_values[VAR_D]           = pkt->duration;
141     s->var_values[VAR_SIZE]        = pkt->size;
142     s->var_values[VAR_KEY]         = !!(pkt->flags & AV_PKT_FLAG_KEY);
143     s->var_values[VAR_POS]         = pkt->pos;
144 
145     if (s->var_values[VAR_STARTPTS] == AV_NOPTS_VALUE)
146         s->var_values[VAR_STARTPTS] = pkt->pts;
147 
148     if (s->var_values[VAR_STARTDTS] == AV_NOPTS_VALUE)
149         s->var_values[VAR_STARTDTS] = pkt->dts;
150 
151     res = av_expr_eval(s->amount_pexpr, s->var_values, NULL);
152 
153     if (isnan(res))
154         amount = 0;
155     else if (res < 0)
156         amount = (s->state % 10001 + 1);
157     else
158         amount = (int)res;
159 
160     if (s->drop_str) {
161         res = av_expr_eval(s->drop_pexpr, s->var_values, NULL);
162 
163         if (isnan(res))
164             drop = 0;
165         else if (res < 0)
166             drop = !(s->state % FFABS((int)res));
167         else
168             drop = !!res;
169     }
170 
171     if(s->dropamount) {
172         drop = !(s->state % s->dropamount);
173     }
174 
175     av_log(ctx, AV_LOG_VERBOSE, "Stream #%d packet %d pts %"PRId64" - amount %d drop %d\n",
176            pkt->stream_index, (unsigned int)s->var_values[VAR_N], pkt->pts, amount, drop);
177 
178     if (drop) {
179         s->var_values[VAR_STATE] = ++s->state;
180         av_packet_unref(pkt);
181         return AVERROR(EAGAIN);
182     }
183 
184     if (amount) {
185         ret = av_packet_make_writable(pkt);
186         if (ret < 0) {
187             av_packet_unref(pkt);
188             return ret;
189         }
190     }
191 
192     for (i = 0; i < pkt->size; i++) {
193         s->state += pkt->data[i] + 1;
194         if (amount && s->state % amount == 0)
195             pkt->data[i] = s->state;
196     }
197 
198     s->var_values[VAR_STATE] = s->state;
199 
200     return 0;
201 }
202 
noise_close(AVBSFContext * bsf)203 static void noise_close(AVBSFContext *bsf)
204 {
205     NoiseContext *s = bsf->priv_data;
206 
207     av_expr_free(s->amount_pexpr);
208     av_expr_free(s->drop_pexpr);
209     s->amount_pexpr = s->drop_pexpr = NULL;
210 }
211 
212 #define OFFSET(x) offsetof(NoiseContext, x)
213 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_BSF_PARAM)
214 static const AVOption options[] = {
215     { "amount",     NULL, OFFSET(amount_str),     AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
216     { "drop",       NULL, OFFSET(drop_str),       AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS },
217     { "dropamount", NULL, OFFSET(dropamount),     AV_OPT_TYPE_INT,    { .i64 = 0    }, 0, INT_MAX, FLAGS },
218     { NULL },
219 };
220 
221 static const AVClass noise_class = {
222     .class_name = "noise",
223     .item_name  = av_default_item_name,
224     .option     = options,
225     .version    = LIBAVUTIL_VERSION_INT,
226 };
227 
228 const FFBitStreamFilter ff_noise_bsf = {
229     .p.name         = "noise",
230     .p.priv_class   = &noise_class,
231     .priv_data_size = sizeof(NoiseContext),
232     .init           = noise_init,
233     .close          = noise_close,
234     .filter         = noise,
235 };
236