From patchwork Fri Feb 25 23:43:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jack Bruienne X-Patchwork-Id: 34523 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6838:d078:0:0:0:0 with SMTP id x24csp614810nkx; Fri, 25 Feb 2022 15:43:29 -0800 (PST) X-Google-Smtp-Source: ABdhPJyQ1ZHUka95+yW+2viGjx1XjdKoDK4ymZbTK8W/zxepyTDz8F1qMpZTSYttQzs5gj28aaL3 X-Received: by 2002:a17:906:9509:b0:6d0:fbc5:eb4a with SMTP id u9-20020a170906950900b006d0fbc5eb4amr7808139ejx.228.1645832608806; Fri, 25 Feb 2022 15:43:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1645832608; cv=none; d=google.com; s=arc-20160816; b=VzZGR/x26zHKQibo3AT2DHUWICM+bU6sqTWSiA1POdvZQzl8yeI2HETXS2WH/mGAxG hH8wm3g+6xFvt4dwgWf079OyJNObYuzCnq8HJXdaEJ0U3iHABKs8A90EpuQCBB7XTh24 AD/IiU50crN3jPdprhVfp/o26bF7ei756Q7aCQm8bq5dCLfj+ngQQiKQ47AmdP6I4EiH dmkiZGYA/BalFwsNjdm+UfIW4ma9FkTgVdnnFf3xszxA3siZVdU5HvpOJmRB+QFArxnK eNqwiVLgtVQ7UDMFvK8H/zoZNEJdKBJu9ZjyB188iauIttam1w4bRVwa3y54l2nh/7DZ 6+xQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject :content-language:to:from:user-agent:mime-version:date:message-id :dkim-signature:delivered-to; bh=EkK8nVurxTwrGchK2RTubLijbrrz8AGQdUI5KzW75xg=; b=oYR91751HQPhPhp2vUXJ1l3iye+e89zLs3bEhDmY8DWBkx/TcEkGbqx+v1AJJbqblz kDl+dj7Fj+OdePtKFr3tPDjIt4kGKO6jqLRpEwQL556lOW4z1wEPvQSRJawXwNTtPCWd EkXdU8KJMI0XKIIwTnjPx1I2cb40aj4YS6onBab0G8MiBXElRUlTYPG63i7Jy7DEPjJZ 7ZeS0sJ0l5QaYVjdZk4zv+E12N2Ec+KnNbKzYX8SAlPrn+dyBOoCYrEa3Y4vf2igVgIB 7nZqzGDsOB2A1fBKYXdxHaRqZA79mrP91EGDeTWw1H3kaakL2+9BkgMkr0aemnGnmLnQ HBdA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=b+iFBjGJ; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id j17-20020aa7ca51000000b004135251bb25si2571473edt.189.2022.02.25.15.43.28; Fri, 25 Feb 2022 15:43:28 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=b+iFBjGJ; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2F7F168A76F; Sat, 26 Feb 2022 01:43:26 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-il1-f180.google.com (mail-il1-f180.google.com [209.85.166.180]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D500E68A70F for ; Sat, 26 Feb 2022 01:43:19 +0200 (EET) Received: by mail-il1-f180.google.com with SMTP id w4so5551981ilj.5 for ; Fri, 25 Feb 2022 15:43:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:date:mime-version:user-agent:from:subject:to :content-language; bh=F4Cywb8dpwLoFjgNlAAnIfuOwzDwiutamq1m6NatK00=; b=b+iFBjGJ764CpmL2+VSCIgALg914XmwoGO96DcfRFa/0si6bOvIcrbtMcbTmRKdSGr 4IroN6s7nGuAK+d4HvqT1iu9VOAROmHA2bZWUR/VBzMGorWJpjj4t/QFXD8yZVQtZrnK mkeVgS1LvujJl3fX5TwCiAOIOehuoDpy7qQxZX8GoKj07FWTihBcyTlS157yyyXZCfd2 +Uvqk5Wb46nvKEbmna74yJXvgYSgyz39D7FMMHLMAi9OYlxSqj4kHw8WHpah/freFuVE GKDchag6WxqbkHnDGwt9RR8KaZWPWKaNlWFXp0txcNFSwzTR5wGsH9h8HniNghxENtrb PJKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:from :subject:to:content-language; bh=F4Cywb8dpwLoFjgNlAAnIfuOwzDwiutamq1m6NatK00=; b=dCn6CVfICbwMMzyUUaKxPHYBaRGb+O7BXwawWxTwYCXiAR2jUTnz0XEWSV7W7PyApl WlJQhPS/EkTF+UKqi0MdhdVatMz2zS3hlkdstsFVyWbno3e1iDdOCp3SiXwTKwFSN3me SbJrzSqKs3kr4GObmalgeVqp+cYa+bb3LilytBP6+2E0YBUbjVjHeepk2lKJ7iyAZRgS Ay8FizwW+sH5VS24wSsc3wtnb06lQnYCAP24kLDy7Wk6jDLp+NMGWenP6kNGSR+UtVE/ MtIr4jU9o6vesnhYZplkif5UNQCicSskn/t/wbc6AfcU6gTXElfYYGqcjCj3Wl0jlMrw 88kQ== X-Gm-Message-State: AOAM533p/RcHZCkTy/MEADx8jn7lcg/QK+9JL1E2lRXBg2F4sNrddz9q O/EKMc7Df4wBgBt0TVN0inZUsnqTW23T5Q== X-Received: by 2002:a92:7d0e:0:b0:2be:c4db:12d2 with SMTP id y14-20020a927d0e000000b002bec4db12d2mr8374324ilc.61.1645832598159; Fri, 25 Feb 2022 15:43:18 -0800 (PST) Received: from [192.168.7.86] (c-68-40-205-18.hsd1.mi.comcast.net. [68.40.205.18]) by smtp.gmail.com with ESMTPSA id b24-20020a5d8d98000000b006409ad493fbsm2217457ioj.21.2022.02.25.15.43.17 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 25 Feb 2022 15:43:17 -0800 (PST) Message-ID: Date: Fri, 25 Feb 2022 18:43:16 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.6.1 From: Jack Bruienne To: ffmpeg-devel@ffmpeg.org Content-Language: en-US Subject: [FFmpeg-devel] [PATCH v2 1/2] libavcodec: Added DFPWM1a codec X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: U9rTx1KLFlFr From the wiki page (https://wiki.vexatos.com/dfpwm): > DFPWM (Dynamic Filter Pulse Width Modulation) is an audio codec > created by Ben “GreaseMonkey” Russell in 2012, originally to be used > as a voice codec for asiekierka's pixmess, a C remake of 64pixels. > It is a 1-bit-per-sample codec which uses a dynamic-strength one-pole > low-pass filter as a predictor. Due to the fact that a raw DPFWM decoding > creates a high-pitched whine, it is often followed by some post-processing > filters to make the stream more listenable. It has recently gained popularity through the ComputerCraft mod for Minecraft, which added support for audio through this codec, as well as the Computronics expansion which preceeded the official support. These both implement the slightly adjusted 1a version of the codec, which is the version I have chosen for this patch. This patch adds a new codec (with encoding and decoding) for DFPWM1a. The codec sources are pretty simple: they use the reference codec with a basic wrapper to connect it to the FFmpeg AVCodec system. This patch will be highly useful to ComputerCraft developers who are working with audio, as it is the standard format for audio, and there are few user-friendly encoders out there. It will streamline the process for importing audio, replacing the need to write code or use tools that require very specific input formats. You may use the CraftOS-PC program (https://www.craftos-pc.cc) to test out DFPWM playback. To use it, run the program and type this command: "attach left speaker" Then run "speaker play " for each file. The app runs in a sandbox, so files have to be transferred in first; the easiest way to do this is to simply drag the file on the window. (Or copy files to the folder at https://www.craftos-pc.cc/docs/saves.) Sample DFPWM files can be generated with an online tool at https://music.madefor.cc. This is the current best way to encode DFPWM files. Simply drag an audio file onto the page, and it will encode it, giving a download link on the page. I've made sure to update all of the docs as per Developer§7, and I've tested it as per section 8. Test files encoded to DFPWM play correctly in ComputerCraft, and other files that work in CC are correctly decoded. I have also verified that corrupt files do not crash the decoder - this should theoretically not be an issue as the result size is constant with respect to the input size. Signed-off-by: Jack Bruienne --- Changelog | 1 + MAINTAINERS | 1 + doc/general_contents.texi | 1 + libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 2 + libavcodec/codec_desc.c | 7 +++ libavcodec/codec_id.h | 1 + libavcodec/dfpwmdec.c | 129 ++++++++++++++++++++++++++++++++++++++ libavcodec/dfpwmenc.c | 123 ++++++++++++++++++++++++++++++++++++ libavcodec/utils.c | 2 + libavcodec/version.h | 2 +- 11 files changed, 270 insertions(+), 1 deletion(-) create mode 100644 libavcodec/dfpwmdec.c create mode 100644 libavcodec/dfpwmenc.c diff --git a/Changelog b/Changelog index 5ad2cef..5170a6a 100644 --- a/Changelog +++ b/Changelog @@ -4,6 +4,7 @@ releases are sorted from youngest to oldest. version 5.1: - dialogue enhance audio filter - dropped obsolete XvMC hwaccel +- DFPWM audio encoder/decoder version 5.0: diff --git a/MAINTAINERS b/MAINTAINERS index f33ccbd..57b6f33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -161,6 +161,7 @@ Codecs: cscd.c Reimar Doeffinger cuviddec.c Timo Rothenpieler dca* foo86 + dfpwm* Jack Bruienne dirac* Rostislav Pehlivanov dnxhd* Baptiste Coudurier dolby_e* foo86 diff --git a/doc/general_contents.texi b/doc/general_contents.texi index df1692c..14aeaed 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -1194,6 +1194,7 @@ following image formats are supported: @item CRI HCA @tab @tab X @item Delphine Software International CIN audio @tab @tab X @tab Codec used in Delphine Software International games. +@item DFPWM @tab X @tab X @item Digital Speech Standard - Standard Play mode (DSS SP) @tab @tab X @item Discworld II BMV Audio @tab @tab X @item COOK @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 6076b4a..7474220 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -289,6 +289,8 @@ OBJS-$(CONFIG_DERF_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o diractab.o \ dirac_arith.o dirac_dwt.o dirac_vlc.o OBJS-$(CONFIG_DFA_DECODER) += dfa.o +OBJS-$(CONFIG_DFPWM_DECODER) += dfpwmdec.o +OBJS-$(CONFIG_DFPWM_ENCODER) += dfpwmenc.o OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o dnxhddata.o OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o dnxhddata.o OBJS-$(CONFIG_DOLBY_E_DECODER) += dolby_e.o dolby_e_parse.o kbdwin.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d1e1019..c3a0c26 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -437,6 +437,8 @@ extern const AVCodec ff_bmv_audio_decoder; extern const AVCodec ff_cook_decoder; extern const AVCodec ff_dca_encoder; extern const AVCodec ff_dca_decoder; +extern const AVCodec ff_dfpwm_encoder; +extern const AVCodec ff_dfpwm_decoder; extern const AVCodec ff_dolby_e_decoder; extern const AVCodec ff_dsd_lsbf_decoder; extern const AVCodec ff_dsd_msbf_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 725c687..81f3b3c 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3237,6 +3237,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("MSN Siren"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_DFPWM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dfpwm", + .long_name = NULL_IF_CONFIG_SMALL("DFPWM (Dynamic Filter Pulse Width Modulation)"), + .props = AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ab265ec..3ffb9bd 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -516,6 +516,7 @@ enum AVCodecID { AV_CODEC_ID_HCA, AV_CODEC_ID_FASTAUDIO, AV_CODEC_ID_MSNSIREN, + AV_CODEC_ID_DFPWM, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/dfpwmdec.c b/libavcodec/dfpwmdec.c new file mode 100644 index 0000000..73d4538 --- /dev/null +++ b/libavcodec/dfpwmdec.c @@ -0,0 +1,129 @@ +/* + * DFPWM decoder + * Copyright (c) 2022 Jack Bruienne + * Copyright (c) 2012, 2016 Ben "GreaseMonkey" Russell + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DFPWM1a decoder + */ + +#include "libavutil/internal.h" +#include "avcodec.h" +#include "codec_id.h" +#include "internal.h" + +typedef struct { + int fq, q, s, lt; +} DFPWMState; + +// DFPWM codec from https://github.com/ChenThread/dfpwm/blob/master/1a/ +// Licensed in the public domain + +#ifndef CONST_PREC +#define CONST_PREC 10 +#endif + +static void au_decompress(DFPWMState *state, int fs, int len, uint8_t *outbuf, uint8_t *inbuf) +{ + int i, j; + uint8_t d; + for (i = 0; i < len; i++) { + // get bits + d = *(inbuf++); + for (j = 0; j < 8; j++) { + int nq, lq, st, ns, ov; + // set target + int t = ((d&1) ? 127 : -128); + d >>= 1; + + // adjust charge + nq = state->q + ((state->s * (t-state->q) + (1<<(CONST_PREC-1)))>>CONST_PREC); + if(nq == state->q && nq != t) + state->q += (t == 127 ? 1 : -1); + lq = state->q; + state->q = nq; + + // adjust strength + st = (t != state->lt ? 0 : (1<s; + if(ns != st) + ns += (st != 0 ? 1 : -1); +#if CONST_PREC > 8 + if(ns < 1+(1<<(CONST_PREC-8))) ns = 1+(1<<(CONST_PREC-8)); +#endif + state->s = ns; + + // FILTER: perform antijerk + ov = (t != state->lt ? (nq+lq)>>1 : nq); + + // FILTER: perform LPF + state->fq += ((fs*(ov-state->fq) + 0x80)>>8); + ov = state->fq; + + // output sample + *(outbuf++) = ov + 128; + + state->lt = t; + } + } +} + +static av_cold int dfpwm_dec_init(struct AVCodecContext *ctx) +{ + DFPWMState *state = ctx->priv_data; + + state->fq = 0; + state->q = 0; + state->s = 0; + state->lt = -128; + + return 0; +} + +static int dfpwm_dec_frame(struct AVCodecContext *ctx, void *data, + int *got_frame, struct AVPacket *packet) +{ + DFPWMState *state = ctx->priv_data; + AVFrame *frame = data; + + frame->format = AV_SAMPLE_FMT_U8; + frame->nb_samples = packet->size * 8; + frame->channel_layout = AV_CH_LAYOUT_MONO; + + ff_get_buffer(ctx, frame, 0); + + au_decompress(state, 100, packet->size, frame->data[0], packet->data); + + if (got_frame) *got_frame = 1; + return packet->size; +} + +const AVCodec ff_dfpwm_decoder = { + .name = "dfpwm", + .long_name = NULL_IF_CONFIG_SMALL("DFPWM1a audio"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_DFPWM, + .priv_data_size = sizeof(DFPWMState), + .init = dfpwm_dec_init, + .decode = dfpwm_dec_frame, + .capabilities = AV_CODEC_CAP_VARIABLE_FRAME_SIZE | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, +}; \ No newline at end of file diff --git a/libavcodec/dfpwmenc.c b/libavcodec/dfpwmenc.c new file mode 100644 index 0000000..5fcc0c1 --- /dev/null +++ b/libavcodec/dfpwmenc.c @@ -0,0 +1,123 @@ +/* + * DFPWM encoder + * Copyright (c) 2022 Jack Bruienne + * Copyright (c) 2012, 2016 Ben "GreaseMonkey" Russell + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DFPWM1a encoder + */ + +#include "libavutil/internal.h" +#include "avcodec.h" +#include "codec_id.h" +#include "internal.h" + +typedef struct { + int fq, q, s, lt; +} DFPWMState; + +// DFPWM codec from https://github.com/ChenThread/dfpwm/blob/master/1a/ +// Licensed in the public domain + +#ifndef CONST_PREC +#define CONST_PREC 10 +#endif + +// note, len denotes how many compressed bytes there are (uncompressed bytes / 8). +static void au_compress(DFPWMState *state, int len, uint8_t *outbuf, uint8_t *inbuf) +{ + int i, j; + uint8_t d = 0; + for (i = 0; i < len; i++) { + for (j = 0; j < 8; j++) { + int nq, st, ns; + // get sample + int v = *(inbuf++) - 128; + // set bit / target + int t = (v < state->q || v == -128 ? -128 : 127); + d >>= 1; + if(t > 0) + d |= 0x80; + + // adjust charge + nq = state->q + ((state->s * (t-state->q) + (1<<(CONST_PREC-1)))>>CONST_PREC); + if(nq == state->q && nq != t) + nq += (t == 127 ? 1 : -1); + state->q = nq; + + // adjust strength + st = (t != state->lt ? 0 : (1<s; + if(ns != st) + ns += (st != 0 ? 1 : -1); +#if CONST_PREC > 8 + if(ns < 1+(1<<(CONST_PREC-8))) ns = 1+(1<<(CONST_PREC-8)); +#endif + state->s = ns; + + state->lt = t; + } + + // output bits + *(outbuf++) = d; + } +} + +static av_cold int dfpwm_enc_init(struct AVCodecContext *ctx) +{ + DFPWMState *state = ctx->priv_data; + + state->fq = 0; + state->q = 0; + state->s = 0; + state->lt = -128; + + return 0; +} + +static int dfpwm_enc_frame(struct AVCodecContext *ctx, struct AVPacket *packet, + const struct AVFrame *frame, int *got_packet) +{ + DFPWMState *state = ctx->priv_data; + int size = frame->nb_samples / 8 + (frame->nb_samples % 8 > 0 ? 1 : 0); + + if (packet->size < size) av_grow_packet(packet, size - packet->size); + else if (packet->size > size) av_shrink_packet(packet, size); + + au_compress(state, size, packet->data, frame->data[0]); + + if (got_packet) *got_packet = 1; + return 0; +} + +const AVCodec ff_dfpwm_encoder = { + .name = "dfpwm", + .long_name = NULL_IF_CONFIG_SMALL("DFPWM1a audio"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_DFPWM, + .priv_data_size = sizeof(DFPWMState), + .init = dfpwm_enc_init, + .encode2 = dfpwm_enc_frame, + .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NONE}, + .channel_layouts = (const uint64_t[]){AV_CH_LAYOUT_MONO, 0}, + .capabilities = AV_CODEC_CAP_VARIABLE_FRAME_SIZE, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, +}; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 6f9d90a..066da76 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -577,6 +577,8 @@ enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be) int av_get_bits_per_sample(enum AVCodecID codec_id) { switch (codec_id) { + case AV_CODEC_ID_DFPWM: + return 1; case AV_CODEC_ID_ADPCM_SBPRO_2: return 2; case AV_CODEC_ID_ADPCM_SBPRO_3: diff --git a/libavcodec/version.h b/libavcodec/version.h index d900503..84f3979 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 59 -#define LIBAVCODEC_VERSION_MINOR 21 +#define LIBAVCODEC_VERSION_MINOR 22 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From patchwork Fri Feb 25 23:43:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jack Bruienne X-Patchwork-Id: 34522 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6838:d078:0:0:0:0 with SMTP id x24csp614940nkx; Fri, 25 Feb 2022 15:43:44 -0800 (PST) X-Google-Smtp-Source: ABdhPJzw4BT85n1dUVRARcyQvHuJ6G8/kIqs1DmvVplLe8fJnHDevvOsGMqXvKU9gdAlNHpncoS8 X-Received: by 2002:a17:906:715:b0:6b7:21d5:dd0a with SMTP id y21-20020a170906071500b006b721d5dd0amr7835407ejb.500.1645832624577; Fri, 25 Feb 2022 15:43:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1645832624; cv=none; d=google.com; s=arc-20160816; b=ZV8dSW91RSWu6kerPMpkYrV3pUPXBfZm372+Dxq0ir508S/FzYfW2yYK54u9MSmVt8 B+vjuo7girMrrz9nm+wX7/xmROBerZLutRU6FK9yFOww+eGjZJQdG2Tt82B9KeT71Td8 WdqLHnd39naSxbBatUzXj8CLNuu74JsVmVruaIgDSUs1pxHU7aAKtGssD28JaVW2ZRrN FyatSY1adC2Hh5mYexqFtOk/r+/JmO5vk/3yp7pwP6xZlPb44onJwXhOxSXuCq6OT06j dBJJ8e2MOaXGpFqyufhCwgcQO/7w+7gtgG+qnvF4wGfqSy0nG37Xjq6AeRZbGUn3kZHr ymzg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject :content-language:to:from:user-agent:mime-version:date:message-id :dkim-signature:delivered-to; bh=1gt0QP3IUBD8eiDoGkyJfHzN/ZkQLPuPA20JBCHnViQ=; b=ukmUYxCbgX07qXsvUx6qvRJByUwNFaVseA2cJQ5w2/OOcfqUm1rUfLwWx4fpoFEagf SReAjB2v318hVq3wVdFxIv/RZ2gNu+uGlfM8o2tW0BZ8IBYKFG4ybicOywv1iF7ueifR p3zLgsIvVlXqMnTr0pxJSH6TMmm5onCuX8kGWSaDclG7HUXWipPHKHk/Iv5gfXwX+cpS DzMTIRB+Uhh7pc/dBxdBDFB57Isih08X2DKaYOZsyZ2VAcRZaSko13JSSw+ZgRTqVpiQ 0D/kxsAjQM/U5Mh2KSgcNhgLwNdPgnBmfoBPROqIDGSjI2iy0Y3E0KcsCiKfuyUH2/Mg e8Rw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=KDaJNjTM; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id c16-20020a17090603d000b006cfec4c6e35si2603976eja.494.2022.02.25.15.43.43; Fri, 25 Feb 2022 15:43:44 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=KDaJNjTM; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 51FF368A7E9; Sat, 26 Feb 2022 01:43:41 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-il1-f178.google.com (mail-il1-f178.google.com [209.85.166.178]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 54D6568A35C for ; Sat, 26 Feb 2022 01:43:35 +0200 (EET) Received: by mail-il1-f178.google.com with SMTP id c14so5562005ilm.4 for ; Fri, 25 Feb 2022 15:43:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=message-id:date:mime-version:user-agent:from:subject:to :content-language; bh=wx6wHGeXP7g40vUrieLXLM4Z6UC2OeJs8TaXAe1AfoQ=; b=KDaJNjTMHw7QqS7O6s0snrIcbfHHmP9+Xz6Jvpu0jSmKX7nxwqU7Zvld8dYCE881Nx AIWLSik6c6M/ZIo6E9jTSa/ZlNTxnlkaEXXoUdpwJlfcgRoNd4PdgMGNAVjyN6jNV6CY sW+dFwbBLf0p4G4oWG3z9gvVy8yiHrK/0+mpdVKPf0nUTtT+cNBdEk+DbZu/N9LENDPG GR9MYTMc1GkfoNjaiiqb28UbUwzCXt9f8zN/rukP5PherI7edVv3xL4VVupJEtfeuUII uxH7Ij4WeZZ1ptBrcnRG7hukGG1SwFhCpb9Oyboz1rXsHdSMCEkacS8SJhZt4QUpDwfE 8tVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:message-id:date:mime-version:user-agent:from :subject:to:content-language; bh=wx6wHGeXP7g40vUrieLXLM4Z6UC2OeJs8TaXAe1AfoQ=; b=4/niizpxlzlLqRspxHlzTFdNpXdlQdyVqrJ0CqtlWPknQFqRXmEz0dsMwfElUOXHnl 4p6jyrZWfZPApO2OUxHo7Ch1STYscy7GDkpQnNGutjgC1TN8+tPmZyO6ZFwjmJPDxRC8 4ro1hbwgUMt4XLqlUPZwstuNLelN8KR6ibuDPP2RtGzuNjU7lmAJPLCkfHm9krrbRExP h/a6gMmYNm0UUd7CjSHJcF0FLS1c0BLpPoFA/xU54UqjnE0PqZmTXIaJ54VE2P0K2Owc 31Dz4HbephRfVgq6HhS7oHKukRX5842CxxP9oXiRhAcjisaZ8/cJjdqV54MXdGsiUJ9n Ldcw== X-Gm-Message-State: AOAM531JvajfBu1C1EdyPuKLyR6vR1vlQTJFohfPLVa+0053yF8+8Ef/ Q/zw2A+5QopvXp6jeBqklcdmLf2v3MaLiw== X-Received: by 2002:a05:6e02:1bc5:b0:2c2:7bc9:8e8f with SMTP id x5-20020a056e021bc500b002c27bc98e8fmr8516558ilv.5.1645832613615; Fri, 25 Feb 2022 15:43:33 -0800 (PST) Received: from [192.168.7.86] (c-68-40-205-18.hsd1.mi.comcast.net. [68.40.205.18]) by smtp.gmail.com with ESMTPSA id q24-20020a6bf218000000b006416f8414dfsm2116647ioh.12.2022.02.25.15.43.32 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 25 Feb 2022 15:43:32 -0800 (PST) Message-ID: Date: Fri, 25 Feb 2022 18:43:31 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.6.1 From: Jack Bruienne To: ffmpeg-devel@ffmpeg.org Content-Language: en-US Subject: [FFmpeg-devel] [PATCH v2 2/2] libavformat: Add DFPWM raw format X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: GN4o0DZ9a1Sf This patch builds on my previous DFPWM codec patch, adding a raw audio format to be able to read/write the raw files that are most commonly used (as no other container format supports it yet). The muxers are mostly copied from the PCM demuxer and the raw muxers, as DFPWM is typically stored as raw data. Please see the previous patch for more information on DFPWM. Signed-off-by: Jack Bruienne --- Changelog | 2 +- MAINTAINERS | 1 + doc/general_contents.texi | 1 + libavformat/Makefile | 2 + libavformat/allformats.c | 2 + libavformat/dfpwmdec.c | 107 ++++++++++++++++++++++++++++++++++++++ libavformat/rawenc.c | 13 +++++ libavformat/version.h | 4 +- 8 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 libavformat/dfpwmdec.c diff --git a/Changelog b/Changelog index 5170a6a..ec688da 100644 --- a/Changelog +++ b/Changelog @@ -4,7 +4,7 @@ releases are sorted from youngest to oldest. version 5.1: - dialogue enhance audio filter - dropped obsolete XvMC hwaccel -- DFPWM audio encoder/decoder +- DFPWM audio encoder/decoder and raw muxer/demuxer version 5.0: diff --git a/MAINTAINERS b/MAINTAINERS index 57b6f33..931cf4b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -416,6 +416,7 @@ Muxers/Demuxers: dashdec.c Steven Liu dashenc.c Karthick Jeyapal daud.c Reimar Doeffinger + dfpwmdec.c Jack Bruienne dss.c Oleksij Rempel dtsdec.c foo86 dtshddec.c Paul B Mahol diff --git a/doc/general_contents.texi b/doc/general_contents.texi index 14aeaed..fcd9da1 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -578,6 +578,7 @@ library: @item raw aptX @tab X @tab X @item raw aptX HD @tab X @tab X @item raw Chinese AVS video @tab X @tab X +@item raw DFPWM @tab X @tab X @item raw Dirac @tab X @tab X @item raw DNxHD @tab X @tab X @item raw DTS @tab X @tab X diff --git a/libavformat/Makefile b/libavformat/Makefile index 6566e40..b89073a 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -165,6 +165,8 @@ OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o OBJS-$(CONFIG_DERF_DEMUXER) += derf.o pcm.o OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o +OBJS-$(CONFIG_DFPWM_DEMUXER) += dfpwmdec.o pcm.o +OBJS-$(CONFIG_DFPWM_MUXER) += rawenc.o OBJS-$(CONFIG_DHAV_DEMUXER) += dhav.o OBJS-$(CONFIG_DIRAC_DEMUXER) += diracdec.o rawdec.o OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d066a77..587ad59 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -124,6 +124,8 @@ extern const AVOutputFormat ff_daud_muxer; extern const AVInputFormat ff_dcstr_demuxer; extern const AVInputFormat ff_derf_demuxer; extern const AVInputFormat ff_dfa_demuxer; +extern const AVInputFormat ff_dfpwm_demuxer; +extern const AVOutputFormat ff_dfpwm_muxer; extern const AVInputFormat ff_dhav_demuxer; extern const AVInputFormat ff_dirac_demuxer; extern const AVOutputFormat ff_dirac_muxer; diff --git a/libavformat/dfpwmdec.c b/libavformat/dfpwmdec.c new file mode 100644 index 0000000..ad5bfa5 --- /dev/null +++ b/libavformat/dfpwmdec.c @@ -0,0 +1,107 @@ +/* + * RAW PCM demuxers + * Copyright (c) 2002 Fabrice Bellard + * Copyright (c) 2022 Jack Bruienne + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "avformat.h" +#include "internal.h" +#include "pcm.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/avassert.h" + +typedef struct DFPWMAudioDemuxerContext { + AVClass *class; + int sample_rate; +} DFPWMAudioDemuxerContext; + +static int dfpwm_read_header(AVFormatContext *s) +{ + DFPWMAudioDemuxerContext *s1 = s->priv_data; + AVCodecParameters *par; + AVStream *st; + uint8_t *mime_type = NULL; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + par = st->codecpar; + + par->codec_type = AVMEDIA_TYPE_AUDIO; + par->codec_id = s->iformat->raw_codec_id; + par->sample_rate = s1->sample_rate; + par->channels = 1; + + av_opt_get(s->pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type); + if (mime_type && s->iformat->mime_type) { + int rate = 0; + const char *options; + if (av_stristart(mime_type, s->iformat->mime_type, &options)) { /* audio/L16 */ + while (options = strchr(options, ';')) { + options++; + if (!rate) + sscanf(options, " rate=%d", &rate); + } + if (rate <= 0) { + av_log(s, AV_LOG_ERROR, + "Invalid sample_rate found in mime_type \"%s\"\n", + mime_type); + av_freep(&mime_type); + return AVERROR_INVALIDDATA; + } + par->sample_rate = rate; + } + } + av_freep(&mime_type); + + par->bits_per_coded_sample = av_get_bits_per_sample(par->codec_id); + + av_assert0(par->bits_per_coded_sample > 0); + + par->block_align = 1; + + avpriv_set_pts_info(st, 64, 1, par->sample_rate); + return 0; +} + +static const AVOption dfpwm_options[] = { + { "sample_rate", "", offsetof(DFPWMAudioDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 44100}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; +static const AVClass dfpwm_demuxer_class = { + .class_name = "dfpwm demuxer", + .item_name = av_default_item_name, + .option = dfpwm_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVInputFormat ff_dfpwm_demuxer = { + .name = "dfpwm", + .long_name = NULL_IF_CONFIG_SMALL("raw DFPWM1a data"), + .priv_data_size = sizeof(DFPWMAudioDemuxerContext), + .read_header = dfpwm_read_header, + .read_packet = ff_pcm_read_packet, + .read_seek = ff_pcm_read_seek, + .flags = AVFMT_GENERIC_INDEX, + .extensions = "dfpwm", + .raw_codec_id = AV_CODEC_ID_DFPWM, + .priv_class = &dfpwm_demuxer_class, +}; \ No newline at end of file diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c index 4bbae77..17b627b 100644 --- a/libavformat/rawenc.c +++ b/libavformat/rawenc.c @@ -192,6 +192,19 @@ const AVOutputFormat ff_data_muxer = { }; #endif +#if CONFIG_DFPWM_MUXER +const AVOutputFormat ff_dfpwm_muxer = { + .name = "dfpwm", + .long_name = NULL_IF_CONFIG_SMALL("raw DFPWM1a audio"), + .extensions = "dfpwm", + .audio_codec = AV_CODEC_ID_DFPWM, + .video_codec = AV_CODEC_ID_NONE, + .init = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_DIRAC_MUXER const AVOutputFormat ff_dirac_muxer = { .name = "dirac", diff --git a/libavformat/version.h b/libavformat/version.h index 2623457..0f89af4 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,8 +32,8 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 59 -#define LIBAVFORMAT_VERSION_MINOR 17 -#define LIBAVFORMAT_VERSION_MICRO 102 +#define LIBAVFORMAT_VERSION_MINOR 18 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \