Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # enable-libavresample.patch
- #
- # Adds libavresample support. Created by diffing Thomas Goyne's GIT repo
- # with official ffms SVN.
- #
- diff -ru ffmpegsource/configure.ac ffms2/configure.ac
- --- ffmpegsource/configure.ac 2013-02-27 16:53:39.230691825 +0100
- +++ ffms2/configure.ac 2013-02-27 16:53:31.737713841 +0100
- @@ -181,6 +181,25 @@
- AC_MSG_RESULT([no])
- ])
- +AC_ARG_ENABLE(avresample,
- + AS_HELP_STRING([--enable-avresample],
- + [use libavresample for audio resampling]))
- +AS_IF([test x$enable_avresample != xno], [
- + PKG_CHECK_MODULES(AVRESAMPLE, [libavresample >= 1.0.0], [enable_avresample=yes], [
- + AS_IF([test x$enable_avresample = xyes],
- + [AC_MSG_ERROR([--enable-avresample was specified, but avresample 1.0.0+ could not be found.])])
- + enable_avresample=no
- + ])
- +])
- +
- +AS_IF([test x$enable_avresample],
- + [libavresample="libavresample"
- + AC_DEFINE([WITH_AVRESAMPLE], [1], [Use avresample])])
- +
- +AC_SUBST([AVRESAMPLE_CFLAGS])
- +AC_SUBST([AVRESAMPLE_LIBS])
- +AC_SUBST([libavresample])
- +
- AC_MSG_CHECKING([whether -Wl,-Bsymbolic is needed])
- if test "$enable_shared" = yes; then
- _LDFLAGS="$LDFLAGS"
- diff -ru ffmpegsource/ffms2.pc.in ffms2/ffms2.pc.in
- --- ffmpegsource/ffms2.pc.in 2013-02-27 16:53:38.924039701 +0100
- +++ ffms2/ffms2.pc.in 2013-02-27 16:53:31.737713841 +0100
- @@ -7,7 +7,7 @@
- Name: ffms2
- Description: The Fabulous FM Library 2
- -Requires.private: libavformat libavcodec libswscale libavutil
- +Requires.private: libavformat libavcodec libswscale libavutil @libavresample@
- Version: @FFMS_VERSION@
- Libs.private: @ZLIB_LDFLAGS@ -lz
- Libs: -L${libdir} -lffms2
- diff -ru ffmpegsource/include/ffmscompat.h ffms2/include/ffmscompat.h
- --- ffmpegsource/include/ffmscompat.h 2013-02-27 16:53:38.920706525 +0100
- +++ ffms2/include/ffmscompat.h 2013-02-27 16:53:31.737713841 +0100
- @@ -71,6 +71,15 @@
- # define FFMS_CodecID AVCodecID
- # undef CodecID
- # endif
- +# if VERSION_CHECK(LIBAVCODEC_VERSION_INT, <, 54, 28, 0, 54, 59, 100)
- +# define avcodec_free_frame av_free
- +# endif
- +#endif
- +
- +#ifdef LIBAVUTIL_VERSION_INT
- +# if VERSION_CHECK(LIBAVUTIL_VERSION_INT, <, 51, 27, 0, 51, 46, 100)
- +# define av_get_packed_sample_fmt(fmt) (fmt < AV_SAMPLE_FMT_U8P ? fmt : fmt - (AV_SAMPLE_FMT_U8P - AV_SAMPLE_FMT_U8))
- +# endif
- #endif
- #endif // FFMSCOMPAT_H
- diff -ru ffmpegsource/include/ffms.h ffms2/include/ffms.h
- --- ffmpegsource/include/ffms.h 2013-02-27 16:53:38.920706525 +0100
- +++ ffms2/include/ffms.h 2013-02-27 16:53:31.737713841 +0100
- @@ -113,6 +113,7 @@
- FFMS_ERROR_TRACK, // track handling
- FFMS_ERROR_WAVE_WRITER, // WAVE64 file writer
- FFMS_ERROR_CANCELLED, // operation aborted
- + FFMS_ERROR_RESAMPLING, // audio resampling (libavresample)
- // Subtypes - what caused the error
- FFMS_ERROR_UNKNOWN = 20, // unknown error
- @@ -237,6 +238,53 @@
- FFMS_CR_JPEG = 2 // 2^n-1, or "fullrange"
- } FFMS_ColorRanges;
- +typedef enum FFMS_MixingCoefficientType {
- + FFMS_MIXING_COEFFICIENT_Q8 = 0,
- + FFMS_MIXING_COEFFICIENT_Q15 = 1,
- + FFMS_MIXING_COEFFICIENT_FLT = 2
- +} FFMS_MixingCoefficientType;
- +
- +typedef enum FFMS_MatrixEncoding {
- + FFMS_MATRIX_ENCODING_NONE = 0,
- + FFMS_MATRIX_ENCODING_DOBLY = 1,
- + FFMS_MATRIX_ENCODING_PRO_LOGIC_II = 2
- +} FFMS_MatrixEncoding;
- +
- +typedef enum FFMS_ResampleFilterType {
- + FFMS_RESAMPLE_FILTER_CUBIC = 0,
- + FFMS_RESAMPLE_FILTER_SINC = 1,
- + FFMS_RESAMPLE_FILTER_KAISER = 2
- +} FFMS_ResampleFilterType;
- +
- +typedef enum FFMS_AudioDitherMethod {
- + FFMS_RESAMPLE_DITHER_NONE = 0,
- + FFMS_RESAMPLE_DITHER_RECTANGULAR = 1,
- + FFMS_RESAMPLE_DITHER_TRIANGULAR = 2,
- + FFMS_RESAMPLE_DITHER_TRIANGULAR_HIGHPASS = 3,
- + FFMS_RESAMPLE_DITHER_TRIANGULAR_NOISESHAPING = 4
- +} FFMS_AudioDitherMethod;
- +
- +typedef struct FFMS_ResampleOptions {
- + int64_t ChannelLayout;
- + FFMS_SampleFormat SampleFormat;
- + int SampleRate;
- + FFMS_MixingCoefficientType MixingCoefficientType;
- + double CenterMixLevel;
- + double SurroundMixLevel;
- + double LFEMixLevel;
- + int Normalize;
- + int ForceResample;
- + int ResampleFilterSize;
- + int ResamplePhaseShift;
- + int LinearInterpolation;
- + double CutoffFrequencyRatio;
- + FFMS_MatrixEncoding MatrixedStereoEncoding;
- + FFMS_ResampleFilterType FilterType;
- + int KaiserBeta;
- + FFMS_AudioDitherMethod DitherMethod;
- +} FFMS_ResampleOptions;
- +
- +
- typedef struct FFMS_Frame {
- uint8_t *Data[4];
- int Linesize[4];
- @@ -319,6 +367,9 @@
- FFMS_API(void) FFMS_ResetOutputFormatV(FFMS_VideoSource *V);
- 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) */
- FFMS_API(void) FFMS_ResetInputFormatV(FFMS_VideoSource *V);
- +FFMS_API(FFMS_ResampleOptions *) FFMS_CreateResampleOptions(FFMS_AudioSource *A); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */
- +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) */
- +FFMS_API(void) FFMS_DestroyResampleOptions(FFMS_ResampleOptions *options); /* Introduced in FFMS_VERSION ((2 << 24) | (15 << 16) | (4 << 8) | 0) */
- FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index);
- FFMS_API(int) FFMS_GetSourceType(FFMS_Index *Index);
- FFMS_API(int) FFMS_GetSourceTypeI(FFMS_Indexer *Indexer);
- diff -ru ffmpegsource/Makefile.am ffms2/Makefile.am
- --- ffmpegsource/Makefile.am 2013-02-27 16:53:39.310688030 +0100
- +++ ffms2/Makefile.am 2013-02-27 16:53:31.724381141 +0100
- @@ -9,7 +9,7 @@
- INCLUDES = -I. -I$(top_srcdir)/include -I$(top_srcdir)/src/config @LIBAV_CFLAGS@ @ZLIB_CPPFLAGS@ -include config.h
- lib_LTLIBRARIES = src/core/libffms2.la
- -src_core_libffms2_la_LIBADD = @LIBAV_LIBS@ @ZLIB_LDFLAGS@ -lz @LTUNDEF@
- +src_core_libffms2_la_LIBADD = @LIBAV_LIBS@ @AVRESAMPLE_LIBS@ @ZLIB_LDFLAGS@ -lz @LTUNDEF@
- src_core_libffms2_la_SOURCES = \
- src/core/audiosource.h \
- src/core/audiosource.cpp \
- diff -ru ffmpegsource/src/config/config.h.in ffms2/src/config/config.h.in
- --- ffmpegsource/src/config/config.h.in 2013-02-27 16:53:39.017368608 +0100
- +++ ffms2/src/config/config.h.in 2013-02-27 16:53:31.744380192 +0100
- @@ -90,5 +90,8 @@
- /* Version number of package */
- #undef VERSION
- +/* Use avresample */
- +#undef WITH_AVRESAMPLE
- +
- /* Define to `unsigned int' if <sys/types.h> does not define. */
- #undef size_t
- diff -ru ffmpegsource/src/config/libs.cpp ffms2/src/config/libs.cpp
- --- ffmpegsource/src/config/libs.cpp 2013-02-27 16:53:39.017368608 +0100
- +++ ffms2/src/config/libs.cpp 2013-02-27 16:53:31.744380192 +0100
- @@ -45,6 +45,9 @@
- #pragma comment(lib, "libavcodec.a")
- #pragma comment(lib, "libavformat.a")
- #pragma comment(lib, "libswscale.a")
- +#ifdef WITH_AVRESAMPLE
- +#pragma comment(lib, "libavresample.a")
- +#endif
- #ifdef WITH_OPENCORE_AMR_NB
- #ifdef WITH_GCC_LIBAV
- diff -ru ffmpegsource/src/core/audiosource.cpp ffms2/src/core/audiosource.cpp
- --- ffmpegsource/src/core/audiosource.cpp 2013-02-27 16:53:39.137362917 +0100
- +++ ffms2/src/core/audiosource.cpp 2013-02-27 16:53:31.744380192 +0100
- @@ -23,17 +23,45 @@
- #include <algorithm>
- #include <cassert>
- +namespace {
- +
- + int64_t ChannelLayout;
- + FFMS_SampleFormat SampleFormat;
- + int SampleRate;
- +#define MAPPER(m, n) OptionMapper<FFMS_ResampleOptions>(n, &FFMS_ResampleOptions::m)
- +OptionMapper<FFMS_ResampleOptions> resample_options[] = {
- + MAPPER(ChannelLayout, "out_channel_layout"),
- + MAPPER(SampleFormat, "out_sample_fmt"),
- + MAPPER(SampleRate, "out_sample_rate"),
- + MAPPER(MixingCoefficientType, "mix_coeff_type"),
- + MAPPER(CenterMixLevel, "center_mix_level"),
- + MAPPER(SurroundMixLevel, "surround_mix_level"),
- + MAPPER(LFEMixLevel, "lfe_mix_level"),
- + MAPPER(Normalize, "normalize_mix_level"),
- + MAPPER(ForceResample, "force_resampling"),
- + MAPPER(ResampleFilterSize, "filter_size"),
- + MAPPER(ResamplePhaseShift, "phase_shift"),
- + MAPPER(LinearInterpolation, "linear_interp"),
- + MAPPER(CutoffFrequencyRatio, "cutoff"),
- + MAPPER(MatrixedStereoEncoding, "matrix_encoding"),
- + MAPPER(FilterType, "filter_type"),
- + MAPPER(KaiserBeta, "kaiser_beta"),
- + MAPPER(DitherMethod, "dither_method")
- +};
- +#undef MAPPER
- +
- +}
- +
- FFMS_AudioSource::FFMS_AudioSource(const char *SourceFile, FFMS_Index &Index, int Track)
- : Delay(0)
- , MaxCacheBlocks(50)
- , BytesPerSample(0)
- -, Decoded(0)
- +, NeedsResample(false)
- , CurrentSample(-1)
- , PacketNumber(0)
- , CurrentFrame(NULL)
- , TrackNumber(Track)
- , SeekOffset(0)
- -, DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10)
- , Index(Index)
- {
- if (Track < 0 || Track >= static_cast<int>(Index.size()))
- @@ -57,44 +85,14 @@
- Index.AddRef();
- }
- -
- #define EXCESSIVE_CACHE_SIZE 400
- void FFMS_AudioSource::Init(const FFMS_Index &Index, int DelayMode) {
- - // The first packet after a seek is often decoded incorrectly, which
- - // makes it impossible to ever correctly seek back to the beginning, so
- - // store the first block now
- -
- - // In addition, anything with the same PTS as the first packet can't be
- - // distinguished from the first packet and so can't be seeked to, so
- - // store those as well
- -
- - // Some of LAVF's splitters don't like to seek to the beginning of the
- - // file (ts and?), so cache a few blocks even if PTSes are unique
- - // Packet 7 is the last packet I've had be unseekable to, so cache up to
- - // 10 for a bit of an extra buffer
- - CacheIterator end = Cache.end();
- - while (PacketNumber < Frames.size() &&
- - ((Frames[0].PTS != ffms_av_nopts_value && Frames[PacketNumber].PTS == Frames[0].PTS) ||
- - Cache.size() < 10)) {
- -
- - // Vorbis in particular seems to like having 60+ packets at the start of the file with a PTS of 0,
- - // so we might need to expand the search range to account for that.
- - if (Cache.size() >= MaxCacheBlocks - 1) {
- - if (MaxCacheBlocks >= EXCESSIVE_CACHE_SIZE)
- - throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_ALLOCATION_FAILED, "Exceeded the search range for an initial valid audio PTS");
- - MaxCacheBlocks *= 2;
- - }
- -
- + // Decode the first packet to ensure all properties are initialized
- + // Don't cache it since it might be in the wrong format
- + // Instead, leave it in DecodeFrame and it'll get cached later
- + while (DecodeFrame->nb_samples == 0)
- DecodeNextBlock();
- - if (Decoded)
- - CacheBlock(end, CurrentSample, Decoded, &DecodingBuffer[0]);
- - }
- - // Store the iterator to the last element of the cache which is used for
- - // correctness rather than speed, so that when looking for one to delete
- - // we know how much to skip
- - CacheNoDelete = Cache.end();
- - --CacheNoDelete;
- // Read properties of the audio which may not be available until the first
- // frame has been decoded
- @@ -104,6 +102,11 @@
- throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_CODEC,
- "Codec returned zero size audio");
- + if (av_sample_fmt_is_planar(CodecContext->sample_fmt)) {
- + std::auto_ptr<FFMS_ResampleOptions> opt(CreateResampleOptions());
- + SetOutputFormat(opt.get());
- + }
- +
- if (DelayMode < FFMS_DELAY_NO_SHIFT)
- throw FFMS_Exception(FFMS_ERROR_INDEX, FFMS_ERROR_INVALID_ARGUMENT,
- "Bad audio delay compensation mode");
- @@ -146,8 +149,133 @@
- AP.NumSamples += Delay;
- }
- -void FFMS_AudioSource::CacheBlock(CacheIterator &pos, int64_t Start, size_t Samples, uint8_t *SrcData) {
- - Cache.insert(pos, AudioBlock(Start, Samples, SrcData, Samples * BytesPerSample));
- +void FFMS_AudioSource::CacheBeginning() {
- + // Nothing to do if the cache is already populated
- + if (!Cache.empty()) return;
- +
- + // The first frame is already decoded, so add it to the cache
- + CacheBlock(Cache.end());
- +
- + // The first packet after a seek is often decoded incorrectly, which
- + // makes it impossible to ever correctly seek back to the beginning, so
- + // store the first block now
- +
- + // In addition, anything with the same PTS as the first packet can't be
- + // distinguished from the first packet and so can't be seeked to, so
- + // store those as well
- +
- + // Some of LAVF's splitters don't like to seek to the beginning of the
- + // file (ts and?), so cache a few blocks even if PTSes are unique
- + // Packet 7 is the last packet I've had be unseekable to, so cache up to
- + // 10 for a bit of an extra buffer
- + CacheIterator end = Cache.end();
- + while (PacketNumber < Frames.size() &&
- + ((Frames[0].PTS != ffms_av_nopts_value && Frames[PacketNumber].PTS == Frames[0].PTS) ||
- + Cache.size() < 10)) {
- +
- + // Vorbis in particular seems to like having 60+ packets at the start
- + // of the file with a PTS of 0, so we might need to expand the search
- + // range to account for that.
- + // Expanding slightly before it's strictly needed to ensure there's a
- + // bit of space for an actual cache
- + if (Cache.size() >= MaxCacheBlocks - 5) {
- + if (MaxCacheBlocks >= EXCESSIVE_CACHE_SIZE)
- + throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_ALLOCATION_FAILED,
- + "Exceeded the search range for an initial valid audio PTS");
- + MaxCacheBlocks *= 2;
- + }
- +
- + DecodeNextBlock(&end);
- + }
- + // Store the iterator to the last element of the cache which is used for
- + // correctness rather than speed, so that when looking for one to delete
- + // we know how much to skip
- + CacheNoDelete = Cache.end();
- + --CacheNoDelete;
- +}
- +
- +void FFMS_AudioSource::SetOutputFormat(const FFMS_ResampleOptions *opt) {
- + if (!Cache.empty())
- + throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_USER,
- + "Cannot change the output format after audio decoding has begun");
- +
- + BytesPerSample = av_get_bytes_per_sample(static_cast<AVSampleFormat>(opt->SampleFormat)) * av_get_channel_layout_nb_channels(opt->ChannelLayout);
- +
- + NeedsResample =
- + opt->SampleFormat != (int)CodecContext->sample_fmt ||
- + opt->SampleRate != AP.SampleRate ||
- + opt->ChannelLayout != AP.ChannelLayout ||
- + opt->ForceResample;
- + if (!NeedsResample) return;
- +
- + if (opt->SampleRate != AP.SampleRate)
- + throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
- + "Sample rate changes are currently unsupported.");
- +
- +#ifdef WITH_AVRESAMPLE
- + if (opt->SampleRate != AP.SampleRate)
- + throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
- + "Changing the audio sample rate is currently not supported");
- +
- + std::auto_ptr<FFMS_ResampleOptions> oldOptions(ReadOptions(ResampleContext, resample_options));
- + SetOptions(opt, ResampleContext, resample_options);
- + av_opt_set_int(ResampleContext, "in_sample_rate", AP.SampleRate, 0);
- + av_opt_set_int(ResampleContext, "in_sample_fmt", CodecContext->sample_fmt, 0);
- + av_opt_set_int(ResampleContext, "in_channel_layout", AP.ChannelLayout, 0);
- +
- + if (avresample_open(ResampleContext)) {
- + SetOptions(oldOptions.get(), ResampleContext, resample_options);
- + avresample_open(ResampleContext);
- + throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNKNOWN,
- + "Could not open avresample context");
- + }
- +#else
- + if (opt->SampleFormat != AP.SampleFormat || opt->SampleRate != AP.SampleRate || opt->ChannelLayout != AP.ChannelLayout)
- + throw FFMS_Exception(FFMS_ERROR_RESAMPLING, FFMS_ERROR_UNSUPPORTED,
- + "FFMS was not built with resampling enabled. The only supported conversion is interleaving planar audio.");
- +#endif
- +}
- +
- +FFMS_ResampleOptions *FFMS_AudioSource::CreateResampleOptions() const {
- +#ifdef WITH_AVRESAMPLE
- + FFMS_ResampleOptions *ret = ReadOptions(ResampleContext, resample_options);
- +#else
- + FFMS_ResampleOptions *ret = new FFMS_ResampleOptions;
- + memset(ret, 0, sizeof(FFMS_ResampleOptions));
- +#endif
- + ret->SampleRate = AP.SampleRate;
- + ret->SampleFormat = static_cast<FFMS_SampleFormat>(AP.SampleFormat);
- + ret->ChannelLayout = AP.ChannelLayout;
- + return ret;
- +}
- +
- +void FFMS_AudioSource::ResampleAndCache(CacheIterator pos) {
- + AudioBlock& block = *Cache.insert(pos, AudioBlock(CurrentSample, DecodeFrame->nb_samples));
- + block.Data.reserve(DecodeFrame->nb_samples * BytesPerSample);
- +
- +#ifdef WITH_AVRESAMPLE
- + block.Data.resize(block.Data.capacity());
- +
- + uint8_t *OutPlanes[1] = { static_cast<uint8_t *>(&block.Data[0]) };
- + avresample_convert(ResampleContext,
- + OutPlanes, block.Data.size(), DecodeFrame->nb_samples,
- + DecodeFrame->extended_data, DecodeFrame->nb_samples * av_get_bytes_per_sample(CodecContext->sample_fmt), DecodeFrame->nb_samples);
- +#else
- + int width = av_get_bytes_per_sample(CodecContext->sample_fmt);
- + uint8_t **Data = DecodeFrame->extended_data;
- +
- + for (int s = 0; s < DecodeFrame->nb_samples; ++s) {
- + for (int c = 0; c < CodecContext->channels; ++c)
- + block.Data.insert(block.Data.end(), &Data[c][s * width], &Data[c][(s + 1) * width]);
- + }
- +#endif
- +}
- +
- +void FFMS_AudioSource::CacheBlock(CacheIterator pos) {
- + if (NeedsResample)
- + ResampleAndCache(pos);
- + else
- + Cache.insert(pos, AudioBlock(CurrentSample, DecodeFrame->nb_samples, DecodeFrame->extended_data[0], DecodeFrame->nb_samples * BytesPerSample));
- if (Cache.size() >= MaxCacheBlocks) {
- // Kill the oldest one
- @@ -162,45 +290,45 @@
- }
- }
- -void FFMS_AudioSource::DecodeNextBlock() {
- - if (BytesPerSample == 0) BytesPerSample = av_get_bytes_per_sample(CodecContext->sample_fmt) * CodecContext->channels;
- -
- +void FFMS_AudioSource::DecodeNextBlock(CacheIterator *pos) {
- CurrentFrame = &Frames[PacketNumber];
- AVPacket Packet;
- if (!ReadPacket(&Packet))
- - throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_UNKNOWN, "ReadPacket unexpectedly failed to read a packet");
- + throw FFMS_Exception(FFMS_ERROR_PARSER, FFMS_ERROR_UNKNOWN,
- + "ReadPacket unexpectedly failed to read a packet");
- // ReadPacket may have changed the packet number
- CurrentFrame = &Frames[PacketNumber];
- CurrentSample = CurrentFrame->SampleStart;
- - ++PacketNumber;
- - uint8_t *Buf = &DecodingBuffer[0];
- + bool GotSamples = false;
- uint8_t *Data = Packet.data;
- while (Packet.size > 0) {
- - int TempOutputBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE * 10 - (Buf - &DecodingBuffer[0]);
- - int Ret = avcodec_decode_audio3(CodecContext, (int16_t *)Buf, &TempOutputBufSize, &Packet);
- + DecodeFrame.reset();
- + int GotFrame = 0;
- + int Ret = avcodec_decode_audio4(CodecContext, DecodeFrame, &GotFrame, &Packet);
- // Should only ever happen if the user chose to ignore decoding errors
- // during indexing, so continue to just ignore decoding errors
- if (Ret < 0) break;
- - if (Ret > 0) {
- + if (Ret > 0 && GotFrame) {
- Packet.size -= Ret;
- Packet.data += Ret;
- - Buf += TempOutputBufSize;
- + if (DecodeFrame->nb_samples > 0) {
- + GotSamples = true;
- + if (pos)
- + CacheBlock(*pos);
- + }
- }
- }
- Packet.data = Data;
- FreePacket(&Packet);
- - Decoded = (Buf - &DecodingBuffer[0]) / BytesPerSample;
- - if (Decoded == 0) {
- - // zero sample packets aren't included in the index so we didn't
- - // actually move to the next packet
- - --PacketNumber;
- - }
- + // Zero sample packets aren't included in the index
- + if (GotSamples)
- + ++PacketNumber;
- }
- static bool SampleStartComp(const TFrameInfo &a, const TFrameInfo &b) {
- @@ -216,6 +344,8 @@
- throw FFMS_Exception(FFMS_ERROR_DECODING, FFMS_ERROR_INVALID_ARGUMENT,
- "Out of bounds audio samples requested");
- + CacheBeginning();
- +
- uint8_t *Dst = static_cast<uint8_t*>(Buf);
- // Apply audio delay (if any) and fill any samples before the start time with zero
- @@ -253,10 +383,12 @@
- }
- // Decode another block
- else {
- + CacheIterator cachePos = it; --cachePos;
- +
- if (Start < CurrentSample && SeekOffset == -1)
- throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Audio stream is not seekable");
- - if (SeekOffset >= 0 && (Start < CurrentSample || Start > CurrentSample + Decoded * 5)) {
- + if (SeekOffset >= 0 && (Start < CurrentSample || Start > CurrentSample + DecodeFrame->nb_samples * 5)) {
- TFrameInfo f;
- f.SampleStart = Start;
- int NewPacketNumber = std::distance(Frames.begin(), std::lower_bound(Frames.begin(), Frames.end(), f, SampleStartComp));
- @@ -266,32 +398,22 @@
- // Only seek forward if it'll actually result in moving forward
- if (Start < CurrentSample || static_cast<size_t>(NewPacketNumber) > PacketNumber) {
- PacketNumber = NewPacketNumber;
- - Decoded = 0;
- CurrentSample = -1;
- + DecodeFrame.reset();
- avcodec_flush_buffers(CodecContext);
- Seek();
- }
- }
- - // Decode everything between the last keyframe and the block we want
- + // Decode until we hit the block we want
- if (PacketNumber >= Frames.size())
- throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Seeking is severely broken");
- - while (CurrentSample + Decoded <= Start && PacketNumber < Frames.size())
- - DecodeNextBlock();
- + while (CurrentSample + DecodeFrame->nb_samples <= Start && PacketNumber < Frames.size())
- + DecodeNextBlock(&it);
- if (CurrentSample > Start)
- throw FFMS_Exception(FFMS_ERROR_SEEKING, FFMS_ERROR_CODEC, "Seeking is severely broken");
- - CacheBlock(it, CurrentSample, Decoded, &DecodingBuffer[0]);
- -
- - size_t FirstSample = static_cast<size_t>(Start - CurrentSample);
- - size_t Samples = static_cast<size_t>(Decoded - FirstSample);
- - size_t Bytes = FFMIN(Samples, static_cast<size_t>(Count)) * BytesPerSample;
- -
- - memcpy(Dst, &DecodingBuffer[FirstSample * BytesPerSample], Bytes);
- -
- - Start += Samples;
- - Count -= Samples;
- - Dst += Bytes;
- + it = cachePos;
- }
- }
- }
- diff -ru ffmpegsource/src/core/audiosource.h ffms2/src/core/audiosource.h
- --- ffmpegsource/src/core/audiosource.h 2013-02-27 16:53:39.130696566 +0100
- +++ ffms2/src/core/audiosource.h 2013-02-27 16:53:31.744380192 +0100
- @@ -46,7 +46,6 @@
- #endif
- struct FFMS_AudioSource {
- -private:
- struct AudioBlock {
- int64_t Age;
- int64_t Start;
- @@ -54,9 +53,17 @@
- std::vector<uint8_t> Data;
- AudioBlock(int64_t Start, int64_t Samples, uint8_t *SrcData, size_t SrcBytes)
- - : Start(Start)
- - , Samples(Samples)
- - , Data(SrcData, SrcData + SrcBytes)
- + : Start(Start)
- + , Samples(Samples)
- + , Data(SrcData, SrcData + SrcBytes)
- + {
- + static int64_t Now = 0;
- + Age = Now++;
- + }
- +
- + AudioBlock(int64_t Start, int64_t Samples)
- + : Start(Start)
- + , Samples(Samples)
- {
- static int64_t Now = 0;
- Age = Now++;
- @@ -74,11 +81,18 @@
- CacheIterator CacheNoDelete;
- // bytes per sample * number of channels
- size_t BytesPerSample;
- - // Number of samples stored in the decoding buffer
- - size_t Decoded;
- - // Insert a block into the cache
- - void CacheBlock(CacheIterator &pos, int64_t Start, size_t Samples, uint8_t *SrcData);
- + bool NeedsResample;
- + FFResampleContext ResampleContext;
- +
- + // Insert the current audio frame into the cache
- + void CacheBlock(CacheIterator pos);
- +
- + // Interleave the current audio frame and insert it into the cache
- + void ResampleAndCache(CacheIterator pos);
- +
- + // Cache the unseekable beginning of the file once the output format is set
- + void CacheBeginning();
- // Called after seeking
- virtual void Seek() { };
- @@ -99,13 +113,13 @@
- int SeekOffset;
- // Buffer which audio is decoded into
- - AlignedBuffer<uint8_t> DecodingBuffer;
- + ScopedFrame DecodeFrame;
- FFMS_Index &Index;
- FFMS_Track Frames;
- FFCodecContext CodecContext;
- FFMS_AudioProperties AP;
- - void DecodeNextBlock();
- + void DecodeNextBlock(CacheIterator *cachePos = 0);
- // Initialization which has to be done after the codec is opened
- void Init(const FFMS_Index &Index, int DelayMode);
- @@ -116,6 +130,9 @@
- FFMS_Track *GetTrack() { return &Frames; }
- const FFMS_AudioProperties& GetAudioProperties() const { return AP; }
- void GetAudio(void *Buf, int64_t Start, int64_t Count);
- +
- + FFMS_ResampleOptions *CreateResampleOptions() const;
- + void SetOutputFormat(const FFMS_ResampleOptions *opt);
- };
- class FFLAVFAudio : public FFMS_AudioSource {
- diff -ru ffmpegsource/src/core/ffms.cpp ffms2/src/core/ffms.cpp
- --- ffmpegsource/src/core/ffms.cpp 2013-02-27 16:53:39.137362917 +0100
- +++ ffms2/src/core/ffms.cpp 2013-02-27 16:53:31.744380192 +0100
- @@ -256,6 +256,24 @@
- V->ResetInputFormat();
- }
- +FFMS_API(FFMS_ResampleOptions *) FFMS_CreateResampleOptions(FFMS_AudioSource *A) {
- + return A->CreateResampleOptions();
- +}
- +
- +FFMS_API(void) FFMS_DestroyResampleOptions(FFMS_ResampleOptions *options) {
- + delete options;
- +}
- +
- +FFMS_API(int) FFMS_SetOutputFormatA(FFMS_AudioSource *A, const FFMS_ResampleOptions *options, FFMS_ErrorInfo *ErrorInfo) {
- + ClearErrorInfo(ErrorInfo);
- + try {
- + A->SetOutputFormat(options);
- + } catch (FFMS_Exception &e) {
- + return e.CopyOut(ErrorInfo);
- + }
- + return FFMS_ERROR_SUCCESS;
- +}
- +
- FFMS_API(void) FFMS_DestroyIndex(FFMS_Index *Index) {
- assert(Index != NULL);
- if (Index == NULL)
- diff -ru ffmpegsource/src/core/indexing.cpp ffms2/src/core/indexing.cpp
- --- ffmpegsource/src/core/indexing.cpp 2013-02-27 16:53:39.134029741 +0100
- +++ ffms2/src/core/indexing.cpp 2013-02-27 16:53:31.744380192 +0100
- @@ -693,7 +693,6 @@
- , ANC(0)
- , ANCPrivate(0)
- , SourceFile(Filename)
- -, DecodingBuffer(AVCODEC_MAX_AUDIO_FRAME_SIZE * 10)
- {
- FFMS_Index::CalculateFileSignature(Filename, &Filesize, Digest);
- }
- @@ -702,9 +701,9 @@
- }
- -void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize) {
- +void FFMS_Indexer::WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track) {
- // Delay writer creation until after an audio frame has been decoded. This ensures that all parameters are known when writing the headers.
- - if (DBSize <= 0) return;
- + if (DecodeFrame->nb_samples) return;
- if (!AudioContext.W64Writer) {
- FFMS_AudioProperties AP;
- @@ -715,6 +714,8 @@
- return;
- }
- + int Format = av_get_packed_sample_fmt(AudioContext.CodecContext->sample_fmt);
- +
- std::vector<char> WName(FNSize);
- (*ANC)(SourceFile.c_str(), Track, &AP, &WName[0], FNSize, ANCPrivate);
- std::string WN(&WName[0]);
- @@ -724,14 +725,14 @@
- av_get_bytes_per_sample(AudioContext.CodecContext->sample_fmt),
- AudioContext.CodecContext->channels,
- AudioContext.CodecContext->sample_rate,
- - (AudioContext.CodecContext->sample_fmt == AV_SAMPLE_FMT_FLT) || (AudioContext.CodecContext->sample_fmt == AV_SAMPLE_FMT_DBL));
- + (Format == AV_SAMPLE_FMT_FLT) || (Format == AV_SAMPLE_FMT_DBL));
- } catch (...) {
- throw FFMS_Exception(FFMS_ERROR_WAVE_WRITER, FFMS_ERROR_FILE_WRITE,
- "Failed to write wave data");
- }
- }
- - AudioContext.W64Writer->WriteData(&DecodingBuffer[0], DBSize);
- + AudioContext.W64Writer->WriteData(*DecodeFrame);
- }
- int64_t FFMS_Indexer::IndexAudioPacket(int Track, AVPacket *Packet, SharedAudioContext &Context, FFMS_Index &TrackIndices) {
- @@ -739,8 +740,10 @@
- int64_t StartSample = Context.CurrentSample;
- int Read = 0;
- while (Packet->size > 0) {
- - int dbsize = AVCODEC_MAX_AUDIO_FRAME_SIZE*10;
- - int Ret = avcodec_decode_audio3(CodecContext, (int16_t *)&DecodingBuffer[0], &dbsize, Packet);
- + DecodeFrame.reset();
- +
- + int GotFrame = 0;
- + int Ret = avcodec_decode_audio4(CodecContext, DecodeFrame, &GotFrame, Packet);
- if (Ret < 0) {
- if (ErrorHandling == FFMS_IEH_ABORT) {
- throw FFMS_Exception(FFMS_ERROR_CODEC, FFMS_ERROR_DECODING, "Audio decoding error");
- @@ -756,13 +759,14 @@
- Packet->data += Ret;
- Read += Ret;
- - CheckAudioProperties(Track, CodecContext);
- + if (GotFrame) {
- + CheckAudioProperties(Track, CodecContext);
- - if (dbsize > 0)
- - Context.CurrentSample += dbsize / (av_get_bytes_per_sample(CodecContext->sample_fmt) * CodecContext->channels);
- + Context.CurrentSample += DecodeFrame->nb_samples;
- - if (DumpMask & (1 << Track))
- - WriteAudio(Context, &TrackIndices, Track, dbsize);
- + if (DumpMask & (1 << Track))
- + WriteAudio(Context, &TrackIndices, Track);
- + }
- }
- Packet->size += Read;
- Packet->data -= Read;
- diff -ru ffmpegsource/src/core/indexing.h ffms2/src/core/indexing.h
- --- ffmpegsource/src/core/indexing.h 2013-02-27 16:53:39.127363391 +0100
- +++ ffms2/src/core/indexing.h 2013-02-27 16:53:31.744380192 +0100
- @@ -155,7 +155,6 @@
- };
- struct FFMS_Indexer {
- -private:
- std::map<int, FFMS_AudioProperties> LastAudioProperties;
- protected:
- int IndexMask;
- @@ -166,12 +165,12 @@
- TAudioNameCallback ANC;
- void *ANCPrivate;
- std::string SourceFile;
- - AlignedBuffer<uint8_t> DecodingBuffer;
- + ScopedFrame DecodeFrame;
- int64_t Filesize;
- uint8_t Digest[20];
- - void WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track, int DBSize);
- + void WriteAudio(SharedAudioContext &AudioContext, FFMS_Index *Index, int Track);
- void CheckAudioProperties(int Track, AVCodecContext *Context);
- int64_t IndexAudioPacket(int Track, AVPacket *Packet, SharedAudioContext &Context, FFMS_Index &TrackIndices);
- void ParseVideoPacket(SharedVideoContext &VideoContext, AVPacket &pkt, int *RepeatPict, int *FrameType, bool *Invisible);
- diff -ru ffmpegsource/src/core/utils.cpp ffms2/src/core/utils.cpp
- --- ffmpegsource/src/core/utils.cpp 2013-02-27 16:53:39.134029741 +0100
- +++ ffms2/src/core/utils.cpp 2013-02-27 16:53:31.744380192 +0100
- @@ -214,10 +214,32 @@
- pkt.size = 0;
- }
- +extern "C" {
- +#if VERSION_CHECK(LIBAVUTIL_VERSION_INT, >=, 52, 2, 0, 52, 6, 100)
- +#include <libavutil/channel_layout.h>
- +#elif VERSION_CHECK(LIBAVUTIL_VERSION_INT, >=, 51, 26, 0, 51, 45, 100)
- +#include <libavutil/audioconvert.h>
- +#else
- +static int64_t av_get_default_channel_layout(int nb_channels) {
- + switch(nb_channels) {
- + case 1: return AV_CH_LAYOUT_MONO;
- + case 2: return AV_CH_LAYOUT_STEREO;
- + case 3: return AV_CH_LAYOUT_SURROUND;
- + case 4: return AV_CH_LAYOUT_QUAD;
- + case 5: return AV_CH_LAYOUT_5POINT0;
- + case 6: return AV_CH_LAYOUT_5POINT1;
- + case 7: return AV_CH_LAYOUT_6POINT1;
- + case 8: return AV_CH_LAYOUT_7POINT1;
- + default: return 0;
- + }
- +}
- +#endif
- +}
- +
- void FillAP(FFMS_AudioProperties &AP, AVCodecContext *CTX, FFMS_Track &Frames) {
- - AP.SampleFormat = static_cast<FFMS_SampleFormat>(CTX->sample_fmt);
- + AP.SampleFormat = static_cast<FFMS_SampleFormat>(av_get_packed_sample_fmt(CTX->sample_fmt));
- AP.BitsPerSample = av_get_bytes_per_sample(CTX->sample_fmt) * 8;
- - AP.Channels = CTX->channels;;
- + AP.Channels = CTX->channels;
- AP.ChannelLayout = CTX->channel_layout;
- AP.SampleRate = CTX->sample_rate;
- if (!Frames.empty()) {
- @@ -225,6 +247,9 @@
- AP.FirstTime = ((Frames.front().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
- AP.LastTime = ((Frames.back().PTS * Frames.TB.Num) / (double)Frames.TB.Den) / 1000;
- }
- +
- + if (AP.ChannelLayout == 0)
- + AP.ChannelLayout = av_get_default_channel_layout(AP.Channels);
- }
- #ifdef HAALISOURCE
- diff -ru ffmpegsource/src/core/utils.h ffms2/src/core/utils.h
- --- ffmpegsource/src/core/utils.h 2013-02-27 16:53:39.127363391 +0100
- +++ ffms2/src/core/utils.h 2013-02-27 16:53:31.744380192 +0100
- @@ -31,9 +31,13 @@
- extern "C" {
- #include "stdiostream.h"
- #include <libavutil/mem.h>
- +#include <libavutil/opt.h>
- #include <libavformat/avformat.h>
- #include <libavcodec/avcodec.h>
- #include <libswscale/swscale.h>
- +#ifdef WITH_AVRESAMPLE
- +#include <libavresample/avresample.h>
- +#endif
- }
- // must be included after ffmpeg headers
- @@ -133,6 +137,34 @@
- }
- };
- +template<typename T, T *(*Alloc)(), void (*Del)(T **)>
- +class unknown_size {
- + T *ptr;
- +
- + unknown_size(unknown_size const&);
- + unknown_size& operator=(unknown_size const&);
- +public:
- + operator T*() const { return ptr; }
- + operator void*() const { return ptr; }
- + T *operator->() const { return ptr; }
- +
- + unknown_size() : ptr(Alloc()) { }
- + ~unknown_size() { Del(&ptr); }
- +};
- +
- +class ScopedFrame : public unknown_size<AVFrame, avcodec_alloc_frame, avcodec_free_frame> {
- +public:
- + void reset() {
- + avcodec_get_frame_defaults(*this);
- + }
- +};
- +
- +#ifdef WITH_AVRESAMPLE
- +typedef unknown_size<AVAudioResampleContext, avresample_alloc_context, avresample_free> FFResampleContext;
- +#else
- +typedef struct {} FFResampleContext;
- +#endif
- +
- inline void DeleteHaaliCodecContext(AVCodecContext *CodecContext) {
- av_freep(&CodecContext->extradata);
- av_freep(&CodecContext);
- @@ -228,4 +240,68 @@
- void FlushBuffers(AVCodecContext *CodecContext);
- +namespace optdetail {
- + template<typename T>
- + T get_av_opt(void *v, const char *name) {
- + return static_cast<T>(av_get_int(v, name, 0));
- + }
- +
- + template<>
- + inline double get_av_opt<double>(void *v, const char *name) {
- + return av_get_double(v, name, 0);
- + }
- +
- + template<typename T>
- + void set_av_opt(void *v, const char *name, T value) {
- + av_opt_set_int(v, name, value, 0);
- + }
- +
- + template<>
- + inline void set_av_opt<double>(void *v, const char *name, double value) {
- + av_opt_set_double(v, name, value, 0);
- + }
- +}
- +
- +template<typename FFMS_Struct>
- +class OptionMapper {
- + struct OptionMapperBase {
- + virtual void ToOpt(const FFMS_Struct *src, void *dst) const=0;
- + virtual void FromOpt(FFMS_Struct *dst, void *src) const=0;
- + };
- +
- + template<typename T>
- + class OptionMapperImpl : public OptionMapperBase {
- + T (FFMS_Struct::*ptr);
- + const char *name;
- +
- + public:
- + OptionMapperImpl(T (FFMS_Struct::*ptr), const char *name) : ptr(ptr), name(name) { }
- + void ToOpt(const FFMS_Struct *src, void *dst) const { optdetail::set_av_opt(dst, name, src->*ptr); }
- + void FromOpt(FFMS_Struct *dst, void *src) const { dst->*ptr = optdetail::get_av_opt<T>(src, name); }
- + };
- +
- + OptionMapperBase *impl;
- +
- +public:
- + template<typename T>
- + OptionMapper(const char *opt_name, T (FFMS_Struct::*member)) : impl(new OptionMapperImpl<T>(member, opt_name)) { }
- +
- + void ToOpt(const FFMS_Struct *src, void *dst) const { impl->ToOpt(src, dst); }
- + void FromOpt(FFMS_Struct *dst, void *src) const { impl->FromOpt(dst, src); }
- +};
- +
- +template<typename T, int N>
- +T *ReadOptions(void *opt, OptionMapper<T> (&options)[N]) {
- + T *ret = new T;
- + for (int i = 0; i < N; ++i)
- + options[i].FromOpt(ret, opt);
- + return ret;
- +}
- +
- +template<typename T, int N>
- +void SetOptions(const T* src, void *opt, OptionMapper<T> (&options)[N]) {
- + for (int i = 0; i < N; ++i)
- + options[i].ToOpt(src, opt);
- +}
- +
- #endif
- diff -ru ffmpegsource/src/core/wave64writer.cpp ffms2/src/core/wave64writer.cpp
- --- ffmpegsource/src/core/wave64writer.cpp 2013-02-27 16:53:39.134029741 +0100
- +++ ffms2/src/core/wave64writer.cpp 2013-02-27 16:53:31.744380192 +0100
- @@ -106,7 +106,16 @@
- WavFile.seekp(CPos, std::ios::beg);
- }
- -void Wave64Writer::WriteData(void *Data, std::streamsize Length) {
- - WavFile.write(reinterpret_cast<char *>(Data), Length);
- +void Wave64Writer::WriteData(AVFrame const& Frame) {
- + uint64_t Length = Frame.nb_samples * BytesPerSample * Channels;
- + if (Channels > 1 && av_sample_fmt_is_planar(static_cast<AVSampleFormat>(Frame.format))) {
- + for (int32_t sample = 0; sample < Frame.nb_samples; ++sample) {
- + for (int32_t channel = 0; channel < Channels; ++channel)
- + WavFile.write(reinterpret_cast<char *>(&Frame.extended_data[channel][sample * BytesPerSample]), BytesPerSample);
- + }
- + }
- + else {
- + WavFile.write(reinterpret_cast<char *>(Frame.extended_data[0]), Length);
- + }
- BytesWritten += Length;
- }
- diff -ru /tmp/ffmpegsource/src/ffmpegsource/src/core/wave64writer.h ffms2/src/core/wave64writer.h
- --- /tmp/ffmpegsource/src/ffmpegsource/src/core/wave64writer.h 2013-02-27 16:53:39.127363391 +0100
- +++ ffms2/src/core/wave64writer.h 2013-02-27 16:53:31.744380192 +0100
- @@ -28,8 +28,8 @@
- class Wave64Writer {
- public:
- Wave64Writer(const char *Filename, uint16_t BitsPerSample, uint16_t Channels, uint32_t SamplesPerSec, bool IsFloat);
- ~Wave64Writer();
- - void WriteData(void *Data, std::streamsize Length);
- + void WriteData(AVFrame const& Frame);
- private:
- ffms_fstream WavFile;
- int32_t BytesPerSample;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement