From 1bb9d908da63b22cc9c5ad848b99f57ab6be323b Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Wed, 2 Nov 2016 00:20:51 +0300 Subject: [PATCH] added scaling support --- CMakeLists.txt | 2 +- ffcpp/Frame.cpp | 27 ++++++++++++++++++++++++++- ffcpp/Frame.h | 3 +++ ffcpp/Scaler.cpp | 33 +++++++++++++++++++++++++++++++++ ffcpp/Scaler.h | 26 ++++++++++++++++++++++++++ main.cpp | 13 +++++++++++-- 6 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 ffcpp/Scaler.cpp create mode 100644 ffcpp/Scaler.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a0c8811..c98e874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,6 @@ link_directories(${FFMPEG_LIBRARY_DIRS}) #message(FATAL_ERROR ${FFMPEG_LIBRARIES}) -set(SOURCE_FILES main.cpp ffcpp/MediaFile.cpp ffcpp/MediaFile.h ffcpp/ffcpp.cpp ffcpp/ffcpp.h ffcpp/Stream.cpp ffcpp/Stream.h ffcpp/Codec.cpp ffcpp/Codec.h ffcpp/Packet.cpp ffcpp/Packet.h ffcpp/Frame.cpp ffcpp/Frame.h ffcpp/FifoQueue.cpp ffcpp/FifoQueue.h) +set(SOURCE_FILES main.cpp ffcpp/MediaFile.cpp ffcpp/MediaFile.h ffcpp/ffcpp.cpp ffcpp/ffcpp.h ffcpp/Stream.cpp ffcpp/Stream.h ffcpp/Codec.cpp ffcpp/Codec.h ffcpp/Packet.cpp ffcpp/Packet.h ffcpp/Frame.cpp ffcpp/Frame.h ffcpp/FifoQueue.cpp ffcpp/FifoQueue.h ffcpp/Scaler.cpp ffcpp/Scaler.h) add_executable(ffConv ${SOURCE_FILES}) target_link_libraries(ffConv ${FFMPEG_LIBRARIES}) \ No newline at end of file diff --git a/ffcpp/Frame.cpp b/ffcpp/Frame.cpp index 9e4b5d2..59e9405 100644 --- a/ffcpp/Frame.cpp +++ b/ffcpp/Frame.cpp @@ -4,7 +4,7 @@ namespace ffcpp { - Frame::Frame() { + Frame::Frame(): _buffer(nullptr) { _frame = av_frame_alloc(); } @@ -19,11 +19,34 @@ namespace ffcpp { throwIfError(res, "cannot initialize buffer in audio frame"); } + Frame::Frame(int width, int height, AVPixelFormat pixelFormat): Frame() { + + /* + _frame->width = width; + _frame->height = height; + _frame->format = pixelFormat; + + int res = av_frame_get_buffer(_frame, 0); + throwIfError(res, "cannot initialize buffer in video frame"); + */ + + _frame->width = width; + _frame->height = height; + _frame->format = pixelFormat; + int size = av_image_get_buffer_size(pixelFormat, width, height, 32); + _buffer = (uint8_t*)av_malloc(size*sizeof(uint8_t)); + int res = av_image_fill_arrays((uint8_t**)_frame->data, _frame->linesize, _buffer, pixelFormat, width, height, 32); + throwIfError(res, "cannot initialize video frame"); + } + Frame::Frame(Frame &&frame) { *this = std::move(frame); } Frame::~Frame() { + if(_buffer) { + av_free(_buffer); + } if(_frame) { av_frame_free(&_frame); } @@ -31,7 +54,9 @@ namespace ffcpp { Frame& Frame::operator=(Frame&& frame) { _frame = frame._frame; + _buffer = frame._buffer; frame._frame = nullptr; + frame._buffer = nullptr; return *this; } diff --git a/ffcpp/Frame.h b/ffcpp/Frame.h index 6dce306..354cc51 100644 --- a/ffcpp/Frame.h +++ b/ffcpp/Frame.h @@ -3,17 +3,20 @@ extern "C" { #include + #include } namespace ffcpp { class Frame { private: + uint8_t* _buffer; AVFrame* _frame; public: Frame(); Frame(int size, int channels, AVSampleFormat sampleFormat, int sampleRate); + Frame(int width, int height, AVPixelFormat pixelFormat); Frame(Frame&& frame); ~Frame(); diff --git a/ffcpp/Scaler.cpp b/ffcpp/Scaler.cpp new file mode 100644 index 0000000..e163faf --- /dev/null +++ b/ffcpp/Scaler.cpp @@ -0,0 +1,33 @@ +#include "Scaler.h" +#include + +namespace ffcpp { + + ffcpp::Scaler::Scaler(int srcWidth, int srcHeight, AVPixelFormat srcPixFmt, int dstWidth, int dstHeight, + AVPixelFormat dstPixFmt) { + _dstWidth = dstWidth; + _dstHeight = dstHeight; + _dstPixFmt = dstPixFmt; + _swsContext = sws_getContext(srcWidth, srcHeight, srcPixFmt, dstWidth, dstHeight, dstPixFmt, SWS_BICUBIC, + nullptr, nullptr, nullptr); + if(!_swsContext) { + throw new std::runtime_error("cannot create scale context"); + } + } + + Frame Scaler::scale(Frame &inFrame) { + Frame outFrame(_dstWidth, _dstHeight, _dstPixFmt); + + AVFrame* fin = inFrame; + AVFrame* fout = outFrame; + fout->pts = fin->pts; + + int res = sws_scale(_swsContext, (uint8_t const * const *)fin->data, fin->linesize, 0, fin->height, fout->data, fout->linesize); + if(res < 0) { + throw new std::runtime_error("scale error"); + } + + return outFrame; + } + +} diff --git a/ffcpp/Scaler.h b/ffcpp/Scaler.h new file mode 100644 index 0000000..e528497 --- /dev/null +++ b/ffcpp/Scaler.h @@ -0,0 +1,26 @@ +#ifndef FFCONV_SCALER_H +#define FFCONV_SCALER_H + +extern "C" { + #include +} + +#include "Frame.h" + +namespace ffcpp { + + class Scaler { + private: + SwsContext* _swsContext; + int _dstHeight; + int _dstWidth; + AVPixelFormat _dstPixFmt; + + public: + Scaler(int srcWidth, int srcHeight, AVPixelFormat srcPixFmt, int dstWidth, int dstHeight, AVPixelFormat dstPixFmt); + Frame scale(Frame& inFrame); + }; + +} + +#endif //FFCONV_SCALER_H diff --git a/main.cpp b/main.cpp index fc721bc..d6443f2 100644 --- a/main.cpp +++ b/main.cpp @@ -2,10 +2,14 @@ #include "ffcpp/ffcpp.h" #include "ffcpp/MediaFile.h" #include "ffcpp/FifoQueue.h" +#include "ffcpp/Scaler.h" constexpr int VIDEO_STREAM_INDEX = 0; constexpr int AUDIO_STREAM_INDEX = 1; +constexpr int VIDEO_WIDTH = 854; +constexpr int VIDEO_HEIGHT = 480; + namespace ff = ffcpp; void flushEncoder(ff::MediaFile& file, ff::Codec& encoder, const ff::Stream& inStream, const ff::Stream& outStream, int streamIndex) { @@ -32,7 +36,9 @@ int main(int argc, char** argv) { ff::Codec& vDecoder = vStream.codec(); ff::Codec& aDecoder = aStream.codec(); - ff::Stream& outVStream = output.addVideoStream(AV_CODEC_ID_H264, vDecoder.width(), vDecoder.height(), AV_PIX_FMT_YUV420P); + 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, AV_PIX_FMT_YUV420P); ff::Codec& vEncoder = outVStream.codec(); ff::Stream& outAStream = output.addAudioStream(AV_CODEC_ID_VORBIS, aDecoder.channels(), aDecoder.sampleRate()); @@ -49,9 +55,11 @@ int main(int argc, char** argv) { int64_t aPts = 0; ff::FifoQueue fifo(aEncoder.sampleFormat(), aEncoder.channels(), aEncoder.frameSize()); + ff::Scaler scaler(vDecoder.width(), vDecoder.height(), vDecoder.pixelFormat(), VIDEO_WIDTH, outHeight, AV_PIX_FMT_YUV420P); while(auto packet = input.readPacket()) { AVMediaType packetType = input.packetType(packet); if(packetType == AVMEDIA_TYPE_AUDIO) { + continue; auto frame = aDecoder.decode(packet); fifo.addSamples(frame); if(!fifo.enoughSamples()) continue; @@ -69,6 +77,7 @@ int main(int argc, char** argv) { } } else if(packetType == AVMEDIA_TYPE_VIDEO) { auto frame = vDecoder.decode(packet); + frame = scaler.scale(frame); frame.setPictureType(AV_PICTURE_TYPE_NONE); auto encPacket = vEncoder.encode(frame); if(!encPacket) continue; @@ -79,7 +88,7 @@ int main(int argc, char** argv) { } flushEncoder(output, vEncoder, vStream, outVStream, VIDEO_STREAM_INDEX); - flushEncoder(output, aEncoder, aStream, outAStream, AUDIO_STREAM_INDEX); + //flushEncoder(output, aEncoder, aStream, outAStream, AUDIO_STREAM_INDEX); output.writeTrailer(); return 0;