2011년 7월 8일 금요일

ffmpeg 스케일러(scaler) 사용법 - how to use ffmpeg scaler

< VideoScaler.h >

#ifndef __VIDEO_SCALER_H__
#define __VIDEO_SCALER_H__

extern "C" {
#include "libavcodec\avcodec.h"
#include "libswscale\swscale.h"
}

#include "FFMPEGUtil.h"

class VideoScaler
{
public:
VideoScaler();
virtual ~VideoScaler();

int resetScaler(int srcWidth, int srcHeight, AVPixelFormat pixFmtSrc,
int targetWidth, int targetHeight, AVPixelFormat pixFmtDst);
void freeScaler();
int processScaler(AVFrame *frame);

int srcWidth() { return m_nSrcWidth; }
int srcHeight() { return m_nSrcHeight; }
int targetWidth() { return m_nTargetWidth; }
int targetHeight() { return m_nTargetHeight; }
int bitCount() { return GetBitPerPixel(m_pixFmtDst); }

AVPixelFormat srcPixFormat() { return m_pixFmtSrc; }
AVPixelFormat dstPixFormat() { return m_pixFmtDst; }

unsigned char* picture() { return m_pPicture; }
int size() { return m_nTargetWidth*m_nTargetHeight*(GetBitPerPixel(m_pixFmtDst)>>3); }

protected:
struct SwsContext* m_pScaler;
AVPixelFormat m_pixFmtSrc;
AVPixelFormat m_pixFmtDst;
int m_nSrcWidth, m_nSrcHeight;
int m_nTargetWidth, m_nTargetHeight;
unsigned char *m_pPicture;
};

#endif

< VideoScaler.cpp >

#include "VideoScaler.h"

VideoScaler::VideoScaler()
{
m_pScaler = NULL;
m_nSrcWidth = m_nSrcHeight = 0;
m_nTargetWidth = m_nTargetHeight = 0;
m_pPicture = NULL;
m_pixFmtSrc = m_pixFmtDst = AV_PIX_FMT_NONE;
}

VideoScaler::~VideoScaler()
{
freeScaler();
}

int VideoScaler::resetScaler(int srcWidth, int srcHeight, AVPixelFormat pixFmtSrc,
int targetWidth, int targetHeight, enum AVPixelFormat pixFmtDst)
{
if (srcWidth <= 0 || srcHeight <= 0) return -1;
if (targetWidth <= 0 || targetHeight <= 0) return -1;
if (pixFmtSrc == AV_PIX_FMT_NONE || pixFmtDst == AV_PIX_FMT_NONE) return -1;

if (m_pPicture) {
delete[] m_pPicture;
m_pPicture = NULL;
}

if (m_pScaler) {
sws_freeContext(m_pScaler);
m_pScaler = NULL;
}

int flags = SWS_BILINEAR;
//int flags = SWS_FAST_BILINEAR;
m_pScaler = sws_getContext(srcWidth, srcHeight, pixFmtSrc,
targetWidth, targetHeight, pixFmtDst, flags, NULL, NULL, NULL);

m_nSrcWidth = srcWidth;
m_nSrcHeight = srcHeight;
m_nTargetWidth = targetWidth;
m_nTargetHeight = targetHeight;

m_pixFmtSrc = pixFmtSrc;
m_pixFmtDst = pixFmtDst;

m_pPicture = new unsigned char[size()];

return 0;
}

void VideoScaler::freeScaler()
{
if (m_pScaler) {
sws_freeContext(m_pScaler);
m_pScaler = NULL;
}
if (m_pPicture) {
delete[] m_pPicture;
m_pPicture = NULL;
}

m_nSrcWidth = m_nSrcHeight = 0;
m_nTargetWidth = m_nTargetHeight = 0;
m_pixFmtSrc = m_pixFmtDst = AV_PIX_FMT_NONE;
}

int VideoScaler::processScaler(AVFrame *frame)
{
unsigned char *ptr = m_pPicture;

unsigned char *src_buf[4];
src_buf[0] = frame->data[0];
src_buf[1] = frame->data[1];
src_buf[2] = frame->data[2];
src_buf[3] = NULL;

int src_stride[4];
src_stride[0] = frame->linesize[0];
src_stride[1] = frame->linesize[1];
src_stride[2] = frame->linesize[2];
src_stride[3] = 0;

unsigned char *dst_buf[4];
dst_buf[0] = ptr;
dst_buf[1] = NULL;
dst_buf[2] = NULL;
dst_buf[3] = NULL;

int pitch = m_nTargetWidth * (GetBitPerPixel(m_pixFmtDst) >> 3);
int dst_stride[4];
dst_stride[0] = pitch;
dst_stride[1] = pitch;
dst_stride[2] = pitch;
dst_stride[3] = pitch;

int ret = -1;
if (m_pScaler) {
ret = sws_scale(m_pScaler, src_buf, src_stride, 0, m_nSrcHeight, dst_buf, dst_stride);
#if 0
FILE *fp = fopen("d:\\test.ppm", "wb");
fprintf(fp, "P6\n%d %d\n255\n", m_nTargetWidth, m_nTargetHeight);
fwrite(ptr, m_nTargetWidth*m_nTargetHeight*(m_nBitCount/8), 1, fp);
fclose(fp);
#endif
}

return ret;
}

< FFMPEGUtil.cpp >

int GetBitPerPixel(AVPixelFormat pix_fmt)
{
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
return av_get_bits_per_pixel(desc);
}

< 사용 >
...
m_pScaler = new VideoScaler();
...
int scaleFrame(AVFrame *frame, int targetWidth, int targetHeight, AVPixelFormat pix_fmt)
{
if (frame->width != m_pScaler->srcWidth() || frame->height != m_pScaler->srcHeight() || 
targetWidth != m_pScaler->targetWidth() || targetHeight != m_pScaler->targetHeight() ||
frame->format != m_pScaler->srcPixFormat() || pix_fmt != m_pScaler->dstPixFormat()) 
{
if (m_pScaler->resetScaler(frame->width, frame->height, (AVPixelFormat)frame->format,
targetWidth, targetHeight, pix_fmt) < 0) 
{
printf("failed to reset scaler\n");
return -1;
}
}

if (m_pScaler->processScaler(frame) < 0) {
printf("failed to process scale\n");
return -1;
}
    ...
    doSomething(m_pScaler->picture(), m_pScaler->size());
}

댓글 없음:

댓글 쓰기