1/* 2 * DFPWM decoder 3 * Copyright (c) 2022 Jack Bruienne 4 * Copyright (c) 2012, 2016 Ben "GreaseMonkey" Russell 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23/** 24 * @file 25 * DFPWM1a decoder 26 */ 27 28#include "libavutil/internal.h" 29#include "avcodec.h" 30#include "codec_id.h" 31#include "codec_internal.h" 32#include "internal.h" 33 34typedef struct { 35 int fq, q, s, lt; 36} DFPWMState; 37 38// DFPWM codec from https://github.com/ChenThread/dfpwm/blob/master/1a/ 39// Licensed in the public domain 40 41static void au_decompress(DFPWMState *state, int fs, int len, 42 uint8_t *outbuf, const uint8_t *inbuf) 43{ 44 unsigned d; 45 for (int i = 0; i < len; i++) { 46 // get bits 47 d = *(inbuf++); 48 for (int j = 0; j < 8; j++) { 49 int nq, lq, st, ns, ov; 50 // set target 51 int t = ((d&1) ? 127 : -128); 52 d >>= 1; 53 54 // adjust charge 55 nq = state->q + ((state->s * (t-state->q) + 512)>>10); 56 if(nq == state->q && nq != t) 57 nq += (t == 127 ? 1 : -1); 58 lq = state->q; 59 state->q = nq; 60 61 // adjust strength 62 st = (t != state->lt ? 0 : 1023); 63 ns = state->s; 64 if(ns != st) 65 ns += (st != 0 ? 1 : -1); 66 if(ns < 8) ns = 8; 67 state->s = ns; 68 69 // FILTER: perform antijerk 70 ov = (t != state->lt ? (nq+lq+1)>>1 : nq); 71 72 // FILTER: perform LPF 73 state->fq += ((fs*(ov-state->fq) + 0x80)>>8); 74 ov = state->fq; 75 76 // output sample 77 *(outbuf++) = ov + 128; 78 79 state->lt = t; 80 } 81 } 82} 83 84static av_cold int dfpwm_dec_init(struct AVCodecContext *ctx) 85{ 86 DFPWMState *state = ctx->priv_data; 87 88 if (ctx->ch_layout.nb_channels <= 0) { 89 av_log(ctx, AV_LOG_ERROR, "Invalid number of channels\n"); 90 return AVERROR(EINVAL); 91 } 92 93 state->fq = 0; 94 state->q = 0; 95 state->s = 0; 96 state->lt = -128; 97 98 ctx->sample_fmt = AV_SAMPLE_FMT_U8; 99 ctx->bits_per_raw_sample = 8; 100 101 return 0; 102} 103 104static int dfpwm_dec_frame(struct AVCodecContext *ctx, AVFrame *frame, 105 int *got_frame, struct AVPacket *packet) 106{ 107 DFPWMState *state = ctx->priv_data; 108 int ret; 109 110 if (packet->size * 8LL % ctx->ch_layout.nb_channels) 111 return AVERROR_PATCHWELCOME; 112 113 frame->nb_samples = packet->size * 8LL / ctx->ch_layout.nb_channels; 114 if (frame->nb_samples <= 0) { 115 av_log(ctx, AV_LOG_ERROR, "invalid number of samples in packet\n"); 116 return AVERROR_INVALIDDATA; 117 } 118 119 if ((ret = ff_get_buffer(ctx, frame, 0)) < 0) 120 return ret; 121 122 au_decompress(state, 140, packet->size, frame->data[0], packet->data); 123 124 *got_frame = 1; 125 return packet->size; 126} 127 128const FFCodec ff_dfpwm_decoder = { 129 .p.name = "dfpwm", 130 .p.long_name = NULL_IF_CONFIG_SMALL("DFPWM1a audio"), 131 .p.type = AVMEDIA_TYPE_AUDIO, 132 .p.id = AV_CODEC_ID_DFPWM, 133 .priv_data_size = sizeof(DFPWMState), 134 .init = dfpwm_dec_init, 135 FF_CODEC_DECODE_CB(dfpwm_dec_frame), 136 .p.capabilities = AV_CODEC_CAP_DR1, 137 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 138}; 139