diff --git a/include/ffcpp/Codec.h b/include/ffcpp/Codec.h
index e5b1ef2..681ab7f 100644
--- a/include/ffcpp/Codec.h
+++ b/include/ffcpp/Codec.h
@@ -27,12 +27,14 @@ namespace ffcpp {
public:
Codec();
- Codec(AVCodecContext* ctx, CodecType type);
+ Codec(AVCodecID codecId, CodecType type, AVCodecParameters* params = nullptr);
Codec(AVCodecContext* ctx, AVCodec* codec);
~Codec();
operator AVCodecContext*() const;
+ const AVCodec* nativeCodecPtr() const;
+
int width() const;
int height() const;
AVRational timeBase() const;
@@ -47,6 +49,13 @@ namespace ffcpp {
void setWidth(int width);
void setHeight(int height);
void setPixelFormat(AVPixelFormat pixelFormat);
+ void setTimeBase(AVRational timeBase);
+ void setSampleFormat(AVSampleFormat sampleFormat);
+ void setGlobalQuality(int quality);
+ void setChannelCount(int channels);
+ void setChannelLayout(uint64_t layout);
+ void setSampleRate(int sampleRate);
+ void setStdCompliance(int compliance);
FramePtr decode(Packet& packet);
Packet encode(FramePtr frame);
diff --git a/include/ffcpp/Stream.h b/include/ffcpp/Stream.h
index ca14e53..8c838e1 100644
--- a/include/ffcpp/Stream.h
+++ b/include/ffcpp/Stream.h
@@ -21,7 +21,7 @@ namespace ffcpp {
public:
Stream();
Stream(AVStream* stream);
- Stream(AVStream* stream, AVCodec* encoder);
+ Stream(AVStream* stream, CodecPtr codec);
operator AVStream*() const;
CodecPtr codec();
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a04caa8..34c01af 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,8 +1,6 @@
project(ffcpp)
find_package(FFMPEG REQUIRED)
-# FIXME: FFMPEG_INCLUDE_DIR is incorrect and causes errors
-# http://stackoverflow.com/questions/35982639/ctime-std-namespace-conflict
include_directories(${FFMPEG_INCLUDE_DIR})
link_directories(${FFMPEG_LIBRARY_DIRS})
diff --git a/src/Codec.cpp b/src/Codec.cpp
index 6b5d2f1..1f3d2a1 100644
--- a/src/Codec.cpp
+++ b/src/Codec.cpp
@@ -8,18 +8,26 @@ namespace ffcpp {
}
- Codec::Codec(AVCodecContext *ctx, CodecType type): _codecCtx(ctx) {
- if(type == CodecType::Encoder) {
- _codec = avcodec_find_encoder(ctx->codec_id);
- } else {
- _codec = avcodec_find_decoder(ctx->codec_id);
- }
+ Codec::Codec(AVCodecID codecId, CodecType type, AVCodecParameters* params /* = nullptr */) {
+ if(type == CodecType::Encoder) {
+ _codec = avcodec_find_encoder(codecId);
+ } else {
+ _codec = avcodec_find_decoder(codecId);
+ }
- if(!_codec) throw std::runtime_error("cannot find codec");
+ if(!_codec) throw std::runtime_error("cannot find codec");
- int res = avcodec_open2(_codecCtx, _codec, nullptr);
- throwIfError(res, "cannot open codec");
- }
+ _codecCtx = avcodec_alloc_context3(_codec);
+ if(!_codecCtx) throw std::runtime_error("cannot allocate codec context");
+
+ if(params) {
+ int res = avcodec_parameters_to_context(_codecCtx, params);
+ if(res < 0) throwIfError(res, "cannot copy codec papameters from stream");
+ }
+
+ int res = avcodec_open2(_codecCtx, _codec, nullptr);
+ throwIfError(res, "cannot open codec");
+ }
Codec::Codec(AVCodecContext *ctx, AVCodec *codec) {
_codecCtx = ctx;
@@ -32,8 +40,13 @@ namespace ffcpp {
Codec::~Codec() {
if(_codecCtx) {
avcodec_close(_codecCtx);
- }
- }
+ }
+ }
+
+ const AVCodec *Codec::nativeCodecPtr() const
+ {
+ return _codec;
+ }
Codec::operator AVCodecContext*() const {
return _codecCtx;
@@ -88,9 +101,51 @@ namespace ffcpp {
}
void Codec::setPixelFormat(AVPixelFormat pixelFormat) {
- _codecCtx->pix_fmt = pixelFormat;
+ if(pixelFormat == AV_PIX_FMT_NONE) {
+ _codecCtx->pix_fmt = _codec->pix_fmts[0];
+ } else {
+ _codecCtx->pix_fmt = pixelFormat;
+ }
}
+ void Codec::setTimeBase(AVRational timeBase) {
+ _codecCtx->time_base = timeBase;
+ }
+
+ void Codec::setSampleFormat(AVSampleFormat sampleFormat)
+ {
+ if(sampleFormat == AV_SAMPLE_FMT_NONE) {
+ _codecCtx->sample_fmt = _codec->sample_fmts[0];
+ } else {
+ _codecCtx->sample_fmt = sampleFormat;
+ }
+ }
+
+ void Codec::setGlobalQuality(int quality)
+ {
+ _codecCtx->global_quality = quality;
+ }
+
+ void Codec::setChannelCount(int channels)
+ {
+ _codecCtx->channels = channels;
+ }
+
+ void Codec::setChannelLayout(uint64_t layout)
+ {
+ _codecCtx->channel_layout = layout;
+ }
+
+ void Codec::setSampleRate(int sampleRate)
+ {
+ _codecCtx->sample_rate = sampleRate;
+ }
+
+ void Codec::setStdCompliance(int compliance)
+ {
+ _codecCtx->strict_std_compliance = compliance;
+ }
+
Codec::Codec(Codec&& c) noexcept {
*this = std::move(c);
}
@@ -105,13 +160,18 @@ namespace ffcpp {
FramePtr Codec::decode(Packet &packet) {
FramePtr frame = std::make_shared();
- int gotPicture = 0;
- auto decFunc = (_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO ? avcodec_decode_video2 : avcodec_decode_audio4);
- while(!gotPicture) {
- int res = decFunc(_codecCtx, frame->nativePtr(), &gotPicture, packet);
- if(res < 0) throw std::runtime_error("cannot decode packet");
- }
+ int res = avcodec_send_packet(_codecCtx, packet);
+ if(res < 0) throw std::runtime_error("cannot decode packet");
+
+ while (res >= 0) {
+ res = avcodec_receive_frame(_codecCtx, frame->nativePtr());
+ if(res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
+ break;
+ } else if(res < 0) {
+ throw std::runtime_error("cannot decode packet");
+ }
+ }
if(_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO) {
frame->guessPts();
@@ -124,11 +184,18 @@ namespace ffcpp {
Packet Codec::encode(FramePtr frame) {
Packet packet;
- int gotPacket = 0;
- auto encFunc = (_codecCtx->codec_type == AVMEDIA_TYPE_VIDEO ? avcodec_encode_video2 : avcodec_encode_audio2);
- int res = encFunc(_codecCtx, packet, frame ? frame->nativePtr() : nullptr, &gotPacket);
- if(res < 0) throw std::runtime_error("cannot encode frame");
+ int res = avcodec_send_frame(_codecCtx, frame->nativePtr());
+ if(res < 0) throw std::runtime_error("cannot encode frame");
+
+ while (res >= 0) {
+ res = avcodec_receive_packet(_codecCtx, packet);
+ if(res == AVERROR(EAGAIN) || res == AVERROR_EOF) {
+ break;
+ } else if(res < 0) {
+ throw std::runtime_error("cannot encode frame");
+ }
+ }
return packet;
}
diff --git a/src/MediaFile.cpp b/src/MediaFile.cpp
index 7fe9737..9f00d6d 100644
--- a/src/MediaFile.cpp
+++ b/src/MediaFile.cpp
@@ -16,7 +16,7 @@ namespace ffcpp {
_streams.reserve(_formatCtx->nb_streams);
for(size_t i = 0; i < _formatCtx->nb_streams; ++i) {
- auto codecType = _formatCtx->streams[i]->codec->codec_type;
+ auto codecType = _formatCtx->streams[i]->codecpar->codec_type;
if(codecType != AVMEDIA_TYPE_VIDEO && codecType != AVMEDIA_TYPE_AUDIO)
continue;
@@ -45,7 +45,7 @@ namespace ffcpp {
bool MediaFile::hasStream(AVMediaType type) const {
for(size_t i = 0; i < _formatCtx->nb_streams; ++i) {
- if(_formatCtx->streams[i]->codec->codec_type == type) {
+ if(_formatCtx->streams[i]->codecpar->codec_type == type) {
return true;
}
}
@@ -63,7 +63,7 @@ namespace ffcpp {
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(_formatCtx->streams[i]->codecpar->codec_type == type) {
if(curIndex == index) {
return _streams[i];
} else {
@@ -98,22 +98,15 @@ namespace ffcpp {
}
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");
+ CodecPtr codec = std::make_shared(codecID, CodecType::Encoder);
- AVStream* stream = avformat_new_stream(_formatCtx, codec);
+ AVStream* stream = avformat_new_stream(_formatCtx, codec->nativeCodecPtr());
if(!stream) throw std::runtime_error("cannot create stream");
- AVCodecContext* ctx = stream->codec;
- ctx->width = width;
- ctx->height = height;
- ctx->time_base = timeBase;
-
- if(pixelFormat == AV_PIX_FMT_NONE) {
- ctx->pix_fmt = codec->pix_fmts[0];
- } else {
- ctx->pix_fmt = pixelFormat;
- }
+ codec->setWidth(width);
+ codec->setHeight(height);
+ codec->setTimeBase(timeBase);
+ codec->setPixelFormat(pixelFormat);
auto sPtr = std::make_shared(stream, codec);
_streams.emplace_back(sPtr);
@@ -121,24 +114,18 @@ namespace ffcpp {
}
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");
+ CodecPtr codec = std::make_shared(codecID, CodecType::Encoder);
- AVStream* stream = avformat_new_stream(_formatCtx, codec);
+ AVStream* stream = avformat_new_stream(_formatCtx, codec->nativeCodecPtr());
if(!stream) throw std::runtime_error("cannot create stream");
- AVCodecContext* ctx = stream->codec;
- if(sampleFormat == AV_SAMPLE_FMT_NONE) {
- ctx->sample_fmt = codec->sample_fmts[0];
- } else {
- ctx->sample_fmt = sampleFormat;
- }
- ctx->global_quality = 10;
- ctx->channels = channels;
- ctx->channel_layout = (uint64_t)av_get_default_channel_layout(channels);
- ctx->sample_rate = sampleRate;
- ctx->time_base = AVRational {1, sampleRate};
- ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
+ codec->setSampleFormat(sampleFormat);
+ codec->setGlobalQuality(10);
+ codec->setChannelCount(channels);
+ codec->setChannelLayout(av_get_default_channel_layout(channels));
+ codec->setSampleRate(sampleRate);
+ codec->setTimeBase(AVRational {1, sampleRate});
+ codec->setStdCompliance(FF_COMPLIANCE_EXPERIMENTAL);
auto sPtr = std::make_shared(stream, codec);
_streams.emplace_back(sPtr);
@@ -154,7 +141,7 @@ namespace ffcpp {
}
AVMediaType MediaFile::packetType(const Packet &packet) {
- return _formatCtx->streams[packet.streamIndex()]->codec->codec_type;
+ return _formatCtx->streams[packet.streamIndex()]->codecpar->codec_type;
}
void MediaFile::writeHeader() {
diff --git a/src/Stream.cpp b/src/Stream.cpp
index 057d140..7e1abf0 100644
--- a/src/Stream.cpp
+++ b/src/Stream.cpp
@@ -7,11 +7,10 @@ namespace ffcpp {
}
Stream::Stream(AVStream *stream): _stream(stream) {
- _codec = std::make_shared(_stream->codec, CodecType::Decoder);
+ _codec = std::make_shared(_stream->codecpar->codec_id, CodecType::Decoder);
}
- Stream::Stream(AVStream *stream, AVCodec* encoder): _stream(stream) {
- _codec = std::make_shared(_stream->codec, encoder);
+ Stream::Stream(AVStream *stream, CodecPtr codec): _stream(stream), _codec(codec) {
}
Stream::operator AVStream*() const {