added scaling support

This commit is contained in:
Selim Mustafaev 2016-11-02 00:20:51 +03:00
parent a9e042eb4f
commit 1bb9d908da
6 changed files with 100 additions and 4 deletions

View File

@ -11,6 +11,6 @@ link_directories(${FFMPEG_LIBRARY_DIRS})
#message(FATAL_ERROR ${FFMPEG_LIBRARIES}) #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}) add_executable(ffConv ${SOURCE_FILES})
target_link_libraries(ffConv ${FFMPEG_LIBRARIES}) target_link_libraries(ffConv ${FFMPEG_LIBRARIES})

View File

@ -4,7 +4,7 @@
namespace ffcpp { namespace ffcpp {
Frame::Frame() { Frame::Frame(): _buffer(nullptr) {
_frame = av_frame_alloc(); _frame = av_frame_alloc();
} }
@ -19,11 +19,34 @@ namespace ffcpp {
throwIfError(res, "cannot initialize buffer in audio frame"); 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) { Frame::Frame(Frame &&frame) {
*this = std::move(frame); *this = std::move(frame);
} }
Frame::~Frame() { Frame::~Frame() {
if(_buffer) {
av_free(_buffer);
}
if(_frame) { if(_frame) {
av_frame_free(&_frame); av_frame_free(&_frame);
} }
@ -31,7 +54,9 @@ namespace ffcpp {
Frame& Frame::operator=(Frame&& frame) { Frame& Frame::operator=(Frame&& frame) {
_frame = frame._frame; _frame = frame._frame;
_buffer = frame._buffer;
frame._frame = nullptr; frame._frame = nullptr;
frame._buffer = nullptr;
return *this; return *this;
} }

View File

@ -3,17 +3,20 @@
extern "C" { extern "C" {
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
} }
namespace ffcpp { namespace ffcpp {
class Frame { class Frame {
private: private:
uint8_t* _buffer;
AVFrame* _frame; AVFrame* _frame;
public: public:
Frame(); Frame();
Frame(int size, int channels, AVSampleFormat sampleFormat, int sampleRate); Frame(int size, int channels, AVSampleFormat sampleFormat, int sampleRate);
Frame(int width, int height, AVPixelFormat pixelFormat);
Frame(Frame&& frame); Frame(Frame&& frame);
~Frame(); ~Frame();

33
ffcpp/Scaler.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "Scaler.h"
#include <stdexcept>
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;
}
}

26
ffcpp/Scaler.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef FFCONV_SCALER_H
#define FFCONV_SCALER_H
extern "C" {
#include <libswscale/swscale.h>
}
#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

View File

@ -2,10 +2,14 @@
#include "ffcpp/ffcpp.h" #include "ffcpp/ffcpp.h"
#include "ffcpp/MediaFile.h" #include "ffcpp/MediaFile.h"
#include "ffcpp/FifoQueue.h" #include "ffcpp/FifoQueue.h"
#include "ffcpp/Scaler.h"
constexpr int VIDEO_STREAM_INDEX = 0; constexpr int VIDEO_STREAM_INDEX = 0;
constexpr int AUDIO_STREAM_INDEX = 1; constexpr int AUDIO_STREAM_INDEX = 1;
constexpr int VIDEO_WIDTH = 854;
constexpr int VIDEO_HEIGHT = 480;
namespace ff = ffcpp; namespace ff = ffcpp;
void flushEncoder(ff::MediaFile& file, ff::Codec& encoder, const ff::Stream& inStream, const ff::Stream& outStream, int streamIndex) { 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& vDecoder = vStream.codec();
ff::Codec& aDecoder = aStream.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::Codec& vEncoder = outVStream.codec();
ff::Stream& outAStream = output.addAudioStream(AV_CODEC_ID_VORBIS, aDecoder.channels(), aDecoder.sampleRate()); 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; 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.width(), vDecoder.height(), vDecoder.pixelFormat(), VIDEO_WIDTH, outHeight, AV_PIX_FMT_YUV420P);
while(auto packet = input.readPacket()) { while(auto packet = input.readPacket()) {
AVMediaType packetType = input.packetType(packet); AVMediaType packetType = input.packetType(packet);
if(packetType == AVMEDIA_TYPE_AUDIO) { if(packetType == AVMEDIA_TYPE_AUDIO) {
continue;
auto frame = aDecoder.decode(packet); auto frame = aDecoder.decode(packet);
fifo.addSamples(frame); fifo.addSamples(frame);
if(!fifo.enoughSamples()) continue; if(!fifo.enoughSamples()) continue;
@ -69,6 +77,7 @@ int main(int argc, char** argv) {
} }
} else if(packetType == AVMEDIA_TYPE_VIDEO) { } else if(packetType == AVMEDIA_TYPE_VIDEO) {
auto frame = vDecoder.decode(packet); auto frame = vDecoder.decode(packet);
frame = scaler.scale(frame);
frame.setPictureType(AV_PICTURE_TYPE_NONE); frame.setPictureType(AV_PICTURE_TYPE_NONE);
auto encPacket = vEncoder.encode(frame); auto encPacket = vEncoder.encode(frame);
if(!encPacket) continue; if(!encPacket) continue;
@ -79,7 +88,7 @@ int main(int argc, char** argv) {
} }
flushEncoder(output, vEncoder, vStream, outVStream, VIDEO_STREAM_INDEX); 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(); output.writeTrailer();
return 0; return 0;