ffmpeg decode (ffmpeg을 이용한 디코더) C
#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() //파일(스트림)을 열고 해더를 읽습니다.
av_packet_alloc() //AVPacket을 메모리에 할당하고 필드를 기본값으로 설정합니다.
av_init_packet() //패킷의 필드를 기본값으로 초기화합니다.
av_new_packet() //패킷을 원하는 크기로 할당하고 초기화합니다.
av_frame_alloc() //AVFrame을 메모리에 할당하고 필드를 기본값으로 설정합니다.
ffmpeg Struct Reference
'Programming > C and C++' 카테고리의 다른 글
FFMPEG 영상 열기부터 각 프레임 가져오기 까지 (0) | 2018.09.23 |
---|