Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

enable-libavresample.patch

By: a guest on Feb 27th, 2013  |  syntax: Diff  |  size: 35.62 KB  |  views: 30  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. # enable-libavresample.patch
  2. #
  3. # Adds libavresample support. Created by diffing Thomas Goyne's GIT repo
  4. # with official ffms SVN.
  5. #
  6.  
  7. diff -ru ffmpegsource/configure.ac ffms2/configure.ac
  8. --- ffmpegsource/configure.ac   2013-02-27 16:53:39.230691825 +0100
  9. +++ ffms2/configure.ac  2013-02-27 16:53:31.737713841 +0100
  10. @@ -181,6 +181,25 @@
  11.                AC_MSG_RESULT([no])
  12.              ])
  13.  
  14. +AC_ARG_ENABLE(avresample,
  15. +              AS_HELP_STRING([--enable-avresample],
  16. +                             [use libavresample for audio resampling]))
  17. +AS_IF([test x$enable_avresample != xno], [
  18. +  PKG_CHECK_MODULES(AVRESAMPLE, [libavresample >= 1.0.0], [enable_avresample=yes], [
  19. +    AS_IF([test x$enable_avresample = xyes],
  20. +          [AC_MSG_ERROR([--enable-avresample was specified, but avresample 1.0.0+ could not be found.])])
  21. +    enable_avresample=no
  22. +  ])
  23. +])
  24. +
  25. +AS_IF([test x$enable_avresample],
  26. +      [libavresample="libavresample"
  27. +       AC_DEFINE([WITH_AVRESAMPLE], [1], [Use avresample])])
  28. +
  29. +AC_SUBST([AVRESAMPLE_CFLAGS])
  30. +AC_SUBST([AVRESAMPLE_LIBS])
  31. +AC_SUBST([libavresample])
  32. +
  33.  AC_MSG_CHECKING([whether -Wl,-Bsymbolic is needed])
  34.  if test "$enable_shared" = yes; then
  35.      _LDFLAGS="$LDFLAGS"
  36. diff -ru ffmpegsource/ffms2.pc.in ffms2/ffms2.pc.in
  37. --- ffmpegsource/ffms2.pc.in    2013-02-27 16:53:38.924039701 +0100
  38. +++ ffms2/ffms2.pc.in   2013-02-27 16:53:31.737713841 +0100
  39. @@ -7,7 +7,7 @@
  40.  
  41.  Name: ffms2
  42.  Description: The Fabulous FM Library 2
  43. -Requires.private: libavformat libavcodec libswscale libavutil
  44. +Requires.private: libavformat libavcodec libswscale libavutil @libavresample@
  45.  Version: @FFMS_VERSION@
  46.  Libs.private: @ZLIB_LDFLAGS@ -lz
  47.  Libs: -L${libdir} -lffms2
  48. diff -ru ffmpegsource/include/ffmscompat.h ffms2/include/ffmscompat.h
  49. --- ffmpegsource/include/ffmscompat.h   2013-02-27 16:53:38.920706525 +0100
  50. +++ ffms2/include/ffmscompat.h  2013-02-27 16:53:31.737713841 +0100
  51. @@ -71,6 +71,15 @@
  52.  #       define FFMS_CodecID AVCodecID
  53.  #       undef CodecID
  54.  #   endif
  55. +#   if VERSION_CHECK(LIBAVCODEC_VERSION_INT, <, 54, 28, 0, 54, 59, 100)
  56. +#       define avcodec_free_frame av_free
  57. +#   endif
  58. +#endif
  59. +
  60. +#ifdef LIBAVUTIL_VERSION_INT
  61. +#      if VERSION_CHECK(LIBAVUTIL_VERSION_INT, <, 51, 27, 0, 51, 46, 100)
  62. +#              define av_get_packed_sample_fmt(fmt) (fmt < AV_SAMPLE_FMT_U8P ? fmt : fmt - (AV_SAMPLE_FMT_U8P - AV_SAMPLE_FMT_U8))
  63. +#      endif
  64.  #endif
  65.  
  66.  #endif // FFMSCOMPAT_H
  67. diff -ru ffmpegsource/include/ffms.h ffms2/include/ffms.h
  68. --- ffmpegsource/include/ffms.h 2013-02-27 16:53:38.920706525 +0100
  69. +++ ffms2/include/ffms.h        2013-02-27 16:53:31.737713841 +0100
  70. @@ -113,6 +113,7 @@
  71.         FFMS_ERROR_TRACK,                               // track handling
  72.         FFMS_ERROR_WAVE_WRITER,                 // WAVE64 file writer
  73.         FFMS_ERROR_CANCELLED,                   // operation aborted
  74. +       FFMS_ERROR_RESAMPLING,                  // audio resampling (libavresample)
  75.  
  76.         // Subtypes - what caused the error
  77.         FFMS_ERROR_UNKNOWN = 20,                // unknown error
  78. @@ -237,6 +238,53 @@
  79.         FFMS_CR_JPEG            = 2 // 2^n-1, or "fullrange"
  80.  } FFMS_ColorRanges;
  81.  
  82. +typedef enum FFMS_MixingCoefficientType {
  83. +       FFMS_MIXING_COEFFICIENT_Q8  = 0,
  84. +       FFMS_MIXING_COEFFICIENT_Q15 = 1,
  85. +       FFMS_MIXING_COEFFICIENT_FLT = 2
  86. +} FFMS_MixingCoefficientType;
  87. +
  88. +typedef enum FFMS_MatrixEncoding {
  89. +       FFMS_MATRIX_ENCODING_NONE         = 0,
  90. +       FFMS_MATRIX_ENCODING_DOBLY        = 1,
  91. +       FFMS_MATRIX_ENCODING_PRO_LOGIC_II = 2
  92. +} FFMS_MatrixEncoding;
  93. +
  94. +typedef enum FFMS_ResampleFilterType {
  95. +       FFMS_RESAMPLE_FILTER_CUBIC  = 0,
  96. +       FFMS_RESAMPLE_FILTER_SINC   = 1,
  97. +       FFMS_RESAMPLE_FILTER_KAISER = 2
  98. +} FFMS_ResampleFilterType;
  99. +
  100. +typedef enum FFMS_AudioDitherMethod {
  101. +       FFMS_RESAMPLE_DITHER_NONE                    = 0,
  102. +       FFMS_RESAMPLE_DITHER_RECTANGULAR             = 1,
  103. +       FFMS_RESAMPLE_DITHER_TRIANGULAR              = 2,
  104. +       FFMS_RESAMPLE_DITHER_TRIANGULAR_HIGHPASS     = 3,
  105. +       FFMS_RESAMPLE_DITHER_TRIANGULAR_NOISESHAPING = 4
  106. +} FFMS_AudioDitherMethod;
  107. +
  108. +typedef struct FFMS_ResampleOptions {
  109. +       int64_t ChannelLayout;
  110. +       FFMS_SampleFormat SampleFormat;
  111. +       int SampleRate;
  112. +       FFMS_MixingCoefficientType MixingCoefficientType;
  113. +       double CenterMixLevel;
  114. +       double SurroundMixLevel;
  115. +       double LFEMixLevel;
  116. +       int Normalize;
  117. +       int ForceResample;
  118. +       int ResampleFilterSize;
  119. +       int ResamplePhaseShift;
  120. +       int LinearInterpolation;
  121. +       double CutoffFrequencyRatio;
  122. +       FFMS_MatrixEncoding MatrixedStereoEncoding;
  123. +       FFMS_ResampleFilterType FilterType;
  124. +       int KaiserBeta;
  125. +       FFMS_AudioDitherMethod DitherMethod;
  126. +} FFMS_ResampleOptions;
  127. +
  128. +
  129.  typedef struct FFMS_Frame {
  130.         uint8_t *Data[4];
  131.         int Linesize[4];
  132. @@ -319,6 +367,9 @@
  133.  FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V);
  134.  FFMS_API(int) FFMS_SetInputFormatV(FFMS_VideoSource *V, int ColorSpace, int ColorRange, int Format, FFMS_ErrorInfo *ErrorInfo); /* Introduced in FFMS_VERSION ((2 << 24) | (17 << 16) | (1 << 8) | 0) */
  135.  FFMS_API(void) FFMS_ResetInputFormatV(FFMS_VideoSource *V);
  136. +FFMS_API(FFMS_ResampleOptions *) FFMS_CreateResampleOptions(FFMS_AudioSource *A); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */
  137. +FFMS_API(int) FFMS_SetOutputFormatA(FFMS_AudioSource *A, const FFMS_ResampleOptions*options, FFMS_ErrorInfo *ErrorInfo); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */
  138. +FFMS_API(void) FFMS_DestroyResampleOptions(FFMS_ResampleOptions *options); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */
  139.  FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index);
  140.  FFMS_API(int) FFMS_GetSourceType(FFMS_Index *Index);
  141.  FFMS_API(int) FFMS_GetSourceTypeI(FFMS_Indexer *Indexer);
  142. diff -ru ffmpegsource/Makefile.am ffms2/Makefile.am
  143. --- ffmpegsource/Makefile.am    2013-02-27 16:53:39.310688030 +0100
  144. +++ ffms2/Makefile.am   2013-02-27 16:53:31.724381141 +0100
  145. @@ -9,7 +9,7 @@
  146.  INCLUDES = -I. -I$(top_srcdir)/include -I$(top_srcdir)/src/config @LIBAV_CFLAGS@ @ZLIB_CPPFLAGS@ -include config.h
  147.  
  148.  lib_LTLIBRARIES = src/core/libffms2.la
  149. -src_core_libffms2_la_LIBADD = @LIBAV_LIBS@ @ZLIB_LDFLAGS@ -lz @LTUNDEF@
  150. +src_core_libffms2_la_LIBADD = @LIBAV_LIBS@ @AVRESAMPLE_LIBS@ @ZLIB_LDFLAGS@ -lz @LTUNDEF@
  151.  src_core_libffms2_la_SOURCES = \
  152.         src/core/audiosource.h \
  153.         src/core/audiosource.cpp \
  154. diff -ru ffmpegsource/src/config/config.h.in ffms2/src/config/config.h.in
  155. --- ffmpegsource/src/config/config.h.in 2013-02-27 16:53:39.017368608 +0100
  156. +++ ffms2/src/config/config.h.in        2013-02-27 16:53:31.744380192 +0100
  157. @@ -90,5 +90,8 @@
  158.  /* Version number of package */
  159.  #undef VERSION
  160.  
  161. +/* Use avresample */
  162. +#undef WITH_AVRESAMPLE
  163. +
  164.  /* Define to `unsigned int' if <sys/types.h> does not define. */
  165.  #undef size_t
  166. diff -ru ffmpegsource/src/config/libs.cpp ffms2/src/config/libs.cpp
  167. --- ffmpegsource/src/config/libs.cpp    2013-02-27 16:53:39.017368608 +0100
  168. +++ ffms2/src/config/libs.cpp   2013-02-27 16:53:31.744380192 +0100
  169. @@ -45,6 +45,9 @@
  170.  #pragma comment(lib, "libavcodec.a")
  171.  #pragma comment(lib, "libavformat.a")
  172.  #pragma comment(lib, "libswscale.a")
  173. +#ifdef WITH_AVRESAMPLE
  174. +#pragma comment(lib, "libavresample.a")
  175. +#endif
  176.  
  177.  #ifdef WITH_OPENCORE_AMR_NB
  178.  #ifdef WITH_GCC_LIBAV
  179. diff -ru ffmpegsource/src/core/audiosource.cpp ffms2/src/core/audiosource.cpp
  180. --- ffmpegsource/src/core/audiosource.cpp       2013-02-27 16:53:39.137362917 +0100
  181. +++ ffms2/src/core/audiosource.cpp      2013-02-27 16:53:31.744380192 +0100
  182. @@ -23,17 +23,45 @@
  183.  #include <algorithm>
  184.  #include <cassert>
  185.  
  186. +namespace {
  187. +
  188. +       int64_t ChannelLayout;
  189. +       FFMS_SampleFormat SampleFormat;
  190. +       int SampleRate;
  191. +#define MAPPER(m, n) OptionMapper<FFMS_ResampleOptions>(n, &FFMS_ResampleOptions::m)
  192. +OptionMapper<FFMS_ResampleOptions> resample_options[] = {
  193. +       MAPPER(ChannelLayout,          "out_channel_layout"),
  194. +       MAPPER(SampleFormat,           "out_sample_fmt"),
  195. +       MAPPER(SampleRate,             "out_sample_rate"),
  196. +       MAPPER(MixingCoefficientType,  "mix_coeff_type"),
  197. +       MAPPER(CenterMixLevel,         "center_mix_level"),
  198. +       MAPPER(SurroundMixLevel,       "surround_mix_level"),
  199. +       MAPPER(LFEMixLevel,            "lfe_mix_level"),
  200. +       MAPPER(Normalize,              "normalize_mix_level"),
  201. +       MAPPER(ForceResample,          "force_resampling"),
  202. +       MAPPER(ResampleFilterSize,     "filter_size"),
  203. +       MAPPER(ResamplePhaseShift,     "phase_shift"),
  204. +       MAPPER(LinearInterpolation,    "linear_interp"),
  205. +       MAPPER(CutoffFrequencyRatio,   "cutoff"),
  206. +       MAPPER(MatrixedStereoEncoding, "matrix_encoding"),
  207. +       MAPPER(FilterType,             "filter_type"),
  208. +       MAPPER(KaiserBeta,             "kaiser_beta"),
  209. +       MAPPER(DitherMethod,           "dither_method")
  210. +};
  211. +#undef MAPPER
  212. +
  213. +}
  214. +
  215.  FFMS_AudioSource::FFMS_AudioSource(const char *SourceFile, FFMS_Index &Index, int Track)
  216.  : Delay(0)
  217.  , MaxCacheBlocks(50)
  218.  , BytesPerSample(0)
  219. -, Decoded(0)
  220. +, NeedsResample(false)
  221.  , CurrentSample(-1)
  222.  , PacketNumber(0)
  223.  , CurrentFrame(NULL)
  224.  , TrackNumber(Track)
  225.  , SeekOffset(0)
  226. -, DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10)
  227.  , Index(Index)
  228.  {
  229.         if (Track < 0 || Track >= static_cast<int>(Index.size()))
  230. @@ -57,44 +85,14 @@
  231.         Index.AddRef();
  232.  }
  233.  
  234. -
  235.  #define EXCESSIVE_CACHE_SIZE 400
  236.  
  237.  void FFMS_AudioSource::Init(const FFMS_Index &Index, int DelayMode) {
  238. -       // The first packet after a seek is often decoded incorrectly, which
  239. -       // makes it impossible to ever correctly seek back to the beginning, so
  240. -       // store the first block now
  241. -
  242. -       // In addition, anything with the same PTS as the first packet can't be
  243. -       // distinguished from the first packet and so can't be seeked to, so
  244. -       // store those as well
  245. -
  246. -       // Some of LAVF's splitters don't like to seek to the beginning of the
  247. -       // file (ts and?), so cache a few blocks even if PTSes are unique
  248. -       // Packet 7 is the last packet I've had be unseekable to, so cache up to
  249. -       // 10 for a bit of an extra buffer
  250. -       CacheIterator end = Cache.end();
  251. -       while (PacketNumber < Frames.size() &&
  252. -               ((Frames[0].PTS != ffms_av_nopts_value && Frames[PacketNumber].PTS == Frames[0].PTS) ||
  253. -                Cache.size() < 10)) {
  254. -
  255. -               // Vorbis in particular seems to like having 60+ packets at the start of the file with a PTS of 0,
  256. -               // so we might need to expand the search range to account for that.
  257. -               if (Cache.size() >= MaxCacheBlocks - 1) {
  258. -                        if (MaxCacheBlocks >= EXCESSIVE_CACHE_SIZE)
  259. -                                throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_ALLOCATION_FAILED, "Exceeded the search range for an initial valid audio PTS");
  260. -                       MaxCacheBlocks *= 2;
  261. -               }
  262. -
  263. +       // Decode the first packet to ensure all properties are initialized
  264. +       // Don't cache it since it might be in the wrong format
  265. +       // Instead, leave it in DecodeFrame and it'll get cached later
  266. +       while (DecodeFrame->nb_samples == 0)
  267.                 DecodeNextBlock();
  268. -               if (Decoded)
  269. -                       CacheBlock(end, CurrentSample, Decoded, &DecodingBuffer[0]);
  270. -       }
  271. -       // Store the iterator to the last element of the cache which is used for
  272. -       // correctness rather than speed, so that when looking for one to delete
  273. -       // we know how much to skip
  274. -       CacheNoDelete = Cache.end();
  275. -       --CacheNoDelete;
  276.  
  277.         // Read properties of the audio which may not be available until the first
  278.         // frame has been decoded
  279. @@ -104,6 +102,11 @@
  280.                 throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
  281.                         "Codec returned zero size audio");
  282.  
  283. +       if (av_sample_fmt_is_planar(CodecContext->sample_fmt)) {
  284. +               std::auto_ptr<FFMS_ResampleOptions> opt(CreateResampleOptions());
  285. +               SetOutputFormat(opt.get());
  286. +       }
  287. +
  288.         if (DelayMode < FFMS_DELAY_NO_SHIFT)
  289.                 throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
  290.                         "Bad audio delay compensation mode");
  291. @@ -146,8 +149,133 @@
  292.         AP.NumSamples += Delay;
  293.  }
  294.  
  295. -void FFMS_AudioSource::CacheBlock(CacheIterator &pos, int64_t Start, size_t Samples, uint8_t *SrcData) {
  296. -       Cache.insert(pos, AudioBlock(Start, Samples, SrcData, Samples * BytesPerSample));
  297. +void FFMS_AudioSource::CacheBeginning() {
  298. +       // Nothing to do if the cache is already populated
  299. +       if (!Cache.empty()) return;
  300. +
  301. +       // The first frame is already decoded, so add it to the cache
  302. +       CacheBlock(Cache.end());
  303. +
  304. +       // The first packet after a seek is often decoded incorrectly, which
  305. +       // makes it impossible to ever correctly seek back to the beginning, so
  306. +       // store the first block now
  307. +
  308. +       // In addition, anything with the same PTS as the first packet can't be
  309. +       // distinguished from the first packet and so can't be seeked to, so
  310. +       // store those as well
  311. +
  312. +       // Some of LAVF's splitters don't like to seek to the beginning of the
  313. +       // file (ts and?), so cache a few blocks even if PTSes are unique
  314. +       // Packet 7 is the last packet I've had be unseekable to, so cache up to
  315. +       // 10 for a bit of an extra buffer
  316. +       CacheIterator end = Cache.end();
  317. +       while (PacketNumber < Frames.size() &&
  318. +               ((Frames[0].PTS != ffms_av_nopts_value && Frames[PacketNumber].PTS == Frames[0].PTS) ||
  319. +                Cache.size() < 10)) {
  320. +
  321. +               // Vorbis in particular seems to like having 60+ packets at the start
  322. +               // of the file with a PTS of 0, so we might need to expand the search
  323. +               // range to account for that.
  324. +               // Expanding slightly before it's strictly needed to ensure there's a
  325. +               // bit of space for an actual cache
  326. +               if (Cache.size() >= MaxCacheBlocks - 5) {
  327. +                        if (MaxCacheBlocks >= EXCESSIVE_CACHE_SIZE)
  328. +                               throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_ALLOCATION_FAILED,
  329. +                                       "Exceeded the search range for an initial valid audio PTS");
  330. +                       MaxCacheBlocks *= 2;
  331. +               }
  332. +
  333. +               DecodeNextBlock(&end);
  334. +       }
  335. +       // Store the iterator to the last element of the cache which is used for
  336. +       // correctness rather than speed, so that when looking for one to delete
  337. +       // we know how much to skip
  338. +       CacheNoDelete = Cache.end();
  339. +       --CacheNoDelete;
  340. +}
  341. +
  342. +void FFMS_AudioSource::SetOutputFormat(const FFMS_ResampleOptions *opt) {
  343. +       if (!Cache.empty())
  344. +               throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_USER,
  345. +                       "Cannot change the output format after audio decoding has begun");
  346. +
  347. +       BytesPerSample = av_get_bytes_per_sample(static_cast<AVSampleFormat>(opt->SampleFormat)) * av_get_channel_layout_nb_channels(opt->ChannelLayout);
  348. +
  349. +       NeedsResample =
  350. +               opt->SampleFormat != (int)CodecContext->sample_fmt ||
  351. +               opt->SampleRate != AP.SampleRate ||
  352. +               opt->ChannelLayout != AP.ChannelLayout ||
  353. +               opt->ForceResample;
  354. +       if (!NeedsResample) return;
  355. +
  356. +       if (opt->SampleRate != AP.SampleRate)
  357. +               throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
  358. +                       "Sample rate changes are currently unsupported.");
  359. +
  360. +#ifdef WITH_AVRESAMPLE
  361. +       if (opt->SampleRate != AP.SampleRate)
  362. +               throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
  363. +                       "Changing the audio sample rate is currently not supported");
  364. +
  365. +       std::auto_ptr<FFMS_ResampleOptions> oldOptions(ReadOptions(ResampleContext, resample_options));
  366. +       SetOptions(opt, ResampleContext, resample_options);
  367. +       av_opt_set_int(ResampleContext, "in_sample_rate", AP.SampleRate, 0);
  368. +       av_opt_set_int(ResampleContext, "in_sample_fmt", CodecContext->sample_fmt, 0);
  369. +       av_opt_set_int(ResampleContext, "in_channel_layout", AP.ChannelLayout, 0);
  370. +
  371. +       if (avresample_open(ResampleContext)) {
  372. +               SetOptions(oldOptions.get(), ResampleContext, resample_options);
  373. +               avresample_open(ResampleContext);
  374. +               throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNKNOWN,
  375. +                       "Could not open avresample context");
  376. +       }
  377. +#else
  378. +       if (opt->SampleFormat != AP.SampleFormat || opt->SampleRate != AP.SampleRate || opt->ChannelLayout != AP.ChannelLayout)
  379. +               throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
  380. +                       "FFMS was not built with resampling enabled. The only supported conversion is interleaving planar audio.");
  381. +#endif
  382. +}
  383. +
  384. +FFMS_ResampleOptions *FFMS_AudioSource::CreateResampleOptions() const {
  385. +#ifdef WITH_AVRESAMPLE
  386. +       FFMS_ResampleOptions *ret = ReadOptions(ResampleContext, resample_options);
  387. +#else
  388. +       FFMS_ResampleOptions *ret = new FFMS_ResampleOptions;
  389. +       memset(ret, 0, sizeof(FFMS_ResampleOptions));
  390. +#endif
  391. +       ret->SampleRate = AP.SampleRate;
  392. +       ret->SampleFormat = static_cast<FFMS_SampleFormat>(AP.SampleFormat);
  393. +       ret->ChannelLayout = AP.ChannelLayout;
  394. +       return ret;
  395. +}
  396. +
  397. +void FFMS_AudioSource::ResampleAndCache(CacheIterator pos) {
  398. +       AudioBlock& block = *Cache.insert(pos, AudioBlock(CurrentSample, DecodeFrame->nb_samples));
  399. +       block.Data.reserve(DecodeFrame->nb_samples * BytesPerSample);
  400. +
  401. +#ifdef WITH_AVRESAMPLE
  402. +       block.Data.resize(block.Data.capacity());
  403. +
  404. +       uint8_t *OutPlanes[1] = { static_cast<uint8_t *>(&block.Data[0]) };
  405. +       avresample_convert(ResampleContext,
  406. +               OutPlanes, block.Data.size(), DecodeFrame->nb_samples,
  407. +               DecodeFrame->extended_data, DecodeFrame->nb_samples * av_get_bytes_per_sample(CodecContext->sample_fmt), DecodeFrame->nb_samples);
  408. +#else
  409. +       int width = av_get_bytes_per_sample(CodecContext->sample_fmt);
  410. +       uint8_t **Data = DecodeFrame->extended_data;
  411. +
  412. +       for (int s = 0; s < DecodeFrame->nb_samples; ++s) {
  413. +               for (int c = 0; c < CodecContext->channels; ++c)
  414. +                       block.Data.insert(block.Data.end(), &Data[c][s * width], &Data[c][(s + 1) * width]);
  415. +       }
  416. +#endif
  417. +}
  418. +
  419. +void FFMS_AudioSource::CacheBlock(CacheIterator pos) {
  420. +       if (NeedsResample)
  421. +               ResampleAndCache(pos);
  422. +       else
  423. +               Cache.insert(pos, AudioBlock(CurrentSample, DecodeFrame->nb_samples, DecodeFrame->extended_data[0], DecodeFrame->nb_samples * BytesPerSample));
  424.  
  425.         if (Cache.size() >= MaxCacheBlocks) {
  426.                 // Kill the oldest one
  427. @@ -162,45 +290,45 @@
  428.         }
  429.  }
  430.  
  431. -void FFMS_AudioSource::DecodeNextBlock() {
  432. -       if (BytesPerSample == 0) BytesPerSample = av_get_bytes_per_sample(CodecContext->sample_fmt) * CodecContext->channels;
  433. -
  434. +void FFMS_AudioSource::DecodeNextBlock(CacheIterator *pos) {
  435.         CurrentFrame = &Frames[PacketNumber];
  436.  
  437.         AVPacket Packet;
  438.         if (!ReadPacket(&Packet))
  439. -               throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_UNKNOWN, "ReadPacket unexpectedly failed to read a packet");
  440. +               throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_UNKNOWN,
  441. +                       "ReadPacket unexpectedly failed to read a packet");
  442.  
  443.         // ReadPacket may have changed the packet number
  444.         CurrentFrame = &Frames[PacketNumber];
  445.         CurrentSample = CurrentFrame->SampleStart;
  446. -       ++PacketNumber;
  447.  
  448. -       uint8_t *Buf = &DecodingBuffer[0];
  449. +       bool GotSamples = false;
  450.         uint8_t *Data = Packet.data;
  451.         while (Packet.size > 0) {
  452. -               int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 10 - (Buf - &DecodingBuffer[0]);
  453. -               int Ret = avcodec_decode_audio3(CodecContext, (int16_t *)Buf, &TempOutputBufSize, &Packet);
  454. +               DecodeFrame.reset();
  455. +               int GotFrame = 0;
  456. +               int Ret = avcodec_decode_audio4(CodecContext, DecodeFrame, &GotFrame, &Packet);
  457.  
  458.                 // Should only ever happen if the user chose to ignore decoding errors
  459.                 // during indexing, so continue to just ignore decoding errors
  460.                 if (Ret < 0) break;
  461.  
  462. -               if (Ret > 0) {
  463. +               if (Ret > 0 && GotFrame) {
  464.                         Packet.size -= Ret;
  465.                         Packet.data += Ret;
  466. -                       Buf += TempOutputBufSize;
  467. +                       if (DecodeFrame->nb_samples > 0) {
  468. +                               GotSamples = true;
  469. +                               if (pos)
  470. +                                       CacheBlock(*pos);
  471. +                       }
  472.                 }
  473.         }
  474.         Packet.data = Data;
  475.         FreePacket(&Packet);
  476.  
  477. -       Decoded = (Buf - &DecodingBuffer[0]) / BytesPerSample;
  478. -       if (Decoded == 0) {
  479. -               // zero sample packets aren't included in the index so we didn't
  480. -               // actually move to the next packet
  481. -               --PacketNumber;
  482. -       }
  483. +       // Zero sample packets aren't included in the index
  484. +       if (GotSamples)
  485. +               ++PacketNumber;
  486.  }
  487.  
  488.  static bool SampleStartComp(const TFrameInfo &a, const TFrameInfo &b) {
  489. @@ -216,6 +344,8 @@
  490.                 throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_INVALID_ARGUMENT,
  491.                         "Out of bounds audio samples requested");
  492.  
  493. +       CacheBeginning();
  494. +
  495.         uint8_t *Dst = static_cast<uint8_t*>(Buf);
  496.  
  497.         // Apply audio delay (if any) and fill any samples before the start time with zero
  498. @@ -253,10 +383,12 @@
  499.                 }
  500.                 // Decode another block
  501.                 else {
  502. +                       CacheIterator cachePos = it; --cachePos;
  503. +
  504.                         if (Start < CurrentSample && SeekOffset == -1)
  505.                                 throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Audio stream is not seekable");
  506.  
  507. -                       if (SeekOffset >= 0 && (Start < CurrentSample || Start > CurrentSample + Decoded * 5)) {
  508. +                       if (SeekOffset >= 0 && (Start < CurrentSample || Start > CurrentSample + DecodeFrame->nb_samples * 5)) {
  509.                                 TFrameInfo f;
  510.                                 f.SampleStart = Start;
  511.                                 int NewPacketNumber = std::distance(Frames.begin(), std::lower_bound(Frames.begin(), Frames.end(), f, SampleStartComp));
  512. @@ -266,32 +398,22 @@
  513.                                 // Only seek forward if it'll actually result in moving forward
  514.                                 if (Start < CurrentSample || static_cast<size_t>(NewPacketNumber) > PacketNumber) {
  515.                                         PacketNumber = NewPacketNumber;
  516. -                                       Decoded = 0;
  517.                                         CurrentSample = -1;
  518. +                                       DecodeFrame.reset();
  519.                                         avcodec_flush_buffers(CodecContext);
  520.                                         Seek();
  521.                                 }
  522.                         }
  523.  
  524. -                       // Decode everything between the last keyframe and the block we want
  525. +                       // Decode until we hit the block we want
  526.                         if (PacketNumber >= Frames.size())
  527.                                 throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Seeking is severely broken");
  528. -                       while (CurrentSample + Decoded <= Start && PacketNumber < Frames.size())
  529. -                               DecodeNextBlock();
  530. +                       while (CurrentSample + DecodeFrame->nb_samples <= Start && PacketNumber < Frames.size())
  531. +                               DecodeNextBlock(&it);
  532.                         if (CurrentSample > Start)
  533.                                 throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Seeking is severely broken");
  534.  
  535. -                       CacheBlock(it, CurrentSample, Decoded, &DecodingBuffer[0]);
  536. -
  537. -                       size_t FirstSample = static_cast<size_t>(Start - CurrentSample);
  538. -                       size_t Samples = static_cast<size_t>(Decoded - FirstSample);
  539. -                       size_t Bytes = FFMIN(Samples, static_cast<size_t>(Count)) * BytesPerSample;
  540. -
  541. -                       memcpy(Dst, &DecodingBuffer[FirstSample * BytesPerSample], Bytes);
  542. -
  543. -                       Start += Samples;
  544. -                       Count -= Samples;
  545. -                       Dst += Bytes;
  546. +                       it = cachePos;
  547.                 }
  548.         }
  549.  }
  550. diff -ru ffmpegsource/src/core/audiosource.h ffms2/src/core/audiosource.h
  551. --- ffmpegsource/src/core/audiosource.h 2013-02-27 16:53:39.130696566 +0100
  552. +++ ffms2/src/core/audiosource.h        2013-02-27 16:53:31.744380192 +0100
  553. @@ -46,7 +46,6 @@
  554.  #endif
  555.  
  556.  struct FFMS_AudioSource {
  557. -private:
  558.         struct AudioBlock {
  559.                 int64_t Age;
  560.                 int64_t Start;
  561. @@ -54,9 +53,17 @@
  562.                 std::vector<uint8_t> Data;
  563.  
  564.                 AudioBlock(int64_t Start, int64_t Samples, uint8_t *SrcData, size_t SrcBytes)
  565. -                       : Start(Start)
  566. -                       , Samples(Samples)
  567. -                       , Data(SrcData, SrcData + SrcBytes)
  568. +               : Start(Start)
  569. +               , Samples(Samples)
  570. +               , Data(SrcData, SrcData + SrcBytes)
  571. +               {
  572. +                       static int64_t Now = 0;
  573. +                       Age = Now++;
  574. +               }
  575. +
  576. +               AudioBlock(int64_t Start, int64_t Samples)
  577. +               : Start(Start)
  578. +               , Samples(Samples)
  579.                 {
  580.                         static int64_t Now = 0;
  581.                         Age = Now++;
  582. @@ -74,11 +81,18 @@
  583.         CacheIterator CacheNoDelete;
  584.         // bytes per sample * number of channels
  585.         size_t BytesPerSample;
  586. -       // Number of samples stored in the decoding buffer
  587. -       size_t Decoded;
  588.  
  589. -       // Insert a block into the cache
  590. -       void CacheBlock(CacheIterator &pos, int64_t Start, size_t Samples, uint8_t *SrcData);
  591. +       bool NeedsResample;
  592. +       FFResampleContext ResampleContext;
  593. +
  594. +       // Insert the current audio frame into the cache
  595. +       void CacheBlock(CacheIterator pos);
  596. +
  597. +       // Interleave the current audio frame and insert it into the cache
  598. +       void ResampleAndCache(CacheIterator pos);
  599. +
  600. +       // Cache the unseekable beginning of the file once the output format is set
  601. +       void CacheBeginning();
  602.  
  603.         // Called after seeking
  604.         virtual void Seek() { };
  605. @@ -99,13 +113,13 @@
  606.         int SeekOffset;
  607.  
  608.         // Buffer which audio is decoded into
  609. -       AlignedBuffer<uint8_t> DecodingBuffer;
  610. +       ScopedFrame DecodeFrame;
  611.         FFMS_Index &Index;
  612.         FFMS_Track Frames;
  613.         FFCodecContext CodecContext;
  614.         FFMS_AudioProperties AP;
  615.  
  616. -       void DecodeNextBlock();
  617. +       void DecodeNextBlock(CacheIterator *cachePos = 0);
  618.         // Initialization which has to be done after the codec is opened
  619.         void Init(const FFMS_Index &Index, int DelayMode);
  620.  
  621. @@ -116,6 +130,9 @@
  622.         FFMS_Track *GetTrack() { return &Frames; }
  623.         const FFMS_AudioProperties& GetAudioProperties() const { return AP; }
  624.         void GetAudio(void *Buf, int64_t Start, int64_t Count);
  625. +
  626. +       FFMS_ResampleOptions *CreateResampleOptions() const;
  627. +       void SetOutputFormat(const FFMS_ResampleOptions *opt);
  628.  };
  629.  
  630.  class FFLAVFAudio : public FFMS_AudioSource {
  631. diff -ru ffmpegsource/src/core/ffms.cpp ffms2/src/core/ffms.cpp
  632. --- ffmpegsource/src/core/ffms.cpp      2013-02-27 16:53:39.137362917 +0100
  633. +++ ffms2/src/core/ffms.cpp     2013-02-27 16:53:31.744380192 +0100
  634. @@ -256,6 +256,24 @@
  635.         V->ResetInputFormat();
  636.  }
  637.  
  638. +FFMS_API(FFMS_ResampleOptions *) FFMS_CreateResampleOptions(FFMS_AudioSource *A) {
  639. +       return A->CreateResampleOptions();
  640. +}
  641. +
  642. +FFMS_API(void) FFMS_DestroyResampleOptions(FFMS_ResampleOptions *options) {
  643. +       delete options;
  644. +}
  645. +
  646. +FFMS_API(int) FFMS_SetOutputFormatA(FFMS_AudioSource *A, const FFMS_ResampleOptions *options, FFMS_ErrorInfo *ErrorInfo) {
  647. +       ClearErrorInfo(ErrorInfo);
  648. +       try {
  649. +               A->SetOutputFormat(options);
  650. +       } catch (FFMS_Exception &e) {
  651. +               return e.CopyOut(ErrorInfo);
  652. +       }
  653. +       return FFMS_ERROR_SUCCESS;
  654. +}
  655. +
  656.  FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index) {
  657.         assert(Index != NULL);
  658.         if (Index == NULL)
  659. diff -ru ffmpegsource/src/core/indexing.cpp ffms2/src/core/indexing.cpp
  660. --- ffmpegsource/src/core/indexing.cpp  2013-02-27 16:53:39.134029741 +0100
  661. +++ ffms2/src/core/indexing.cpp 2013-02-27 16:53:31.744380192 +0100
  662. @@ -693,7 +693,6 @@
  663.  , ANC(0)
  664.  , ANCPrivate(0)
  665.  , SourceFile(Filename)
  666. -, DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10)
  667.  {
  668.         FFMS_Index::CalculateFileSignature(Filename, &Filesize, Digest);
  669.  }
  670. @@ -702,9 +701,9 @@
  671.  
  672.  }
  673.  
  674. -void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize) {
  675. +void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track) {
  676.         // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers.
  677. -       if (DBSize <= 0) return;
  678. +       if (DecodeFrame->nb_samples) return;
  679.  
  680.         if (!AudioContext.W64Writer) {
  681.                 FFMS_AudioProperties AP;
  682. @@ -715,6 +714,8 @@
  683.                         return;
  684.                 }
  685.  
  686. +               int Format = av_get_packed_sample_fmt(AudioContext.CodecContext->sample_fmt);
  687. +
  688.                 std::vector<char> WName(FNSize);
  689.                 (*ANC)(SourceFile.c_str(), Track, &AP, &WName[0], FNSize, ANCPrivate);
  690.                 std::string WN(&WName[0]);
  691. @@ -724,14 +725,14 @@
  692.                                         av_get_bytes_per_sample(AudioContext.CodecContext->sample_fmt),
  693.                                         AudioContext.CodecContext->channels,
  694.                                         AudioContext.CodecContext->sample_rate,
  695. -                                       (AudioContext.CodecContext->sample_fmt == AV_SAMPLE_FMT_FLT) || (AudioContext.CodecContext->sample_fmt == AV_SAMPLE_FMT_DBL));
  696. +                                       (Format == AV_SAMPLE_FMT_FLT) || (Format == AV_SAMPLE_FMT_DBL));
  697.                 } catch (...) {
  698.                         throw FFMS_Exception(FFMS_ERROR_WAVE_WRITER, FFMS_ERROR_FILE_WRITE,
  699.                                 "Failed to write wave data");
  700.                 }
  701.         }
  702.  
  703. -       AudioContext.W64Writer->WriteData(&DecodingBuffer[0], DBSize);
  704. +       AudioContext.W64Writer->WriteData(*DecodeFrame);
  705.  }
  706.  
  707.  int64_t FFMS_Indexer::IndexAudioPacket(int Track, AVPacket *Packet, SharedAudioContext &Context, FFMS_Index &TrackIndices) {
  708. @@ -739,8 +740,10 @@
  709.         int64_t StartSample = Context.CurrentSample;
  710.         int Read = 0;
  711.         while (Packet->size > 0) {
  712. -               int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10;
  713. -               int Ret = avcodec_decode_audio3(CodecContext, (int16_t *)&DecodingBuffer[0], &dbsize, Packet);
  714. +               DecodeFrame.reset();
  715. +
  716. +               int GotFrame = 0;
  717. +               int Ret = avcodec_decode_audio4(CodecContext, DecodeFrame, &GotFrame, Packet);
  718.                 if (Ret < 0) {
  719.                         if (ErrorHandling == FFMS_IEH_ABORT) {
  720.                                 throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING, "Audio decoding error");
  721. @@ -756,13 +759,14 @@
  722.                 Packet->data += Ret;
  723.                 Read += Ret;
  724.  
  725. -               CheckAudioProperties(Track, CodecContext);
  726. +               if (GotFrame) {
  727. +                       CheckAudioProperties(Track, CodecContext);
  728.  
  729. -               if (dbsize > 0)
  730. -                       Context.CurrentSample += dbsize / (av_get_bytes_per_sample(CodecContext->sample_fmt) * CodecContext->channels);
  731. +                       Context.CurrentSample += DecodeFrame->nb_samples;
  732.  
  733. -               if (DumpMask & (1 << Track))
  734. -                       WriteAudio(Context, &TrackIndices, Track, dbsize);
  735. +                       if (DumpMask & (1 << Track))
  736. +                               WriteAudio(Context, &TrackIndices, Track);
  737. +               }
  738.         }
  739.         Packet->size += Read;
  740.         Packet->data -= Read;
  741. diff -ru ffmpegsource/src/core/indexing.h ffms2/src/core/indexing.h
  742. --- ffmpegsource/src/core/indexing.h    2013-02-27 16:53:39.127363391 +0100
  743. +++ ffms2/src/core/indexing.h   2013-02-27 16:53:31.744380192 +0100
  744. @@ -155,7 +155,6 @@
  745.  };
  746.  
  747.  struct FFMS_Indexer {
  748. -private:
  749.         std::map<int, FFMS_AudioProperties> LastAudioProperties;
  750.  protected:
  751.         int IndexMask;
  752. @@ -166,12 +165,12 @@
  753.         TAudioNameCallback ANC;
  754.         void *ANCPrivate;
  755.         std::string SourceFile;
  756. -       AlignedBuffer<uint8_t> DecodingBuffer;
  757. +       ScopedFrame DecodeFrame;
  758.  
  759.         int64_t Filesize;
  760.         uint8_t Digest[20];
  761.  
  762. -       void WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize);
  763. +       void WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track);
  764.         void CheckAudioProperties(int Track, AVCodecContext *Context);
  765.         int64_t IndexAudioPacket(int Track, AVPacket *Packet, SharedAudioContext &Context, FFMS_Index &TrackIndices);
  766.         void ParseVideoPacket(SharedVideoContext &VideoContext, AVPacket &pkt, int *RepeatPict, int *FrameType, bool *Invisible);
  767. diff -ru ffmpegsource/src/core/utils.cpp ffms2/src/core/utils.cpp
  768. --- ffmpegsource/src/core/utils.cpp     2013-02-27 16:53:39.134029741 +0100
  769. +++ ffms2/src/core/utils.cpp    2013-02-27 16:53:31.744380192 +0100
  770. @@ -214,10 +214,32 @@
  771.         pkt.size = 0;
  772.  }
  773.  
  774. +extern "C" {
  775. +#if VERSION_CHECK(LIBAVUTIL_VERSION_INT, >=, 52, 2, 0, 52, 6, 100)
  776. +#include <libavutil/channel_layout.h>
  777. +#elif VERSION_CHECK(LIBAVUTIL_VERSION_INT, >=, 51, 26, 0, 51, 45, 100)
  778. +#include <libavutil/audioconvert.h>
  779. +#else
  780. +static int64_t av_get_default_channel_layout(int nb_channels) {
  781. +       switch(nb_channels) {
  782. +               case 1: return AV_CH_LAYOUT_MONO;
  783. +               case 2: return AV_CH_LAYOUT_STEREO;
  784. +               case 3: return AV_CH_LAYOUT_SURROUND;
  785. +               case 4: return AV_CH_LAYOUT_QUAD;
  786. +               case 5: return AV_CH_LAYOUT_5POINT0;
  787. +               case 6: return AV_CH_LAYOUT_5POINT1;
  788. +               case 7: return AV_CH_LAYOUT_6POINT1;
  789. +               case 8: return AV_CH_LAYOUT_7POINT1;
  790. +               default: return 0;
  791. +       }
  792. +}
  793. +#endif
  794. +}
  795. +
  796.  void FillAP(FFMS_AudioProperties &AP, AVCodecContext *CTX, FFMS_Track &Frames) {
  797. -       AP.SampleFormat = static_cast<FFMS_SampleFormat>(CTX->sample_fmt);
  798. +       AP.SampleFormat = static_cast<FFMS_SampleFormat>(av_get_packed_sample_fmt(CTX->sample_fmt));
  799.         AP.BitsPerSample = av_get_bytes_per_sample(CTX->sample_fmt) * 8;
  800. -       AP.Channels = CTX->channels;;
  801. +       AP.Channels = CTX->channels;
  802.         AP.ChannelLayout = CTX->channel_layout;
  803.         AP.SampleRate = CTX->sample_rate;
  804.         if (!Frames.empty()) {
  805. @@ -225,6 +247,9 @@
  806.                 AP.FirstTime = ((Frames.front().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
  807.                 AP.LastTime = ((Frames.back().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
  808.         }
  809. +
  810. +       if (AP.ChannelLayout == 0)
  811. +               AP.ChannelLayout = av_get_default_channel_layout(AP.Channels);
  812.  }
  813.  
  814.  #ifdef HAALISOURCE
  815. diff -ru ffmpegsource/src/core/utils.h ffms2/src/core/utils.h
  816. --- ffmpegsource/src/core/utils.h       2013-02-27 16:53:39.127363391 +0100
  817. +++ ffms2/src/core/utils.h      2013-02-27 16:53:31.744380192 +0100
  818. @@ -31,9 +31,13 @@
  819.  extern "C" {
  820.  #include "stdiostream.h"
  821.  #include <libavutil/mem.h>
  822. +#include <libavutil/opt.h>
  823.  #include <libavformat/avformat.h>
  824.  #include <libavcodec/avcodec.h>
  825.  #include <libswscale/swscale.h>
  826. +#ifdef WITH_AVRESAMPLE
  827. +#include <libavresample/avresample.h>
  828. +#endif
  829.  }
  830.  
  831.  // must be included after ffmpeg headers
  832. @@ -133,6 +137,34 @@
  833.         }
  834.  };
  835.  
  836. +template<typename T, T *(*Alloc)(), void (*Del)(T **)>
  837. +class unknown_size {
  838. +       T *ptr;
  839. +
  840. +       unknown_size(unknown_size const&);
  841. +       unknown_size& operator=(unknown_size const&);
  842. +public:
  843. +       operator T*() const { return ptr; }
  844. +       operator void*() const { return ptr; }
  845. +       T *operator->() const { return ptr; }
  846. +
  847. +       unknown_size() : ptr(Alloc()) { }
  848. +       ~unknown_size() { Del(&ptr); }
  849. +};
  850. +
  851. +class ScopedFrame : public unknown_size<AVFrame, avcodec_alloc_frame, avcodec_free_frame> {
  852. +public:
  853. +       void reset() {
  854. +               avcodec_get_frame_defaults(*this);
  855. +       }
  856. +};
  857. +
  858. +#ifdef WITH_AVRESAMPLE
  859. +typedef unknown_size<AVAudioResampleContext, avresample_alloc_context, avresample_free> FFResampleContext;
  860. +#else
  861. +typedef struct {} FFResampleContext;
  862. +#endif
  863. +
  864.  inline void DeleteHaaliCodecContext(AVCodecContext *CodecContext) {
  865.         av_freep(&CodecContext->extradata);
  866.         av_freep(&CodecContext);
  867. @@ -228,4 +240,68 @@
  868.  
  869.  void FlushBuffers(AVCodecContext *CodecContext);
  870.  
  871. +namespace optdetail {
  872. +       template<typename T>
  873. +       T get_av_opt(void *v, const char *name) {
  874. +               return static_cast<T>(av_get_int(v, name, 0));
  875. +       }
  876. +
  877. +       template<>
  878. +       inline double get_av_opt<double>(void *v, const char *name) {
  879. +               return av_get_double(v, name, 0);
  880. +       }
  881. +
  882. +       template<typename T>
  883. +       void set_av_opt(void *v, const char *name, T value) {
  884. +               av_opt_set_int(v, name, value, 0);
  885. +       }
  886. +
  887. +       template<>
  888. +       inline void set_av_opt<double>(void *v, const char *name, double value) {
  889. +               av_opt_set_double(v, name, value, 0);
  890. +       }
  891. +}
  892. +
  893. +template<typename FFMS_Struct>
  894. +class OptionMapper {
  895. +       struct OptionMapperBase {
  896. +               virtual void ToOpt(const FFMS_Struct *src, void *dst) const=0;
  897. +               virtual void FromOpt(FFMS_Struct *dst, void *src) const=0;
  898. +       };
  899. +
  900. +       template<typename T>
  901. +       class OptionMapperImpl : public OptionMapperBase {
  902. +               T (FFMS_Struct::*ptr);
  903. +               const char *name;
  904. +
  905. +       public:
  906. +               OptionMapperImpl(T (FFMS_Struct::*ptr), const char *name) : ptr(ptr), name(name) { }
  907. +               void ToOpt(const FFMS_Struct *src, void *dst) const { optdetail::set_av_opt(dst, name, src->*ptr); }
  908. +               void FromOpt(FFMS_Struct *dst, void *src) const { dst->*ptr = optdetail::get_av_opt<T>(src, name); }
  909. +       };
  910. +
  911. +       OptionMapperBase *impl;
  912. +
  913. +public:
  914. +       template<typename T>
  915. +       OptionMapper(const char *opt_name, T (FFMS_Struct::*member)) : impl(new OptionMapperImpl<T>(member, opt_name)) { }
  916. +
  917. +       void ToOpt(const FFMS_Struct *src, void *dst) const { impl->ToOpt(src, dst); }
  918. +       void FromOpt(FFMS_Struct *dst, void *src) const { impl->FromOpt(dst, src); }
  919. +};
  920. +
  921. +template<typename T, int N>
  922. +T *ReadOptions(void *opt, OptionMapper<T> (&options)[N]) {
  923. +       T *ret = new T;
  924. +       for (int i = 0; i < N; ++i)
  925. +               options[i].FromOpt(ret, opt);
  926. +       return ret;
  927. +}
  928. +
  929. +template<typename T, int N>
  930. +void SetOptions(const T* src, void *opt, OptionMapper<T> (&options)[N]) {
  931. +       for (int i = 0; i < N; ++i)
  932. +               options[i].ToOpt(src, opt);
  933. +}
  934. +
  935.  #endif
  936. diff -ru ffmpegsource/src/core/wave64writer.cpp ffms2/src/core/wave64writer.cpp
  937. --- ffmpegsource/src/core/wave64writer.cpp      2013-02-27 16:53:39.134029741 +0100
  938. +++ ffms2/src/core/wave64writer.cpp     2013-02-27 16:53:31.744380192 +0100
  939. @@ -106,7 +106,16 @@
  940.                 WavFile.seekp(CPos, std::ios::beg);
  941.  }
  942.  
  943. -void Wave64Writer::WriteData(void *Data, std::streamsize Length) {
  944. -       WavFile.write(reinterpret_cast<char *>(Data), Length);
  945. +void Wave64Writer::WriteData(AVFrame const& Frame) {
  946. +       uint64_t Length = Frame.nb_samples * BytesPerSample * Channels;
  947. +       if (Channels > 1 && av_sample_fmt_is_planar(static_cast<AVSampleFormat>(Frame.format))) {
  948. +               for (int32_t sample = 0; sample < Frame.nb_samples; ++sample) {
  949. +                       for (int32_t channel = 0; channel < Channels; ++channel)
  950. +                               WavFile.write(reinterpret_cast<char *>(&Frame.extended_data[channel][sample * BytesPerSample]), BytesPerSample);
  951. +               }
  952. +       }
  953. +       else {
  954. +               WavFile.write(reinterpret_cast<char *>(Frame.extended_data[0]), Length);
  955. +       }
  956.         BytesWritten += Length;
  957.  }
  958. diff -ru /tmp/ffmpegsource/src/ffmpegsource/src/core/wave64writer.h ffms2/src/core/wave64writer.h
  959. --- /tmp/ffmpegsource/src/ffmpegsource/src/core/wave64writer.h  2013-02-27 16:53:39.127363391 +0100
  960. +++ ffms2/src/core/wave64writer.h       2013-02-27 16:53:31.744380192 +0100
  961. @@ -28,8 +28,8 @@
  962.  class Wave64Writer {
  963.  public:
  964.         Wave64Writer(const char *Filename, uint16_t BitsPerSample, uint16_t Channels, uint32_t SamplesPerSec, bool IsFloat);
  965.         ~Wave64Writer();
  966. -       void WriteData(void *Data, std::streamsize Length);
  967. +       void WriteData(AVFrame const& Frame);
  968.  private:
  969.         ffms_fstream WavFile;
  970.         int32_t BytesPerSample;