FFmpeg
aptxenc.c
Go to the documentation of this file.
1 /*
2  * Audio Processing Technology codec for Bluetooth (aptX)
3  *
4  * Copyright (C) 2017 Aurelien Jacobs <aurel@gnuage.org>
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 #include "config_components.h"
24 
26 #include "aptx.h"
27 #include "audio_frame_queue.h"
28 #include "codec_internal.h"
29 #include "encode.h"
30 #include "internal.h"
31 
32 typedef struct AptXEncContext {
36 
37 /*
38  * Half-band QMF analysis filter realized with a polyphase FIR filter.
39  * Split into 2 subbands and downsample by 2.
40  * So for each pair of samples that goes in, one sample goes out,
41  * split into 2 separate subbands.
42  */
45  const int32_t coeffs[NB_FILTERS][FILTER_TAPS],
46  int shift,
48  int32_t *low_subband_output,
49  int32_t *high_subband_output)
50 {
52  int i;
53 
54  for (i = 0; i < NB_FILTERS; i++) {
56  subbands[i] = aptx_qmf_convolution(&signal[i], coeffs[i], shift);
57  }
58 
59  *low_subband_output = av_clip_intp2(subbands[0] + subbands[1], 23);
60  *high_subband_output = av_clip_intp2(subbands[0] - subbands[1], 23);
61 }
62 
63 /*
64  * Two stage QMF analysis tree.
65  * Split 4 input samples into 4 subbands and downsample by 4.
66  * So for each group of 4 samples that goes in, one sample goes out,
67  * split into 4 separate subbands.
68  */
70  int32_t samples[4],
71  int32_t subband_samples[4])
72 {
73  int32_t intermediate_samples[4];
74  int i;
75 
76  /* Split 4 input samples into 2 intermediate subbands downsampled to 2 samples */
77  for (i = 0; i < 2; i++)
80  &samples[2*i],
81  &intermediate_samples[0+i],
82  &intermediate_samples[2+i]);
83 
84  /* Split 2 intermediate subband samples into 4 final subbands downsampled to 1 sample */
85  for (i = 0; i < 2; i++)
88  &intermediate_samples[2*i],
89  &subband_samples[2*i+0],
90  &subband_samples[2*i+1]);
91 }
92 
95  const int32_t *intervals, int32_t nb_intervals)
96 {
97  int32_t idx = 0;
98  int i;
99 
100  for (i = nb_intervals >> 1; i > 0; i >>= 1)
101  if (MUL64(factor, intervals[idx + i]) <= ((int64_t)value << 24))
102  idx += i;
103 
104  return idx;
105 }
106 
108  int32_t sample_difference,
109  int32_t dither,
110  int32_t quantization_factor,
112 {
113  const int32_t *intervals = tables->quantize_intervals;
114  int32_t quantized_sample, dithered_sample, parity_change;
115  int32_t d, mean, interval, inv, sample_difference_abs;
116  int64_t error;
117 
118  sample_difference_abs = FFABS(sample_difference);
119  sample_difference_abs = FFMIN(sample_difference_abs, (1 << 23) - 1);
120 
121  quantized_sample = aptx_bin_search(sample_difference_abs >> 4,
122  quantization_factor,
123  intervals, tables->tables_size);
124 
125  d = rshift32_clip24(MULH(dither, dither), 7) - (1 << 23);
126  d = rshift64(MUL64(d, tables->quantize_dither_factors[quantized_sample]), 23);
127 
128  intervals += quantized_sample;
129  mean = (intervals[1] + intervals[0]) / 2;
130  interval = (intervals[1] - intervals[0]) * (-(sample_difference < 0) | 1);
131 
132  dithered_sample = rshift64_clip24(MUL64(dither, interval) + ((int64_t)av_clip_intp2(mean + d, 23) << 32), 32);
133  error = ((int64_t)sample_difference_abs << 20) - MUL64(dithered_sample, quantization_factor);
134  quantize->error = FFABS(rshift64(error, 23));
135 
136  parity_change = quantized_sample;
137  if (error < 0)
138  quantized_sample--;
139  else
140  parity_change--;
141 
142  inv = -(sample_difference < 0);
143  quantize->quantized_sample = quantized_sample ^ inv;
144  quantize->quantized_sample_parity_change = parity_change ^ inv;
145 }
146 
148 {
149  int32_t subband_samples[4];
150  int subband;
151  aptx_qmf_tree_analysis(&channel->qmf, samples, subband_samples);
153  for (subband = 0; subband < NB_SUBBANDS; subband++) {
154  int32_t diff = av_clip_intp2(subband_samples[subband] - channel->prediction[subband].predicted_sample, 23);
155  aptx_quantize_difference(&channel->quantize[subband], diff,
156  channel->dither[subband],
157  channel->invert_quantize[subband].quantization_factor,
158  &ff_aptx_quant_tables[hd][subband]);
159  }
160 }
161 
163 {
164  if (aptx_check_parity(channels, idx)) {
165  int i;
166  Channel *c;
167  static const int map[] = { 1, 2, 0, 3 };
168  Quantize *min = &channels[NB_CHANNELS-1].quantize[map[0]];
169  for (c = &channels[NB_CHANNELS-1]; c >= channels; c--)
170  for (i = 0; i < NB_SUBBANDS; i++)
171  if (c->quantize[map[i]].error < min->error)
172  min = &c->quantize[map[i]];
173 
174  /* Forcing the desired parity is done by offsetting by 1 the quantized
175  * sample from the subband featuring the smallest quantization error. */
176  min->quantized_sample = min->quantized_sample_parity_change;
177  }
178 }
179 
181 {
183  return (((channel->quantize[3].quantized_sample & 0x06) | parity) << 13)
184  | (((channel->quantize[2].quantized_sample & 0x03) ) << 11)
185  | (((channel->quantize[1].quantized_sample & 0x0F) ) << 7)
186  | (((channel->quantize[0].quantized_sample & 0x7F) ) << 0);
187 }
188 
190 {
192  return (((channel->quantize[3].quantized_sample & 0x01E) | parity) << 19)
193  | (((channel->quantize[2].quantized_sample & 0x00F) ) << 15)
194  | (((channel->quantize[1].quantized_sample & 0x03F) ) << 9)
195  | (((channel->quantize[0].quantized_sample & 0x1FF) ) << 0);
196 }
197 
200  uint8_t *output)
201 {
202  int channel;
203  for (channel = 0; channel < NB_CHANNELS; channel++)
204  aptx_encode_channel(&ctx->channels[channel], samples[channel], ctx->hd);
205 
206  aptx_insert_sync(ctx->channels, &ctx->sync_idx);
207 
208  for (channel = 0; channel < NB_CHANNELS; channel++) {
210  if (ctx->hd)
211  AV_WB24(output + 3*channel,
212  aptxhd_pack_codeword(&ctx->channels[channel]));
213  else
214  AV_WB16(output + 2*channel,
215  aptx_pack_codeword(&ctx->channels[channel]));
216  }
217 }
218 
219 static int aptx_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
220  const AVFrame *frame, int *got_packet_ptr)
221 {
222  AptXEncContext *const s0 = avctx->priv_data;
223  AptXContext *const s = &s0->common;
224  int pos, ipos, channel, sample, output_size, ret;
225 
226  if ((ret = ff_af_queue_add(&s0->afq, frame)) < 0)
227  return ret;
228 
229  output_size = s->block_size * frame->nb_samples/4;
230  if ((ret = ff_get_encode_buffer(avctx, avpkt, output_size, 0)) < 0)
231  return ret;
232 
233  for (pos = 0, ipos = 0; pos < output_size; pos += s->block_size, ipos += 4) {
235 
236  for (channel = 0; channel < NB_CHANNELS; channel++)
237  for (sample = 0; sample < 4; sample++)
238  samples[channel][sample] = (int32_t)AV_RN32A(&frame->data[channel][4*(ipos+sample)]) >> 8;
239 
240  aptx_encode_samples(s, samples, avpkt->data + pos);
241  }
242 
243  ff_af_queue_remove(&s0->afq, frame->nb_samples, &avpkt->pts, &avpkt->duration);
244  *got_packet_ptr = 1;
245  return 0;
246 }
247 
249 {
250  AptXEncContext *const s = avctx->priv_data;
251  ff_af_queue_close(&s->afq);
252  return 0;
253 }
254 
256 {
257  AptXEncContext *const s = avctx->priv_data;
258 
259  ff_af_queue_init(avctx, &s->afq);
260 
261  if (!avctx->frame_size || avctx->frame_size % 4)
262  avctx->frame_size = 1024;
263  avctx->internal->pad_samples = 4;
264 
265  return ff_aptx_init(avctx);
266 }
267 
268 #if CONFIG_APTX_ENCODER
269 const FFCodec ff_aptx_encoder = {
270  .p.name = "aptx",
271  CODEC_LONG_NAME("aptX (Audio Processing Technology for Bluetooth)"),
272  .p.type = AVMEDIA_TYPE_AUDIO,
273  .p.id = AV_CODEC_ID_APTX,
274  .p.capabilities = AV_CODEC_CAP_DR1,
275  .priv_data_size = sizeof(AptXEncContext),
278  .close = aptx_close,
280  .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } },
281  .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P,
283  .p.supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0},
284 };
285 #endif
286 
287 #if CONFIG_APTX_HD_ENCODER
288 const FFCodec ff_aptx_hd_encoder = {
289  .p.name = "aptx_hd",
290  CODEC_LONG_NAME("aptX HD (Audio Processing Technology for Bluetooth)"),
291  .p.type = AVMEDIA_TYPE_AUDIO,
292  .p.id = AV_CODEC_ID_APTX_HD,
293  .p.capabilities = AV_CODEC_CAP_DR1,
294  .priv_data_size = sizeof(AptXEncContext),
297  .close = aptx_close,
299  .p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_STEREO, { 0 } },
300  .p.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P,
302  .p.supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0},
303 };
304 #endif
ff_aptx_quant_tables
ConstTables ff_aptx_quant_tables[2][NB_SUBBANDS]
Definition: aptx.c:313
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:31
AVCodecContext::frame_size
int frame_size
Number of samples per channel in an audio frame.
Definition: avcodec.h:1035
Channel
Definition: aptx.h:81
FILTER_TAPS
#define FILTER_TAPS
Definition: aptx.h:46
ff_af_queue_remove
void ff_af_queue_remove(AudioFrameQueue *afq, int nb_samples, int64_t *pts, int64_t *duration)
Remove frame(s) from the queue.
Definition: audio_frame_queue.c:75
AV_CHANNEL_LAYOUT_STEREO
#define AV_CHANNEL_LAYOUT_STEREO
Definition: channel_layout.h:369
aptx_quantized_parity
static int32_t aptx_quantized_parity(Channel *channel)
Definition: aptx.h:188
ff_af_queue_close
void ff_af_queue_close(AudioFrameQueue *afq)
Close AudioFrameQueue.
Definition: audio_frame_queue.c:36
aptx_encode_frame
static int aptx_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr)
Definition: aptxenc.c:219
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:225
QMFAnalysis
Definition: aptx.h:53
ff_af_queue_init
av_cold void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq)
Initialize AudioFrameQueue.
Definition: audio_frame_queue.c:28
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:374
ff_aptx_hd_encoder
const FFCodec ff_aptx_hd_encoder
encode.h
ff_aptx_generate_dither
void ff_aptx_generate_dither(Channel *channel)
Definition: aptx.c:385
AV_SAMPLE_FMT_S32P
@ AV_SAMPLE_FMT_S32P
signed 32 bits, planar
Definition: samplefmt.h:65
FFCodec
Definition: codec_internal.h:119
AVPacket::duration
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:392
subbands
subbands
Definition: aptx.h:37
AptXContext
Definition: aptx.h:92
QMFAnalysis::inner_filter_signal
FilterSignal inner_filter_signal[NB_FILTERS][NB_FILTERS]
Definition: aptx.h:55
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:123
aptx_qmf_tree_analysis
static void aptx_qmf_tree_analysis(QMFAnalysis *qmf, int32_t samples[4], int32_t subband_samples[4])
Definition: aptxenc.c:69
AptXEncContext
Definition: aptxenc.c:32
NB_FILTERS
@ NB_FILTERS
Definition: vf_waveform.c:54
quantize
static int quantize(CinepakEncContext *s, int h, uint8_t *data[4], int linesize[4], int v1mode, strip_info *info, mb_encoding encoding)
Definition: cinepakenc.c:699
audio_frame_queue.h
MULH
#define MULH
Definition: mathops.h:42
tables
Writing a table generator This documentation is preliminary Parts of the API are not good and should be changed Basic concepts A table generator consists of two *_tablegen c and *_tablegen h The h file will provide the variable declarations and initialization code for the tables
Definition: tablegen.txt:10
FF_CODEC_ENCODE_CB
#define FF_CODEC_ENCODE_CB(func)
Definition: codec_internal.h:307
ff_af_queue_add
int ff_af_queue_add(AudioFrameQueue *afq, const AVFrame *f)
Add a frame to the queue.
Definition: audio_frame_queue.c:44
AV_CH_LAYOUT_STEREO
#define AV_CH_LAYOUT_STEREO
Definition: channel_layout.h:211
aptx_pack_codeword
static uint16_t aptx_pack_codeword(Channel *channel)
Definition: aptxenc.c:180
av_cold
#define av_cold
Definition: attributes.h:90
ff_aptx_encoder
const FFCodec ff_aptx_encoder
s
#define s(width, name)
Definition: cbs_vp9.c:256
ConstTables
Definition: aptx.h:99
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
NB_CHANNELS
@ NB_CHANNELS
Definition: aptx.h:34
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:363
CODEC_OLD_CHANNEL_LAYOUTS
#define CODEC_OLD_CHANNEL_LAYOUTS(...)
Definition: codec_internal.h:294
AudioFrameQueue
Definition: audio_frame_queue.h:32
ctx
AVFormatContext * ctx
Definition: movenc.c:48
channels
channels
Definition: aptx.h:31
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:264
aptxhd_pack_codeword
static uint32_t aptxhd_pack_codeword(Channel *channel)
Definition: aptxenc.c:189
AptXEncContext::afq
AudioFrameQueue afq
Definition: aptxenc.c:34
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:64
QMFAnalysis::outer_filter_signal
FilterSignal outer_filter_signal[NB_FILTERS]
Definition: aptx.h:54
aptx_qmf_convolution
static av_always_inline int32_t aptx_qmf_convolution(FilterSignal *signal, const int32_t coeffs[FILTER_TAPS], int shift)
Definition: aptx.h:174
aptx_qmf_polyphase_analysis
static av_always_inline void aptx_qmf_polyphase_analysis(FilterSignal signal[NB_FILTERS], const int32_t coeffs[NB_FILTERS][FILTER_TAPS], int shift, int32_t samples[NB_FILTERS], int32_t *low_subband_output, int32_t *high_subband_output)
Definition: aptxenc.c:44
av_clip_intp2
#define av_clip_intp2
Definition: common.h:116
AV_WB16
#define AV_WB16(p, v)
Definition: intreadwrite.h:405
AVCodecContext::internal
struct AVCodecInternal * internal
Private context used for internal data.
Definition: avcodec.h:433
aptx_qmf_outer_coeffs
static const int32_t aptx_qmf_outer_coeffs[NB_FILTERS][FILTER_TAPS]
Definition: aptx.h:132
FilterSignal
Definition: aptx.h:48
aptx_encode_samples
static void aptx_encode_samples(AptXContext *ctx, int32_t samples[NB_CHANNELS][4], uint8_t *output)
Definition: aptxenc.c:198
aptx.h
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AptXEncContext::common
AptXContext common
Definition: aptxenc.c:33
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:301
codec_internal.h
shift
static int shift(int a, int b)
Definition: bonk.c:253
aptx_qmf_inner_coeffs
static const int32_t aptx_qmf_inner_coeffs[NB_FILTERS][FILTER_TAPS]
Definition: aptx.h:147
AV_SAMPLE_FMT_NONE
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:56
sample
#define sample
Definition: flacdsp_template.c:44
parity
mcdeint parity
Definition: vf_mcdeint.c:266
AV_WB24
#define AV_WB24(p, d)
Definition: intreadwrite.h:450
aptx_quantize_difference
static void aptx_quantize_difference(Quantize *quantize, int32_t sample_difference, int32_t dither, int32_t quantization_factor, ConstTables *tables)
Definition: aptxenc.c:107
aptx_encode_init
static av_cold int aptx_encode_init(AVCodecContext *avctx)
Definition: aptxenc.c:255
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:367
AVSampleFormat
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:55
av_always_inline
#define av_always_inline
Definition: attributes.h:49
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
aptx_qmf_filter_signal_push
static av_always_inline void aptx_qmf_filter_signal_push(FilterSignal *signal, int32_t sample)
Definition: aptx.h:162
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:211
AV_RN32A
#define AV_RN32A(p)
Definition: intreadwrite.h:526
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
pos
unsigned int pos
Definition: spdifenc.c:412
ff_aptx_init
av_cold int ff_aptx_init(AVCodecContext *avctx)
Definition: aptx.c:508
AVCodecContext
main external API structure.
Definition: avcodec.h:398
channel_layout.h
ff_aptx_invert_quantize_and_prediction
void ff_aptx_invert_quantize_and_prediction(Channel *channel, int hd)
Definition: aptx.c:497
aptx_bin_search
static av_always_inline int32_t aptx_bin_search(int32_t value, int32_t factor, const int32_t *intervals, int32_t nb_intervals)
Definition: aptxenc.c:94
ff_get_encode_buffer
int ff_get_encode_buffer(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int flags)
Get a buffer for a packet.
Definition: encode.c:79
AVCodecInternal::pad_samples
int pad_samples
Audio encoders can set this flag during init to indicate that they want the small last frame to be pa...
Definition: internal.h:69
MUL64
#define MUL64(a, b)
Definition: mathops.h:55
samples
Filter the word “frame” indicates either a video frame or a group of audio samples
Definition: filter_design.txt:8
mean
static float mean(const float *input, int size)
Definition: vf_nnedi.c:857
factor
static const int factor[16]
Definition: vf_pp7.c:76
s0
#define s0
Definition: regdef.h:37
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
diff
static av_always_inline int diff(const uint32_t a, const uint32_t b)
Definition: vf_palettegen.c:139
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:425
AVPacket
This structure stores compressed data.
Definition: packet.h:351
d
d
Definition: ffmpeg_filter.c:156
int32_t
int32_t
Definition: audioconvert.c:56
aptx_encode_channel
static void aptx_encode_channel(Channel *channel, int32_t samples[4], int hd)
Definition: aptxenc.c:147
aptx_close
static av_cold int aptx_close(AVCodecContext *avctx)
Definition: aptxenc.c:248
AV_CODEC_ID_APTX
@ AV_CODEC_ID_APTX
Definition: codec_id.h:520
NB_SUBBANDS
@ NB_SUBBANDS
Definition: aptx.h:42
AV_CODEC_ID_APTX_HD
@ AV_CODEC_ID_APTX_HD
Definition: codec_id.h:521
channel
channel
Definition: ebur128.h:39
Quantize
Definition: aptx.h:58
aptx_insert_sync
static void aptx_insert_sync(Channel channels[NB_CHANNELS], int32_t *idx)
Definition: aptxenc.c:162
aptx_check_parity
static int aptx_check_parity(Channel channels[NB_CHANNELS], int32_t *idx)
Definition: aptx.h:201
min
float min
Definition: vorbis_enc_data.h:429
dither
static const uint8_t dither[8][8]
Definition: vf_fspp.c:58