본문 바로가기
TIL/FFmpeg

Custom IO-Context of FFmpeg 구현

by DandyU 2015. 1. 28.

FFmpeg에 Custom File IO를 추가하여 콘텐츠 데이터를 직접 전해주기

 

FFmpeg을 통해 콘텐츠를 디코딩할 때 libavformat에서 제공하는 avformat_open_input() 메소드에 콘텐츠의 경로를 설정하는 것이 일반적이다.

이렇게 하면 libavformat에서 알아서 경로의 콘텐츠 데이터를 읽어간다.

 

만약, libavformat에 직접 콘텐츠의 데이터를 제공하고 싶다면 어떻게 해야할까?(내가 만든 IO를 통해서 데이터를 읽어갈 수 있도록)

구글링을 열심히해서 Code Project에 관련 글을 찾았다.

 

@ Creating Custom FFmpeg IO-Context

http://www.codeproject.com/Tips/489450/Creating-Custom-FFmpeg-IO-Context

 

요약하면,

1. AVIOContext를 만들어야 하고

2. 두 번째 avformat_open_input()을 호출 할 때 만든 AVIOContext 를 설정해줘야 한다.

 

1. AVIOCOntext 생성

 

- AVIOContext 구조체 변수를 아래와 같이 생성한다. RandomAccessAsset은 File IO 관련 클래스다.

 

const int bufferLength = AVPROBE_PADDING_SIZE * 1024;
unsigned char buffer[bufferLength];

RandomAccessAsset *asset = new RandomAccessAsset("c:/video.mp4"); // 콘텐츠 데이터를 Access하는 클래스

 

AVIOContext *customIoCtx = avio_alloc_context(buffer, bufferLength, 0, asset, readForCustomIo, NULL, seekForCustomIo);

 

 

- readForCustomIo 메소드

ptr을 통해서 avio_alloc_context()에 입력한 asset 오브젝트를 받아 콘텐츠 데이터를 Read를 하면 된다. 참고로 static으로 선언되어야 한다.

 

int readForCustomIo(void *ptr, uint8_t *buffer, int bufferLength) {
  RandomAccessAsset *asset = (RandomAccessAsset *) ptr;

  return asset->read(buffer, 0, bufferLength);
}

 

 

- seekForCustomIo 메소드

 

//whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZE
int64_t seekForCustomIo(void *ptr, int64_t pos, int whence) {
  RandomAccessAsset *asset = (RandomAccessAsset *) ptr;

  RandomAccessAsset::RAA_SEEK_MODE seekMode;

  switch (whence) {
  case SEEK_SET:
    seekMode = RandomAccessAsset::RAA_SEEK_SET;
    break;
  case SEEK_CUR:
    seekMode = RandomAccessAsset::RAA_SEEK_CUR;
    break;
  case SEEK_END:
    seekMode = RandomAccessAsset::RAA_SEEK_END;
    break;
  case AVSEEK_SIZE: // it to return the filesize without seeking anywhere.
    return asset->length();
  default:
    seekMode = RandomAccessAsset::RAA_SEEK_SET;
  }

 

  return asset->seek(pos, seekMode);
}

 

 

 

2. avformat_open_input()에 AVIOContext를 설정

 

 

int readLength = assetObject->read(buffer, 0, bufferLength);
assetObject->seek(0, RandomAccessAsset::RAA_SEEK_SET);

 

// Set the ProbeData-structure

AVProbeData probeData;
probeData.buf = buffer; // Buffer must have AVPROBE_PADDING_SIZE.
probeData.buf_size = readLength;
probeData.filename = "";

 

AVFormatContext* pFormatCtx = avformat_alloc_context();

 

// Set the Custom IO-COntext
pFormatCtx->pb = customIoCtx;

 

// Determine the input-format
pFormatCtx->iformat = av_probe_input_format(&probeData, 1);
pFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;

 

if (avformat_open_input(&pFormatCtx, "", NULL, NULL) != 0)
  return -1;

 

 

 

 

 

댓글