RaGo

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libavcodec/avcodec.h> #include <libavdevice\avdevice.h> #include <libavfilter\avfilter.h> #include <libavformat\avformat.h> #include <libavutil\avutil.h> int main() { av_register_all(); //ffmpeg를 사용하기전 초기화 AVCodec * pVideoCodec; AVCodec * pAudioCodec; AVPacket packet = *av_packet_alloc(); //패킷 데이터 //av_init_packet(&packet); //av_new_packet(&packet, AV_INPUT_BUFFER_PADDING_SIZE); AVCodecContext * m_Context; //디코딩 정보 AVFormatContext * pFormatCtx = NULL; int ret = avformat_open_input(&pFormatCtx, "E:\\sample.mp4", NULL, NULL); //미디어 파일 열기 file주소 or URL //파일의 헤더로 부터 파일 포맷에 대한 정보를 읽어낸 뒤 AVFormatContext에 저장한다. //그 뒤의 인자들은 각각 Input Source (스트리밍 URL이나 파일경로), Input Format, demuxer의 추가옵션 이다. if (ret != 0) { av_log(NULL, AV_LOG_ERROR, "File Open Failed\n"); exit(-1); } ret = avformat_find_stream_info(pFormatCtx, NULL); //열어놓은 미디어 파일의 스트림 정보를 가져온다 if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Fail to get Stream Inform\n"); exit(-1); } int VSI = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);//비디오 스트림 정보를 가져온다. int ASI = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, VSI, NULL, 0);//오디오 스트림 정보를 가져온다. /*분석중...*/ av_dump_format(pFormatCtx, 0, "E:\\sample.mp4", 0); /*codec_id에 맞는 비디오 디코더를 찾는다*/ pVideoCodec = avcodec_find_decoder(pFormatCtx->streams[VSI]->codecpar->codec_id); if (pVideoCodec == NULL) { av_log(NULL, AV_LOG_ERROR, "No Decoder\n"); exit(-1); } pAudioCodec = avcodec_find_decoder(pFormatCtx->streams[ASI]->codecpar->codec_id); if (pAudioCodec == NULL) { av_log(NULL, AV_LOG_ERROR, "No Decoder\n"); exit(-1); } /*디코더 메모리 할당*/ AVCodecContext *pVCtx = avcodec_alloc_context3(pVideoCodec); AVCodecContext *pACtx = avcodec_alloc_context3(pAudioCodec); //추가한코드 분석중 if(avcodec_parameters_to_context(pVCtx, pFormatCtx->streams[VSI]->codecpar)<0) { printf("avcodec_parameters_to_context Error\n"); exit(-1); } if (avcodec_parameters_to_context(pACtx, pFormatCtx->streams[ASI]->codecpar)<0) { printf("avcodec_parameters_to_context Error\n"); exit(-1); } /* *디코더 정보를 찾을 수 있다면 AVContext에 그 정보를 넘겨줘서 Decoder를 초기화 함 *세번째 인자 : 디코더 초기화에 필요한 추가 옵션. 비트레이트 정보나 스레트 사용여부를 정해줄 수 있다. */ if (avcodec_open2(pVCtx, pVideoCodec, NULL) < 0) { av_log(NULL, AV_LOG_ERROR, "Fail to Initialize Decoder\n"); exit(-1); } if (avcodec_open2(pACtx, pAudioCodec, NULL) < 0) { av_log(NULL, AV_LOG_ERROR, "Fail to Initialize Decoder\n"); exit(-1); } AVFrame *pAFrame = av_frame_alloc(); //alloc 않하면 밑에서 프레임을 받아올수 없다. AVFrame *pVFrame = av_frame_alloc(); //alloc 않하면 밑에서 프레임을 받아올수 없다. while (av_read_frame(pFormatCtx, &packet) == 0) { if (packet.stream_index == VSI) {//패킷이 비디오 패킷이면... if (ret = avcodec_send_packet(pVCtx, &packet)) { //패킷 데이터를 디코더의 입력으로 제공합니다. printf("avcodec_send_packet failed %d %d %d\n", ret, AVERROR(EINVAL), AVERROR(ENOMEM)); } while (avcodec_receive_frame(pVCtx, pVFrame) >= 0) { //디코더의 출력을 pVFrame으로 받아옵니다. //TODO 디코딩에 성공하면 이부분에서 pVframe을 가져와 사용한다. } } else if (packet.stream_index == ASI) {//패킷이 오디오 패킷이면... if (ret = avcodec_send_packet(pACtx, &packet)) { printf("avcodec_send_packet failed %d %d %d\n", ret, AVERROR(EINVAL), AVERROR(ENOMEM)); } while (avcodec_receive_frame(pACtx, pAFrame) >= 0) { //TODO 디코딩에 성공하면 이부분에서 pVframe을 가져와 사용한다. } } av_packet_unref(&packet); } }

ffmpeg function Reference

* 모든(?) 혹은 대부분의 function은 실행에 실패했을경우 음수값을 반환하며 음수값에따라 오류를 판단한다.

av_register_all() //libavformat을 초기화합니다


avformat_open_input() //파일(스트림)을 열고 해더를 읽습니다.

avformat_find_stream_info() //스트림 정보를 얻기 위해 미디어 파일의 패킷을 읽습니다.

av_find_best_stream() //스트림에서 사용자가 원하는 스트림을 찾아 int형으로 반환합니다. [비디오, 오디오, 자막]
avcodec_find_decoder() //매개변수의 코덱 ID가 일치하는 디코더를 찾습니다.
avcodec_alloc_context3() //코덱을 이용하여AVCodecContext를 할당 필드를 디폴트 치로 설정하고 포인터를 반환합니다.
avcodec_parameters_to_context() //AVCodecParameters을 기반으로 AVCodecContext를 채웁니다.
avcodec_open2() //AVCodecContext를 주어진 AVCodec을 이용해 초기화 합니다. 이 작업을 하기전에 avcodec_alloc_context3()가 먼저 처리되야합니다.

av_packet_alloc() //AVPacket을 메모리에 할당하고 필드를 기본값으로 설정합니다.

av_init_packet() //패킷의 필드를 기본값으로 초기화합니다.

av_new_packet() //패킷을 원하는 크기로 할당하고 초기화합니다.


av_frame_alloc() //AVFrame을 메모리에 할당하고 필드를 기본값으로 설정합니다.


avcodec_send_packet() // 패킷 데이터를 디코더에 입력합니다.
av_read_frame() // 스트림의 다음의 프레임을 리턴합니다.
avcodec_receive_frame() // 디코더에서 디코딩 된 프레임을 반환합니다.
av_packet_unref() // 패킷이 참조하는 버퍼를 참조 해제하고 나머지 패킷 필드를 기본값으로 재설정


ffmpeg Struct Reference

AVCodec

AVCodecContext

AVPacket

AVFormatContext

AVFrame