欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ffmpeg音视频同步

程序员文章站 2022-07-02 08:52:09
...

没有实现,可能是时间戳同步问题 

#include <stdio.h>
#include<iostream>
#include<Windows.h>
#define __STDC_CONSTANT_MACROS

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/imgutils.h"
#include "libavutil/time.h"
#include "libavutil/avstring.h"
#include "libswresample/swresample.h"
#include "SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <SDL/SDL.h>
#ifdef __cplusplus
};
#endif
#endif

/*
FIX: H.264 in some container format (FLV, MP4, MKV etc.) need
"h264_mp4toannexb" bitstream filter (BSF)
*Add SPS,PPS in front of IDR frame
*Add start code ("0,0,0,1") in front of NALU
H.264 in some container (MPEG2TS) don't need this BSF.
*/
//'1': Use H.264 Bitstream Filter 
#define USE_H264BSF 0

/*
FIX:AAC in some container format (FLV, MP4, MKV etc.) need
"aac_adtstoasc" bitstream filter (BSF)
*/
//'1': Use AAC Bitstream Filter 
#define USE_AACBSF 0



#define USE_SDL 1

#define SWR_CH_MAX 32
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio

/* The output bit rate in bit/s */
#define OUTPUT_BIT_RATE 96000
/* The number of output channels */
#define OUTPUT_CHANNELS 2

//Refresh Event
#define SFM_REFRESH_EVENT  (SDL_USEREVENT + 1)

#define SFM_BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit = 0;
#pragma region print info function

//Show Dshow Device
void show_dshow_device() {
	AVFormatContext *ifmt_ctx = avformat_alloc_context();
	AVDictionary* options = NULL;
	av_dict_set(&options, "list_devices", "true", 0);
	AVInputFormat *iformat = av_find_input_format("dshow");
	printf("========Device Info=============\n");
	avformat_open_input(&ifmt_ctx, "video=dummy", iformat, &options);
	printf("================================\n");
}

//Show Dshow Device Option
void show_dshow_device_option() {
	AVFormatContext *ifmt_ctx = avformat_alloc_context();
	AVDictionary* options = NULL;
	av_dict_set(&options, "list_options", "true", 0);
	AVInputFormat *iformat = av_find_input_format("dshow");
	printf("========Device Option Info======\n");
	avformat_open_input(&ifmt_ctx, "video=USB2.0 PC CAMERA", iformat, &options);
	printf("================================\n");
}

//Show VFW Device
void show_vfw_device() {
	AVFormatContext *ifmt_ctx = avformat_alloc_context();
	AVInputFormat *iformat = av_find_input_format("vfwcap");
	printf("========VFW Device Info======\n");
	avformat_open_input(&ifmt_ctx, "list", iformat, NULL);
	printf("=============================\n");
}

//Show AVFoundation Device
void show_avfoundation_device() {
	AVFormatContext *ifmt_ctx = avformat_alloc_context();
	AVDictionary* options = NULL;
	av_dict_set(&options, "list_devices", "true", 0);
	AVInputFormat *iformat = av_find_input_format("avfoundation");
	printf("==AVFoundation Device Info===\n");
	avformat_open_input(&ifmt_ctx, "", iformat, &options);
	printf("=============================\n");
}
#pragma endregion

int sfp_refresh_thread(void *opaque)
{
	thread_exit = 0;
	while (!thread_exit) {
		SDL_Event event;
		event.type = SFM_REFRESH_EVENT;
		SDL_PushEvent(&event);
		SDL_Delay(40);
	}
	thread_exit = 0;
	//Break
	SDL_Event event;
	event.type = SFM_BREAK_EVENT;
	SDL_PushEvent(&event);

	return 0;
}
static  Uint8  *audio_chunk;
static  Uint32  audio_len;
static  Uint8  *audio_pos;
/* The audio function callback takes the following parameters:
* stream: A pointer to the audio buffer to be filled
* len: The length (in bytes) of the audio buffer
*/
void  fill_audio(void *udata, Uint8 *stream, int len) {
	//SDL 2.0
	SDL_memset(stream, 0, len);
	if (audio_len == 0)
		return;

	len = (len>audio_len ? audio_len : len);	/*  Mix  as  much  data  as  possible  */

	SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
	audio_pos += len;
	audio_len -= len;
}
static char *dup_wchar_to_utf8(wchar_t *w)
{
	char *s = NULL;
	int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
	s = (char *)av_malloc(l);
	if (s)
		WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
	return s;
}

//setup_array函数摘自ffmpeg例程
static void setup_array(uint8_t* out[SWR_CH_MAX], AVFrame* in_frame, int format, int samples)
{
	if (av_sample_fmt_is_planar((AVSampleFormat)format))
	{
		int i; int plane_size = av_get_bytes_per_sample((AVSampleFormat)(format & 0xFF)) * samples; format &= 0xFF;

		//从decoder出来的frame中的data数据不是连续分布的,所以不能这样写:
		in_frame->data[0] + i*plane_size;
		for (i = 0; i < in_frame->channels; i++)
		{
			out[i] = in_frame->data[i];
		}
	}
	else
	{
		out[0] = in_frame->data[0];
	}
}


int main(int argc, char* argv[])
{
	
	AVFormatContext	*ifmt_ctx_video = NULL;
	AVFormatContext	*ifmt_ctx_audio = NULL;
	AVCodecContext	*inCodecCtx_v;
	AVCodecContext	*inCodecCtx_a;
	int in_videoindex;
	int in_audioindex;
	AVCodec			*in_video_Codec = NULL;
	AVCodec			*in_audio_Codec = NULL;

	AVAudioFifo *fifo = NULL;

	AVFormatContext *ofmt_ctx = NULL;
	AVOutputFormat *ofmt = NULL;
	AVCodecContext	*outCodecCtx_v = NULL;
	AVCodecContext	*outCodecCtx_a = NULL;
	int out_videoindex;
	int out_audioindex;
	AVStream		*out_video_st = NULL;
	AVStream		*out_audio_st = NULL;
	AVCodec			*out_video_Codec = NULL;
	AVCodec			*out_audio_Codec = NULL;

	//AVPacket		pkt;
	int				ret = -1;
	int				got_frame = -1;
	int				got_packet = -1;
	int64_t cur_pts_v = 0, cur_pts_a = 0;
	static int64_t audio_pts = 0;

	int frame_index = 0;
	int frame_index_a = 0;
	//const char  *out_filename = "rtmp://localhost:1935/live/room";;
	const char  *out_filename = "d:/test33.flv";
	int64_t start_time = 0;



	//av_register_all();
	avformat_network_init();
	//Register Device
	avdevice_register_all();

	//Show Dshow Device
	show_dshow_device();
	//Show Device Options
	show_dshow_device_option();
	//Show VFW Options
	show_vfw_device();
	AVInputFormat *ifmt = av_find_input_format("dshow");
	
#pragma region open camera
	//分配视频输入上下文
	ifmt_ctx_video = avformat_alloc_context();
	//Set own video device's name
	char * psCameraName = dup_wchar_to_utf8(L"video=USB2.0 PC CAMERA");
	if (avformat_open_input(&ifmt_ctx_video, "video=USB2.0 PC CAMERA", ifmt, NULL) != 0) {
		printf("Couldn't open input stream.(无法打开视频输入流)\n");
		return -1;
	}

	if (avformat_find_stream_info(ifmt_ctx_video, NULL) < 0)
	{
		printf("Couldn't find stream information.(无法获取流信息)\n");
		return -1;
	}

	in_videoindex = -1;

	for (int i = 0; i < ifmt_ctx_video->nb_streams; i++)
	{
		if (ifmt_ctx_video->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			in_videoindex = i;
			break;
		}
	}

	if (in_videoindex == -1)
	{
		printf("Couldn't find a video stream.(没有找到视频流)\n");
		return -1;
	}
	in_video_Codec = avcodec_find_decoder(ifmt_ctx_video->streams[in_videoindex]->codecpar->codec_id);
	inCodecCtx_v = avcodec_alloc_context3(in_video_Codec);
	avcodec_parameters_to_context(inCodecCtx_v, ifmt_ctx_video->streams[in_videoindex]->codecpar);
	
	if (in_video_Codec == NULL)
	{
		printf("Codec not found.(无法找到视频解码器编码)\n");
		return -1;
	}
	if (avcodec_open2(inCodecCtx_v, in_video_Codec, NULL) < 0)
	{
		printf("Could not open codec.(无法打开视频解码器)\n");
		return -1;
	}
	//Dump Format video------------
	av_dump_format(ifmt_ctx_video, 0, "video=USB2.0 PC CAMERA", 0);
#pragma endregion

#pragma region open mic
	
	ifmt_ctx_audio = avformat_alloc_context();

	char * psMicDevName = dup_wchar_to_utf8(L"audio=麦克风 (USB2.0 MIC)");
	if (avformat_open_input(&ifmt_ctx_audio, psMicDevName, ifmt, NULL) != 0) {
		printf("Couldn't open input stream.(无法打开输入流)\n");
		return -1;
	}
	AVDictionary* pOptions = NULL;
	ifmt_ctx_audio->probesize = 1 * 1024;
	ifmt_ctx_audio->max_analyze_duration = 1 * AV_TIME_BASE;
	if (avformat_find_stream_info(ifmt_ctx_audio, &pOptions) < 0)
	{
		printf("Couldn't find stream information.(无法获取流信息)\n");
		return -1;
	}
	in_audioindex = -1;
	for (int i = 0; i < ifmt_ctx_audio->nb_streams; i++)
		if (ifmt_ctx_audio->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			in_audioindex = i;
			break;
		}
	if (in_audioindex == -1)
	{
		printf("Couldn't find a video stream.(没有找到视频流)\n");
		return -1;
	}
	in_audio_Codec = avcodec_find_decoder(ifmt_ctx_audio->streams[in_audioindex]->codecpar->codec_id);
	if (in_audio_Codec == NULL)
	{
		printf("Codec not found.(无法找到视频解码器编码)\n");
		return -1;
	}

	inCodecCtx_a = avcodec_alloc_context3(NULL);

	avcodec_parameters_to_context(inCodecCtx_a, ifmt_ctx_audio->streams[in_audioindex]->codecpar);
	
	if (avcodec_open2(inCodecCtx_a, in_audio_Codec, NULL) < 0)
	{
		printf("Could not open codec.(无法打开视频解码器)\n");
		return -1;
	}
	//Dump Format audio------------
	av_dump_format(ifmt_ctx_audio, 0, psMicDevName, 0);
	
#pragma endregion
#pragma region output
	avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_filename);
	if (!ofmt_ctx) {
		printf("Could not create output context(不能创建输出上下文)\n");
		return -1;
	}
	ofmt = ofmt_ctx->oformat;
	if (ifmt_ctx_video->streams[in_videoindex]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
	{

		//set codec context param
		out_video_Codec = avcodec_find_encoder(AV_CODEC_ID_H264);
		if (!out_video_Codec) {
			printf("can not find encoder !\n");
			return -1;
		}
		outCodecCtx_v = avcodec_alloc_context3(out_video_Codec);
		if (!outCodecCtx_v) {
			printf("can not alloc context!\n");
			return -1;
		}
		// take first format from list of supported formats
		outCodecCtx_v->pix_fmt = AV_PIX_FMT_YUV422P;
		outCodecCtx_v->height = ifmt_ctx_video->streams[in_videoindex]->codecpar->height;
		outCodecCtx_v->width = ifmt_ctx_video->streams[in_videoindex]->codecpar->width;
		outCodecCtx_v->sample_aspect_ratio = inCodecCtx_a->sample_aspect_ratio; // 采样宽高比:像素宽/像素高
		outCodecCtx_v->time_base.num = 1;
		outCodecCtx_v->time_base.den = 25;
		outCodecCtx_v->framerate = inCodecCtx_v->framerate;
		outCodecCtx_v->bit_rate = 400000;
		outCodecCtx_v->gop_size = 250;

		if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
			outCodecCtx_v->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

		outCodecCtx_v->qmin = 10;
		outCodecCtx_v->qmax = 51;
		outCodecCtx_v->max_b_frames = 3;

		//Optional Param  
		AVDictionary *param = 0;
		av_dict_set(&param, "preset", "ultrafast", 0);
		//解码时花屏,加上有花屏,去掉有延时
		av_dict_set(&param, "tune", "zerolatency", 0);
		//av_dict_set(&param, "rtbufsize", 3041280 , 0);
		if (avcodec_open2(outCodecCtx_v, out_video_Codec, &param) < 0) {
			printf("Failed to open encoder! (编码器打开失败!)\n");
			return -1;
		}
		out_video_st = avformat_new_stream(ofmt_ctx, out_video_Codec);

		if (!out_video_st)
		{
			printf("can not new stream for output!\n");
			return -1;
		}
		out_video_st->time_base.num = 1;
		out_video_st->time_base.den = 25;
		//video_st->codec = oCodecCtx;
		avcodec_parameters_from_context(out_video_st->codecpar, outCodecCtx_v);
		out_videoindex = out_video_st->index;

	}
	
	if (ifmt_ctx_audio->streams[in_audioindex]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
	{
		/*
		for (int i = 0; i < ifmt_ctx_audio->nb_streams; i++) {
			//根据输入流创建输出流(Create output AVStream according to input AVStream)
			AVStream *in_stream = ifmt_ctx_audio->streams[i];
			AVCodec *codec = NULL;
			codec = avcodec_find_decoder(in_stream->codecpar->codec_id);

			AVStream *out_stream = avformat_new_stream(ofmt_ctx, codec);
			if (!out_stream) {
				printf("Failed allocating output stream\n");
				ret = AVERROR_UNKNOWN;
				goto end;
			}
			out_audioindex = out_stream->index;
			AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
			ret = avcodec_parameters_to_context(codec_ctx, in_stream->codecpar);
			if (ret < 0)
			{
				printf("Failed to copy in_stream codecpar to codec context\n");
				goto end;
			}
			codec_ctx->codec_tag = 0;
			if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
				codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
			ret = avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);
			out_stream->codecpar->codec_tag = 0;


			if (ret < 0)
			{
				printf("Failed to copy codec context to out_stream codecpar context\n");
				goto end;
			}
			//avcodec_free_context(&codec_ctx);
		}
		*/
	
		//set codec context param
		out_audio_Codec = avcodec_find_encoder(AV_CODEC_ID_MP3);
		if (!out_audio_Codec) {
			printf("can not find encoder !\n");
			return -1;
		}
		//初始化音频输出流
		//out_audio_st = avformat_new_stream(ofmt_ctx, out_audio_Codec);
		out_audio_st = avformat_new_stream(ofmt_ctx, out_audio_Codec);
		if (!out_audio_st)
		{
			printf("can not new stream for output!\n");
			return -1;
		}
		out_audioindex = out_audio_st->index;
		//分配音频输出上下文
		outCodecCtx_a = avcodec_alloc_context3(out_audio_Codec);
		if (!outCodecCtx_a) {
			printf("can not alloc context!\n");
			return -1;
		}
		avcodec_parameters_to_context(outCodecCtx_a, out_audio_st->codecpar);
		

		//set codec context param
		//use default audio encoder
		//use the input audio encoder
		outCodecCtx_a->sample_rate = inCodecCtx_a->sample_rate;
		outCodecCtx_a->channel_layout = inCodecCtx_a->channel_layout;
		outCodecCtx_a->channels = av_get_channel_layout_nb_channels(inCodecCtx_a->channel_layout);
		if (outCodecCtx_a->channel_layout == 0)
		{
			outCodecCtx_a->channel_layout = AV_CH_LAYOUT_STEREO;
			outCodecCtx_a->channels = av_get_channel_layout_nb_channels(outCodecCtx_a->channel_layout);
		}
		//AV_SAMPLE_FMT_FLTP
		outCodecCtx_a->sample_fmt = AV_SAMPLE_FMT_S16P;
		//outCodecCtx_a->sample_fmt = out_audio_Codec->sample_fmts[0];

		//AVRational time_base = { 1, inCodecCtx_a->sample_rate };
		//out_audio_st->time_base = time_base;
		//AVRational time_base = { 1, ifmt_ctx_audio->streams[in_audioindex]->codecpar->sample_rate };
		//out_audio_st->time_base = time_base;
		//out_audioindex = out_audio_st->index;
		//outCodecCtx_a->time_base = time_base;

		outCodecCtx_a->codec_tag = 0;
		if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
			outCodecCtx_a->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
		if (avcodec_open2(outCodecCtx_a, out_audio_Codec, 0) < 0)
		{
			//编码器打开失败,退出程序
			return -1;
		}
		avcodec_parameters_from_context(out_audio_st->codecpar,outCodecCtx_a);
		out_audio_st->codecpar->codec_tag = 0;
	
	}

	if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_READ_WRITE) < 0)
	{
		printf("can not open output file handle!\n");
		return -1;
	}
	

	if (avformat_write_header(ofmt_ctx, NULL) < 0)
	{
		printf("can not write the header of the output file!\n");
		return -1;
	}

	//Dump Format------------------
	av_dump_format(ofmt_ctx, 0, out_filename, 1);
#pragma endregion
	//prepare before decode and encode
	AVPacket *dec_packet = (AVPacket *)av_malloc(sizeof(AVPacket));
	AVPacket enc_packet;

#pragma region prepare image
	//
	////AVPacket pkt;
	//int y_size = oCodecCtx->width * oCodecCtx->height;
	//av_new_packet(&enc_packet, y_size * 3);
	
	//转码上下文
	struct SwsContext *img_convert_ctx;
	img_convert_ctx = sws_getContext(inCodecCtx_v->width, inCodecCtx_v->height,
		inCodecCtx_v->pix_fmt, outCodecCtx_v->width, outCodecCtx_v->height, AV_PIX_FMT_YUV422P, SWS_BICUBIC, NULL, NULL, NULL);

	struct SwsContext *img_convert_ctx_SDL;
	img_convert_ctx_SDL = sws_getContext(inCodecCtx_v->width, inCodecCtx_v->height,
		inCodecCtx_v->pix_fmt, outCodecCtx_v->width, outCodecCtx_v->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

	AVFrame	*pFrame_vedio, *pFrameYUV, *pFrameYUV_SDL;
	pFrameYUV = av_frame_alloc();
	pFrameYUV_SDL = av_frame_alloc();
	//设置帧的格式、宽度和高度,否则会出现
	//1.AVFrame.format is not set
	//2.AVFrame.width or height is not set
	pFrameYUV->format = outCodecCtx_v->pix_fmt;
	pFrameYUV->width = outCodecCtx_v->width;
	pFrameYUV->height = outCodecCtx_v->height;

	pFrameYUV_SDL->format = AV_PIX_FMT_YUV420P;
	pFrameYUV_SDL->width = outCodecCtx_v->width;
	pFrameYUV_SDL->height = outCodecCtx_v->height;

	// 存储图像数据
	uint8_t *out_buffer_vedio;
	// av_image_get_buffer_size:返回使用给定参数存储图像所需的数据量的字节大小
	out_buffer_vedio = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV422P, outCodecCtx_v->width, outCodecCtx_v->height, 1));
	// 根据指定的图像参数和提供的数组设置数据指针和线条(data pointers and linesizes)
	av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer_vedio, AV_PIX_FMT_YUV422P, outCodecCtx_v->width, outCodecCtx_v->height, 1);

	// 存储图像数据
	uint8_t *out_buffer_SDL;
	// av_image_get_buffer_size:返回使用给定参数存储图像所需的数据量的字节大小
	out_buffer_SDL = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, outCodecCtx_v->width, outCodecCtx_v->height, 1));
	// 根据指定的图像参数和提供的数组设置数据指针和线条(data pointers and linesizes)
	av_image_fill_arrays(pFrameYUV_SDL->data, pFrameYUV_SDL->linesize, out_buffer_SDL, AV_PIX_FMT_YUV420P, outCodecCtx_v->width, outCodecCtx_v->height, 1);
	
#pragma endregion

#pragma region prepare Mic
	
	//音频参数
	if (!(fifo = av_audio_fifo_alloc(outCodecCtx_a->sample_fmt, outCodecCtx_a->channels, 1)))
	{
		fprintf(stderr, "Could not allocate FIFO\n");
		return AVERROR(ENOMEM);
	}
	//Swr
	struct SwrContext *au_convert_ctx;
	au_convert_ctx = swr_alloc();
	au_convert_ctx = swr_alloc_set_opts(au_convert_ctx,
		av_get_default_channel_layout(outCodecCtx_a->channels), AV_SAMPLE_FMT_S16P, 44100,
		av_get_default_channel_layout(inCodecCtx_a->channels), inCodecCtx_a->sample_fmt, inCodecCtx_a->sample_rate,
		0,
		NULL);
	swr_init(au_convert_ctx);


	//Out Audio Param
	uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
	//AAC:1024  MP3:1152
	int out_nb_samples = inCodecCtx_a->frame_size;


	//FIX:Some Codec's Context Information is missing
	int64_t in_channel_layout = av_get_default_channel_layout(inCodecCtx_a->channels);
	

	AVFrame	*pFrame_audio, *pFrameMP3;
	pFrameMP3 = av_frame_alloc();
	//设置帧的格式、宽度和高度,否则会出现
	//1.AVFrame.format is not set
	//2.AVFrame.width or height is not set
	pFrameMP3->format = outCodecCtx_a->pix_fmt;
	pFrameMP3->nb_samples = outCodecCtx_a->frame_size;
	
	int stream_mapping_size = ifmt_ctx_audio->nb_streams;
	int *stream_mapping = (int *)av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));
	if (!stream_mapping) {
		ret = AVERROR(ENOMEM);
		goto end;
	}
#pragma endregion

	

#if USE_SDL
	
	//SDL----------------------------
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
		printf("Could not initialize SDL - %s\n", SDL_GetError());
		return -1;
	}
	int screen_w = 0, screen_h = 0;
	SDL_Window *screen;
	screen_w = outCodecCtx_v->width;
	screen_h = outCodecCtx_v->height;
	//screen = SDL_SetVideoMode(screen_w, screen_h, 0, 0);
	//SDL 2.0 Support for multiple windows
	screen = SDL_CreateWindow("Simplest FFmpeg Device", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
		screen_w, screen_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	if (!screen) {
		printf("SDL: could not set video mode - exiting:%s\n", SDL_GetError());
		return -1;
	}
	SDL_Texture *sdlTexture;
	//bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, screen);

	SDL_Renderer* sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
	Uint32 pixformat = 0;
	//IYUV: Y + U + V  (3 planes)
	//YV12: Y + V + U  (3 planes)
	pixformat = SDL_PIXELFORMAT_IYUV;

	sdlTexture = SDL_CreateTexture(sdlRenderer, pixformat, SDL_TEXTUREACCESS_STREAMING, outCodecCtx_v->width, outCodecCtx_v->height);
	SDL_Rect rect;
	rect.x = 0;
	rect.y = 0;
	rect.w = screen_w;
	rect.h = screen_h;
	//SDL End------------------------
	//------------------------------
	
	SDL_Thread *video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL);
	//
	SDL_Event event;

	//SDL_AudioSpec wanted_spec;
	////SDL_AudioSpec
	//wanted_spec.freq = 44100;
	//wanted_spec.format = AUDIO_S16SYS;
	//wanted_spec.channels = av_get_default_channel_layout(outCodecCtx_a->channels);
	//wanted_spec.silence = 0;
	//wanted_spec.samples = out_nb_samples;
	//wanted_spec.callback = fill_audio;
	//wanted_spec.userdata = inCodecCtx_a;

	//if (SDL_OpenAudio(&wanted_spec, NULL)<0) {
	//	printf("can't open audio.\n");
	//	return -1;
	//}
#endif // USE_SDL
	

	start_time = av_gettime();
	while (1) {
		//Wait
		SDL_WaitEvent(&event);
		if (event.type == SFM_REFRESH_EVENT)
		{
			av_init_packet(dec_packet);
			//Get an AVPacket
			if (av_compare_ts(cur_pts_v, ifmt_ctx_video->streams[in_videoindex]->time_base, cur_pts_a, ifmt_ctx_audio->streams[in_audioindex]->time_base) < 0) 
			{
				if (cur_pts_v > 10000)
				{
					thread_exit = 1;
				}
				got_frame = -1;
				got_packet = -1;
				if (av_read_frame(ifmt_ctx_video, dec_packet) >= 0)
				{
					if (dec_packet->stream_index == in_videoindex)
					{
						pFrame_vedio = av_frame_alloc();
						if (!pFrame_vedio) {
							printf("alloc pFrame Failed.\n");
							return -1;
						}
						//ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
						ret = avcodec_send_packet(inCodecCtx_v, dec_packet);
						got_frame = avcodec_receive_frame(inCodecCtx_v, pFrame_vedio);
						if (ret < 0)
						{
							av_frame_free(&pFrame_vedio);
							printf("Decode Error.\n");
							return -1;
						}
						if (got_frame == 0)
						{

							//转码成YUV格式
							sws_scale(img_convert_ctx, (const unsigned char* const*)pFrame_vedio->data, pFrame_vedio->linesize, 0, inCodecCtx_v->height, pFrameYUV->data, pFrameYUV->linesize);
							sws_scale(img_convert_ctx_SDL, (const unsigned char* const*)pFrame_vedio->data, pFrame_vedio->linesize, 0, inCodecCtx_v->height, pFrameYUV_SDL->data, pFrameYUV_SDL->linesize);

							//初始化封装包
							enc_packet.data = NULL;
							enc_packet.size = 0;
							av_init_packet(&enc_packet);

							//编码
							//ret = avcodec_encode_video2(oCodecCtx, &enc_packet, pFrameYUV, &got_encpicture);
							ret = avcodec_send_frame(outCodecCtx_v, pFrameYUV);
							//FIX : non-strictly-monotonic PTS
							AVRational time_base_in = { 1, AV_TIME_BASE }; //{ 1, 1000000 };
							AVRational time_base_conert = outCodecCtx_v->time_base;//{ 1, 1000 };
							pFrameYUV->pts = av_rescale_q(dec_packet->pts, time_base_in, time_base_conert);

							if (ret < 0)
							{
								av_frame_free(&pFrame_vedio);
								printf("Encode Error.\n");
								return -1;
							}
							got_packet = avcodec_receive_packet(outCodecCtx_v, &enc_packet);

							if (got_packet == 0)
							{
								
								enc_packet.stream_index = out_video_st->index;
								//FIX:No PTS (Example: Raw H.264)
								//Simple Write PTS

								if (enc_packet.pts == AV_NOPTS_VALUE)
								{
									//Write PTS
									AVRational time_base1 = ofmt_ctx->streams[out_videoindex]->time_base;
									//Duration between 2 frames (us)
									int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(ofmt_ctx->streams[out_videoindex]->r_frame_rate);
									//Parameters
									enc_packet.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);
									enc_packet.dts = enc_packet.pts;
									enc_packet.duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);
								}
								
									
								if (dec_packet->stream_index == in_videoindex)
								{
									//Delay
									AVRational time_base = { 1, AV_TIME_BASE };//{ 1, 1000 };
									AVRational time_base_q = ofmt_ctx->streams[out_videoindex]->time_base;
									int64_t pts_time = av_rescale_q(dec_packet->dts, time_base, time_base_q);
									int64_t now_time = av_rescale_q(av_gettime(), time_base, time_base_q);
									if (pts_time > now_time)
										av_usleep(pts_time - now_time);
								}
								//Write PTS
								AVRational time_base = ofmt_ctx->streams[out_videoindex]->time_base;//{ 1, 1000 };
								AVRational r_framerate1 = ifmt_ctx_video->streams[in_videoindex]->r_frame_rate;// { 50, 2 };
								AVRational time_base_q = { 1, AV_TIME_BASE };
								//Duration between 2 frames (us)
								int64_t calc_duration = (double)(AV_TIME_BASE)*(1 / av_q2d(r_framerate1));	
																											
								enc_packet.pts = av_rescale_q(frame_index*calc_duration, time_base_q, time_base);
								enc_packet.dts = enc_packet.pts;
								enc_packet.duration = av_rescale_q(calc_duration, time_base_q, time_base); //(double)(calc_duration)*(double)(av_q2d(time_base_q)) / (double)(av_q2d(time_base));
								enc_packet.pos = -1;


								//Print to Screen
								if (enc_packet.stream_index == in_videoindex) {
									frame_index++;
									printf("%8d Send video frames to output URL\n", frame_index);

								}
								cur_pts_v = enc_packet.pts;
								//写到输出上下文
								ret = av_interleaved_write_frame(ofmt_ctx, &enc_packet);
								
							}
							av_packet_unref(&enc_packet);							
						}
						
						av_frame_free(&pFrame_vedio);
						
					}
					av_packet_unref(dec_packet);
#if USE_SDL
					//int y_size = iCodecCtx->width * iCodecCtx->height;

					////SDL---------------------------
					//// 设置纹理数据
					//pFrameYUV_SDL->data[0] = out_buffer;              // Y
					//pFrameYUV_SDL->data[1] = out_buffer + y_size;      // U 
					//pFrameYUV_SDL->data[2] = out_buffer + y_size * 3 / 2;  // V

#if 0
					SDL_UpdateTexture(sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0]);
#else
					SDL_UpdateYUVTexture(sdlTexture, &rect,
						pFrameYUV_SDL->data[0], pFrameYUV_SDL->linesize[0],
						pFrameYUV_SDL->data[1], pFrameYUV_SDL->linesize[1],
						pFrameYUV_SDL->data[2], pFrameYUV_SDL->linesize[2]);
#endif
					// 清理渲染器
					SDL_RenderClear(sdlRenderer);

					// 将纹理数据copy到渲染器
					//将sdlRect区域的图像显示到dstsdlRect区域
					//SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );
					SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, &rect);
					// 显示
					SDL_RenderPresent(sdlRenderer);
					//SDL End-----------------------
#endif
				}
				
			}
			else
			{

				const int output_frame_size = outCodecCtx_a->frame_size;
				//int finished = 0;
				av_init_packet(dec_packet);
				dec_packet->data = NULL;
				dec_packet->size = 0;
				got_frame = -1;
				got_packet = -1;
				if (av_read_frame(ifmt_ctx_audio, dec_packet) >= 0)
				{
					
					if (dec_packet->stream_index == in_audioindex)
					{
						pFrame_audio = av_frame_alloc();
						if (!pFrame_audio) 
						{
							printf("alloc pFrame Failed.\n");
							return -1;
						}

						if (dec_packet->stream_index >= stream_mapping_size ||
							stream_mapping[dec_packet->stream_index] < 0) {
							av_packet_unref(dec_packet);
							continue;
						}

						//ret = avcodec_decode_audio4(inCodecCtx_a, pFrame, &got_picture, packet);
						int ret = avcodec_send_packet(inCodecCtx_a, dec_packet);
						got_frame = avcodec_receive_frame(inCodecCtx_a, pFrame_audio);
						if (ret < 0)
						{

							av_frame_free(&pFrame_audio);
							printf("Decode Error.\n");
							return -1;
						}
						if (got_frame == 0)
						{
							
							//写入fifo
							while (true)
							{
								int fifo_size = av_audio_fifo_size(fifo);
								if (fifo_size >= output_frame_size)
									break;
								uint8_t **converted_input_samples;
								converted_input_samples = (uint8_t **)calloc(outCodecCtx_a->channels,
									sizeof(converted_input_samples));
								ret = av_samples_alloc(converted_input_samples, NULL,
									outCodecCtx_a->channels,
									pFrame_audio->nb_samples,
									outCodecCtx_a->sample_fmt, 0);
								//swr_convert(au_convert_ctx, pFrameMP3->data, pFrameMP3->nb_samples, (const uint8_t**)m_ain, pFrame_audio->nb_samples);
								int conver_num = swr_convert(au_convert_ctx,
									converted_input_samples, pFrame_audio->nb_samples,
									(const uint8_t**)pFrame_audio->extended_data, pFrame_audio->nb_samples);
								ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + pFrame_audio->nb_samples);
								ret = av_audio_fifo_write(fifo, (void **)converted_input_samples, conver_num);

							}
							
							av_init_packet(&enc_packet);
							enc_packet.data = NULL;
							enc_packet.size = 0;
							float sumlen = av_audio_fifo_size(fifo);
							int num = 0;
							//从fifo读出
							while (true)
							{
								int fifo_size = av_audio_fifo_size(fifo);
								if (fifo_size < output_frame_size)
									break;
								const int frame_size = FFMIN(av_audio_fifo_size(fifo),
									outCodecCtx_a->frame_size);
								AVFrame *covert_frame;
								covert_frame = av_frame_alloc();
								covert_frame->nb_samples = output_frame_size;
								covert_frame->channel_layout = outCodecCtx_a->channel_layout;
								covert_frame->format = outCodecCtx_a->sample_fmt;
								covert_frame->sample_rate = outCodecCtx_a->sample_rate;

								ret = av_frame_get_buffer(covert_frame, 0);
								ret = av_audio_fifo_read(fifo, (void **)covert_frame->data, frame_size);

								if (covert_frame) 
								{
									covert_frame->pts = audio_pts;
									audio_pts += covert_frame->nb_samples;
								}

								ret = avcodec_send_frame(outCodecCtx_a, covert_frame);
								got_packet = avcodec_receive_packet(outCodecCtx_a, &enc_packet);
								if (got_packet == 0)
								{
									frame_index_a++;
									AVRational timebase = {1,AV_TIME_BASE };
									int64_t cal_duration = AV_TIME_BASE *(float)covert_frame->nb_samples / (float)covert_frame->sample_rate;

									enc_packet.pts = av_rescale_q_rnd(audio_pts, outCodecCtx_a->time_base,
										ofmt_ctx->streams[out_audio_st->index]->time_base,
										(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
									enc_packet.dts = enc_packet.pts;
									enc_packet.duration = av_rescale_q_rnd(cal_duration, timebase,
										ofmt_ctx->streams[out_audio_st->index]->time_base,
										(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
									//int64_t cal_duration = AV_TIME_BASE *(float)covert_frame->nb_samples / (float)covert_frame->sample_rate;
									//enc_packet.pos = -1;
									//enc_packet.pts = frame_index_a*cal_duration;
									//enc_packet.dts = enc_packet.pts;
									//enc_packet.duration = cal_duration;

									AVRational time_base = ofmt_ctx->streams[out_audioindex]->time_base;//{ 1, 1000 };
									AVRational time_base_q = { 1, AV_TIME_BASE };
									//Delay
									int64_t pts_time = av_rescale_q(enc_packet.pts, time_base, time_base_q);
									int64_t now_time = av_gettime() - start_time;
									if (pts_time > now_time)
										av_usleep(pts_time - now_time);

									//Print to Screen
									if (enc_packet.stream_index == in_audioindex)
									{
										printf("Send %8d audio frames to output URL\n", frame_index_a);

									}
									cur_pts_a = enc_packet.pts;

									ret = av_interleaved_write_frame(ofmt_ctx, &enc_packet);
								}
								av_frame_free(&covert_frame);

							}
							
							av_packet_unref(&enc_packet);

							av_packet_unref(dec_packet);

							av_frame_free(&pFrame_audio);
						}


					}

				}
				av_packet_unref(dec_packet);
			}
		}
		else if (event.type == SDL_QUIT)
		{
			thread_exit = 1;
		}
		else if(event.type == SFM_BREAK_EVENT)
		{
			break;
		}

	}
	SDL_Quit();
	//写文件尾(Write file trailer)
	av_write_trailer(ofmt_ctx);

	//av_free(out_buffer_vedio);
	//av_free(out_buffer_audio);


end:
	if (out_video_st)
		avcodec_close(outCodecCtx_v);
	if (out_audio_st)
		avcodec_close(outCodecCtx_a);
	avformat_close_input(&ifmt_ctx_video);
	avformat_close_input(&ifmt_ctx_audio);
	/* close output */
	if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
		avio_close(ofmt_ctx->pb);
	avformat_free_context(ifmt_ctx_video);
	avformat_free_context(ifmt_ctx_audio);
	avformat_free_context(ofmt_ctx);
	if (ret < 0 && ret != AVERROR_EOF) {
		printf("Error occurred.\n");
		return -1;
	}


	return 0;
}