2014년 10월 23일 목요일

live555 visual c++ project (VS2008)

http://www.mediafire.com/download/gnh5p065adar47a/live555.zip

live.2014.10.21.tar.gz 버전
testProgs 나머지 실행프로그램들은 만들어진 프로젝트 참고하면 쉽게 만들수 있음
x64 버전도 win32 버전 그데로 사용가능
테스트는 첨부된 test.264 사용

2014년 2월 12일 수요일

ffmpeg av_lockmgr_register 사용법

ffmpeg의 thread-safe 하지않은 함수들 - av_register_all, avcodec_open2, avcodec_close
등의 함수들은 보통 호출부에 뮤텍스 락을 걸어주어야 하는데 av_lockmgr_register 함수를
이용하면 이것을 간단하게 해결할 수 있다.

#include <windows.h>
extern "C" {
#include "libavformat/avformat.h"
}

static bool isInit = false;
static HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);

static int lockmgr(void **mtx, enum AVLockOp op)
{
   switch(op) {
      case AV_LOCK_CREATE:
          *mtx = CreateMutex(0, FALSE, 0);
          if(!*mtx)
              return 1;
          return 0;
      case AV_LOCK_OBTAIN:
          return !!WaitForSingleObject(*mtx, INFINITE);
      case AV_LOCK_RELEASE:
          return !!ReleaseMutex(*mtx);
      case AV_LOCK_DESTROY:
          CloseHandle(*mtx);
          return 0;
   }
   return 1;
}

void InitFFmpegLib()
{
WaitForSingleObject(hMutex, INFINITE);

if (!isInit) {
av_register_all();

if (av_lockmgr_register(lockmgr)) {
printf("Could not initialize lock manager!\n");
exit(1);
}
isInit = true;
}

ReleaseMutex(hMutex);
}

프로그램 시작부분에서 InitFFmpegLib() 함수를 호출하면 그 다음부터 thread-unsafe 한
ffmpeg api 함수들은 자동으로 뮤텍스 락을 건다.

2014년 1월 8일 수요일

copy AVFrame using av_image_copy

AVFrame* clone_av_frame(AVFrame *frame)
{
    AVFrame *new_frame = avcodec_alloc_frame();
    enum AVPixelFormat fmt = (enum AVPixelFormat)frame->format;
    int ret = av_image_alloc(new_frame->data, new_frame->linesize, frame->width, frame-height, fmt, 1);
    if (ret < 0) {
        av_free(new_frame->data[0]);
        av_free(new_frame);
        return 0;
    }
    
    av_image_copy(new_frame->data, new_frame->linesize, (const uint8_t **)frame->data, 
                            frame->linesize, fmt, frame->width, frame->height);

    // copy to new frame
    new_frame->width = frame->width;
    new_frame->height = frame->height;
    new_frame->pict_type = frame->pict_type;
    new_frame->format = (int)fmt;
    ...

    return new_frame;
}

void free_av_frame(AVFrame *frame)
{
    if (frame) {
        av_free(frame->data[0]);
        av_free(frame);
    }
}

2013년 12월 26일 목요일

RTP Header Parsing

< RTPHeader.h >

#ifndef __RTP_HEADER_H__
#define __RTP_HEADER_H__

typedef unsigned short      WORD;
typedef unsigned long       DWORD;

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;

typedef unsigned int u_int32_t;
typedef unsigned short u_int16_t;
typedef unsigned char u_int8_t;

typedef struct
{
WORD    cc:     4;      /* csrc count */
WORD    ext:    1;      /* header extension flag */
WORD    pad:    1;      /* padding flag - for encryption */
WORD    ver:    2;      /* protocal version */
WORD    pt:     7;      /* payload type */
WORD    mk:     1;      /* marker bit - for profile */
WORD seq; /* sequence number of this packet */
DWORD ts; /* timestamp of this packet */
DWORD ssrc; /* source of packet */
} RTP_HEADER;

class RtpHeader {
public:
RtpHeader(uint8_t *buf, int len);
virtual ~RtpHeader();

uint8_t* payload();
int length() { return fLength; }
int payloadLen();

uint16_t version() { return fVersion; }
uint16_t padding() { return fPadding; }
uint16_t extension() { return fExtension; }
uint16_t csrcCount() { return fCSRCCount; }
uint16_t markerBit() { return fMarkerBit; }
uint16_t payloadType() { return fPayloadType; }
uint16_t sequenceNum() { return fSequenceNum; }
uint32_t timestamp() { return fTimestamp; }
uint32_t ssrc() { return fSSRC; }

private:
uint8_t* fBuf;
int fLength;
uint16_t fVersion;
uint16_t fPadding;
uint16_t fExtension;
uint16_t fCSRCCount;
uint16_t fMarkerBit;
uint16_t fPayloadType;
uint16_t fSequenceNum;
uint32_t fTimestamp;
uint32_t fSSRC;

uint8_t *fCurPtr;
};

#endif


< RTPHeader.cpp >

#include <Winsock2.h>
#include "RTPHeader.h"

RtpHeader::RtpHeader(uint8_t *buf, int len) : fBuf(NULL), fLength(0), fVersion(0), fPadding(0), fExtension(0), fCSRCCount(0),
fMarkerBit(0), fPayloadType(0), fSequenceNum(0), fTimestamp(0), fSSRC(0)
{
if (len < sizeof(RTP_HEADER))
return;

fBuf = fCurPtr = buf;
fLength = len;

RTP_HEADER *p = (RTP_HEADER *)buf;
fCSRCCount = p->cc;
fExtension = p->ext;
fPadding = p->pad;
fVersion = p->ver;
fPayloadType = p->pt;
fMarkerBit = p->mk;
fSequenceNum = ntohs(p->seq);
fTimestamp = ntohl(p->ts);
fSSRC = ntohl(p->ssrc);

fCurPtr += sizeof(RTP_HEADER);

// check RTP version (it must be 2)
if (fVersion != 2)
DPRINTF("invalid rtp version %u\n", fVersion);

// skip CSRC
if (fCSRCCount > 0) {
if (payloadLen() <= fCSRCCount*4) {
DPRINTF("invalid rtp header, CSRC count error %u\n", fCSRCCount);
} else {
fCurPtr += (fCSRCCount*4);
}
}

// skip Extension field
if (fExtension) {
if (payloadLen() <= 4) {
DPRINTF("invalid rtp header, extension length error\n");
} else {
unsigned extHdr = ntohl(*(unsigned *)fCurPtr); fCurPtr += 4;
unsigned remExtSize = 4*(extHdr&0xFFFF);
if (payloadLen() <= remExtSize) {
DPRINTF("invalid rtp header, extension size error %u\n", remExtSize);
} else {
fCurPtr += remExtSize;
}
}
}

// remove padding
if (fPadding) {
if (payloadLen() <= 0) {
DPRINTF("invalid rtp header, padding error\n");
} else {
unsigned numPaddingBytes = (unsigned)fBuf[fLength-1];
if (payloadLen() <= numPaddingBytes) {
DPRINTF("invalid rtp header, padding number error\n");
} else {
fLength -= numPaddingBytes;
    fPadding = p->pad = 0;
}
}
}
}

RtpHeader::~RtpHeader()
{
}

uint8_t* RtpHeader::payload()
{
return fCurPtr;
}

int RtpHeader::payloadLen()
{
uint8_t *ptrLast = &fBuf[fLength-1];
return ptrLast-fCurPtr+1;
}


< 사용 >
...
RtpHeader *rtp = new RtpHeader((uint8_t*)buf, len);

unsigned short pt = rtp->payloadType();
unsigned short mk = rtp->markerBit();
unsigned short seqnum = rtp->sequenceNum();
unsigned int ts = rtp->timestamp();
unsigned int rtpSSRC = rtp->ssrc();

 delete rtp;

2013년 12월 18일 수요일

vc++에서 ffmpeg dll 로드실패 처리 - avcodec_register_all 실행시 crash

vc++ 에서 ffmpeg dll (--enable-shared 옵션) 링크에 성공한 후 실행하면 첫번째

avcodec_register_all 함수에서 죽는 현상 발생한다.(다른 함수들도 마찬가지)

vc++ property -> Linker -> Optimization -> References 를 Keep Unreferenced Data (/OPT:NOREF)

로 변경해서 적용할것.

2013년 8월 30일 금요일

convert AV_SAMPLE_FMT_FLTP to AV_SAMPLE_FMT_S16 with ffmpeg software resampler

extern "C" {
#include "libavcodec\avcodec.h"
#include "libswresample\swresample.h"
#include "libavutil\opt.h"
};

struct SwrContext *m_pSwrCtx;
AVCodec *m_pCodec;
AVCodecContext *m_pCodecCtx;
AVPacket m_avPacket;
AVFrame *m_pFrame;
uint8_t m_pOutBuf = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE*5];
...

< open resampler >

m_pSwrCtx = swr_alloc();

uint64_t channel_layout = m_pCodecCtx->channel_layout;
if (channel_layout == 0)
channel_layout = av_get_default_channel_layout(m_pCodecCtx->channels);

av_opt_set_int(m_pSwrCtx, "in_channel_layout", channel_layout, 0);
av_opt_set_int(m_pSwrCtx, "in_sample_rate", m_pCodecCtx->sample_rate, 0);
av_opt_set_sample_fmt(m_pSwrCtx, "in_sample_fmt", m_pCodecCtx->sample_fmt, 0);

av_opt_set_int(m_pSwrCtx, "out_channel_layout", channel_layout, 0);
av_opt_set_int(m_pSwrCtx, "out_sample_rate", m_pCodecCtx->sample_rate, 0);
av_opt_set_sample_fmt(m_pSwrCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);


err = swr_init(m_pSwrCtx);

< do resampling >
...
int got_frame;
int retLen = avcodec_decode_audio4(m_pCodecCtx, m_pFrame, &got_frame, &m_avPacket);

if (retLen <= 0) {
DPRINTF("audio decode error : %d\n", retLen);
return retLen;
}

// audio resampling
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_nOutBufSize) {
delete[] m_pOutBuf;
m_pOutBuf = new unsigned char[out_size];
m_nOutBufSize = out_size;
}

retLen = swr_convert(m_pSwrCtx, &m_pOutBuf, out_size,
(const uint8_t **)m_pFrame->extended_data, m_pFrame->nb_samples);

out_size = retLen*m_pCodecCtx->channels*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
m_nOutBufSize = out_size;

return retLen;

< close resampler >

swr_free(&m_pSwrContext);


2013년 7월 4일 목요일

mingw ffmpeg x264 연동 빌드 - mingw ffmpeg with x264 build configuration

* x264 를 먼저 빌드후 ffmpeg 빌드할때 아래와 같이 x264 경로를 명시해준다.

< x264 빌드 >
./configure --enable-win32thread --extra-cflags="-fno-stack-check -fno-stack-protector -mno-stack-arg-probe"

< ffmpeg 빌드 >
./configure --enable-memalign-hack --extra-cflags="-fno-stack-check -fno-stack-protector -mno-stack-arg-probe" --enable-libx264 --enable-gpl --extra-cflags=-I../x264-snapshot-20120208-2245 --extra-ldflags=-L../x264-snapshot-20120208-2245