diff --git a/cmake/modules/FindSDL2.cmake b/cmake/modules/FindSDL2.cmake new file mode 100644 index 0000000..8e0858d --- /dev/null +++ b/cmake/modules/FindSDL2.cmake @@ -0,0 +1,163 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDLmain.h and SDLmain.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +SET(SDL2_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt + ) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES include/SDL2 include + PATHS ${SDL2_SEARCH_PATHS} + ) + +FIND_LIBRARY(SDL2_LIBRARY_TEMP + NAMES SDL2 + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS ${SDL2_SEARCH_PATHS} + ) + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS ${SDL2_SEARCH_PATHS} + ) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +IF(SDL2_LIBRARY_TEMP) + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8c9d2ff..f9a1253 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -6,4 +6,14 @@ target_link_libraries(ffConv ffcpp) project(ffPreview) add_executable(ffPreview ffPreview.cpp) add_dependencies(ffPreview ffcpp) -target_link_libraries(ffPreview ffcpp) \ No newline at end of file +target_link_libraries(ffPreview ffcpp) + +project(ffPlayer) +find_package(SDL2 REQUIRED) +if(NOT SDL2_FOUND) + message(FATAL_ERROR "SDL2 not found") +endif() +include_directories(${SDL2_INCLUDE_DIR}) +add_executable(ffPlayer ffPlayer.cpp) +add_dependencies(ffPlayer ffcpp) +target_link_libraries(ffPlayer ffcpp ${SDL2_LIBRARY}) \ No newline at end of file diff --git a/examples/ffConv.cpp b/examples/ffConv.cpp index 4724487..5e5eada 100644 --- a/examples/ffConv.cpp +++ b/examples/ffConv.cpp @@ -13,11 +13,11 @@ constexpr int VIDEO_HEIGHT = 480; namespace ff = ffcpp; -void flushEncoder(ff::MediaFile& file, ff::Codec& encoder, const ff::Stream& inStream, const ff::Stream& outStream, +void flushEncoder(ff::MediaFile& file, ff::CodecPtr encoder, ff::StreamPtr inStream, const ff::StreamPtr outStream, int streamIndex, AVRational srcTimeBase, AVRational dstTimeBase) { - if(encoder.capabilities() & AV_CODEC_CAP_DELAY) { + if(encoder->capabilities() & AV_CODEC_CAP_DELAY) { while (1) { - auto packet = encoder.encode(nullptr); + auto packet = encoder->encode(nullptr); if(!packet) break; packet.setStreamIndex(streamIndex); @@ -32,24 +32,24 @@ int main(int argc, char** argv) { ff::MediaFile input(argv[1], ff::Mode::Read); ff::MediaFile output(argv[2], ff::Mode::Write); - ff::Stream& vStream = input.videoStream(); - ff::Stream& aStream = input.audioStream(); + auto vStream = input.videoStream(); + auto aStream = input.audioStream(); - ff::Codec& vDecoder = vStream.codec(); - ff::Codec& aDecoder = aStream.codec(); + auto vDecoder = vStream->codec(); + auto aDecoder = aStream->codec(); - double aspect = 1.0*vDecoder.width()/vDecoder.height(); + double aspect = 1.0*vDecoder->width()/vDecoder->height(); int outHeight = (int)(VIDEO_WIDTH/aspect) & ~1; - ff::Stream& outVStream = output.addVideoStream(AV_CODEC_ID_H264, VIDEO_WIDTH, outHeight, vDecoder.timeBase(), AV_PIX_FMT_YUV420P); - ff::Codec& vEncoder = outVStream.codec(); + auto outVStream = output.addVideoStream(AV_CODEC_ID_H264, VIDEO_WIDTH, outHeight, vDecoder->timeBase(), AV_PIX_FMT_YUV420P); + auto vEncoder = outVStream->codec(); - ff::Stream& outAStream = output.addAudioStream(AV_CODEC_ID_VORBIS, 2, 44100, AV_SAMPLE_FMT_FLTP); - ff::Codec& aEncoder = outAStream.codec(); + auto outAStream = output.addAudioStream(AV_CODEC_ID_VORBIS, 2, 44100, AV_SAMPLE_FMT_FLTP); + auto aEncoder = outAStream->codec(); output.writeHeader(); int64_t aPts = 0; - ff::FifoQueue fifo(aEncoder.sampleFormat(), aEncoder.channels(), aEncoder.frameSize()); + ff::FifoQueue fifo(aEncoder->sampleFormat(), aEncoder->channels(), aEncoder->frameSize()); ff::Scaler scaler(vDecoder, vEncoder); ff::Resampler resampler(aDecoder, aEncoder); bool needScaling = ff::Scaler::needScaling(vDecoder, vEncoder); @@ -57,38 +57,38 @@ int main(int argc, char** argv) { while(auto packet = input.readPacket()) { AVMediaType packetType = input.packetType(packet); if(packetType == AVMEDIA_TYPE_AUDIO) { - auto frame = aDecoder.decode(packet); + auto frame = aDecoder->decode(packet); if(needResampling) frame = resampler.resample(frame); fifo.addSamples(frame); // FIXME: we're losing last samples in case when fifo queue isn't full enough for encoder while(fifo.enoughSamples()) { - auto frame = aEncoder.createAudioFrame(); + auto frame = aEncoder->createAudioFrame(); fifo.readFrame(frame); frame.setPts(aPts); aPts += frame.samplesCount(); - auto encPacket = aEncoder.encode(frame); + auto encPacket = aEncoder->encode(frame); if(!encPacket) continue; encPacket.setStreamIndex(AUDIO_STREAM_INDEX); - encPacket.rescaleTimestamps(aEncoder.timeBase(), outAStream.timeBase()); + encPacket.rescaleTimestamps(aEncoder->timeBase(), outAStream->timeBase()); output.writePacket(encPacket); } } else if(packetType == AVMEDIA_TYPE_VIDEO) { - auto frame = vDecoder.decode(packet); + auto frame = vDecoder->decode(packet); if(needScaling) frame = scaler.scale(frame); frame.setPictureType(AV_PICTURE_TYPE_NONE); - auto encPacket = vEncoder.encode(frame); + auto encPacket = vEncoder->encode(frame); if(!encPacket) continue; encPacket.setStreamIndex(VIDEO_STREAM_INDEX); - encPacket.rescaleTimestamps(vStream.timeBase(), outVStream.timeBase()); + encPacket.rescaleTimestamps(vStream->timeBase(), outVStream->timeBase()); output.writePacket(encPacket); } } - flushEncoder(output, vEncoder, vStream, outVStream, VIDEO_STREAM_INDEX, vStream.timeBase(), outVStream.timeBase()); - flushEncoder(output, aEncoder, aStream, outAStream, AUDIO_STREAM_INDEX, aEncoder.timeBase(), outAStream.timeBase()); + flushEncoder(output, vEncoder, vStream, outVStream, VIDEO_STREAM_INDEX, vStream->timeBase(), outVStream->timeBase()); + flushEncoder(output, aEncoder, aStream, outAStream, AUDIO_STREAM_INDEX, aEncoder->timeBase(), outAStream->timeBase()); output.writeTrailer(); return 0; diff --git a/examples/ffPlayer.cpp b/examples/ffPlayer.cpp new file mode 100644 index 0000000..ec1f70f --- /dev/null +++ b/examples/ffPlayer.cpp @@ -0,0 +1,16 @@ +#include "ffcpp/Player.h" +#include + +namespace ff = ffcpp; + +class SDLWindow: public ff::IVideoSink { + +}; + +int main(int argc, char** argv) { + auto wnd = std::make_shared(); + ff::Player player(wnd); + player.setMedia(argv[1]); + + return 0; +} \ No newline at end of file diff --git a/examples/ffPreview.cpp b/examples/ffPreview.cpp index 6438481..030b18d 100644 --- a/examples/ffPreview.cpp +++ b/examples/ffPreview.cpp @@ -11,11 +11,11 @@ int main(int argc, char** argv) { ff::MediaFile input(argv[1], ff::Mode::Read); ff::MediaFile output(argv[2], ff::Mode::Write); - ff::Stream& vStream = input.videoStream(); - ff::Codec& vDecoder = vStream.codec(); + auto vStream = input.videoStream(); + auto vDecoder = vStream->codec(); - ff::Stream& outVStream = output.addVideoStream(AV_CODEC_ID_PNG, vDecoder.width(), vDecoder.height(), vStream.timeBase(), AV_PIX_FMT_RGB24); - ff::Codec& vEncoder = outVStream.codec(); + auto outVStream = output.addVideoStream(AV_CODEC_ID_PNG, vDecoder->width(), vDecoder->height(), vStream->timeBase(), AV_PIX_FMT_RGB24); + auto vEncoder = outVStream->codec(); output.writeHeader(); @@ -24,15 +24,15 @@ int main(int argc, char** argv) { while(auto packet = input.readPacket()) { AVMediaType packetType = input.packetType(packet); if(packetType == AVMEDIA_TYPE_VIDEO) { - auto frame = vDecoder.decode(packet); + auto frame = vDecoder->decode(packet); if(frame.isKeyFrame() && (frame.pts() > 0 || KEY_FRAME_TO_SAVE == 0)) { if(curKeyFrame == KEY_FRAME_TO_SAVE) { frame = scaler.scale(frame); frame.setPictureType(AV_PICTURE_TYPE_NONE); - auto encPacket = vEncoder.encode(frame); + auto encPacket = vEncoder->encode(frame); if(!encPacket) continue; encPacket.setStreamIndex(0); - encPacket.rescaleTimestamps(vStream.timeBase(), outVStream.timeBase()); + encPacket.rescaleTimestamps(vStream->timeBase(), outVStream->timeBase()); output.writePacket(encPacket); break; } else { diff --git a/include/ffcpp/Codec.h b/include/ffcpp/Codec.h index ca29030..ea0a0c2 100644 --- a/include/ffcpp/Codec.h +++ b/include/ffcpp/Codec.h @@ -9,6 +9,8 @@ extern "C" { #include } +#include + namespace ffcpp { enum class CodecType { @@ -16,7 +18,9 @@ namespace ffcpp { Decoder }; - class Codec: public non_copyable { + typedef std::shared_ptr CodecPtr; + + class Codec { private: AVCodec* _codec; AVCodecContext* _codecCtx; @@ -38,6 +42,7 @@ namespace ffcpp { int frameSize() const; int channels() const; int sampleRate() const; + int channelLayout() const; void setWidth(int width); void setHeight(int height); diff --git a/include/ffcpp/MediaFile.h b/include/ffcpp/MediaFile.h index e71b3e9..33e0266 100644 --- a/include/ffcpp/MediaFile.h +++ b/include/ffcpp/MediaFile.h @@ -3,6 +3,7 @@ #include "Stream.h" #include "Packet.h" +#include extern "C" { #include @@ -10,6 +11,7 @@ extern "C" { #include #include +#include namespace ffcpp { @@ -22,7 +24,7 @@ namespace ffcpp { private: AVFormatContext* _formatCtx; Mode _mode; - std::vector _streams; + std::vector _streams; public: MediaFile(const std::string& src, Mode mode); @@ -31,10 +33,10 @@ namespace ffcpp { bool hasVideo() const; bool hasAudio() const; - Stream& videoStream(size_t index = 0); - Stream& audioStream(size_t index = 0); - Stream& addVideoStream(AVCodecID codecID, int width, int height, AVRational timeBase, AVPixelFormat pixelFormat = AV_PIX_FMT_NONE); - Stream& addAudioStream(AVCodecID codecID, int channels, int sampleRate, AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE); + StreamPtr videoStream(size_t index = 0); + StreamPtr audioStream(size_t index = 0); + StreamPtr addVideoStream(AVCodecID codecID, int width, int height, AVRational timeBase, AVPixelFormat pixelFormat = AV_PIX_FMT_NONE); + StreamPtr addAudioStream(AVCodecID codecID, int channels, int sampleRate, AVSampleFormat sampleFormat = AV_SAMPLE_FMT_NONE); Packet readPacket(); AVMediaType packetType(const Packet& packet); @@ -46,7 +48,7 @@ namespace ffcpp { private: bool hasStream(AVMediaType type) const; - Stream& getStream(AVMediaType type, size_t index); + StreamPtr getStream(AVMediaType type, size_t index); }; } diff --git a/include/ffcpp/Player.h b/include/ffcpp/Player.h new file mode 100644 index 0000000..07e6514 --- /dev/null +++ b/include/ffcpp/Player.h @@ -0,0 +1,30 @@ +#ifndef PROJECT_PLAYER_H +#define PROJECT_PLAYER_H + +#include "ffcpp/MediaFile.h" +#include + +namespace ffcpp { + + struct IVideoSink { + + }; + + class Player { + private: + std::shared_ptr _vSink; + std::unique_ptr _curMedia; + StreamPtr _aStream; + StreamPtr _vStream; + + public: + Player(std::shared_ptr vSink); + ~Player(); + + void setMedia(std::string path); + void play(); + }; + +} + +#endif //PROJECT_PLAYER_H diff --git a/include/ffcpp/Resampler.h b/include/ffcpp/Resampler.h index 186d36c..0444d4d 100644 --- a/include/ffcpp/Resampler.h +++ b/include/ffcpp/Resampler.h @@ -2,6 +2,7 @@ #define FFCONV_RESAMPLER_H #include "Frame.h" +#include "Codec.h" extern "C" { #include @@ -19,11 +20,11 @@ namespace ffcpp { public: Resampler(int inChannelLayout, int inSampleRate, AVSampleFormat inSampleFormat, int outChannelLayout, int outSampleRate, AVSampleFormat outSampleFormat); - Resampler(AVCodecContext* decoderCtx, AVCodecContext* encoderCtx); + Resampler(CodecPtr decoder, CodecPtr encoder); ~Resampler(); Frame resample(Frame& inFrame); - static bool needResampling(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx); + static bool needResampling(CodecPtr decoder, CodecPtr encoder); }; } diff --git a/include/ffcpp/Scaler.h b/include/ffcpp/Scaler.h index e7f0569..b9ac918 100644 --- a/include/ffcpp/Scaler.h +++ b/include/ffcpp/Scaler.h @@ -1,12 +1,13 @@ #ifndef FFCONV_SCALER_H #define FFCONV_SCALER_H +#include "Frame.h" +#include "Codec.h" + extern "C" { #include } -#include "Frame.h" - namespace ffcpp { class Scaler { @@ -18,9 +19,9 @@ namespace ffcpp { public: Scaler(int srcWidth, int srcHeight, AVPixelFormat srcPixFmt, int dstWidth, int dstHeight, AVPixelFormat dstPixFmt); - Scaler(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx); + Scaler(CodecPtr decoder, CodecPtr encoder); Frame scale(Frame& inFrame); - static bool needScaling(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx); + static bool needScaling(CodecPtr decoder, CodecPtr encoder); }; } diff --git a/include/ffcpp/Stream.h b/include/ffcpp/Stream.h index fd94c62..eadb80d 100644 --- a/include/ffcpp/Stream.h +++ b/include/ffcpp/Stream.h @@ -7,19 +7,23 @@ extern "C" { #include } +#include + namespace ffcpp { + typedef std::shared_ptr StreamPtr; + class Stream { private: AVStream* _stream; - Codec _codec; + CodecPtr _codec; public: Stream(); Stream(AVStream* stream); Stream(AVStream* stream, AVCodec* encoder); operator AVStream*() const; - Codec& codec(); + CodecPtr codec(); AVRational timeBase() const; void setTimeBase(AVRational timeBase); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8d4415..1fc7910 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,7 +25,9 @@ set(SOURCE_FILES MediaFile.cpp Scaler.cpp ../include/ffcpp/Scaler.h Resampler.cpp - ../include/ffcpp/Resampler.h) + ../include/ffcpp/Resampler.h + Player.cpp + ../include/ffcpp/Player.h ) add_library(ffcpp ${SOURCE_FILES}) target_link_libraries(ffcpp ${FFMPEG_LIBRARIES}) diff --git a/src/Codec.cpp b/src/Codec.cpp index 06f6429..cf3680d 100644 --- a/src/Codec.cpp +++ b/src/Codec.cpp @@ -75,6 +75,10 @@ namespace ffcpp { return _codecCtx->sample_rate; } + int Codec::channelLayout() const { + return (int)_codecCtx->channel_layout; + } + void Codec::setWidth(int width) { _codecCtx->width = width; } diff --git a/src/MediaFile.cpp b/src/MediaFile.cpp index a2cd172..eed4bff 100644 --- a/src/MediaFile.cpp +++ b/src/MediaFile.cpp @@ -16,7 +16,8 @@ namespace ffcpp { _streams.reserve(_formatCtx->nb_streams); for(size_t i = 0; i < _formatCtx->nb_streams; ++i) { - _streams.emplace_back(_formatCtx->streams[i]); + auto stream = std::make_shared(_formatCtx->streams[i]); + _streams.emplace_back(stream); } } else if(mode == Mode::Write) { int res = avformat_alloc_output_context2(&_formatCtx, nullptr, nullptr, src.c_str()); @@ -56,7 +57,7 @@ namespace ffcpp { return hasStream(AVMEDIA_TYPE_AUDIO); } - Stream& MediaFile::getStream(AVMediaType type, size_t index) { + StreamPtr MediaFile::getStream(AVMediaType type, size_t index) { for(size_t i = 0, curIndex = 0; i < _formatCtx->nb_streams; ++i) { if(_formatCtx->streams[i]->codec->codec_type == type) { if(curIndex == index) { @@ -70,11 +71,11 @@ namespace ffcpp { throw std::runtime_error("cannot find stream"); } - Stream& MediaFile::videoStream(size_t index /* = 0 */) { + StreamPtr MediaFile::videoStream(size_t index /* = 0 */) { return getStream(AVMEDIA_TYPE_VIDEO, index); } - Stream& MediaFile::audioStream(size_t index /* = 0 */) { + StreamPtr MediaFile::audioStream(size_t index /* = 0 */) { return getStream(AVMEDIA_TYPE_AUDIO, index); } @@ -92,7 +93,7 @@ namespace ffcpp { } } - Stream& MediaFile::addVideoStream(AVCodecID codecID, int width, int height, AVRational timeBase, AVPixelFormat pixelFormat) { + StreamPtr MediaFile::addVideoStream(AVCodecID codecID, int width, int height, AVRational timeBase, AVPixelFormat pixelFormat) { AVCodec* codec = avcodec_find_encoder(codecID); if(!codec) throw std::runtime_error("cannot find codec"); @@ -110,18 +111,18 @@ namespace ffcpp { ctx->pix_fmt = pixelFormat; } - _streams.emplace_back(stream, codec); - return _streams.back(); + auto sPtr = std::make_shared(stream, codec); + _streams.emplace_back(sPtr); + return sPtr; } - Stream& MediaFile::addAudioStream(AVCodecID codecID, int channels, int sampleRate, AVSampleFormat sampleFormat) { + StreamPtr MediaFile::addAudioStream(AVCodecID codecID, int channels, int sampleRate, AVSampleFormat sampleFormat) { AVCodec* codec = avcodec_find_encoder(codecID); if(!codec) throw std::runtime_error("cannot find codec"); AVStream* stream = avformat_new_stream(_formatCtx, codec); if(!stream) throw std::runtime_error("cannot create stream"); - // TODO: Here we need adjust encoder parameters AVCodecContext* ctx = stream->codec; if(sampleFormat == AV_SAMPLE_FMT_NONE) { ctx->sample_fmt = codec->sample_fmts[0]; @@ -135,8 +136,9 @@ namespace ffcpp { ctx->time_base = AVRational {1, sampleRate}; ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; - _streams.emplace_back(stream, codec); - return _streams.back(); + auto sPtr = std::make_shared(stream, codec); + _streams.emplace_back(sPtr); + return sPtr; } Packet MediaFile::readPacket() { diff --git a/src/Player.cpp b/src/Player.cpp new file mode 100644 index 0000000..c6b28c6 --- /dev/null +++ b/src/Player.cpp @@ -0,0 +1,31 @@ +#include "ffcpp/Player.h" +#include "ffcpp/Stream.h" + +namespace ffcpp { + + Player::Player(std::shared_ptr vSink): _vSink(vSink), _curMedia(nullptr), _aStream(nullptr), _vStream( + nullptr) { + init(); + } + + Player::~Player() { + + } + + void Player::setMedia(std::string path) { + _curMedia = std::make_unique(path, Mode::Read); + + _vStream = _curMedia->videoStream(); + _aStream = _curMedia->audioStream(); + + auto vDecoder = _vStream->codec(); + auto aDecoder = _aStream->codec(); + } + + void Player::play() { + if(!_curMedia) + return; + + + } +} \ No newline at end of file diff --git a/src/Resampler.cpp b/src/Resampler.cpp index f5f35a1..88f80cf 100644 --- a/src/Resampler.cpp +++ b/src/Resampler.cpp @@ -32,9 +32,9 @@ namespace ffcpp { throwIfError(res, "cannot init resampler"); } - Resampler::Resampler(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx) - : Resampler((int)decoderCtx->channel_layout, decoderCtx->sample_rate, decoderCtx->sample_fmt, - (int)encoderCtx->channel_layout, encoderCtx->sample_rate, encoderCtx->sample_fmt) { + Resampler::Resampler(CodecPtr decoder, CodecPtr encoder) + : Resampler(decoder->channelLayout(), decoder->sampleRate(), decoder->sampleFormat(), + encoder->channelLayout(), encoder->sampleRate(), encoder->sampleFormat()) { } Resampler::~Resampler() { @@ -55,11 +55,11 @@ namespace ffcpp { return outFrame; } - bool Resampler::needResampling(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx) { - return (decoderCtx->channels != encoderCtx->channels || - decoderCtx->channel_layout != encoderCtx->channel_layout || - decoderCtx->sample_fmt != encoderCtx->sample_fmt || - decoderCtx->sample_rate != encoderCtx->sample_rate); + bool Resampler::needResampling(CodecPtr decoder, CodecPtr encoder) { + return (decoder->channels() != encoder->channels() || + decoder->channelLayout() != encoder->channelLayout() || + decoder->sampleFormat() != encoder->sampleFormat() || + decoder->sampleRate() != encoder->sampleRate()); } } diff --git a/src/Scaler.cpp b/src/Scaler.cpp index b11c360..f2d3b0c 100644 --- a/src/Scaler.cpp +++ b/src/Scaler.cpp @@ -15,9 +15,9 @@ namespace ffcpp { } } - Scaler::Scaler(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx) - : Scaler(decoderCtx->width, decoderCtx->height, decoderCtx->pix_fmt, - encoderCtx->width, encoderCtx->height, encoderCtx->pix_fmt) { + Scaler::Scaler(CodecPtr decoder, CodecPtr encoder) + : Scaler(decoder->width(), decoder->height(), decoder->pixelFormat(), + encoder->width(), encoder->height(), encoder->pixelFormat()) { } @@ -36,10 +36,10 @@ namespace ffcpp { return outFrame; } - bool Scaler::needScaling(AVCodecContext *decoderCtx, AVCodecContext *encoderCtx) { - return (decoderCtx->width != encoderCtx->width || - decoderCtx->height != encoderCtx->height || - decoderCtx->pix_fmt != encoderCtx->pix_fmt); + bool Scaler::needScaling(CodecPtr decoder, CodecPtr encoder) { + return (decoder->width() != encoder->width() || + decoder->height() != encoder->height() || + decoder->pixelFormat() != encoder->pixelFormat()); } } diff --git a/src/Stream.cpp b/src/Stream.cpp index 20699e0..734c856 100644 --- a/src/Stream.cpp +++ b/src/Stream.cpp @@ -6,19 +6,19 @@ namespace ffcpp { Stream::Stream(): _stream(nullptr) { } - Stream::Stream(AVStream *stream): _stream(stream), _codec(_stream->codec, CodecType::Decoder) { - + Stream::Stream(AVStream *stream): _stream(stream) { + _codec = std::make_shared(_stream->codec, CodecType::Decoder); } - Stream::Stream(AVStream *stream, AVCodec* encoder): _stream(stream), _codec(stream->codec, encoder) { - + Stream::Stream(AVStream *stream, AVCodec* encoder): _stream(stream) { + _codec = std::make_shared(_stream->codec, encoder); } Stream::operator AVStream*() const { return _stream; } - Codec& Stream::codec() { + CodecPtr Stream::codec() { return _codec; }