Advertisement
Guest User

enable-libavresample.patch

a guest
Feb 27th, 2013
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 35.62 KB | None | 0 0
  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;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement