[FFmpeg-devel] [PATCH] wavdec: RIFX file format support

Thomas Volkert silvo at gmx.net
Mon Dec 15 11:10:08 CET 2014


This fixes ticket #1978.

From: Thomas Volkert <thomas at homer-conferencing.com>

---
  Changelog                 |  1 +
  libavformat/act.c         |  2 +-
  libavformat/asfdec.c      |  2 +-
  libavformat/avidec.c      |  2 +-
  libavformat/dxa.c         |  2 +-
  libavformat/matroskadec.c |  2 +-
  libavformat/mlvdec.c      |  2 +-
  libavformat/mov.c         |  2 +-
  libavformat/riff.h        |  2 +-
  libavformat/riffdec.c     | 20 ++++++++++++++++--
  libavformat/version.h     |  2 +-
  libavformat/wavdec.c      | 53 
+++++++++++++++++++++++++++++++++--------------
  libavformat/wtvdec.c      |  2 +-
  libavformat/xwma.c        |  2 +-
  14 files changed, 67 insertions(+), 29 deletions(-)

diff --git a/Changelog b/Changelog
index 4c122c4..20341d3 100644
--- a/Changelog
+++ b/Changelog
@@ -3,6 +3,7 @@ releases are sorted from youngest to oldest.

  version <next>:
  - nvenc encoder
+- RIFX format for *.wav files


  version 2.5:
diff --git a/libavformat/act.c b/libavformat/act.c
index 3f223d5..7b6b840 100644
--- a/libavformat/act.c
+++ b/libavformat/act.c
@@ -75,7 +75,7 @@ static int read_header(AVFormatContext *s)

      avio_skip(pb, 16);
      size=avio_rl32(pb);
-    ff_get_wav_header(pb, st->codec, size);
+    ff_get_wav_header(pb, st->codec, size, 0);

      /*
        8000Hz (Fine-rec) file format has 10 bytes long
diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c
index 7f7bb4d..79a255f 100644
--- a/libavformat/asfdec.c
+++ b/libavformat/asfdec.c
@@ -423,7 +423,7 @@ static int 
asf_read_stream_properties(AVFormatContext *s, int64_t size)

      st->codec->codec_type = type;
      if (type == AVMEDIA_TYPE_AUDIO) {
-        int ret = ff_get_wav_header(pb, st->codec, type_specific_size);
+        int ret = ff_get_wav_header(pb, st->codec, type_specific_size, 0);
          if (ret < 0)
              return ret;
          if (is_dvr_ms_audio) {
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index a8318ff..a6ef76b 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -794,7 +794,7 @@ static int avi_read_header(AVFormatContext *s)
  //                    avio_skip(pb, size - 5 * 4);
                      break;
                  case AVMEDIA_TYPE_AUDIO:
-                    ret = ff_get_wav_header(pb, st->codec, size);
+                    ret = ff_get_wav_header(pb, st->codec, size, 0);
                      if (ret < 0)
                          return ret;
                      ast->dshow_block_align = st->codec->block_align;
diff --git a/libavformat/dxa.c b/libavformat/dxa.c
index 6ad1c9f..9da2ffd 100644
--- a/libavformat/dxa.c
+++ b/libavformat/dxa.c
@@ -106,7 +106,7 @@ static int dxa_read_header(AVFormatContext *s)
          ast = avformat_new_stream(s, NULL);
          if (!ast)
              return AVERROR(ENOMEM);
-        ret = ff_get_wav_header(pb, ast->codec, fsize);
+        ret = ff_get_wav_header(pb, ast->codec, fsize, 0);
          if (ret < 0)
              return ret;
          if (ast->codec->sample_rate > 0)
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 9c476c1..bdc9c5f 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -1715,7 +1715,7 @@ static int matroska_parse_tracks(AVFormatContext *s)
              ffio_init_context(&b, track->codec_priv.data,
                                track->codec_priv.size,
                                0, NULL, NULL, NULL, NULL);
-            ret = ff_get_wav_header(&b, st->codec, 
track->codec_priv.size);
+            ret = ff_get_wav_header(&b, st->codec, 
track->codec_priv.size, 0);
              if (ret < 0)
                  return ret;
              codec_id         = st->codec->codec_id;
diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c
index 17bdb17..06ea7b3 100644
--- a/libavformat/mlvdec.c
+++ b/libavformat/mlvdec.c
@@ -142,7 +142,7 @@ static int scan_file(AVFormatContext *avctx, 
AVStream *vst, AVStream *ast, int f
              vst->codec->codec_tag = MKTAG('B', 'I', 'T', 16);
              size -= 164;
          } else if (ast && type == MKTAG('W', 'A', 'V', 'I') && size >= 
16) {
-            ret = ff_get_wav_header(pb, ast->codec, 16);
+            ret = ff_get_wav_header(pb, ast->codec, 16, 0);
              if (ret < 0)
                  return ret;
              size -= 16;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 939296a..6357b79 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -714,7 +714,7 @@ static int mov_read_wfex(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
          return 0;
      st = c->fc->streams[c->fc->nb_streams-1];

-    if ((ret = ff_get_wav_header(pb, st->codec, atom.size)) < 0)
+    if ((ret = ff_get_wav_header(pb, st->codec, atom.size, 0)) < 0)
          av_log(c->fc, AV_LOG_WARNING, "get_wav_header failed\n");

      return ret;
diff --git a/libavformat/riff.h b/libavformat/riff.h
index e925634..15b07a6 100644
--- a/libavformat/riff.h
+++ b/libavformat/riff.h
@@ -62,7 +62,7 @@ void ff_put_bmp_header(AVIOContext *pb, AVCodecContext 
*enc, const AVCodecTag *t
  int ff_put_wav_header(AVIOContext *pb, AVCodecContext *enc, int flags);

  enum AVCodecID ff_wav_codec_get_id(unsigned int tag, int bps);
-int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size);
+int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, 
int big_endian);

  extern const AVCodecTag ff_codec_bmp_tags[]; // exposed through 
avformat_get_riff_video_tags()
  extern const AVCodecTag ff_codec_wav_tags[];
diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c
index 88e2229..ac7d822 100644
--- a/libavformat/riffdec.c
+++ b/libavformat/riffdec.c
@@ -19,6 +19,8 @@
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
02110-1301 USA
   */

+#include <netinet/in.h>
+
  #include "libavutil/dict.h"
  #include "libavutil/error.h"
  #include "libavutil/log.h"
@@ -80,7 +82,8 @@ static void parse_waveformatex(AVIOContext *pb, 
AVCodecContext *c)
      }
  }

-int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size)
+/* "big_endian" values are needed for RIFX file format */
+int ff_get_wav_header(AVIOContext *pb, AVCodecContext *codec, int size, 
int big_endian)
  {
      int id;

@@ -93,10 +96,20 @@ int ff_get_wav_header(AVIOContext *pb, 
AVCodecContext *codec, int size)
      codec->sample_rate = avio_rl32(pb);
      codec->bit_rate    = avio_rl32(pb) * 8;
      codec->block_align = avio_rl16(pb);
+    if (big_endian) {
+        id                 = ntohs(id);
+        codec->channels    = ntohs(codec->channels);
+        codec->sample_rate = ntohl(codec->sample_rate);
+        codec->bit_rate    = ntohl(codec->bit_rate / 8) * 8;
+        codec->block_align = ntohs(codec->block_align);
+    }
      if (size == 14) {  /* We're dealing with plain vanilla WAVEFORMAT */
          codec->bits_per_coded_sample = 8;
      } else
-        codec->bits_per_coded_sample = avio_rl16(pb);
+        if(!big_endian)
+            codec->bits_per_coded_sample = avio_rl16(pb);
+        else
+            codec->bits_per_coded_sample = ntohs(avio_rl16(pb));
      if (id == 0xFFFE) {
          codec->codec_tag = 0;
      } else {
@@ -105,6 +118,9 @@ int ff_get_wav_header(AVIOContext *pb, 
AVCodecContext *codec, int size)
codec->bits_per_coded_sample);
      }
      if (size >= 18) {  /* We're obviously dealing with WAVEFORMATEX */
+        if (big_endian)
+            avpriv_report_missing_feature(codec, "WAVEFORMATEX support 
for RIFX files\n");
+
          int cbSize = avio_rl16(pb); /* cbSize */
          size  -= 18;
          cbSize = FFMIN(size, cbSize);
diff --git a/libavformat/version.h b/libavformat/version.h
index 6664f2b..d39dd5d 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -31,7 +31,7 @@

  #define LIBAVFORMAT_VERSION_MAJOR 56
  #define LIBAVFORMAT_VERSION_MINOR  15
-#define LIBAVFORMAT_VERSION_MICRO 105
+#define LIBAVFORMAT_VERSION_MICRO 106

  #define LIBAVFORMAT_VERSION_INT 
AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c
index 9c4e2df..3f6a9e1 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -24,6 +24,7 @@
   */

  #include <stdint.h>
+#include <netinet/in.h>

  #include "libavutil/avassert.h"
  #include "libavutil/dict.h"
@@ -57,14 +58,18 @@ typedef struct WAVDemuxContext {
      int smv_cur_pt;
      int smv_given_first;
      int unaligned; // e.g. if an odd number of bytes ID3 tag was 
prepended
+    int rifx; // RIFX: integer byte order for parameters is big endian
  } WAVDemuxContext;

  #if CONFIG_WAV_DEMUXER

-static int64_t next_tag(AVIOContext *pb, uint32_t *tag)
+static int64_t next_tag(AVIOContext *pb, uint32_t *tag, int big_endian)
  {
      *tag = avio_rl32(pb);
-    return avio_rl32(pb);
+    if (!big_endian)
+        return avio_rl32(pb);
+    else
+        return ntohl(avio_rl32(pb));
  }

  /* RIFF chunks are always at even offsets relative to where they 
start. */
@@ -84,7 +89,7 @@ static int64_t find_tag(WAVDemuxContext * wav, 
AVIOContext *pb, uint32_t tag1)
      for (;;) {
          if (avio_feof(pb))
              return AVERROR_EOF;
-        size = next_tag(pb, &tag);
+        size = next_tag(pb, &tag, wav->rifx);
          if (tag == tag1)
              break;
          wav_seek_tag(wav, pb, size, SEEK_CUR);
@@ -98,7 +103,7 @@ static int wav_probe(AVProbeData *p)
      if (p->buf_size <= 32)
          return 0;
      if (!memcmp(p->buf + 8, "WAVE", 4)) {
-        if (!memcmp(p->buf, "RIFF", 4))
+        if ((!memcmp(p->buf, "RIFF", 4)) || (!memcmp(p->buf, "RIFX", 4)))
              /* Since the ACT demuxer has a standard WAV header at the 
top of
               * its own, the returned score is decreased to avoid a probe
               * conflict between ACT and WAV. */
@@ -121,6 +126,7 @@ static void handle_stream_probing(AVStream *st)
  static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, 
AVStream **st)
  {
      AVIOContext *pb = s->pb;
+    WAVDemuxContext *wav = s->priv_data;
      int ret;

      /* parse fmt header */
@@ -128,7 +134,7 @@ static int wav_parse_fmt_tag(AVFormatContext *s, 
int64_t size, AVStream **st)
      if (!*st)
          return AVERROR(ENOMEM);

-    ret = ff_get_wav_header(pb, (*st)->codec, size);
+    ret = ff_get_wav_header(pb, (*st)->codec, size, wav->rifx);
      if (ret < 0)
          return ret;
      handle_stream_probing(*st);
@@ -242,7 +248,7 @@ static int wav_read_header(AVFormatContext *s)
  {
      int64_t size, av_uninit(data_size);
      int64_t sample_count = 0;
-    int rf64;
+    int rf64 = 0;
      uint32_t tag;
      AVIOContext *pb      = s->pb;
      AVStream *st         = NULL;
@@ -254,16 +260,31 @@ static int wav_read_header(AVFormatContext *s)

      wav->smv_data_ofs = -1;

-    /* check RIFF header */
-    tag = avio_rl32(pb);
+    wav->rifx = 0;

-    rf64 = tag == MKTAG('R', 'F', '6', '4');
-    if (!rf64 && tag != MKTAG('R', 'I', 'F', 'F'))
+    /* read chunk ID */
+    switch (avio_rl32(pb)) {
+    case MKTAG('R', 'I', 'F', 'F'):
+        break;
+    case MKTAG('R', 'I', 'F', 'X'):
+        wav->rifx = 1;
+        break;
+    case MKTAG('R', 'F', '6', '4'):
+        rf64 = 1;
+        break;
+    default:
+        av_log(s, AV_LOG_ERROR, "invalid start in RIFF header\n");
          return AVERROR_INVALIDDATA;
-    avio_rl32(pb); /* file size */
-    tag = avio_rl32(pb);
-    if (tag != MKTAG('W', 'A', 'V', 'E'))
+    }
+
+    /* read chunk size */
+    avio_rl32(pb);
+
+    /* read format */
+    if (avio_rl32(pb) != MKTAG('W', 'A', 'V', 'E')) {
+        av_log(s, AV_LOG_ERROR, "invalid format in RIFF header\n");
          return AVERROR_INVALIDDATA;
+    }

      if (rf64) {
          if (avio_rl32(pb) != MKTAG('d', 's', '6', '4'))
@@ -288,7 +309,7 @@ static int wav_read_header(AVFormatContext *s)

      for (;;) {
          AVStream *vst;
-        size         = next_tag(pb, &tag);
+        size         = next_tag(pb, &tag, wav->rifx);
          next_tag_ofs = avio_tell(pb) + size;

          if (avio_feof(pb))
@@ -328,7 +349,7 @@ static int wav_read_header(AVFormatContext *s)
              break;
          case MKTAG('f', 'a', 'c', 't'):
              if (!sample_count)
-                sample_count = avio_rl32(pb);
+                sample_count = (!wav->rifx ? avio_rl32(pb) : 
ntohl(avio_rl32(pb)));
              break;
          case MKTAG('b', 'e', 'x', 't'):
              if ((ret = wav_parse_bext_tag(s, size)) < 0)
@@ -662,7 +683,7 @@ static int w64_read_header(AVFormatContext *s)

          if (!memcmp(guid, ff_w64_guid_fmt, 16)) {
              /* subtract chunk header size - normal wav file doesn't 
count it */
-            ret = ff_get_wav_header(pb, st->codec, size - 24);
+            ret = ff_get_wav_header(pb, st->codec, size - 24, 0);
              if (ret < 0)
                  return ret;
              avio_skip(pb, FFALIGN(size, INT64_C(8)) - size);
diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c
index 4009964..7fc5e63 100644
--- a/libavformat/wtvdec.c
+++ b/libavformat/wtvdec.c
@@ -670,7 +670,7 @@ static AVStream * parse_media_type(AVFormatContext 
*s, AVStream *st, int sid,
          if (!st)
              return NULL;
          if (!ff_guidcmp(formattype, ff_format_waveformatex)) {
-            int ret = ff_get_wav_header(pb, st->codec, size);
+            int ret = ff_get_wav_header(pb, st->codec, size, 0);
              if (ret < 0)
                  return NULL;
          } else {
diff --git a/libavformat/xwma.c b/libavformat/xwma.c
index 5d29d0b..b172120 100644
--- a/libavformat/xwma.c
+++ b/libavformat/xwma.c
@@ -75,7 +75,7 @@ static int xwma_read_header(AVFormatContext *s)
      if (!st)
          return AVERROR(ENOMEM);

-    ret = ff_get_wav_header(pb, st->codec, size);
+    ret = ff_get_wav_header(pb, st->codec, size, 0);
      if (ret < 0)
          return ret;
      st->need_parsing = AVSTREAM_PARSE_NONE;
-- 
1.9.1




More information about the ffmpeg-devel mailing list