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 30static 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 46enum 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 62typedef 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 78static 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 126static 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 203static 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) 214static 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 221static 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 228const 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