FFMPEG 영상 열기부터 각 프레임 가져오기 까지
Programming/C and C++2018. 9. 23. 23:26
#include <stdio.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(int argc, char *argv[]) { AVCodec * pVideoCodec; //비디오코덱 정보 AVCodec * pAudioCodec; //오디오코덱 정보 AVFrame *pAFrame = av_frame_alloc(); //각 오디오 프레임 정보 AVFrame *pVFrame = av_frame_alloc(); //각 비디오 프레임 정보 AVPacket packet = *av_packet_alloc(); //패킷 데이터 AVFormatContext * pFormatCtx = NULL; if (avformat_open_input(&pFormatCtx, "C:\\sample.mp4", NULL, NULL) < 0) { av_log(NULL, AV_LOG_ERROR, "File Open Failed\n"); exit(-1); } // 미디어 파일 열기 file주소 or URL // 파일의 헤더로 부터 파일 포맷에 대한 정보를 읽어낸 뒤 AVFormatContext에 저장한다. // 그 뒤의 인자들은 각각 Input Source (스트리밍 URL이나 파일경로), Input Format, demuxer의 추가옵션 이다. if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { av_log(NULL, AV_LOG_ERROR, "Fail to get Stream Info\n"); exit(-1); } //미디어 파일의 스트림 정보를 가져온다 int VSI = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pVideoCodec, 0);//비디오 스트림 정보를 가져온다. int ASI = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, VSI, &pAudioCodec, 0);//오디오 스트림 정보를 가져온다. // 1 : 미디어 파일 핸들 // 2 : 찾을 스트림의 유형 비디오,오디오등 // 3 : 사용자가 요구한 스트림의 번호 ?? // 4 : ?? // 5 : NULL이 아닐경우 AVCodec ** 형식으로 스트림의 디코더 코덱 정보를 반환합니다. // 6 : Flag 현재 쓰이지 않음 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); } //스트림 정보의 파라미터 값을 기반으로 디코더를 채 웁니다. double time = av_q2d(pFormatCtx->streams[VSI]->time_base) * pFormatCtx->streams[VSI]->duration; printf("TIme Base : %lf", av_q2d(pFormatCtx->streams[VSI]->time_base)); printf("[재생시간 초]%.2lf", time); 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); } // 디코더 정보를 찾을 수 있다면 AVContext에 그 정보를 넘겨줘서 Decoder를 초기화 함 // 세번째 인자 : 디코더 초기화에 필요한 추가 옵션. 비트레이트 정보나 스레트 사용여부를 정해줄 수 있다. while (av_read_frame(pFormatCtx, &packet) == 0) { int err = 0; double time = av_q2d(pFormatCtx->streams[VSI]->time_base) * packet.pts; //현재 시간 if (packet.stream_index == VSI) {//패킷이 비디오 패킷이면... if (err = avcodec_send_packet(pVCtx, &packet)) { //패킷 데이터를 디코더의 입력으로 제공합니다. printf("avcodec_send_packet failed %d %d %d\n", err, AVERROR(EINVAL), AVERROR(ENOMEM)); } if (avcodec_receive_frame(pVCtx, pVFrame) >= 0) { //디코더의 출력을 pVFrame으로 받아옵니다. //TODO 디코딩에 성공하면 이부분에서 pVframe을 가져와 사용한다. printf("%.2lf\n", time); } } else if (packet.stream_index == ASI) {//패킷이 오디오 패킷이면... if (err = avcodec_send_packet(pACtx, &packet)) { printf("avcodec_send_packet failed %d %d %d\n", err, AVERROR(EINVAL), AVERROR(ENOMEM)); } if (avcodec_receive_frame(pACtx, pAFrame) >= 0) { //TODO 디코딩에 성공하면 이부분에서 pVframe을 가져와 사용한다. } } av_packet_unref(&packet); } // av_read_frame 스트림에서 다음 프레임을 가져와 페킷으로 리턴합니다. // avcodec_send_packet 패킷 데이터를 디코더의 입력으로 제공합니다. // avcodec_receive_frame 디코딩한 결과가 반환됩니다. return 0; }
'Programming > C and C++' 카테고리의 다른 글
ffmpeg decode (ffmpeg을 이용한 디코더) C (0) | 2018.05.08 |
---|