주 메뉴 열기

wwiki β

FFmpeg 개발

Jhkim (토론 | 기여)님의 2020년 5월 31일 (일) 01:15 판 (libavformat(lavf))

목차

libavformat(lavf)

I/O and Muxing/Demuxing Library.

다양한 미디어 컨테이너 형식을 처리하기 위한 라이브러리입니다. 데이터에 액세스하기 위한 여러 프로토콜(예: 파일, tcp, http 및 기타)을 지원하는 I/O모듈이 있습니다. lavf를 사용하기 전에 av_register_all()을 호출하여 컴파일된 모든 muxer, 디먹서 및 프로토콜을 등록해야 합니다. libavformat의 네트워크 기능을 사용하려면 avformat_network_init()를 호출해야 합니다.

멀티플렉싱 및 디먹싱에 사용되는 기본 lavf 구조는 AVFormatContext이며, 읽거나 쓰는 파일에 대한 모든 정보를 내보냅니다.

가장 중요한 것은 AVFormatContext에 다음이 포함되어 있습니다.

  • 입력 또는 출력 포맷: 입력을 위해 자동 감지되거나 사용자가 설정합니다. 항상 출력을 위해 사용자에 의해 설정됩니다.
  • AVStreams(파일에 저장된 모든 기본 스트림의 describe)의 배열
  • I/O 컨텍스트: lavf에 의해 열리거나 입력을 위해 사용자가 설정하며, 항상 출력을 위해 사용자가 설정합니다

(de)muxers에 옵션 전달

AVOptions 메커니즘을 사용하여 lavf muxers 및 demuxer를 구성 할 수 있습니다. 형식독립적인 일반 libavformat옵션은 AVFormatContext으로 제공한다. 사용자 프로그램에서 할당된 AVFormatContext(혹은 avformat_get_class()를 호출하여 얻은 AVClass로부터) av_opt_next()나 av_opt_find()함수를 호출해서 검사할 수 있다.

모듈

Core Functions

libavformat기능을 쿼리하거나 핵심구조체를 할당하는 함수들

int avformat_network_init (void)

이것은 선택 사항이며 더 이상 권장되지 않습니다.

이 기능은 구형 GnuTLS 또는 OpenSSL 라이브러리의 스레드 안전 문제를 해결하기 위해서만 존재합니다. 최신(4.0이상)버전에서 사용할 필요가 없다. 구형 OpenSSL등을 사용하는 경우에 스레드를 사용하기 전에 호출해라.

디먹싱

디먹서는 미디어 파일을 읽고 패킷(chunks of data, AVPacket)으로 분리한다.

패킷은 하나의 기본 스트림에 속하는 하나 개 이상의 인코딩 된 프레임을 포함한다. lavf API에서는 파일을 열기 위해서 avformat_open_input()함수를 호출한 후, 단일패킷을 읽기 위해서 av_read_frame()함수를 호출한 후, 마지막으로 avformat_close_input()을 호출해서 정리한다.

미디어 파일 열기

파일을 열기 위해서는 avformat_open_input()함수에 파일의 url을 전달해야 한다. 다음 코드처럼.

const char    *url = "file:in.mp3";
AVFormatContext *s = NULL;
int ret = avformat_open_input(&s, url, NULL, NULL);
if (ret < 0)
    abort();

위 코드는 AVFormatContext를 할당하고, 파일을 열어(포맷을 자동인식) 미디어파일 헤더를 읽고, 정보를 s에 내보낸다. 어떤 포맷은 헤더를 가지고 있지 않거나 충분한 정보를 저장하고 있지 않으므로, 놓친 정보를 찾기 위해서 avformat_find_stream_info() 함수를 호출해서 몇 프레임을 디코드를 시도해 보아라.

몇몇 경우에 avformat_alloc_context()를 호출해서 AVFormatContext를 미리 할당하고 avformat_open_input()에 전달하기 전에 조정하는 것이 좋습니다. lavf 내부 I/O layer대신에 입력 데이터를 읽기 위해서 custom function을 호출하려는 경우이다. 그렇게 하려면 avio_alloc_context()로 AVIOContext를 생성하고, 읽기콜백에 그것을 전달하세요. 그리고 AVFormatContext의 pb필드를 새로 생성한 AVIOContext로 설정해라.

파일포맷은 avformat_open_input()이 리턴할 때까지 알 수 없으므로, 미리 할당된 context에 private options을 디먹서에 설정하는 것은 불가능하다. 대신에 avformat_open_input()함수에 AVDictionary를 전달해서 가능하다.

AVDictionary *options = NULL;
av_dict_set(&options, "video_size", "640x480", 0);
av_dict_set(&options, "pixel_format", "rgb24", 0);
if (avformat_open_input(&s, url, NULL, &options) < 0)
    abort();
av_dict_free(&options);

이 코드는 private options인 'video_size', 'pixel_format'을 디먹서에게 전달한다. rowvideo 디먹서의 경우에 필요하다. 그렇지 않으면 원시 비디오 데이터를 어떻게 해석할지 알 수 없다. 만약 원시 비디오와 다르다고 판명되면, 디먹서에 의해 인식되지 않으므로 적용되지 않을 것이다. 인식되지 않은 그런 옵션은 options dictionary에 반환된다.(인식된 옵션들은 사용된다.) 다음처럼 인식되지 않은 옵션들은 원하는 대로 처리할 수도 있다.

AVDictionaryEntry *e;
if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) {
    fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key);
    abort();
}

파일 읽기가 끝난 후에 avformat_close_input()을 호출해야 한다. 파일과 관련된 모든 것들을 해제한다.

열린 파일에서 읽기

열린 AVFormatContext에서 데이터를 읽는 것은 av_read_frame()를 반복적으로 호출하면 된다. 호출할 때마다 인코딩된 데이터인 하나의 AVStream을 포함한 AVPacket(AVPacket.stream_index번호로 식별된다.)을 리턴한다. 데이터를 디코딩하려면 패킷을 libavcodec의 디코딩 함수인 avcodec_send_packet()이나 avcodec_decode_subtitle2()에 직접 전달할 수 있다.

AVPacket.pts, AVPacket.dts, AVPacket.duration은 타이밍정보가 설정된다. 만약 스트림이 제공하지 않는다면 pts와 dts가 AV_NOPTS_VALUE이고 duration은 0이다. 타이밍 정보는 AVStream.time_base단위로 표시됩니다. 즉, 시간단위를 곱하여 초로 변환한다.

반환된 패킷에 AVPacket.buf가 설정되어 있으면 패킷이 동적으로 할당되므로 사용자가 이를 무한정 유지할 수 있다. 그렇지 않으면 AVPacket.buf는 NULL이고, 패킷 데이터는 디먹서 안의 정적 저장소에 백업되고(backed) 파일을 닫거나 av_read_frame()를 호출할 때까지만 유효하다. 더 사용하려면 av_dup_packet()함수가 av_malloc()를 호출해서 그것을 복사할 수 있다. 두 경우 모두 더 이상 필요하지 않으면 av_packet_unref()를 호출해서 패킷을 해제한다.

외부링크