- Notifications
You must be signed in to change notification settings - Fork50
[WIP] add avfilter#180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Changes fromall commits
Commits
Show all changes
16 commits Select commitHold shift + click to select a range
44b24cd
CMake: added avfilter when build the project
3d4b67f
Library: added avfilter license
4b7dc83
Added FilterGraph
ec6b1de
common: load filters when preloadCodecsAndFormats
c613802
Merge branch 'develop' of https://github.com/avTranscoder/avTranscode…
11b72e8
Frame: added isVideo/AudioFrame methods
bb02458
AudioFrame: added getChannelLayout method
d441d25
filter: added Filter class
bec1155
FilterGraph: used Filter class to manage a graph of video/audio filters
b2b5d0a
StreamTranscoder: added a FilterGraph attribute
e25fef4
StreamTranscoder: process filtering at each frame when transcode
00007c9
StreamTranscoder: added getFilterGraph method
612ac4e
StreamTranscoder: updated doc
35d273c
filter: added classes to SWIG interface
1dc1f09
FilterGraph: fixed channel layout value of abuffer
6371c40
pyTest: added testFilter to check filter classes
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
4 changes: 4 additions & 0 deletionssrc/AvTranscoder/Library.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletionssrc/AvTranscoder/avTranscoder.i
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletionssrc/AvTranscoder/common.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletionssrc/AvTranscoder/data/decoded/AudioFrame.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletionssrc/AvTranscoder/data/decoded/Frame.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletionssrc/AvTranscoder/data/decoded/Frame.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletionssrc/AvTranscoder/decoder/AudioGenerator.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletionssrc/AvTranscoder/filter/Filter.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#include "Filter.hpp" | ||
extern "C" { | ||
#include <libavfilter/avfilter.h> | ||
} | ||
#include <stdexcept> | ||
namespace avtranscoder | ||
{ | ||
Filter::Filter(const std::string& name, const std::string& options, const std::string& instanceName) | ||
: _filter(NULL) | ||
, _context(NULL) | ||
, _options(options) | ||
, _instanceName(instanceName.empty() ? name : instanceName) | ||
{ | ||
_filter = avfilter_get_by_name(name.c_str()); | ||
if(!_filter) | ||
{ | ||
std::string msg("Cannot find filter "); | ||
msg += name; | ||
msg += ". It will not be added to the filter graph."; | ||
throw std::runtime_error(msg); | ||
} | ||
} | ||
Filter::~Filter() | ||
{ | ||
avfilter_free(_context); | ||
} | ||
std::string Filter::getName() const | ||
{ | ||
return _filter->name ? std::string(_filter->name) : ""; | ||
} | ||
} |
40 changes: 40 additions & 0 deletionssrc/AvTranscoder/filter/Filter.hpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#ifndef _AV_TRANSCODER_FILTER_FILTER_HPP_ | ||
#define _AV_TRANSCODER_FILTER_FILTER_HPP_ | ||
#include <AvTranscoder/common.hpp> | ||
struct AVFilter; | ||
struct AVFilterContext; | ||
namespace avtranscoder | ||
{ | ||
/** | ||
* @brief Describe a filter and its options. | ||
**/ | ||
class AvExport Filter | ||
{ | ||
public: | ||
Filter(const std::string& name, const std::string& options = "", const std::string& instanceName = ""); | ||
~Filter(); | ||
std::string getName() const; | ||
std::string getOptions() const { return _options; } | ||
std::string getInstanceName() const { return _instanceName; } | ||
#ifndef SWIG | ||
AVFilter& getAVFilter() { return *_filter; } | ||
AVFilterContext* getAVFilterContext() { return _context; } | ||
void setAVFilterContext(AVFilterContext* newContext) { _context = newContext; } | ||
#endif | ||
private: | ||
AVFilter* _filter; | ||
AVFilterContext* _context; | ||
std::string _options; | ||
std::string _instanceName; | ||
}; | ||
} | ||
#endif |
184 changes: 184 additions & 0 deletionssrc/AvTranscoder/filter/FilterGraph.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
#include "FilterGraph.hpp" | ||
#include <AvTranscoder/util.hpp> | ||
#include <AvTranscoder/data/decoded/AudioFrame.hpp> | ||
#include <AvTranscoder/data/decoded/VideoFrame.hpp> | ||
extern "C" { | ||
#include <libavfilter/avfilter.h> | ||
#include <libavfilter/buffersrc.h> | ||
#include <libavfilter/buffersink.h> | ||
} | ||
#include <stdexcept> | ||
#include <sstream> | ||
namespace avtranscoder | ||
{ | ||
FilterGraph::FilterGraph(const ICodec& codec) | ||
: _graph(avfilter_graph_alloc()) | ||
, _filters() | ||
, _codec(codec) | ||
, _isInit(false) | ||
{ | ||
if(!_graph) | ||
throw std::runtime_error("Unable to create filter graph: out of memory."); | ||
} | ||
FilterGraph::~FilterGraph() | ||
{ | ||
for(std::vector<Filter*>::iterator it = _filters.begin(); it < _filters.end(); ++it) | ||
{ | ||
it = _filters.erase(it); | ||
} | ||
avfilter_graph_free(&_graph); | ||
} | ||
void FilterGraph::process(Frame& frame) | ||
{ | ||
if(!hasFilters()) | ||
{ | ||
LOG_DEBUG("No filter to process.") | ||
return; | ||
} | ||
// init filter graph | ||
if(!_isInit) | ||
init(frame); | ||
// setup source frame | ||
int ret = av_buffersrc_write_frame(_filters.at(0)->getAVFilterContext(), &frame.getAVFrame()); | ||
if(ret < 0) | ||
{ | ||
throw std::runtime_error("Error when adding a frame to the source buffer used to start to process filters: " + | ||
getDescriptionFromErrorCode(ret)); | ||
} | ||
// pull filtered data from the filter graph | ||
for(;;) | ||
{ | ||
ret = av_buffersink_get_frame(_filters.at(_filters.size() - 1)->getAVFilterContext(), &frame.getAVFrame()); | ||
if(ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) | ||
break; | ||
if(ret < 0) | ||
{ | ||
throw std::runtime_error("Error reading buffer from buffersink: " + getDescriptionFromErrorCode(ret)); | ||
} | ||
} | ||
} | ||
Filter& FilterGraph::addFilter(const std::string& filterName, const std::string& filterOptions, | ||
const std::string& instanceName) | ||
{ | ||
LOG_INFO("Add filter " << filterName << " to the graph.") | ||
Filter* filter = new Filter(filterName, filterOptions, instanceName); | ||
_filters.push_back(filter); | ||
return *_filters.back(); | ||
} | ||
void FilterGraph::init(const Frame& frame) | ||
{ | ||
// push filters to the graph | ||
pushInBuffer(frame); | ||
for(size_t i = 1; i < _filters.size(); ++i) | ||
{ | ||
pushFilter(*_filters.at(i)); | ||
} | ||
pushOutBuffer(frame); | ||
// connect filters | ||
for(size_t index = 0; index < _filters.size() - 1; ++index) | ||
{ | ||
LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(index + 1)->getName()) | ||
const int err = | ||
avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(index + 1)->getAVFilterContext(), 0); | ||
if(err < 0) | ||
{ | ||
throw std::runtime_error("Error when connecting filters."); | ||
} | ||
} | ||
// configuring the graph | ||
LOG_INFO("Configuring filter graph.") | ||
const int err = avfilter_graph_config(_graph, NULL); | ||
if(err < 0) | ||
{ | ||
throw std::runtime_error("Error configuring the filter graph: " + getDescriptionFromErrorCode(err)); | ||
} | ||
_isInit = true; | ||
} | ||
void FilterGraph::pushFilter(Filter& filter) | ||
{ | ||
AVFilterContext* context = NULL; | ||
const int err = avfilter_graph_create_filter(&context, &filter.getAVFilter(), filter.getInstanceName().c_str(), | ||
filter.getOptions().c_str(), NULL, _graph); | ||
filter.setAVFilterContext(context); | ||
if(err < 0) | ||
{ | ||
std::string msg("Cannot add filter "); | ||
msg += filter.getName(); | ||
msg += " (instance="; | ||
msg += filter.getInstanceName(); | ||
msg += ") to the graph: "; | ||
msg += getDescriptionFromErrorCode(err); | ||
throw std::runtime_error(msg); | ||
} | ||
} | ||
void FilterGraph::pushInBuffer(const Frame& frame) | ||
{ | ||
std::string filterName; | ||
std::stringstream filterOptions; | ||
// audio frame | ||
if(frame.isAudioFrame()) | ||
{ | ||
filterName = "abuffer"; | ||
const AudioFrame& audioFrame = dynamic_cast<const AudioFrame&>(frame); | ||
filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" | ||
<< _codec.getAVCodecContext().time_base.den << ":"; | ||
filterOptions << "sample_rate=" << audioFrame.getSampleRate() << ":"; | ||
filterOptions << "sample_fmt=" << getSampleFormatName(audioFrame.getSampleFormat()) << ":"; | ||
filterOptions << "channel_layout=0x" << std::hex << audioFrame.getChannelLayout(); | ||
} | ||
// video frame | ||
else if(frame.isVideoFrame()) | ||
{ | ||
filterName = "buffer"; | ||
const VideoFrame& videoFrame = dynamic_cast<const VideoFrame&>(frame); | ||
filterOptions << "video_size=" << videoFrame.getWidth() << "x" << videoFrame.getHeight() << ":"; | ||
filterOptions << "pix_fmt=" << getPixelFormatName(videoFrame.getPixelFormat()) << ":"; | ||
filterOptions << "time_base=" << _codec.getAVCodecContext().time_base.num << "/" | ||
<< _codec.getAVCodecContext().time_base.den << ":"; | ||
filterOptions << "pixel_aspect=" << _codec.getAVCodecContext().sample_aspect_ratio.num << "/" | ||
<< _codec.getAVCodecContext().sample_aspect_ratio.den; | ||
} | ||
// invalid frame | ||
else | ||
throw std::runtime_error("Cannot create input buffer of filter graph: the given frame is invalid."); | ||
// add in buffer | ||
Filter* in = new Filter(filterName, filterOptions.str(), "in"); | ||
LOG_INFO("Add filter '" << filterName << "' at the beginning of the graph.") | ||
_filters.insert(_filters.begin(), in); | ||
pushFilter(*in); | ||
} | ||
void FilterGraph::pushOutBuffer(const Frame& frame) | ||
{ | ||
std::string filterName; | ||
if(frame.isAudioFrame()) | ||
filterName = "abuffersink"; | ||
else if(frame.isVideoFrame()) | ||
filterName = "buffersink"; | ||
else | ||
throw std::runtime_error("Cannot create output buffer of filter graph: the given frame is invalid."); | ||
// add out buffer | ||
Filter& out = addFilter(filterName, "", "out"); | ||
pushFilter(out); | ||
} | ||
} |
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.