[FFmpeg-devel] [PATCH 08/12] avradio/sdr: Move IFFT and block size to main context

Michael Niedermayer michael at niedermayer.cc
Wed Jul 12 00:19:06 EEST 2023


This avoids duplicating this per stream instance

Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
---
 libavradio/sdr.h      |  12 +++-
 libavradio/sdrdemux.c | 144 ++++++++++++++++++++++++------------------
 2 files changed, 91 insertions(+), 65 deletions(-)

diff --git a/libavradio/sdr.h b/libavradio/sdr.h
index 834b1f40b4..79e48e6162 100644
--- a/libavradio/sdr.h
+++ b/libavradio/sdr.h
@@ -99,13 +99,10 @@ typedef struct FIFOElement {
 } FIFOElement;
 
 typedef struct SDRStream {
-    AVTXContext *ifft_ctx;
     AVTXContext *fft_ctx;
     AVTXContext *ifft_p2_ctx;
-    av_tx_fn ifft;
     av_tx_fn fft;
     av_tx_fn ifft_p2;
-    int block_size;
     int processing_index;
     float *out_buf;
     AVComplexFloat *block;
@@ -160,11 +157,20 @@ typedef struct SDRContext {
     int sample_size;
     double sample_scale;
 
+    int64_t am_bandwidth;
+    int64_t fm_bandwidth;
     int64_t fm_bandwidth_p2;
+    int am_block_size;
+    int fm_block_size;
     int fm_block_size_p2;
     int rds_ring_size;
     float *fm_window_p2;
 
+    AVTXContext *am_ifft_ctx;
+    AVTXContext *fm_ifft_ctx;
+    av_tx_fn am_ifft;
+    av_tx_fn fm_ifft;
+
     int am_mode;                            ///< AMMode but using int for generic option access
     int emphasis_mode;
     int am_fft_ref;
diff --git a/libavradio/sdrdemux.c b/libavradio/sdrdemux.c
index 8b8c126380..443f48aebb 100644
--- a/libavradio/sdrdemux.c
+++ b/libavradio/sdrdemux.c
@@ -541,7 +541,7 @@ static double find_peak_macleod(const SDRContext *sdr, const AVComplexFloat *dat
 static int probe_am(SDRContext *sdr)
 {
     int i;
-    int bandwidth_f = 6000;
+    int bandwidth_f = sdr->am_bandwidth;
     int half_bw_i = bandwidth_f * (int64_t)sdr->block_size / sdr->sdr_sample_rate;
     int border_i = (sdr->sdr_sample_rate - sdr->bandwidth) * sdr->block_size / sdr->sdr_sample_rate;
     double avg = 0;
@@ -675,7 +675,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
     int len   = (bandwidth * 2ll * sdr->block_size + sdr->sdr_sample_rate/2) / sdr->sdr_sample_rate;
     float *newbuf;
     float scale;
-    int sample_rate = sdr->sdr_sample_rate * (int64_t)sst->block_size / sdr->block_size;
+    int sample_rate = sdr->sdr_sample_rate * (int64_t)sdr->am_block_size / sdr->block_size;
     int ret, i;
     double current_station_i;
     float limits[2] = {-0.0, 0.0};
@@ -685,7 +685,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
 #define CARRIER_SEARCH 2
     if (index + len + CARRIER_SEARCH>= 2*sdr->block_size ||
         index - len - CARRIER_SEARCH < 0 ||
-        2*len + 1 > 2*sst->block_size)
+        2*len + 1 > 2*sdr->am_block_size)
         return AVERROR(ERANGE);
 
     current_station_i = find_am_carrier(sdr, sdr->block, 2*sdr->block_size, sdr->len2block, index, CARRIER_SEARCH, len);
@@ -699,21 +699,21 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         am_mode = AMEnvelope;
     }
 
-    newbuf = av_malloc(sizeof(*sst->out_buf) * 2 * sst->block_size);
+    newbuf = av_malloc(sizeof(*sst->out_buf) * 2 * sdr->am_block_size);
     if (!newbuf)
         return AVERROR(ENOMEM);
 #define SEPC 4
 
     i = 2*len+1;
     memcpy(sst->block, sdr->block + index - len, sizeof(*sst->block) * i);
-    memset(sst->block + i, 0, sizeof(*sst->block) * (2 * sst->block_size - i));
+    memset(sst->block + i, 0, sizeof(*sst->block) * (2 * sdr->am_block_size - i));
 
-    sst->ifft(sst->ifft_ctx, sst->iblock  , sst->block, sizeof(AVComplexFloat));
+    sdr->am_ifft(sdr->am_ifft_ctx, sst->iblock  , sst->block, sizeof(AVComplexFloat));
 
     if (am_mode == AMEnvelope) {
         double vdotw = 0;
         double wdot = 0; // could be precalculated
-        for (i = 0; i<2*sst->block_size; i++) {
+        for (i = 0; i<2*sdr->am_block_size; i++) {
             float w = sst->window[i];
             float v = sqrt(len2(sst->iblock[i]));
             sst->iblock[i].re = v;
@@ -724,7 +724,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         }
 
         vdotw /= wdot ;
-        for (i = 0; i<2*sst->block_size; i++) {
+        for (i = 0; i<2*sdr->am_block_size; i++) {
             float w = sst->window[i];
             sst->iblock[i].re -= w*vdotw;
         }
@@ -735,14 +735,14 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         memset(sst->block, 0, sizeof(*sst->block) * i);
         for (i = len-SEPC+1; i<len+SEPC; i++)
             sst->block[i] = sdr->block[index + i - len];
-        sst->ifft(sst->ifft_ctx, sst->icarrier, sst->block, sizeof(AVComplexFloat));
+        sdr->am_ifft(sdr->am_ifft_ctx, sst->icarrier, sst->block, sizeof(AVComplexFloat));
 
-        synchronous_am_demodulationN(sst->iblock, sst->icarrier, sst->window, 2*sst->block_size, 1);
+        synchronous_am_demodulationN(sst->iblock, sst->icarrier, sst->window, 2*sdr->am_block_size, 1);
         scale = 0.9;
     } else {
         // Synchronous demodulation using Macleod based systhesized carrier
         double fcorr = F2INDEX(freq) - index + len;
-        double theta = -M_PI*fcorr / sst->block_size;
+        double theta = -M_PI*fcorr / sdr->am_block_size;
         AVComplexDouble mdelta = {cos(theta), sin(theta)};
         AVComplexDouble m = {1,0};
         AVComplexDouble dc1 = {0,0};
@@ -751,7 +751,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         double dcw = 0;
         float amp, stamp, wamp;
 
-        for(i = 0; i<2*sst->block_size; i++) {
+        for(i = 0; i<2*sdr->am_block_size; i++) {
             double tmp;
             AVComplexFloat v = sst->iblock[i];
             sst->iblock[i].re = v.re*m.re - v.im*m.im;
@@ -773,7 +773,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         wamp = amp/stamp;
 
         mm = (AVComplexFloat){dc1.re * amp, -dc1.im * amp};
-        for(i = 0; i<2*sst->block_size; i++) {
+        for(i = 0; i<2*sdr->am_block_size; i++) {
             AVComplexFloat v = sst->iblock[i];
             sst->iblock[i].re = v.re*mm.re - v.im*mm.im - sst->window[i] * wamp;
             sst->iblock[i].im = v.re*mm.im + v.im*mm.re;
@@ -782,7 +782,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         scale = 0.9;
     }
 
-    for(i = 0; i<2*sst->block_size; i++) {
+    for(i = 0; i<2*sdr->am_block_size; i++) {
         av_assert0(isfinite(sst->iblock[i].re));
         av_assert0(isfinite(sst->iblock[i].im));
         limits[0] = FFMIN(limits[0], FFMIN(sst->iblock[i].re - sst->iblock[i].im,  sst->iblock[i].re + sst->iblock[i].im));
@@ -791,17 +791,17 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
     av_assert1(FFMAX(limits[1], -limits[0]) >= 0);
     scale = FFMIN(scale, 0.98 / FFMAX(limits[1], -limits[0]));
 
-    for(i = 0; i<sst->block_size; i++) {
+    for(i = 0; i<sdr->am_block_size; i++) {
         float m, q;
 
         m = sst->out_buf[2*i+0] + (sst->iblock[i                  ].re) * sst->window[i                  ] * scale;
-        newbuf[2*i+0]           = (sst->iblock[i + sst->block_size].re) * sst->window[i + sst->block_size] * scale;
+        newbuf[2*i+0]           = (sst->iblock[i + sdr->am_block_size].re) * sst->window[i + sdr->am_block_size] * scale;
 
         switch(am_mode) {
         case AMMidSide:
         case AMLeftRight:
             q = sst->out_buf[2*i+1] +  sst->iblock[i                  ].im * sst->window[i                  ] * scale;
-            newbuf[2*i+1]           =  sst->iblock[i + sst->block_size].im * sst->window[i + sst->block_size] * scale;
+            newbuf[2*i+1]           =  sst->iblock[i + sdr->am_block_size].im * sst->window[i + sdr->am_block_size] * scale;
             switch(am_mode) {
             case AMMidSide:
                 q *= 0.5;
@@ -828,7 +828,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
         }
     }
 
-    ret = av_packet_from_data(pkt, (void*)sst->out_buf, sizeof(*sst->out_buf) * 2 * sst->block_size);
+    ret = av_packet_from_data(pkt, (void*)sst->out_buf, sizeof(*sst->out_buf) * 2 * sdr->am_block_size);
     if (ret < 0)
         av_free(sst->out_buf);
     sst->out_buf = newbuf;
@@ -849,7 +849,7 @@ static int demodulate_am(SDRContext *sdr, int stream_index, AVPacket *pkt)
 static int probe_fm(SDRContext *sdr)
 {
     int i;
-    int bandwidth_f  = 180*1000;
+    int bandwidth_f  = sdr->fm_bandwidth;
     int half_bw_i = bandwidth_f * (int64_t)sdr->block_size / sdr->sdr_sample_rate;
     float last_score[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
     int border_i = (sdr->sdr_sample_rate - FFMIN(sdr->bandwidth, sdr->sdr_sample_rate*7/8)) * sdr->block_size / sdr->sdr_sample_rate;
@@ -938,19 +938,21 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
 {
     AVStream *st   = sdr->avfmt->streams[stream_index];
     SDRStream *sst = st->priv_data;
-    double freq    = sst->station->frequency;
-    int64_t bandwidth = sst->station->bandwidth;
+    Station *station = sst->station;
+
+    double freq    = station->frequency;
+    int64_t bandwidth = station->bandwidth;
     int index = lrint(F2INDEX(freq));
     int len   = (bandwidth * 2ll * sdr->block_size + sdr->sdr_sample_rate/2) / sdr->sdr_sample_rate;
     float *newbuf;
     float scale;
-    int sample_rate    = sdr->sdr_sample_rate * (int64_t)sst->block_size    / sdr->block_size;
+    int sample_rate    = sdr->sdr_sample_rate * (int64_t)sdr->fm_block_size    / sdr->block_size;
     int sample_rate_p2 = sdr->sdr_sample_rate * (int64_t)sdr->fm_block_size_p2 / sdr->block_size;
     int ret, i;
     float clip = 1.0;
-    int carrier19_i = 2L*sst->block_size*19000 / sample_rate;
-    int len17_i     = 2L*sst->block_size*16500 / sample_rate;
-    int len2_4_i    = 2L*sst->block_size* 2400 / sample_rate;
+    int carrier19_i = 2L*sdr->fm_block_size*19000 / sample_rate;
+    int len17_i     = 2L*sdr->fm_block_size*16500 / sample_rate;
+    int len2_4_i    = 2L*sdr->fm_block_size* 2400 / sample_rate;
     double carrier19_i_exact;
     int W= 5;
 
@@ -961,21 +963,21 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
 
     if (index + len >= 2*sdr->block_size ||
         index - len < 0 ||
-        2*len + 1   > 2*sst->block_size)
+        2*len + 1   > 2*sdr->fm_block_size)
     return AVERROR(ERANGE);
 
-    newbuf = av_malloc(sizeof(*sst->out_buf) * 2 * sst->block_size);
+    newbuf = av_malloc(sizeof(*sst->out_buf) * 2 * sdr->fm_block_size);
     if (!newbuf)
         return AVERROR(ENOMEM);
 
     i = 2*len+1;
     memcpy(sst->block, sdr->block + index, sizeof(*sst->block) * (len + 1));
-    memcpy(sst->block + 2 * sst->block_size - len, sdr->block + index - len, sizeof(*sst->block) * len);
-    memset(sst->block + len + 1, 0, sizeof(*sst->block) * (2 * sst->block_size - i));
+    memcpy(sst->block + 2 * sdr->fm_block_size - len, sdr->block + index - len, sizeof(*sst->block) * len);
+    memset(sst->block + len + 1, 0, sizeof(*sst->block) * (2 * sdr->fm_block_size - i));
 
-    sst->ifft(sst->ifft_ctx, sst->iblock, sst->block, sizeof(AVComplexFloat));
+    sdr->fm_ifft(sdr->fm_ifft_ctx, sst->iblock, sst->block, sizeof(AVComplexFloat));
 
-    for (i = 0; i<2*sst->block_size - 1; i++) {
+    for (i = 0; i<2*sdr->fm_block_size - 1; i++) {
         AVComplexFloat x = sst->iblock[i];
         AVComplexFloat y = sst->iblock[i+1];
         sst->iblock[i].re = atan2(x.im * y.re - x.re * y.im,
@@ -985,18 +987,18 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
     sst->iblock[i].re = 0;
     sst->iblock[i].im = 0;
 
-    av_assert0(sdr->fm_block_size_p2 * 2 < sst->block_size);
+    av_assert0(sdr->fm_block_size_p2 * 2 < sdr->fm_block_size);
     //FIXME this only needs to be a RDFT
     //CONSIDER, this and in fact alot can be done with bandpass and lowpass filters instead of FFTs, find out which is better
     //CONSIDER synthesizing the carrier instead of IFFT, we have all parameters for that
     sst->fft(sst->fft_ctx, sst->block, sst->iblock, sizeof(AVComplexFloat));
     // Only the low N/2+1 are used the upper is just a reflection
 
-    carrier19_i_exact = find_am_carrier(sdr, sst->block, 2*sst->block_size, (void*)(sst->block + 1 + sst->block_size), carrier19_i, 10, 10);
+    carrier19_i_exact = find_am_carrier(sdr, sst->block, 2*sdr->fm_block_size, (void*)(sst->block + 1 + sdr->fm_block_size), carrier19_i, 10, 10);
     carrier19_i = lrint(carrier19_i_exact);
 
     if (carrier19_i >= 0) {
-        i = sst->block_size;
+        i = sdr->fm_block_size;
         memset(sst->block + i, 0, 2*sdr->fm_block_size_p2 * sizeof(AVComplexFloat));
         memcpy(sst->block + i, sst->block + carrier19_i, sizeof(AVComplexFloat)*(W+1));
         memcpy(sst->block + i + 2*sdr->fm_block_size_p2 - W, sst->block + carrier19_i - W, sizeof(AVComplexFloat)*W);
@@ -1018,9 +1020,9 @@ static int demodulate_fm(SDRContext *sdr, int stream_index, AVPacket *pkt)
     memset(sst->block + len17_i, 0, (2*sdr->fm_block_size_p2 - len17_i) * sizeof(AVComplexFloat));
     apply_deemphasis(sdr, sst->block, 2*sdr->fm_block_size_p2, sample_rate_p2, + 1);
     sst->ifft_p2(sst->ifft_p2_ctx, sst->iblock  , sst->block, sizeof(AVComplexFloat));
-    memset(sst->iblock + 2*sdr->fm_block_size_p2, 0 ,(2*sst->block_size -2*sdr->fm_block_size_p2) * sizeof(AVComplexFloat));
+    memset(sst->iblock + 2*sdr->fm_block_size_p2, 0 ,(2*sdr->fm_block_size -2*sdr->fm_block_size_p2) * sizeof(AVComplexFloat));
 
-    scale      = 5 / (M_PI * 2*sst->block_size);
+    scale      = 5 / (M_PI * 2*sdr->fm_block_size);
     for(i = 0; i<sdr->fm_block_size_p2; i++) {
         float m, q;
 
@@ -1094,13 +1096,10 @@ static void free_stream(SDRContext *sdr, int stream_index)
     AVStream *st = s->streams[stream_index];
     SDRStream *sst = st->priv_data;
 
-    av_tx_uninit(&sst->ifft_ctx);
     av_tx_uninit(&sst->fft_ctx);
     av_tx_uninit(&sst->ifft_p2_ctx);
-    sst->ifft = NULL;
     sst->fft  = NULL;
     sst->ifft_p2 = NULL;
-    sst->block_size = 0;
 
     av_freep(&sst->out_buf);
     av_freep(&sst->block);
@@ -1110,6 +1109,16 @@ static void free_stream(SDRContext *sdr, int stream_index)
     av_freep(&sst->window);
 }
 
+static int find_block_size(SDRContext *sdr, int64_t bandwidth)
+{
+    int block_size;
+
+    for (block_size = 4; 2ll * bandwidth * sdr->block_time > block_size; block_size <<= 1)
+        ;
+
+    return FFMIN(sdr->block_size,  block_size);
+}
+
 static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
 {
     AVFormatContext *s = sdr->avfmt;
@@ -1132,17 +1141,10 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
     if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
         free_stream(sdr, stream_index);
 
-        for (sst->block_size = 4; 2ll *sst->station->bandwidth * sdr->block_time > sst->block_size; sst->block_size <<= 1)
-            ;
-        sst->block_size = FFMIN(sdr->block_size,  sst->block_size);
-
-        ret = av_tx_init(&sst->ifft_ctx, &sst->ifft, AV_TX_FLOAT_FFT, 1, 2*sst->block_size, NULL, 0);
-        if (ret < 0)
-            return ret;
-
+        int block_size;
         if (sst->station->modulation == FM) {
             //Allocate 2nd stage demodulation fields if needed
-            ret = av_tx_init(&sst-> fft_ctx, &sst-> fft, AV_TX_FLOAT_FFT, 0, 2*sst->block_size   , NULL, 0);
+            ret = av_tx_init(&sst-> fft_ctx, &sst-> fft, AV_TX_FLOAT_FFT, 0, 2*sdr->fm_block_size   , NULL, 0);
             if (ret < 0)
                 return ret;
 
@@ -1153,19 +1155,21 @@ static int setup_stream(SDRContext *sdr, int stream_index, Station *station)
             sst->iside     = av_malloc(sizeof(*sst->iside)    * 2 * sdr->fm_block_size_p2);
             if (!sst->iside)
                 return AVERROR(ENOMEM);
-        }
-
-        sst->out_buf   = av_mallocz(sizeof(*sst->out_buf) * 2 * sst->block_size);
-        sst->block     = av_malloc(sizeof(*sst-> block)   * 2 * sst->block_size);
-        sst->iblock    = av_malloc(sizeof(*sst->iblock)   * 2 * sst->block_size);
-        sst->icarrier  = av_malloc(sizeof(*sst->icarrier) * 2 * sst->block_size);
-        sst->window    = av_malloc(sizeof(*sst->window)   * 2 * sst->block_size);
+            block_size = sdr->fm_block_size;
+        } else
+            block_size = sdr->am_block_size;
+
+        sst->out_buf   = av_mallocz(sizeof(*sst->out_buf) * 2 * block_size);
+        sst->block     = av_malloc(sizeof(*sst-> block)   * 2 * block_size);
+        sst->iblock    = av_malloc(sizeof(*sst->iblock)   * 2 * block_size);
+        sst->icarrier  = av_malloc(sizeof(*sst->icarrier) * 2 * block_size);
+        sst->window    = av_malloc(sizeof(*sst->window)   * 2 * block_size);
         if (!sst->out_buf || !sst->block || !sst->iblock || !sst->icarrier || !sst->window)
             return AVERROR(ENOMEM);
 
-        avpriv_kbd_window_init(sst->window, sdr->kbd_alpha, sst->block_size);
-        for(int i = sst->block_size; i < 2 * sst->block_size; i++) {
-            sst->window[i] = sst->window[2*sst->block_size - i - 1];
+        avpriv_kbd_window_init(sst->window, sdr->kbd_alpha, block_size);
+        for(int i = block_size; i < 2 * block_size; i++) {
+            sst->window[i] = sst->window[2*block_size - i - 1];
         }
 
         sst->am_amplitude = 0;
@@ -1491,10 +1495,13 @@ int ff_sdr_common_init(AVFormatContext *s)
     av_log(s, AV_LOG_INFO, "Block size %d\n", sdr->block_size);
 
     sdr->block_time = sdr->block_size / (double)sdr->sdr_sample_rate;
-    sdr->fm_bandwidth_p2 = 18 * 1000;
-    if (!sdr->fm_block_size_p2)
-        for (sdr->fm_block_size_p2 = 4; 2ll *sdr->fm_bandwidth_p2 * sdr->block_time > sdr->fm_block_size_p2; sdr->fm_block_size_p2 <<= 1)
-            ;
+    sdr->am_bandwidth    =   6 * 1000;
+    sdr->fm_bandwidth    = 180 * 1000;
+    sdr->fm_bandwidth_p2 =  18 * 1000;
+
+    sdr->am_block_size    = find_block_size(sdr, sdr->am_bandwidth);
+    sdr->fm_block_size    = find_block_size(sdr, sdr->fm_bandwidth);
+    sdr->fm_block_size_p2 = find_block_size(sdr, sdr->fm_bandwidth_p2);
 
     sdr->windowed_block = av_malloc(sizeof(*sdr->windowed_block) * 2 * sdr->block_size);
     sdr->block     = av_malloc(sizeof(*sdr->block    ) * 2 * sdr->block_size);
@@ -1509,6 +1516,15 @@ int ff_sdr_common_init(AVFormatContext *s)
     if (ret < 0)
         return ret;
 
+    ret = av_tx_init(&sdr->am_ifft_ctx, &sdr->am_ifft, AV_TX_FLOAT_FFT, 1, 2*sdr->am_block_size, NULL, 0);
+    if (ret < 0)
+        return ret;
+
+    ret = av_tx_init(&sdr->fm_ifft_ctx, &sdr->fm_ifft, AV_TX_FLOAT_FFT, 1, 2*sdr->fm_block_size, NULL, 0);
+    if (ret < 0)
+        return ret;
+
+
     avpriv_kbd_window_init(sdr->window, sdr->kbd_alpha, sdr->block_size);
 
     for(int i = sdr->block_size; i < 2 * sdr->block_size; i++) {
@@ -1973,7 +1989,11 @@ int ff_sdr_read_close(AVFormatContext *s)
     av_freep(&sdr->fm_window_p2);
 
     av_tx_uninit(&sdr->fft_ctx);
+    av_tx_uninit(&sdr->am_ifft_ctx);
+    av_tx_uninit(&sdr->fm_ifft_ctx);
     sdr->fft = NULL;
+    sdr->am_ifft = NULL;
+    sdr->fm_ifft = NULL;
 
     avio_close(sdr->dump_avio);
 
-- 
2.31.1



More information about the ffmpeg-devel mailing list