FFmpeg과 FFprobe 갈길이멀다

Sieun Sim·2020년 6월 1일
1
post-custom-banner

FFmpeg을 빌드하면
FFprobe 폴더와 FFmpeg폴더가 나뉘는데, 먼저 FFprobe는

FFprobe

(https://ffmpeg.org/ffprobe.html 의 설명 해석해봄)

FFprobe는 멀티미디어 스트림으로부터 정보를 모으고 사람과 기계가 읽을수 있게 프린트한다. 예를 들어 이것은 멀티미디어 스트림에 의해 쓰인 컨테이너와 컨테이너 속 각 미디어 스트림의 포맷을 체크하는데 쓰일 수 있다. 만약 url이 input에 구체화되어 있다면, ffprobe는 url 컨텐츠를 open하고 조사할 것이다. 만약 url이 멀티미디어 파일로써 열릴 수 없거나 인식되지 않으면, 종료 코드가 반환될 것이다.

FFprobe는 단일 어플리케이션으로도 쓰이고 textual 필터와의 조합으로도 쓰인다(더 정교한 통계적 프로세싱이나 플로팅 등으로 수행됨)

ffprobe에 의해 지원되는 포맷을 리스팅하거나 어떤 정보를 보여줄 지 정하거나 어떻게 보여줄 지를 정하기 위해 옵션이 쓰인다.

ffprobe 산출물은 textual 필터를 통해 쉽게 읽히도록 디자인 되어있으며 print_format 옵션으로 구체화되는 writer에 의해 정의되는 form의 하나 이상의 섹션들로 구성되어 있다.

섹션들은 다른 얽혀진 섹션들을 포함하거나 유니크한 이름으로 구분된다.

컨테이너에 저장되거나 스트림에 있는 Metadata 태그들은 FORMAT, STREAM이나 PROGRAM_STREAM 섹션에 의해 인식되고 프린트 되어진다.

한줄요약: ffprobe는 간단한 멀티미디어 스트림 분석기


FFMpeg

FFMpeg의 상위 dir들 중 fftools는 그야말로 ffmpeg을 사용하기 위한 코드들이 있으며 fftools/ffmpeg.c 에 main 함수가 있다. cmdutils에는 커맨드라인의 사용 커맨드라인


다양한 옵션을 가진 FFMpeg의 HLS.c 파일만 해도 2400줄인데 우선 천천히 HLS만이라도 분석해볼까 한다.

apple http steam은 순차적으로 재생되는 미디어 조각 파일들의 플레이리스트로 구성되어 있다. 하나의 비디오 컨텐츠에 대해 다른 bandwidth들에 따라 여러 플레이리스트들이 존재할 수 있으며, 한번에 하나의 bandwidth 변수로 병렬적으로 플레이된다. 이 경우에, 유저는 여러 리스트들을 가지고있는 메인 플레이리스트의 url를 제공받는다. -> master playlist에 대한 설명

KeyType

enum KeyType {
    KEY_NONE,
    KEY_AES_128,
    KEY_SAMPLE_AES
};
  • HLS는 AES128 암호화가 가능한 것으로 알고 있는데 그 옵션인듯하다

Segment

struct segment {
    int64_t duration;
    int64_t url_offset;
    int64_t size;
    char *url;
    char *key;
    enum KeyType key_type;
    uint8_t iv[16];
    /* associated Media Initialization Section, treated as a segment */
    struct segment *init_section;
};

하나의 조각을 표현하는 스트럭트. 지속 시간, offset, 사이즈, url 스트링, key와 key종류(보통 0->None으로 사용했던듯), iv는뭔지 아직 모르겠고 또다른 segment를 가리키는 포인터 init_section이 있다. init_section은 첫번째 조각을 나타내는 걸까?

각각의 플레이리스트는 자기만의 demuxer를 가진다. 지금 active하다면 open AVIOContext를 가진다. 그리고 이 스트림의 다음 패킷을 가지는 AVPacket을 포함할 수 있다.

AV?
AV는 아마 Audio-Visual의 약자인 거 같은데 확실하지않다 대체 뭐라고 검색해야 정확히 나오는건지...

AVIOContext
libavformat/avio.h에 선언되어 있으며 private options를 위한 클래이스이다.
AVIOContext Struct는 Bytestream IO Context로,
libavformat의 avformat_open_input()을 호출 할 때 이 컨텍스트를 설정해서 콘텐츠의 경로를 설정할 수 있다고 한다.
이 그림은 읽거나 쓸 때 buffer, buf_ptr, buf_ptr_max, buf_end, buf_size, and pos 간의 관계를 나타낸다


Reading

Writing

간단하게 버퍼의 시작포인터, 크기, 현재 버퍼의 위치, 버퍼의 끝 위치 부터 체크썸이나 eof_reached, 파일 전체에서의 현재 버퍼의 위치 등 파일 정보를 나타낸 구조체이다.

libavformat/avio.h 에는 AVIODir~ 등 경로 설정 구조체도 있는 등 주로 버퍼나 파일 접근에 관한 내용인 것 같다.

Playlist

struct playlist {
    char url[MAX_URL_SIZE];
    AVIOContext pb;
    uint8_t* read_buffer;
    AVIOContext *input;
    int input_read_done;
    AVIOContext *input_next;
    int input_next_requested;
    AVFormatContext *parent;
    int index;
    AVFormatContext *ctx;
    AVPacket pkt;
    int has_noheader_flag;

    /* main demuxer streams associated with this playlist
     * indexed by the subdemuxer stream indexes */
    AVStream **main_streams;
    int n_main_streams;

    int finished;
    enum PlaylistType type;
    int64_t target_duration;
    int start_seq_no;
    int n_segments;
    struct segment **segments;
    int needed;
    int broken;
    int cur_seq_no;
    int last_seq_no;
    int m3u8_hold_counters;
    int64_t cur_seg_offset;
    int64_t last_load_time;

    /* Currently active Media Initialization Section */
    struct segment *cur_init_section;
    uint8_t *init_sec_buf;
    unsigned int init_sec_buf_size;
    unsigned int init_sec_data_len;
    unsigned int init_sec_buf_read_offset;

    char key_url[MAX_URL_SIZE];
    uint8_t key[16];

    /* ID3 timestamp handling (elementary audio streams have ID3 timestamps
     * (and possibly other ID3 tags) in the beginning of each segment) */
    int is_id3_timestamped; /* -1: not yet known */
    int64_t id3_mpegts_timestamp; /* in mpegts tb */
    int64_t id3_offset; /* in stream original tb */
    uint8_t* id3_buf; /* temp buffer for id3 parsing */
    unsigned int id3_buf_size;
    AVDictionary *id3_initial; /* data from first id3 tag */
    int id3_found; /* ID3 tag found at some point */
    int id3_changed; /* ID3 tag data has changed at some point */
    ID3v2ExtraMeta *id3_deferred_extra; /* stored here until subdemuxer is opened */

    int64_t seek_timestamp;
    int seek_flags;
    int seek_stream_index; /* into subdemuxer stream array */

    /* Renditions associated with this playlist, if any.
     * Alternative rendition playlists have a single rendition associated
     * with them, and variant main Media Playlists may have
     * multiple (playlist-less) renditions associated with them. */
    int n_renditions;
    struct rendition **renditions;

    /* Media Initialization Sections (EXT-X-MAP) associated with this
     * playlist, if any. */
    int n_init_sections;
    struct segment **init_sections;
};

플레이리스트 구조체에는 url, AVIOContext 부터 현재/마지막 시퀀스번호 부터 현재 실행중인 미디어 섹션의 정보 등 플레이리스트와 관련된 정보들이 있다.

struct rendition {
    enum AVMediaType type;
    struct playlist *playlist;
    char group_id[MAX_FIELD_LEN];
    char language[MAX_FIELD_LEN];
    char name[MAX_FIELD_LEN];
    int disposition;
};

rendition은 외부적인 플레이리스트이거나 플레이리스트가 NULL인 경우 메인 플레이리스트에 포함되어 있다. Rendition은 subtitle이나 audio stream의 대체제이다.
미디어타입, 플레이리스트, 언어, 이름 등으로 구성되어있다.


struct variant {
    int bandwidth;

    /* every variant contains at least the main Media Playlist in index 0 */
    int n_playlists;
    struct playlist **playlists;

    char audio_group[MAX_FIELD_LEN];
    char video_group[MAX_FIELD_LEN];
    char subtitles_group[MAX_FIELD_LEN];
};

variant struct는 bandwidth 정보를 포함하며, 적어도 메인 미디어 플레이리스트를 가지고 있다.

post-custom-banner

0개의 댓글