RaGo

#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