< VideoFilter.h >
#ifndef __VIDEO_FILTER_H__
#define __VIDEO_FILTER_H__
extern "C" {
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
}
#include "Mutex.h"
struct VideoFilterParam {
int width;
int height;
AVPixelFormat pix_fmt;
AVRational time_base;
AVRational sample_aspect_ratio;
};
class VideoFilter
{
public:
VideoFilter();
virtual ~VideoFilter();
int initFilter(struct VideoFilterParam ¶m, int vflip, int hflip, int rotate);
void freeFilter();
int processFilter(AVFrame *newFrame, AVFrame *frame);
int checkFilter(struct VideoFilterParam ¶m);
protected:
static void initFilter();
protected:
AVFilterGraph* m_pFilterGraph;
AVFilterContext* m_pBufferSinkCtx;
AVFilterContext* m_pBufferSrcCtx;
AVFrame* m_pFrame;
int m_nWidth;
int m_nHeight;
AVPixelFormat m_nPixelFormat;
AVRational m_timeBase;
AVRational m_sampleAspectRatio;
static MUTEX m_hMutex;
static bool m_bInit;
};
#endif
< VideoFilter.cpp >
#include "VideoFilter.h"
#include "GlobalEnv.h"
#include "CommonType.h"
bool VideoFilter::m_bInit = false;
MUTEX VideoFilter::m_hMutex = PTHREAD_MUTEX_INITIALIZER;
VideoFilter::VideoFilter() : m_pFilterGraph(NULL), m_pBufferSrcCtx(NULL), m_pBufferSinkCtx(NULL), m_pFrame(NULL)
{
initFilter();
m_nWidth = m_nHeight = 0;
m_nPixelFormat = AV_PIX_FMT_NONE;
m_timeBase.den = m_timeBase.num = 0;
m_sampleAspectRatio.den = m_sampleAspectRatio.num = 0;
}
VideoFilter::~VideoFilter()
{
freeFilter();
}
void VideoFilter::initFilter()
{
MUTEX_LOCK(&m_hMutex);
if (!m_bInit) {
avfilter_register_all();
m_bInit = true;
}
MUTEX_UNLOCK(&m_hMutex);
}
int VideoFilter::initFilter(struct VideoFilterParam ¶m, int vflip, int hflip, int rotate)
{
freeFilter();
char args[128];
snprintf(args, sizeof(args),
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
param.width, param.height, param.pix_fmt,
param.time_base.num, param.time_base.den,
param.sample_aspect_ratio.num, param.sample_aspect_ratio.den);
m_pFrame = av_frame_alloc();
m_pFilterGraph = avfilter_graph_alloc();
char errbuf[128];
int err = avfilter_graph_create_filter(&m_pBufferSrcCtx, avfilter_get_by_name("buffer"), "buffer1", args, NULL, m_pFilterGraph);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);
return -1;
}
err = avfilter_graph_create_filter(&m_pBufferSinkCtx, avfilter_get_by_name("buffersink"), "buffersink1", NULL, NULL, m_pFilterGraph);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);
return -1;
}
AVFilterContext *vflipCtx = NULL;
AVFilterContext *hflipCtx = NULL;
AVFilterContext *rotateCtx = NULL;
AVFilterContext *prevCtx = m_pBufferSrcCtx;
if (vflip > 0) {
err = avfilter_graph_create_filter(&vflipCtx, avfilter_get_by_name("vflip"), "vflip1", NULL, NULL, m_pFilterGraph);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);
return -1;
}
err = avfilter_link(prevCtx, 0, vflipCtx, 0);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_link failed, err : %s\n", errbuf);
return -1;
}
prevCtx = vflipCtx;
}
if (hflip > 0) {
err = avfilter_graph_create_filter(&hflipCtx, avfilter_get_by_name("hflip"), "hflip1", NULL, NULL, m_pFilterGraph);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);
return -1;
}
err = avfilter_link(prevCtx, 0, hflipCtx, 0);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_link failed, err : %s\n", errbuf);
return -1;
}
prevCtx = hflipCtx;
}
if (rotate) {
snprintf(args, sizeof(args), "PI*2/360*%d", rotate);
err = avfilter_graph_create_filter(&rotateCtx, avfilter_get_by_name("rotate"), "rotate1", args, NULL, m_pFilterGraph);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_graph_create_filter failed, err : %s\n", errbuf);
return -1;
}
err = avfilter_link(prevCtx, 0, rotateCtx, 0);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_link failed, err : %s\n", errbuf);
return -1;
}
prevCtx = rotateCtx;
}
err = avfilter_link(prevCtx, 0, m_pBufferSinkCtx, 0);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_link failed, err : %s\n", errbuf);
return -1;
}
err = avfilter_graph_config(m_pFilterGraph, NULL);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avfilter_graph_config failed, err : %s\n", errbuf);
return -1;
}
m_nWidth = param.width;
m_nHeight = param.height;
m_nPixelFormat = param.pix_fmt;
m_timeBase.den = param.time_base.den;
m_timeBase.num = param.time_base.num;
m_sampleAspectRatio.den = param.sample_aspect_ratio.den;
m_sampleAspectRatio.num = param.sample_aspect_ratio.num;
return 0;
}
void VideoFilter::freeFilter()
{
avfilter_graph_free(&m_pFilterGraph);
av_frame_free(&m_pFrame);
m_nWidth = m_nHeight = 0;
m_nPixelFormat = AV_PIX_FMT_NONE;
m_timeBase.den = m_timeBase.num = 0;
m_sampleAspectRatio.den = m_sampleAspectRatio.num = 0;
}
AVFrame* copyFrame(AVFrame *frame)
{
AVFrame *new_frame = avcodec_alloc_frame();
if (new_frame) {
if (av_image_alloc(new_frame->data, new_frame->linesize,
frame->width, frame->height, (AVPixelFormat)frame->format, 1) > 0)
{
av_image_copy(new_frame->data, new_frame->linesize,
(const uint8_t **)frame->data, frame->linesize, (AVPixelFormat)frame->format,
frame->width, frame->height);
new_frame->width = frame->width;
new_frame->height = frame->height;
new_frame->pict_type = frame->pict_type;
new_frame->format = frame->format;
return new_frame;
}
else
{
av_free(new_frame->data[0]);
av_free(new_frame);
}
}
return NULL;
}
int VideoFilter::processFilter(AVFrame *newFrame, AVFrame *frame)
{
if (!m_pFilterGraph) return -1;
int ret = av_buffersrc_add_frame_flags(m_pBufferSrcCtx, frame, AV_BUFFERSRC_FLAG_KEEP_REF);
if (ret >= 0) {
while (1) {
ret = av_buffersink_get_frame(m_pBufferSinkCtx, m_pFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;
if (ret < 0) break;
newFrame = copyFrame(m_pFrame);
av_frame_unref(m_pFrame);
}
}
return 0;
}
int VideoFilter::checkFilter(struct VideoFilterParam ¶m)
{
if (m_nWidth != param.width || m_nHeight != param.height ||
m_nPixelFormat != param.pix_fmt ||
m_timeBase.den != param.time_base.den || m_timeBase.num != param.time_base.num ||
m_sampleAspectRatio.den != param.sample_aspect_ratio.den ||
m_sampleAspectRatio.num != param.sample_aspect_ratio.num)
{
return -1;
}
return 0;
}
< VideoFilter 사용 >
AVCodecContext *pCodecCtx;
...
struct VideoFilterParam param;
param.width = pCodecCtx->width;
param.height = pCodecCtx->height;
param.pix_fmt = pCodecCtx->pix_fmt;
param.time_base.den = pCodecCtx->time_base.den;
param.time_base.num = pCodecCtx->time_base.num;
param.sample_aspect_ratio.den = pCodecCtx->sample_aspect_ratio.den;
param.sample_aspect_ratio.num = pCodecCtx->sample_aspect_ratio.num;
...
VideoFilter *filter = new VideoFilter();
...
filter->initFilter(param, 1, 1, 30); // 상하반전, 좌우반전, 30도 회전
...
if (filter->checkFilter(param) < 0) {
filter->freeFilter();
param.width = pCodecCtx->width;
param.height = pCodecCtx->height;
param.pix_fmt = pCodecCtx->pix_fmt;
param.time_base.den = pCodecCtx->time_base.den;
param.time_base.num = pCodecCtx->time_base.num;
param.sample_aspect_ratio.den = pCodecCtx->sample_aspect_ratio.den;
param.sample_aspect_ratio.num = pCodecCtx->sample_aspect_ratio.num;
}
filter->processFilter(newFrame, frame); // newFrame은 처리결과, frame은 디코딩된 프레임
...
filter->freeFilter();
좋은 내용 감사합니다. ffmpeg 관련되서 올려놓으신 코드를 따라가며 공부하고 있는데
답글삭제GlobalEnv.h 파일이 없어서 compile이 안되는데 염치없지만 구할수 있을까요??
GlobalEnv.h는 없어도 됩니다. include 지우고 DXPRINTF => printf같은 출력문으로 바꾸거나 다 지우면됩니다
삭제빠른 답변 감사드립니다.
삭제한가지 더 질문이 있습니다. 해당 포스트는 아니고 ffmpeg muxer file writer를 보면
checkKeyFrame() 함수가 있는데, 해당 함수가 복잡해서 빼 놓으셧다고 댓글이 달려있는데
해당 if 문을 주석처리해도 저장된 파일이 영상은 정상적으로 나오나요??
// if (checkKeyFrame(buf, len) == 1)
// m_avPacket.flags |= AV_PKT_FLAG_KEY;