Some refactoring of ffcpp code (replaced some stack allocated objects with smart pointers). Added project for player example.
This commit is contained in:
parent
9cf1dbd545
commit
94d70b6ce6
163
cmake/modules/FindSDL2.cmake
Normal file
163
cmake/modules/FindSDL2.cmake
Normal file
@ -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 <SDL2/SDL.h>. 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)
|
||||
@ -7,3 +7,13 @@ project(ffPreview)
|
||||
add_executable(ffPreview ffPreview.cpp)
|
||||
add_dependencies(ffPreview ffcpp)
|
||||
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})
|
||||
@ -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;
|
||||
|
||||
16
examples/ffPlayer.cpp
Normal file
16
examples/ffPlayer.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "ffcpp/Player.h"
|
||||
#include <memory>
|
||||
|
||||
namespace ff = ffcpp;
|
||||
|
||||
class SDLWindow: public ff::IVideoSink {
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
auto wnd = std::make_shared<SDLWindow>();
|
||||
ff::Player player(wnd);
|
||||
player.setMedia(argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -9,6 +9,8 @@ extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ffcpp {
|
||||
|
||||
enum class CodecType {
|
||||
@ -16,7 +18,9 @@ namespace ffcpp {
|
||||
Decoder
|
||||
};
|
||||
|
||||
class Codec: public non_copyable {
|
||||
typedef std::shared_ptr<class Codec> 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);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Stream.h"
|
||||
#include "Packet.h"
|
||||
#include <memory>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
@ -10,6 +11,7 @@ extern "C" {
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <bits/shared_ptr.h>
|
||||
|
||||
namespace ffcpp {
|
||||
|
||||
@ -22,7 +24,7 @@ namespace ffcpp {
|
||||
private:
|
||||
AVFormatContext* _formatCtx;
|
||||
Mode _mode;
|
||||
std::vector<Stream> _streams;
|
||||
std::vector<StreamPtr> _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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
30
include/ffcpp/Player.h
Normal file
30
include/ffcpp/Player.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef PROJECT_PLAYER_H
|
||||
#define PROJECT_PLAYER_H
|
||||
|
||||
#include "ffcpp/MediaFile.h"
|
||||
#include <memory>
|
||||
|
||||
namespace ffcpp {
|
||||
|
||||
struct IVideoSink {
|
||||
|
||||
};
|
||||
|
||||
class Player {
|
||||
private:
|
||||
std::shared_ptr<IVideoSink> _vSink;
|
||||
std::unique_ptr<MediaFile> _curMedia;
|
||||
StreamPtr _aStream;
|
||||
StreamPtr _vStream;
|
||||
|
||||
public:
|
||||
Player(std::shared_ptr<IVideoSink> vSink);
|
||||
~Player();
|
||||
|
||||
void setMedia(std::string path);
|
||||
void play();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //PROJECT_PLAYER_H
|
||||
@ -2,6 +2,7 @@
|
||||
#define FFCONV_RESAMPLER_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Codec.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libswresample/swresample.h>
|
||||
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#ifndef FFCONV_SCALER_H
|
||||
#define FFCONV_SCALER_H
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Codec.h"
|
||||
|
||||
extern "C" {
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -7,19 +7,23 @@ extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
}
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ffcpp {
|
||||
|
||||
typedef std::shared_ptr<class Stream> 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);
|
||||
|
||||
@ -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})
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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<Stream>(_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>(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>(stream, codec);
|
||||
_streams.emplace_back(sPtr);
|
||||
return sPtr;
|
||||
}
|
||||
|
||||
Packet MediaFile::readPacket() {
|
||||
|
||||
31
src/Player.cpp
Normal file
31
src/Player.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "ffcpp/Player.h"
|
||||
#include "ffcpp/Stream.h"
|
||||
|
||||
namespace ffcpp {
|
||||
|
||||
Player::Player(std::shared_ptr<IVideoSink> vSink): _vSink(vSink), _curMedia(nullptr), _aStream(nullptr), _vStream(
|
||||
nullptr) {
|
||||
init();
|
||||
}
|
||||
|
||||
Player::~Player() {
|
||||
|
||||
}
|
||||
|
||||
void Player::setMedia(std::string path) {
|
||||
_curMedia = std::make_unique<MediaFile>(path, Mode::Read);
|
||||
|
||||
_vStream = _curMedia->videoStream();
|
||||
_aStream = _curMedia->audioStream();
|
||||
|
||||
auto vDecoder = _vStream->codec();
|
||||
auto aDecoder = _aStream->codec();
|
||||
}
|
||||
|
||||
void Player::play() {
|
||||
if(!_curMedia)
|
||||
return;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<Codec>(_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<Codec>(_stream->codec, encoder);
|
||||
}
|
||||
|
||||
Stream::operator AVStream*() const {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
Codec& Stream::codec() {
|
||||
CodecPtr Stream::codec() {
|
||||
return _codec;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user