Fix crash when using ffmpeg to play mp3 and ogg
authorNelson Ferreira <nelson.ferreira@ieee.org>
Sat, 16 Jan 2016 22:14:03 +0000 (17:14 -0500)
committerNelson Ferreira <nelson.ferreira@ieee.org>
Sat, 16 Jan 2016 22:14:48 +0000 (17:14 -0500)
* src/media/media-ffmpeg.c (media_ffmpeg_analyse_audio): Refactor
detection of sample size using av_get_bytes_per_sample. Error when
format is not supported instead of silently go ahead and possibly
crash later.

* src/media/media.c (sxe_msf_DBL_up): Implement conversion to
internal format from double.
(sxe_msf_DBL_down): Implement from internal format to double.

* src/media/media.h: Declare double encoded samples.

* m4/sxe-mm.m4 (SXE_CHECK_FFMPEG_LIBS): Detect
av_get_bytes_per_sample and av_get_sample_fmt_string.
(SXE_MM_CHECK_FFMPEG): Enforce presenc of av_get_bytes_per_sample
and av_get_sample_fmt_string.

Signed-off-by: Nelson Ferreira <nelson.ferreira@ieee.org>
m4/sxe-mm.m4
src/media/media-ffmpeg.c
src/media/media.c
src/media/media.h

index 92e873d..878c4da 100644 (file)
@@ -388,6 +388,8 @@ AC_DEFUN([SXE_MM_CHECK_FFMPEG], [
                "$ac_cv_lib_avformat_av_seek_frame" = "yes" -a \
                "$ac_cv_lib_avformat_av_register_all" = "yes" -a \
                "$ac_cv_lib_avformat_av_dump_format" = "yes" -a \
+               "$ac_cv_lib_avformat_av_get_sample_fmt_string" = "yes" -a \
+               "$ac_cv_lib_avformat_av_get_bytes_per_sample" = "yes" -a \
                "$ac_cv_lib_avcodec_avcodec_find_decoder" = "yes" -a \
                "$ac_cv_lib_avcodec_avcodec_open2" = "yes" -a \
                "$ac_cv_lib_avutil_av_dict_get" = "yes"; then
@@ -449,6 +451,8 @@ AC_DEFUN([SXE_CHECK_FFMPEG_LIBS], [dnl
        AC_CHECK_LIB([avformat], [av_seek_frame], [:], [:], [${FFMPEG_LIBS}])
        AC_CHECK_LIB([avformat], [av_register_all], [:], [:], [${FFMPEG_LIBS}])
        AC_CHECK_LIB([avformat], [av_dump_format], [:], [:], [${FFMPEG_LIBS}])
+       AC_CHECK_LIB([avformat], [av_get_bytes_per_sample], [:], [:], [${FFMPEG_LIBS}])
+       AC_CHECK_LIB([avformat], [av_get_sample_fmt_string], [:], [:], [${FFMPEG_LIBS}])
        AC_CHECK_LIB([avformat], [avformat_alloc_context], [:], [:], [${FFMPEG_LIBS}])
        AC_CHECK_LIB([avformat], [avformat_free_context], [:], [:], [${FFMPEG_LIBS}])
        AC_CHECK_LIB([avformat], [avio_alloc_context], [:], [:], [${FFMPEG_LIBS}])
index 559b2e9..e9e6710 100644 (file)
@@ -376,39 +376,47 @@ media_ffmpeg_analyse_audio(media_substream *mss, AVFormatContext *avfc, int st)
                mtap->samplerate = avcc->sample_rate;
                mtap->bitrate = media_ffmpeg_bitrate(avcc);
 
+               int sample_bytes =
+                       av_get_bytes_per_sample(avcc->sample_fmt);
+               mtap->samplewidth = 8 * sample_bytes;
+               mtap->framesize = mtap->channels * sample_bytes;
                /* samplewidth and framesize */
                switch (avcc->sample_fmt) {
                case AV_SAMPLE_FMT_U8:
-                       mtap->samplewidth = 8;
-                       mtap->framesize = mtap->channels * 1;
+                       assert(sample_bytes == 1);
                        mtap->msf = sxe_msf_U8;
                        break;
                case AV_SAMPLE_FMT_S16:
-                       mtap->samplewidth = 16;
-                       mtap->framesize = mtap->channels * 2;
+                       assert(sample_bytes == 2);
                        mtap->msf = sxe_msf_S16;
                        break;
-#if defined AV_SAMPLE_FMT_S24
-               case AV_SAMPLE_FMT_S24:
-                       mtap->samplewidth = 32;
-                       mtap->framesize = mtap->channels * 4;
-                       mtap->msf = sxe_msf_S24;
-                       break;
-#endif /* SAMPLE_FMT_S24 */
                case AV_SAMPLE_FMT_S32:
-                       mtap->samplewidth = 32;
-                       mtap->framesize = mtap->channels * 4;
+                       assert(sample_bytes == 4);
                        mtap->msf = sxe_msf_S32;
                        break;
                case AV_SAMPLE_FMT_FLT:
-                       mtap->samplewidth = 8*sizeof(float);
-                       mtap->framesize = mtap->channels * sizeof(float);
+                       assert(sample_bytes == sizeof(float));
                        mtap->msf = sxe_msf_FLT;
                        break;
+               case AV_SAMPLE_FMT_DBL:
+                       assert(sample_bytes == sizeof(double));
+                       mtap->msf = sxe_msf_DBL;
+                       break;
                case AV_SAMPLE_FMT_NONE:
-               default:
                        mtap->samplewidth = 0;
                        break;
+               default:
+                       {
+                               char fmt_name[128];
+                               error(("Unsupported sample format: "
+                                      "%s (%d), %d bytes/sample"),
+                                     av_get_sample_fmt_string(
+                                                              fmt_name,
+                                                              sizeof(fmt_name),
+                                                              avcc->sample_fmt),
+                                     avcc->sample_fmt,
+                                     sample_bytes);
+                       }
                }
        }
        mtap->endianness = 0;
index cc1707a..3d9f973 100644 (file)
@@ -1300,6 +1300,47 @@ sxe_msf_FLT_down(void *d, void *s, size_t len)
        return;
 }
 
+DEFINE_MEDIA_SAMPLE_FORMAT_SIMPLE(sxe_msf_DBL);
+
+static void
+sxe_msf_DBL_up(void *d, void *s, size_t len)
+{
+       /* convert double samples to internal format (S24in32) */
+       size_t i;
+       int32_t *dst = d;
+       double *src = s;
+
+       /* len is the number of samples (== #frame * #channels) */
+       MEDIA_DEBUG_FMT("upsampling DBL->internal: %u samples\n", len);
+
+       for (i = 0; i < len; i++) {
+               dst[i] = (int32_t)(src[i] * SXE_MAX_S24);
+       }
+       MEDIA_DEBUG_FMT("s00:%f d00:%d  s01:%f d01:%d\n",
+                       src[0], dst[0], src[1], dst[1]);
+
+       return;
+}
+
+static void
+sxe_msf_DBL_down(void *d, void *s, size_t len)
+{
+       /* convert samples from internal format (S24in32) to double */
+       int i;
+       float *dst = d;
+       int32_t *src = s;
+
+       /* len is the number of samples (== #frame * #channels) */
+       MEDIA_DEBUG_FMT("downsampling internal->FLT: %u samples\n", len);
+
+       for (i = len-1; i >= 0; i--) {
+               dst[i] = (double)(src[i]) / SXE_MAX_S24;
+       }
+       MEDIA_DEBUG_FMT("d00:%f  d01:%f\n", dst[0], dst[1]);
+
+       return;
+}
+
 /* `effects' */
 DEFINE_MEDIA_SAMPLE_EFFECT(sxe_mse_1ch_to_2ch, _sxe_mse_1ch_to_2ch);
 
index 97e3d1a..39f999f 100644 (file)
@@ -414,6 +414,7 @@ struct audio_coerce_chain_s {
 DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_U8);
 DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_S16);
 DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_FLT);
+DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_DBL);
 DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_S32);
 DECLARE_MEDIA_SAMPLE_FORMAT(sxe_msf_S24); /* format internally used */