h264.c
static int decode_slice_header(H264Context *h, H264Context *h0){
...
...
h->deblocking_filter = 1;
h->slice_alpha_c0_offset = 52;
h->slice_beta_offset = 52;
if( h->pps.deblocking_filter_parameters_present ) {
tmp= get_ue_golomb_31(&s->gb);
if(tmp > 2){
av_log(s->avctx, AV_LOG_ERROR, "deblocking_filter_idc %u out of range\n", tmp);
return -1;
}
h->deblocking_filter= tmp;
if(h->deblocking_filter < 2)
h->deblocking_filter^= 1; // 1<->0
if( h->deblocking_filter ) {
h->slice_alpha_c0_offset += get_se_golomb(&s->gb) << 1;
h->slice_beta_offset += get_se_golomb(&s->gb) << 1;
if( h->slice_alpha_c0_offset > 104U
|| h->slice_beta_offset > 104U){
av_log(s->avctx, AV_LOG_ERROR, "deblocking filter parameters %d %d out of range\n", h->slice_alpha_c0_offset, h->slice_beta_offset);
return -1;
}
}
}
h->deblocking_filter = 0; // turn off deblocking filter
if( s->avctx->skip_loop_filter >= AVDISCARD_ALL
||(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && h->slice_type_nos != AV_PICTURE_TYPE_I)
||(s->avctx->skip_loop_filter >= AVDISCARD_BIDIR && h->slice_type_nos == AV_PICTURE_TYPE_B)
||(s->avctx->skip_loop_filter >= AVDISCARD_NONREF && h->nal_ref_idc == 0))
h->deblocking_filter= 0;
...
...
* 디블러킹 필터를 끄면 화질 열화현상이 발생하지만 약 20% 정도의 성능개선 효과를 볼 수 있다. 작은 화면을 플레이할때는 화질 열화현상이 눈에 잘 띄지않아서 경우에 따라 적용해봄직 하다.
2012년 11월 2일 금요일
2012년 10월 8일 월요일
DirectDraw Surface 에 Win32 GDI 함수로 그리기 - Drawing on DirectDraw Surface with Win32 GDI API
void drawSurface(RECT *rectTarget, IDirectDrawSurface7 *lpSurface)
{
HDC hdc;
hr=lpSurface->GetDC(&hdc);
int targetWidth = rectTarget->right-rectTarget->left;
int targetHeight = rectTarget->bottom-rectTarget->top;
HDC hMemDC;
hMemDC = CreateCompatibleDC(hdc);
HBITMAP hbmMem = CreateCompatibleBitmap(hdc, targetWidth, targetHeight);
SelectObject(hMemDC, hbmMem);
.....
.....
TextOut(hMemDC, ....);
.....
TransparentBlt(hMemDC, ...);
.....
Rectangle(hMemDC, ...);
....
....
DeleteObject(hbmMem);
DeleteDC(hMemDC);
lpSurface->ReleaseDC(hdc);
}
* lpSurface->GetDC()/lpSurface->ReleaseDC() 하면서 lpSurface 는 lock/unlock 이 된다.
따라서 위 함수 내부에서 DirectDraw Blt 함수가 호출되어서는 안된다.
* Win32 GDI 함수는 기본적으로 DirectDraw 계열 함수보다 훨씬 느리기때문에 위 함수를
사용할때는 두 개의 Surface를 두고 Blt 하는 Double-buffering 방식으로 구현하는것이 좋다.
라벨:
directdraw
2012년 9월 4일 화요일
ffmpeg audio encoding/decoding
< Encoder.h >
< Encoder.cpp >
< AudioEncoder.h >
< AudioEncoder.cpp >
< AudioEncoder 사용 >
< Decoder.h >
< Decoder.cpp >
< AudioDecoder.h>
< AudioDecoder.cpp >
< AudioDecoder 사용 >
#ifndef __ENCODER_H__
#define __ENCODER_H__
#include <windows.h>
extern "C" {
#include "libavcodec\avcodec.h"
}
class Encoder
{
public:
Encoder();
virtual ~Encoder();
static void initCodec();
virtual void close();
virtual int encodeFrame(AVFrame *frame) = 0;
AVFrame* frame() { return m_pFrame; }
unsigned char* outBuf() { return m_pOutBuf; }
int outBufSize() { return m_nOutBufSize; }
protected:
int prepareOpen(enum AVCodecID codecId);
protected:
AVCodec* m_pCodec;
AVCodecContext* m_pCodecCtx;
AVPacket m_avPacket;
AVFrame* m_pFrame;
unsigned char* m_pOutBuf;
int m_nOutBufSize;
int m_nOutBufMaxSize;
static HANDLE m_hMutexInit;
static bool m_bInit;
static int m_nCPU;
};
#endif
< Encoder.cpp >
#include "Encoder.h"
#include "GlobalEnv.h"
#include "FFMPEGUtil.h"
bool Encoder::m_bInit = false;
int Encoder::m_nCPU = 1;
HANDLE Encoder::m_hMutexInit = CreateMutex(NULL, FALSE, NULL);
Encoder::Encoder() : m_pCodec(NULL), m_pCodecCtx(NULL), m_pFrame(NULL)
{
initCodec();
m_pOutBuf = NULL;
m_nOutBufMaxSize = m_nOutBufSize = 0;
}
Encoder::~Encoder()
{
close();
}
void Encoder::initCodec()
{
WaitForSingleObject(m_hMutexInit, INFINITE);
if (!m_bInit) {
InitFFmpegLib();
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
m_nCPU = sysinfo.dwNumberOfProcessors;
m_bInit = true;
}
ReleaseMutex(m_hMutexInit);
}
int Encoder::prepareOpen(enum AVCodecID codecId)
{
av_init_packet(&m_avPacket);
m_pCodec = avcodec_find_encoder(codecId);
if (!m_pCodec) {
DXPRINTF("avcodec_find_encoder failed to find codec %d\n", codecId);
return -1;
}
m_pCodecCtx = avcodec_alloc_context3(m_pCodec);
if (!m_pCodecCtx) {
DXPRINTF("avcodec_alloc_context3 failed\n");
return -1;
}
m_pFrame = avcodec_alloc_frame();
if (!m_pFrame) {
DXPRINTF("avcodec_alloc_frame failed\n");
return -1;
}
return 0;
}
void Encoder::close()
{
if (m_pCodecCtx) {
avcodec_close(m_pCodecCtx);
av_free(m_pCodecCtx);
m_pCodecCtx = NULL;
}
avcodec_free_frame(&m_pFrame);
if (m_pOutBuf) {
delete[] m_pOutBuf;
m_pOutBuf = NULL;
}
m_nOutBufMaxSize = m_nOutBufSize = 0;
}
< AudioEncoder.h >
#ifndef __AUDIO_ENCODER_H__
#define __AUDIO_ENCODER_H__
#include "Encoder.h"
class AudioEncoder : public Encoder
{
public:
AudioEncoder();
virtual ~AudioEncoder();
int open(enum AVCodecID codec_id, int bit_rate, int sample_rate, int channels, int channel_layout, enum AVSampleFormat sample_fmt);
virtual void close();
virtual int encodeFrame(AVFrame *frame);
int prepareAudioFrame(unsigned short *pData, int size, int nb_samples);
};
#endif
< AudioEncoder.cpp >
#include "AudioEncoder.h"
#include "GlobalEnv.h"
/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt)
{
const enum AVSampleFormat *p = codec->sample_fmts;
while (*p != AV_SAMPLE_FMT_NONE) {
if (*p == sample_fmt)
return 1;
p++;
}
return 0;
}
/* just pick the highest supported samplerate */
static int select_sample_rate(AVCodec *codec)
{
const int *p;
int best_samplerate = 0;
if (!codec->supported_samplerates)
return 44100;
p = codec->supported_samplerates;
while (*p) {
best_samplerate = FFMAX(*p, best_samplerate);
p++;
}
return best_samplerate;
}
/* select layout with the highest channel count */
static int select_channel_layout(AVCodec *codec)
{
const uint64_t *p;
uint64_t best_ch_layout = 0;
int best_nb_channels = 0;
if (!codec->channel_layouts)
return AV_CH_LAYOUT_STEREO;
p = codec->channel_layouts;
while (*p) {
int nb_channels = av_get_channel_layout_nb_channels(*p);
if (nb_channels > best_nb_channels) {
best_ch_layout = *p;
best_nb_channels = nb_channels;
}
p++;
}
return best_ch_layout;
}
AudioEncoder::AudioEncoder() : Encoder()
{
}
AudioEncoder::~AudioEncoder()
{
}
int AudioEncoder::open(AVCodecID codec_id, int bit_rate, int sample_rate, int channels, int channel_layout, AVSampleFormat sample_fmt)
{
int err;
char errbuf[128];
err = prepareOpen(codec_id);
if (err < 0) return -1;
m_pCodecCtx->bit_rate = bit_rate;
m_pCodecCtx->sample_rate = sample_rate == 0 ? select_sample_rate(m_pCodec) : sample_rate;
m_pCodecCtx->channel_layout = channel_layout == 0 ? select_channel_layout(m_pCodec) : channel_layout;
m_pCodecCtx->channels = channels == 0 ? av_get_channel_layout_nb_channels(m_pCodecCtx->channel_layout) : channels;
m_pCodecCtx->sample_fmt = sample_fmt;
if (!check_sample_fmt(m_pCodec, m_pCodecCtx->sample_fmt)) {
DXPRINTF("failed to open audio encoder, Encoder does not support sample format %s\n",
av_get_sample_fmt_name(m_pCodecCtx->sample_fmt));
return -1;
}
if (err=avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avcodec_open2 %s open failed, err: %d %s\n", avcodec_get_name(codec_id), err, errbuf);
return -1;
}
DXPRINTF("audio encoder opened %s\n", avcodec_get_name(codec_id));
return 0;
}
void AudioEncoder::close()
{
Encoder::close();
}
int AudioEncoder::prepareAudioFrame(unsigned short *pData, int size, int nb_samples)
{
int err;
char errbuf[128];
avcodec_get_frame_defaults(m_pFrame);
m_pFrame->nb_samples = nb_samples == 0 ? m_pCodecCtx->frame_size : nb_samples;
m_pFrame->format = m_pCodecCtx->sample_fmt;
err = avcodec_fill_audio_frame(m_pFrame, m_pCodecCtx->channels, m_pCodecCtx->sample_fmt,
(const uint8_t *)pData, size, 0);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avcodec_fill_audio_frame failed, err : %d %s\n", err, errbuf);
return -1;
}
return 0;
}
int AudioEncoder::encodeFrame(AVFrame *frame)
{
int err;
char errbuf[128];
av_init_packet(&m_avPacket);
m_avPacket.data = NULL;
m_avPacket.size = 0;
int got_output;
err = avcodec_encode_audio2(m_pCodecCtx, &m_avPacket, frame, &got_output);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avcodec_encode_audio2 failed, err : %d %s\n", err, errbuf);
return -1;
}
if (got_output) {
if (m_avPacket.size > 0) {
if (m_nOutBufMaxSize < m_avPacket.size) {
if (m_pOutBuf) delete[] m_pOutBuf;
m_pOutBuf = new unsigned char[m_avPacket.size];
m_nOutBufMaxSize = m_avPacket.size;
}
memcpy(m_pOutBuf, m_avPacket.data, m_avPacket.size);
}
m_nOutBufSize = m_avPacket.size;
av_free_packet(&m_avPacket);
}
return got_output == 1 ? 0 : -1;
}
< AudioEncoder 사용 >
AudioEncoder* m_pEncoder = new AudioEncoder();
m_pEncoder->open(AV_CODEC_ID_PCM_MULAW, 64000, 8000, 1, AV_CH_LAYOUT_MONO, AV_SAMPLE_FMT_S16);
...
m_pEncoder->prepareAudioFrame((unsigned short*)pData, size, nb_samples);
int ret = m_pEncoder->encodeFrame(m_pEncoder->frame());
if (ret > 0) {
fwrite(m_pEncoder->outBuf(), m_pEncoder->outBufSize(), 1, fp);
}
...
m_pEncoder->close();
delete m_pEncoder;
< Decoder.h >
#ifndef __DECODER_H__
#define __DECODER_H__
#include <windows.h>
extern "C" {
#include "libavcodec\avcodec.h"
}
#define MAX_DECODE_BUFFER_SIZE (1024*1024)
class Decoder
{
public:
Decoder();
virtual ~Decoder();
static void initCodec();
virtual int open(enum AVCodecID codecId, int channel);
virtual int open(AVCodecContext *codec, int channel);
virtual void close();
virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame) = 0;
void flush();
enum AVCodecID codecID();
AVFrame* frame() { return m_pFrame; }
int width();
int height();
enum AVPixelFormat pixelFormat();
protected:
virtual int open(enum AVCodecID codecId, AVCodecContext *codec, int channel) = 0;
int prepareOpen(enum AVCodecID codecId, AVCodecContext *codec);
void prepareDecBuffer(unsigned char *inBuf, int inLen);
protected:
AVCodec* m_pCodec;
AVCodecContext* m_pCodecCtx;
AVFrame* m_pFrame;
AVPacket m_avPacket;
unsigned char* m_pDecBuffer;
int m_nDecBufferSize;
bool m_bCodecCtxAlloc;
static HANDLE m_hMutexInit;
static bool m_bInit;
static int m_nCPU;
// dump
FILE *m_pFile;
};
#endif
< Decoder.cpp >
#include "Decoder.h"
#include "GlobalEnv.h"
#include "FFMPEGUtil.h"
bool Decoder::m_bInit = false;
int Decoder::m_nCPU = 1;
HANDLE Decoder::m_hMutexInit = CreateMutex(NULL, FALSE, NULL);
Decoder::Decoder() : m_pCodec(NULL), m_pCodecCtx(NULL), m_pFrame(NULL), m_bCodecCtxAlloc(false), m_pFile(NULL)
{
initCodec();
m_pDecBuffer = new unsigned char[MAX_DECODE_BUFFER_SIZE];
m_nDecBufferSize = MAX_DECODE_BUFFER_SIZE;
}
Decoder::~Decoder()
{
if (m_pDecBuffer) {
delete[] m_pDecBuffer;
m_pDecBuffer = NULL;
}
}
void Decoder::initCodec()
{
WaitForSingleObject(m_hMutexInit, INFINITE);
if (!m_bInit) {
InitFFmpegLib();
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
m_nCPU = sysinfo.dwNumberOfProcessors;
m_bInit = true;
}
ReleaseMutex(m_hMutexInit);
}
int Decoder::open(AVCodecID codecId, int channel)
{
return open(codecId, NULL, channel);
}
int Decoder::open(AVCodecContext *codec, int channel)
{
return open(codec->codec_id, codec, channel);
}
int Decoder::prepareOpen(enum AVCodecID codecId, AVCodecContext *codec)
{
av_init_packet(&m_avPacket);
m_pCodec = avcodec_find_decoder(codecId);
if (!m_pCodec) {
DXPRINTF("avcodec_find_decoder failed to find codec %d\n", codecId);
return -1;
}
if (codec) {
m_pCodecCtx = codec;
m_bCodecCtxAlloc = false;
} else {
m_pCodecCtx = avcodec_alloc_context3(m_pCodec);
if (!m_pCodecCtx) {
DXPRINTF("avcodec_alloc_context3 failed\n");
return -1;
}
m_bCodecCtxAlloc = true;
}
m_pFrame = avcodec_alloc_frame();
if (!m_pFrame) {
DXPRINTF("avcodec_alloc_frame failed\n");
return -1;
}
return 0;
}
void Decoder::close()
{
if (m_bCodecCtxAlloc) {
if (m_pCodecCtx)
avcodec_close(m_pCodecCtx);
av_free(m_pCodecCtx);
m_bCodecCtxAlloc = false;
}
m_pCodecCtx = NULL;
avcodec_free_frame(&m_pFrame);
if (m_pFile) {
fclose(m_pFile);
m_pFile = NULL;
}
}
enum AVCodecID Decoder::codecID()
{
if (m_pCodecCtx)
return m_pCodecCtx->codec_id;
return AV_CODEC_ID_NONE;
}
int Decoder::width()
{
if (m_pCodecCtx)
return m_pCodecCtx->width;
return 0;
}
int Decoder::height()
{
if (m_pCodecCtx)
return m_pCodecCtx->height;
return 0;
}
enum AVPixelFormat Decoder::pixelFormat()
{
if (m_pCodecCtx)
return m_pCodecCtx->pix_fmt;
return AV_PIX_FMT_NONE;
}
void Decoder::prepareDecBuffer(unsigned char *inBuf, int inLen)
{
if (inLen+FF_INPUT_BUFFER_PADDING_SIZE > m_nDecBufferSize) {
delete[] m_pDecBuffer;
m_pDecBuffer = new unsigned char[inLen+FF_INPUT_BUFFER_PADDING_SIZE];
m_nDecBufferSize = inLen+FF_INPUT_BUFFER_PADDING_SIZE;
}
memset(&m_pDecBuffer[inLen], 0, FF_INPUT_BUFFER_PADDING_SIZE);
memcpy(m_pDecBuffer, inBuf, inLen);
av_init_packet(&m_avPacket);
m_avPacket.data = m_pDecBuffer;
m_avPacket.size = inLen;
}
void Decoder::flush()
{
if (m_pCodecCtx)
avcodec_flush_buffers(m_pCodecCtx);
}
< AudioDecoder.h>
#ifndef __AUDIO_DECODER_H__
#define __AUDIO_DECODER_H__
#include "Decoder.h"
extern "C" {
#include "libswresample\swresample.h"
#include "libavutil\opt.h"
}
class AudioDecoder : public Decoder
{
public:
AudioDecoder();
virtual ~AudioDecoder();
virtual void close();
virtual int decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame);
unsigned char* outBuf() { return m_pOutBuf; }
int outBufSize() { return m_nOutBufSize; }
void setExtraData(unsigned char *extradata, int extradatasize);
protected:
virtual int open(enum AVCodecID codecId, AVCodecContext *codec, int channel);
int initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt);
int checkResampler();
protected:
struct SwrContext* m_pSwrCtx;
unsigned char* m_pOutBuf;
int m_nOutBufSize;
int m_nOutBufMaxSize;
unsigned char* m_pExtraData;
int m_nExtraDataSize;
};
#endif
< AudioDecoder.cpp >
#include "AudioDecoder.h"
#include "GlobalEnv.h"
AudioDecoder::AudioDecoder() : Decoder(),
m_pSwrCtx(NULL), m_pOutBuf(NULL), m_nOutBufSize(0), m_nOutBufMaxSize(0), m_pExtraData(NULL), m_nExtraDataSize(0)
{
}
AudioDecoder::~AudioDecoder()
{
}
int AudioDecoder::open(enum AVCodecID codecId, AVCodecContext *codec, int channel)
{
int err;
char errbuf[128];
err = prepareOpen(codecId, codec);
if (err < 0) return -1;
if (m_bCodecCtxAlloc) {
m_pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
m_pCodecCtx->channels = channel;
if (codecId == AV_CODEC_ID_PCM_MULAW) {
m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_U8;
} else if (codecId == AV_CODEC_ID_AAC) {
if (m_pExtraData) {
m_pCodecCtx->extradata = m_pExtraData;
m_pCodecCtx->extradata_size = m_nExtraDataSize;
}
m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
} else {
m_pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
}
}
if (err=avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("avcodec_open2 %s open failed, err: %d %s\n", avcodec_get_name(codecId), err, errbuf);
goto exit;
}
int channel_layout = m_pCodecCtx->channel_layout;
if (channel_layout == 0) {
channel_layout = av_get_default_channel_layout(m_pCodecCtx->channels);
}
err = initResampler(channel_layout, m_pCodecCtx->sample_rate, m_pCodecCtx->sample_fmt);
if (err < 0) goto exit;
DXPRINTF("audio decoder opened %s\n", avcodec_get_name(codecId));
exit:
return err;
}
int AudioDecoder::initResampler(uint64_t channel_layout, int sample_rate, enum AVSampleFormat sample_fmt)
{
int err;
char errbuf[128];
if (m_pSwrCtx) {
swr_free(&m_pSwrCtx);
m_pSwrCtx = NULL;
}
m_pSwrCtx = swr_alloc();
av_opt_set_int(m_pSwrCtx, "in_channel_layout", channel_layout, 0);
av_opt_set_int(m_pSwrCtx, "in_sample_rate", sample_rate, 0);
av_opt_set_sample_fmt(m_pSwrCtx, "in_sample_fmt", sample_fmt, 0);
av_opt_set_int(m_pSwrCtx, "out_channel_layout", channel_layout, 0);
av_opt_set_int(m_pSwrCtx, "out_sample_rate", sample_rate, 0);
av_opt_set_sample_fmt(m_pSwrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
err = swr_init(m_pSwrCtx);
if (err < 0) {
av_strerror(err, errbuf, sizeof(errbuf));
DXPRINTF("swr_init failed, err: %d %s\n", err, errbuf);
return err;
}
return 0;
}
void AudioDecoder::close()
{
Decoder::close();
if (m_pSwrCtx) {
swr_free(&m_pSwrCtx);
m_pSwrCtx = NULL;
}
if (m_pExtraData) {
delete[] m_pExtraData;
m_pExtraData = NULL;
m_nExtraDataSize = 0;
}
if (m_pOutBuf) {
delete[] m_pOutBuf;
m_pOutBuf = NULL;
m_nOutBufMaxSize = m_nOutBufSize = 0;
}
if (m_pFile) {
fclose(m_pFile);
m_pFile = NULL;
}
}
int AudioDecoder::decodeFrame(unsigned char *inBuf, int inLen, AVFrame *frame)
{
if (!m_pCodecCtx || !inBuf || inLen <= 0) return 0;
int retLen = 0, got_frame;
prepareDecBuffer(inBuf, inLen);
__try
{
retLen = avcodec_decode_audio4(m_pCodecCtx, m_pFrame, &got_frame, &m_avPacket);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
GlobalEnv::WriteLogFile("[%s] avcodec_decode_audio4 crashed, (exception code : 0x%x)",
__FUNCTION__, GetExceptionCode());
}
if (retLen <= 0) {
DXPRINTF("audio decode error : %d\n", retLen);
return retLen;
}
int out_size = av_samples_get_buffer_size(NULL, m_pCodecCtx->channels, m_pFrame->nb_samples,
m_pCodecCtx->sample_fmt, 1);
if (out_size > m_nOutBufMaxSize) {
if (m_pOutBuf) delete[] m_pOutBuf;
m_pOutBuf = new unsigned char[out_size];
m_nOutBufMaxSize = out_size;
}
if (m_pSwrCtx) {
// audio resampling
if (checkResampler() < 0) return -1;
__try
{
retLen = swr_convert(m_pSwrCtx, &m_pOutBuf, out_size,
(const uint8_t **)m_pFrame->extended_data, m_pFrame->nb_samples);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
GlobalEnv::WriteLogFile("[%s] swr_convert crashed, (exception code : 0x%x)",
__FUNCTION__, GetExceptionCode());
}
} else {
if (m_pFrame->channels == 1) {
memcpy(m_pOutBuf, m_pFrame->extended_data[0], out_size);
} else {
uint8_t *data0 = m_pFrame->extended_data[0];
uint8_t *data1 = m_pFrame->extended_data[1];
int c = 0;
for (int i=0; i<out_size/2; i+=2) {
m_pOutBuf[c++] = data0[i]; m_pOutBuf[c++] = data0[i+1];
m_pOutBuf[c++] = data1[i]; m_pOutBuf[c++] = data1[i+1];
}
out_size = c;
}
}
out_size = retLen*m_pCodecCtx->channels*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
m_nOutBufSize = out_size;
if (m_pFile)
fwrite(m_pOutBuf, m_nOutBufSize, 1, m_pFile);
return retLen;
}
void AudioDecoder::setExtraData(unsigned char *extradata, int extradatasize)
{
if (m_pExtraData) {
delete[] m_pExtraData;
m_pExtraData = NULL;
m_nExtraDataSize = 0;
}
if (extradata == NULL || extradatasize <= 0)
return;
m_pExtraData = new unsigned char[extradatasize];
memset(m_pExtraData, 0, extradatasize);
memcpy(m_pExtraData, extradata, extradatasize);
m_nExtraDataSize = extradatasize;
}
int AudioDecoder::checkResampler()
{
int err;
int64_t channel_layout = 0;
int64_t sample_rate = 0;
int64_t sample_fmt = -1;
av_opt_get_int(m_pSwrCtx, "in_channel_layout", 0, &channel_layout);
av_opt_get_int(m_pSwrCtx, "in_sample_rate", 0, &sample_rate);
av_opt_get_int(m_pSwrCtx, "in_sample_fmt", 0, &sample_fmt);
if ((m_pCodecCtx->channel_layout != 0) && (channel_layout != m_pCodecCtx->channel_layout) ||
sample_rate != m_pCodecCtx->sample_rate ||
sample_fmt != m_pCodecCtx->sample_fmt) {
err = initResampler(m_pCodecCtx->channel_layout, m_pCodecCtx->sample_rate, m_pCodecCtx->sample_fmt);
if (err < 0)
return err;
}
return 0;
}
< AudioDecoder 사용 >
AudioDecoder *m_pDecoder = new AudioDecoder();
m_pDecoder->open(codec_id, channel);
...
int ret = m_pDecoder->decodeFrame(pData, size, m_pDecoder->frame());
if (ret > 0) {
fwrite(m_pDecoder->outBuf(), m_pDecoder->outBufSize(), 1, fp);
}
...
m_pDecoder->close();
delete m_pDecoder;
라벨:
ffmpeg
DirectDraw Surface Transparent Blt
void CopySurface(IDirectDrawSurface7 *lpSurfaceDst, RECT &rectTarget, IDirectDrawSurface7 *lpSurfaceSrc, RECT &rectSrc)
{
DDBLTFX ddbltfx;
ZeroMemory(&ddbltfx, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
DDCOLORKEY colorKey = {RGB(0,0,0), RGB(0,0,0)}; // Transparent Color - black
ddbltfx.ddckSrcColorkey = colorKey;
DWORD flags = DDBLT_ASYNC | DDBLT_KEYSRCOVERRIDE;
HRESULT hr = lpSurfaceDst->Blt(&rectTarget, lpSurfaceSrc, &rectSrc, flags, &ddbltfx);
if (FAILED(hr)) {
TRACE("[%s] hr:0x%x\n", __FUNCTION__, hr);
}
}
라벨:
directdraw
DirectDraw Surface 알파블랜딩 - DirectDraw Surface Alpha Blending
HBITMAP m_hbm;
BITMAP m_bmpInfo;
...
< 비트맵 로드 - bitmap load >
m_hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(123), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
GetObject(m_hbm, sizeof(m_bmpInfo), &m_bmpInfo);
< 알파블랜딩 - alpha blending >
void drawBitmapAlpha(RECT *rectTarget, IDirectDrawSurface7 *lpSurface)
{
HDC hdc;
if (lpSurface->GetDC(&hdc) != DD_OK || m_hbm == NULL)
return;
/* calculate bitmap size */
int targetWidth = rectTarget->right-rectTarget->left;
int targetHeight = rectTarget->bottom-rectTarget->top;
int cx = rectTarget->left+targetWidth/2;
int cy = rectTarget->top+targetHeight/2;
int bmpWidth = m_bmpInfo.bmWidth;
int bmpHeight = m_bmpInfo.bmHeight;
POINT pt;
pt.x = cx-bmpWidth/2;
pt.y = cy-bmpHeight/2;
HDC hMemDC, hAlphaDC;
BOOL ret;
hMemDC = CreateCompatibleDC(hdc); // create bitmap dc
hAlphaDC = CreateCompatibleDC(hdc); // create alpha dc
HBITMAP hbmAlpha = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
SelectObject(hMemDC, m_hbm);
SelectObject(hAlphaDC, hbmAlpha);
// copy src image to alpha dc
ret = BitBlt(hAlphaDC, 0, 0, bmpWidth, bmpHeight, hdc, pt.x, pt.y, SRCCOPY);
if (!ret) {
TRACE("[%s] BitBlt failed, err:%d\n", __FUNCTION__, GetLastError());
}
// copy bitmap image to alpha dc with transparent
ret = TransparentBlt(hAlphaDC, 0, 0, bmpWidth, bmpHeight, hMemDC, 0, 0, m_bmpInfo.bmWidth, m_bmpInfo.bmHeight, RGB(0, 0, 0));
if (!ret) {
TRACE("[%s] TransparentBlt failed, err:%d\n", __FUNCTION__, GetLastError());
}
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 100;
bf.AlphaFormat = 0;
// alpha blend alpha dc to dest dc
ret = AlphaBlend(hdc, pt.x, pt.y, bmpWidth, bmpHeight, hAlphaDC, 0, 0, bmpWidth, bmpHeight, bf);
if (!ret) {
TRACE("[%s] AlphaBlend failed, err:%d\n", __FUNCTION__, GetLastError());
}
DeleteObject(hbmAlpha);
DeleteDC(hAlphaDC);
DeleteDC(hMemDC);
lpSurface->ReleaseDC(hdc);
}
라벨:
directdraw
2012년 6월 20일 수요일
vc++ 프로젝트 배포를 위한 manifest와 dll 링크
vc++ 로 작성된 프로젝트를 배포하다보면 타겟 PC에서
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
라는 메시지를 출력하면서 실행에 실패하는 경우가 있다. 이것은 dll dependency 에 따른 dll 이 타겟 PC 에 존재하지 않거나 dll 버전이 맞지 않아서 생기는 현상이다.
이 문제를 해결하기 위해서는 올바른 dll 들을 같이 묶어서 배포해야한다.
올바른 버전의 dll 을 찾아내려면 manifest 파일을 봐야하는데 vc++ 프로젝트 속성에 디폴트로 embed manifest 로 되어있다. 따라서 manifest 정보를 보려면 프로젝트 output 파일(exe/dll/ocx)을 텍스트 에디터로 직접 열어서 manifest 정보를 보거나 xxx.intermediate.manifest 파일을 열어봐야한다.
manifest 정보를 보면 대게 아래와 같이 나오는데
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
</assembly>
위와 같이 manifest 정보가 구성되어있을때 Microsoft.VC90.CRT 와 Microsoft.VC90.MFC 두개의 dll 들을 찾아야 하는데 이것은 각각 msvcr90.dll 과 mfc90.dll 이다.
어느 dll 인지 찾으려면 dependency walker 를 이용하면된다. 해당 dll 파일을 찾으려면
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86
아래를 뒤져서 파일을 찾으면 되는데 경우에 따라 dll 버전이 또 다를수 있다. (속성->버전정보)
이럴 경우
C:\WINDOWS\WinSxS
아래를 뒤져서 정확히 버전이 일치하는 dll 파일을 찾아야한다.
"응용 프로그램 구성이 올바르지 않기 때문에 이 응용 프로그램을 시작하지 못했습니다"
라는 메시지를 출력하면서 실행에 실패하는 경우가 있다. 이것은 dll dependency 에 따른 dll 이 타겟 PC 에 존재하지 않거나 dll 버전이 맞지 않아서 생기는 현상이다.
이 문제를 해결하기 위해서는 올바른 dll 들을 같이 묶어서 배포해야한다.
올바른 버전의 dll 을 찾아내려면 manifest 파일을 봐야하는데 vc++ 프로젝트 속성에 디폴트로 embed manifest 로 되어있다. 따라서 manifest 정보를 보려면 프로젝트 output 파일(exe/dll/ocx)을 텍스트 에디터로 직접 열어서 manifest 정보를 보거나 xxx.intermediate.manifest 파일을 열어봐야한다.
manifest 정보를 보면 대게 아래와 같이 나오는데
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='asInvoker' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type='win32' name='Microsoft.VC90.MFC' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
</dependentAssembly>
</dependency>
</assembly>
위와 같이 manifest 정보가 구성되어있을때 Microsoft.VC90.CRT 와 Microsoft.VC90.MFC 두개의 dll 들을 찾아야 하는데 이것은 각각 msvcr90.dll 과 mfc90.dll 이다.
어느 dll 인지 찾으려면 dependency walker 를 이용하면된다. 해당 dll 파일을 찾으려면
C:\Program Files\Microsoft Visual Studio 9.0\VC\redist\x86
아래를 뒤져서 파일을 찾으면 되는데 경우에 따라 dll 버전이 또 다를수 있다. (속성->버전정보)
이럴 경우
C:\WINDOWS\WinSxS
아래를 뒤져서 정확히 버전이 일치하는 dll 파일을 찾아야한다.
2012년 6월 8일 금요일
H.264 RFC3984 NAL 패킷처리 - H.264 RFC3984 NAL Packet Handling
class RTPSource
{
uint8_t* fFrameBuf; // 프레임 버퍼 - 한개 프레임 될때까지 채움
int fFrameBufPos; // 프레임 버퍼 인덱스 - 현재 프레임 버퍼 사이즈
FrameHandlerFunc fFrameHandlerFunc; // 콜백함수 - 한개 프레임이 완성되면 호출
void* fFrameHandlerFuncData; // 콜백함수 데이터
uint8_t* fExtraData; // SPS/PPS 정보
unsigned fExtraDataSize;
...
}
int trimStartCode(uint8_t *buf, int len)
{
uint8_t *ptr = buf;
if (len < 4) return 0;
// trying to find 0x00 0x00 ... 0x01 pattern
// find first 0x00 0x00 bytes
if (ptr[0] == 0x00 && ptr[1] == 0x00) {
// find first 0x01
while (*ptr == 0x00 && ptr < buf+len-1)
ptr++;
if (*ptr != 0x01) { // error - invalid stream
DPRINTF("invalid stream, 0x%02x\n", *ptr);
ptr = buf;
} else {
ptr++;
}
}
return ptr-buf;
}
void RTPSource::copyToFrameBuffer(uint8_t *buf, int len)
{
if (fFrameBufPos+len >= FRAME_BUFFER_SIZE) {
DPRINTF("RTP Frame Buffer overflow %s\n", fCodecName);
fFrameBufPos = 0;
}
memmove(&fFrameBuf[fFrameBufPos], buf, len);
fFrameBufPos += len;
}
void RTPSource::resetFrameBuf()
{
fFrameBufPos = 0;
}
uint64_t RTPSource::getMediaTimestamp(uint32_t timestamp)
{
uint64_t msec = 1000;
uint64_t time_msec = timestamp*msec/fTimestampFrequency;
return time_msec;
}
void H264RTPSource::putStartCode()
{
fFrameBuf[fFrameBufPos++] = 0x00;
fFrameBuf[fFrameBufPos++] = 0x00;
fFrameBuf[fFrameBufPos++] = 0x00;
fFrameBuf[fFrameBufPos++] = 0x01;
}
void H264RTPSource::processFrame(RTPPacketBuffer *packet)
{
uint8_t *buf = (uint8_t *)packet->payload();
int len = packet->payloadLen();
int offset = trimStartCode(buf, len);
buf = &buf[offset];
len -= offset;
uint8_t *buf_ptr = buf;
bool isCompleteFrame = false;
uint32_t media_timestamp = getMediaTimestamp(packet->timestamp());
uint8_t nalUnitType = (buf[0]&0x1F);
if (RTSPCommonEnv::nDebugFlag&DEBUG_FLAG_RTP_PAYLOAD)
DPRINTF("nal_type: %d, size: %d\n", nalUnitType, len);
if (!fIsStartFrame) {
if (fExtraData) {
putStartCode();
copyToFrameBuffer(fExtraData, fExtraDataSize);
}
fIsStartFrame = true;
}
switch (nalUnitType)
{
case 28: { // FU-A
uint8_t startBit = buf[1]&0x80;
uint8_t endBit = buf[1]&0x40;
if (startBit) {
buf_ptr++; len--;
buf[1] = (buf[0]&0xE0) + (buf[1]&0x1F);
putStartCode();
} else {
buf_ptr += 2; len -= 2;
}
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = (endBit != 0);
break;
}
case 5: { // IDR-Picture
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = true;
break;
}
case 7: { // SPS
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = false;
break;
}
case 8: { // PPS
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = false;
break;
}
case 24: { // STAP-A
buf_ptr++; len--;
while (len > 3)
{
uint16_t staplen = (buf_ptr[0]<<8) | (buf_ptr[1]);
if (staplen > len) {
DPRINTF("STAP-A process error, staplen: %d, len\n", staplen, len);
break;
}
buf_ptr += 2; len -= 2;
nalUnitType = buf_ptr[0]&0x1F;
putStartCode();
copyToFrameBuffer(buf_ptr, staplen);
buf_ptr += staplen; len -= staplen;
if (fFrameHandlerFunc)
fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos);
resetFrameBuf();
}
break;
}
default:
putStartCode();
copyToFrameBuffer(buf_ptr, len);
isCompleteFrame = true;
break;
}
if (isCompleteFrame) {
if (fFrameHandlerFunc)
fFrameHandlerFunc(fFrameHandlerFuncData, fFrameType, media_timestamp, fFrameBuf, fFrameBufPos);
resetFrameBuf();
}
}
피드 구독하기:
글 (Atom)