diff --git a/.clang-format b/.clang-format index 5953452..cffdd28 100644 --- a/.clang-format +++ b/.clang-format @@ -4,4 +4,6 @@ IndentWidth: 4 BreakBeforeBraces: Allman AllowShortIfStatementsOnASingleLine: false IndentCaseLabels: false -ColumnLimit: 99 \ No newline at end of file +ColumnLimit: 99 +IndentAccessModifiers: false +AccessModifierOffset: -4 diff --git a/video/decoderiocontext.cpp b/video/decoderiocontext.cpp new file mode 100644 index 0000000..470d740 --- /dev/null +++ b/video/decoderiocontext.cpp @@ -0,0 +1,106 @@ +#include "decoderiocontext.h" + +extern "C" +{ +#include +} + + +// static +int DecoderIOContext::IOReadFunc(void *data, uint8_t *buf, int buf_size) +{ + auto *hctx = static_cast(data); + auto len = hctx->stream->sgetn((char *)buf, buf_size); + if (len <= 0) + { + // Let FFmpeg know that we have reached EOF, or do something else + return AVERROR_EOF; + } + return static_cast(len); +} + +// whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZE +// static +int64_t DecoderIOContext::IOSeekFunc(void *data, int64_t pos, int whence) +{ + auto *hctx = static_cast(data); + + if (whence == AVSEEK_SIZE) + { + // return the file size if you wish to + auto current = hctx->stream->pubseekoff(0, std::ios_base::cur, std::ios_base::in); + auto result = hctx->stream->pubseekoff(0, std::ios_base::end, std::ios_base::in); + hctx->stream->pubseekoff(current, std::ios_base::beg, std::ios_base::in); + return result; + } + + std::ios_base::seekdir dir; + switch (whence) + { + case SEEK_SET: + dir = std::ios_base::beg; + break; + case SEEK_CUR: + dir = std::ios_base::cur; + break; + case SEEK_END: + dir = std::ios_base::end; + break; + default: + return -1LL; + } + + return hctx->stream->pubseekoff(pos, dir); +} + +DecoderIOContext::DecoderIOContext(std::unique_ptr s) + : stream(std::move(s)) +{ + // allocate buffer + bufferSize = 1024 * 64; // FIXME: not sure what size to use + buffer = static_cast(av_malloc(bufferSize)); // see destructor for details + + // allocate the AVIOContext + ioCtx = + avio_alloc_context(buffer, bufferSize, // internal buffer and its size + 0, // write flag (1=true,0=false) + (void *)this, // user data, will be passed to our callback functions + IOReadFunc, + nullptr, // no writing + IOSeekFunc); +} + +DecoderIOContext::~DecoderIOContext() +{ + //CHANNEL_LOG(ffmpeg_closing) << "In DecoderIOContext::~DecoderIOContext()"; + + // NOTE: ffmpeg messes up the buffer + // so free the buffer first then free the context + av_free(ioCtx->buffer); + ioCtx->buffer = nullptr; + av_free(ioCtx); +} + +void DecoderIOContext::initAVFormatContext(AVFormatContext *pCtx) +{ + pCtx->pb = ioCtx; + pCtx->flags |= AVFMT_FLAG_CUSTOM_IO; + + // you can specify a format directly + // pCtx->iformat = av_find_input_format("h264"); + + // or read some of the file and let ffmpeg do the guessing + auto len = stream->sgetn((char *)buffer, bufferSize); + if (len <= 0) + { + return; + } + // reset to beginning of file + stream->pubseekoff(0, std::ios_base::beg, std::ios_base::in); + + AVProbeData probeData = {nullptr}; + probeData.buf = buffer; + probeData.buf_size = bufferSize - 1; + probeData.filename = ""; + pCtx->iformat = av_probe_input_format(&probeData, 1); +} diff --git a/video/decoderiocontext.h b/video/decoderiocontext.h new file mode 100644 index 0000000..b29e91e --- /dev/null +++ b/video/decoderiocontext.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +struct AVIOContext; +struct AVFormatContext; + +class DecoderIOContext +{ +private: + AVIOContext *ioCtx; + uint8_t *buffer; // internal buffer for ffmpeg + int bufferSize; + std::unique_ptr stream; + +public: + DecoderIOContext(std::unique_ptr s); + ~DecoderIOContext(); + + void initAVFormatContext(AVFormatContext * /*pCtx*/); + + static int IOReadFunc(void *data, uint8_t *buf, int buf_size); + static int64_t IOSeekFunc(void *data, int64_t pos, int whence); +}; diff --git a/video/ffmpegdecoder.cpp b/video/ffmpegdecoder.cpp index 5787fd1..bff6c62 100644 --- a/video/ffmpegdecoder.cpp +++ b/video/ffmpegdecoder.cpp @@ -6,6 +6,7 @@ #include "makeguard.h" #include "interlockedadd.h" #include "subtitles.h" +#include "decoderiocontext.h" #include #include @@ -122,116 +123,6 @@ std::unique_ptr GetFrameDecoder(std::unique_ptr aud return std::unique_ptr(new FFmpegDecoder(std::move(audioPlayer))); } -// https://gist.github.com/xlphs/9895065 -class FFmpegDecoder::IOContext -{ -private: - AVIOContext *ioCtx; - uint8_t *buffer; // internal buffer for ffmpeg - int bufferSize; - std::unique_ptr stream; - -public: - IOContext(std::unique_ptr s); - ~IOContext(); - - void initAVFormatContext(AVFormatContext * /*pCtx*/); - - static int IOReadFunc(void *data, uint8_t *buf, int buf_size); - static int64_t IOSeekFunc(void *data, int64_t pos, int whence); -}; - -// static -int FFmpegDecoder::IOContext::IOReadFunc(void *data, uint8_t *buf, int buf_size) -{ - auto *hctx = static_cast(data); - auto len = hctx->stream->sgetn((char*)buf, buf_size); - if (len <= 0) - { - // Let FFmpeg know that we have reached EOF, or do something else - return AVERROR_EOF; - } - return static_cast(len); -} - -// whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZE -// static -int64_t FFmpegDecoder::IOContext::IOSeekFunc(void *data, int64_t pos, int whence) -{ - auto *hctx = static_cast(data); - - if (whence == AVSEEK_SIZE) - { - // return the file size if you wish to - auto current = hctx->stream->pubseekoff(0, std::ios_base::cur, std::ios_base::in); - auto result = hctx->stream->pubseekoff(0, std::ios_base::end, std::ios_base::in); - hctx->stream->pubseekoff(current, std::ios_base::beg, std::ios_base::in); - return result; - } - - std::ios_base::seekdir dir; - switch (whence) - { - case SEEK_SET: dir = std::ios_base::beg; break; - case SEEK_CUR: dir = std::ios_base::cur; break; - case SEEK_END: dir = std::ios_base::end; break; - default: return -1LL; - } - - return hctx->stream->pubseekoff(pos, dir); -} - -FFmpegDecoder::IOContext::IOContext(std::unique_ptr s) - : stream(std::move(s)) -{ - // allocate buffer - bufferSize = 1024 * 64; // FIXME: not sure what size to use - buffer = static_cast(av_malloc(bufferSize)); // see destructor for details - - // allocate the AVIOContext - ioCtx = - avio_alloc_context(buffer, bufferSize, // internal buffer and its size - 0, // write flag (1=true,0=false) - (void *)this, // user data, will be passed to our callback functions - IOReadFunc, - nullptr, // no writing - IOSeekFunc); -} - -FFmpegDecoder::IOContext::~IOContext() -{ - CHANNEL_LOG(ffmpeg_closing) << "In IOContext::~IOContext()"; - - // NOTE: ffmpeg messes up the buffer - // so free the buffer first then free the context - av_free(ioCtx->buffer); - ioCtx->buffer = nullptr; - av_free(ioCtx); -} - -void FFmpegDecoder::IOContext::initAVFormatContext(AVFormatContext *pCtx) -{ - pCtx->pb = ioCtx; - pCtx->flags |= AVFMT_FLAG_CUSTOM_IO; - - // you can specify a format directly - // pCtx->iformat = av_find_input_format("h264"); - - // or read some of the file and let ffmpeg do the guessing - auto len = stream->sgetn((char*)buffer, bufferSize); - if (len <= 0) { - return; - } - // reset to beginning of file - stream->pubseekoff(0, std::ios_base::beg, std::ios_base::in); - - AVProbeData probeData = { nullptr }; - probeData.buf = buffer; - probeData.buf_size = bufferSize - 1; - probeData.filename = ""; - pCtx->iformat = av_probe_input_format(&probeData, 1); -} - ////////////////////////////////////////////////////////////////////////////// FFmpegDecoder::FFmpegDecoder(std::unique_ptr audioPlayer) @@ -460,7 +351,7 @@ bool FFmpegDecoder::openStream(std::unique_ptr stream) { close(); - auto ioCtx = std::make_unique(std::move(stream)); + auto ioCtx = std::make_unique(std::move(stream)); auto formatContext = avformat_alloc_context(); diff --git a/video/ffmpegdecoder.h b/video/ffmpegdecoder.h index 761fcf6..da2bbc3 100644 --- a/video/ffmpegdecoder.h +++ b/video/ffmpegdecoder.h @@ -82,6 +82,9 @@ struct RendezVousData boost::condition_variable cond; }; +class DecoderIOContext; + + // Inspired by http://dranger.com/ffmpeg/ffmpeg.html class FFmpegDecoder final : public IFrameDecoder, public IAudioPlayerCallback @@ -147,7 +150,6 @@ class FFmpegDecoder final : public IFrameDecoder, public IAudioPlayerCallback void setImageConversionFunc(ImageConversionFunc func) override; private: - class IOContext; struct VideoParseContext; // Threads @@ -312,7 +314,7 @@ class FFmpegDecoder final : public IFrameDecoder, public IAudioPlayerCallback std::vector m_audioIndices; - std::unique_ptr m_ioCtx; + std::unique_ptr m_ioCtx; boost::atomic m_referenceTime; diff --git a/video/video.vcxproj b/video/video.vcxproj index 0017fbd..1c35732 100644 --- a/video/video.vcxproj +++ b/video/video.vcxproj @@ -136,6 +136,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/video/video.vcxproj.filters b/video/video.vcxproj.filters index 411f720..2f0681e 100644 --- a/video/video.vcxproj.filters +++ b/video/video.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + @@ -68,6 +71,9 @@ Header Files + + Header Files +