ffs: resample audio in ffs_adec()
authorAli Gholami Rudi <ali@rudi.ir>
Sun, 10 Feb 2013 08:39:17 +0000 (10 12:09 +0330)
committerAli Gholami Rudi <ali@rudi.ir>
Sun, 10 Feb 2013 11:26:12 +0000 (10 14:56 +0330)
Ffmpeg's interface is simply stupid and gets worse with every
release.  I wish there were a saner alternative.

Makefile
fbff.c
ffs.c
ffs.h

index d1cb1cc..53679e6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ FF_PATH = /opt
 CC = cc
 CFLAGS = -I$(FF_PATH)/include -Wall -O2
 LDFLAGS = -L$(FF_PATH)/lib -lavutil -lavformat -lavcodec -lavutil \
-               -lswscale -lz -lm -lpthread
+               -lswscale -lswresample -lz -lm -lpthread
 
 all: fbff
 .c.o:
diff --git a/fbff.c b/fbff.c
index 076613d..a726c79 100644 (file)
--- a/fbff.c
+++ b/fbff.c
@@ -1,9 +1,9 @@
 /*
  * fbff - a small ffmpeg-based framebuffer/oss media player
  *
- * Copyright (C) 2009-2012 Ali Gholami Rudi
+ * Copyright (C) 2009-2013 Ali Gholami Rudi
  *
- * This program is released under GNU GPL version 2.
+ * This program is released under the modified BSD license.
  */
 #include <fcntl.h>
 #include <pty.h>
@@ -297,7 +297,6 @@ static void oss_close(void)
 
 static void *process_audio(void *dat)
 {
-       oss_init();
        while (1) {
                while (!a_reset && (a_conswait() || paused) && !exited)
                        stroll();
@@ -407,8 +406,11 @@ int main(int argc, char *argv[])
                audio = 0;
        if (!video && !audio)
                return 1;
-       if (audio)
+       if (audio) {
+               ffs_aconf(affs);
+               oss_init();
                pthread_create(&a_thread, NULL, process_audio, NULL);
+       }
        if (video) {
                int w, h;
                if (fb_init())
@@ -421,7 +423,7 @@ int main(int argc, char *argv[])
                        float wz = (float) fb_cols() / w / magnify;
                        zoom = hz < wz ? hz : wz;
                }
-               ffs_vsetup(vffs, zoom, fb_mode());
+               ffs_vconf(vffs, zoom, fb_mode());
        }
        term_setup();
        signal(SIGCONT, sigcont);
diff --git a/ffs.c b/ffs.c
index 96d0eaf..c7b4ec7 100644 (file)
--- a/ffs.c
+++ b/ffs.c
@@ -3,11 +3,15 @@
 #include <stdint.h>
 #include <unistd.h>
 #include <sys/time.h>
-#include <libavformat/avformat.h>
 #include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libswresample/swresample.h>
 #include <libswscale/swscale.h>
 #include "ffs.h"
 
+#define FFS_SAMPLEFMT          AV_SAMPLE_FMT_S16
+#define FFS_CHLAYOUT           AV_CH_LAYOUT_STEREO
+
 /* ffmpeg stream */
 struct ffs {
        AVCodecContext *cc;
@@ -21,6 +25,7 @@ struct ffs {
 
        /* decoding video frames */
        struct SwsContext *swsc;
+       struct SwrContext *swrc;
        AVFrame *dst;
        AVFrame *tmp;
 };
@@ -44,6 +49,7 @@ struct ffs *ffs_alloc(char *path, int flags)
        ffs->cc = ffs->fc->streams[ffs->si]->codec;
        if (avcodec_open2(ffs->cc, avcodec_find_decoder(ffs->cc->codec_id), &opt))
                goto failed;
+       ffs->tmp = avcodec_alloc_frame();
        ffs->dst = avcodec_alloc_frame();
        return ffs;
 failed:
@@ -53,6 +59,8 @@ failed:
 
 void ffs_free(struct ffs *ffs)
 {
+       if (ffs->swrc)
+               swr_free(&ffs->swrc);
        if (ffs->swsc)
                sws_freeContext(ffs->swsc);
        if (ffs->dst)
@@ -142,7 +150,7 @@ void ffs_vinfo(struct ffs *ffs, int *w, int *h)
 void ffs_ainfo(struct ffs *ffs, int *rate, int *bps, int *ch)
 {
        *rate = ffs->cc->sample_rate;
-       *ch = ffs->cc->channels;
+       *ch = av_get_channel_layout_nb_channels(FFS_CHLAYOUT);
        *bps = 16;
 }
 
@@ -164,25 +172,37 @@ int ffs_vdec(struct ffs *ffs, void **buf)
        return 0;
 }
 
+static int ffs_bytespersample(ffs)
+{
+       return av_get_bytes_per_sample(FFS_SAMPLEFMT) *
+               av_get_channel_layout_nb_channels(FFS_CHLAYOUT);
+}
+
 int ffs_adec(struct ffs *ffs, void *buf, int blen)
 {
        int rdec = 0;
        AVPacket tmppkt = {0};
        AVPacket *pkt = ffs_pkt(ffs);
+       uint8_t *out[] = {NULL};
        if (!pkt)
                return -1;
        tmppkt.size = pkt->size;
        tmppkt.data = pkt->data;
        while (tmppkt.size > 0) {
-               int size = blen - rdec;
-               int len = avcodec_decode_audio3(ffs->cc, (int16_t *) (buf + rdec),
-                                               &size, &tmppkt);
+               int len, size;
+               len = avcodec_decode_audio4(ffs->cc, ffs->tmp, &size, &tmppkt);
                if (len < 0)
                        break;
                tmppkt.size -= len;
                tmppkt.data += len;
-               if (size > 0)
-                       rdec += size;
+               if (size <= 0)
+                       continue;
+               out[0] = buf + rdec;
+               len = swr_convert(ffs->swrc,
+                       out, (blen - rdec) / ffs_bytespersample(ffs),
+                       (void *) ffs->tmp->extended_data, ffs->tmp->nb_samples);
+               if (len > 0)
+                       rdec += len * ffs_bytespersample(ffs);
        }
        av_free_packet(pkt);
        return rdec;
@@ -203,7 +223,7 @@ static int fbm2pixfmt(int fbm)
        }
 }
 
-void ffs_vsetup(struct ffs *ffs, float zoom, int fbm)
+void ffs_vconf(struct ffs *ffs, float zoom, int fbm)
 {
        int h = ffs->cc->height;
        int w = ffs->cc->width;
@@ -214,12 +234,22 @@ void ffs_vsetup(struct ffs *ffs, float zoom, int fbm)
        ffs->swsc = sws_getContext(w, h, fmt, w * zoom, h * zoom,
                        pixfmt, SWS_FAST_BILINEAR | SWS_CPU_CAPS_MMX2,
                        NULL, NULL, NULL);
-       ffs->tmp = avcodec_alloc_frame();
        n = avpicture_get_size(pixfmt, w * zoom, h * zoom);
        buf = av_malloc(n * sizeof(uint8_t));
        avpicture_fill((AVPicture *) ffs->dst, buf, pixfmt, w * zoom, h * zoom);
 }
 
+void ffs_aconf(struct ffs *ffs)
+{
+       int rate, bps, ch;
+       ffs_ainfo(ffs, &rate, &bps, &ch);
+       ffs->swrc = swr_alloc_set_opts(NULL,
+               FFS_CHLAYOUT, FFS_SAMPLEFMT, rate,
+               ffs->cc->channel_layout, ffs->cc->sample_fmt, ffs->cc->sample_rate,
+               0, NULL);
+       swr_init(ffs->swrc);
+}
+
 void ffs_globinit(void)
 {
        av_register_all();
diff --git a/ffs.h b/ffs.h
index a6f4177..f5a6d48 100644 (file)
--- a/ffs.h
+++ b/ffs.h
@@ -14,10 +14,11 @@ void ffs_wait(struct ffs *ffs);
 int ffs_avdiff(struct ffs *ffs, struct ffs *affs);
 
 /* audio */
+void ffs_aconf(struct ffs *ffs);
 void ffs_ainfo(struct ffs *ffs, int *rate, int *bps, int *ch);
 int ffs_adec(struct ffs *ffs, void *buf, int blen);
 
 /* video */
-void ffs_vsetup(struct ffs *ffs, float zoom, int fbm);
+void ffs_vconf(struct ffs *ffs, float zoom, int fbm);
 void ffs_vinfo(struct ffs *ffs, int *w, int *h);
 int ffs_vdec(struct ffs *ffs, void **buf);