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