基于FFMPEG和SDL的音视频播放器

本代码可以用于播放音视频,同时播放声音和视频图像。

整体工程连接为:基于FFMPEG和SDL的音视频播放器

在写代码的时候发现,音频线程和视频线程delay的时间不同,那么怎样才能设置一个控制线程来控制两个线程的暂停播放呢?各位大神请多多指教。

另外由于直接从一个FormatContext读取音频和视频时,会出现访问不到,主要是因为共享的问题。我是采用直接再读取另外一个formatContext解决的,有没有更好的办法,请多多指教。



下面是代码的介绍:

此函数主要是对视频播放前的准备工作。

int video_set(AVFormatContext *pFormatCtx){

	for(int i=0; i<pFormatCtx->nb_streams; i++)   {
		if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){  
			videoindex=i;  
			break;
		}  
	}
	if(videoindex==-1){  
		printf("Didn't find a video stream.\n");  
		return -1;  
	}  

	AVCodecContext *pCodecCtx=pFormatCtx->streams[videoindex]->codec;  
	AVCodec *pCodec=avcodec_find_decoder(pCodecCtx->codec_id); 
	avcodec_open2(pCodecCtx, pCodec,NULL);
	return 0;
}

此函数主要是对音频播放前的准备工作。

int audio_set(AVFormatContext *pFormatCtx){


	for(int i=0; i<pFormatCtx->nb_streams; i++)   {
		if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){  
			audioindex=i;   
			break;
		}
	}
	AVCodecContext *pAudioCodecCtx=pFormatCtx->streams[audioindex]->codec;  
	AVCodec *pAudioCodec=avcodec_find_decoder(pAudioCodecCtx->codec_id);  
	if(pAudioCodec==NULL){  
		printf("Codec not found.\n");  
		return -1;  
	}  

	// Open codec  
	if(avcodec_open2(pAudioCodecCtx, pAudioCodec,NULL)<0){  
		printf("Could not open codec.\n");  
		return -1;  
	}  
	//SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
	//Out Audio Param  
	uint64_t out_channel_layout=AV_CH_LAYOUT_STEREO;  
	//nb_samples: AAC-1024 MP3-1152  
	int out_nb_samples=pAudioCodecCtx->frame_size;  
	AVSampleFormat out_sample_fmt=AV_SAMPLE_FMT_S16;  
	int out_sample_rate=44100;  
	int out_channels=av_get_channel_layout_nb_channels(out_channel_layout);  
	//Out Buffer Size  
	out_buffer_size=av_samples_get_buffer_size(NULL,out_channels ,out_nb_samples,out_sample_fmt, 1);  

	//SDL_Event event;

	//结构体,包含PCM数据的相关信息
	//SDL_AudioSpec  
	SDL_AudioSpec wanted_spec;
	wanted_spec.freq = out_sample_rate;   
	wanted_spec.format = AUDIO_S16SYS;   
	wanted_spec.channels = out_channels;   
	wanted_spec.silence = 0;   
	wanted_spec.samples = out_nb_samples;   
	wanted_spec.callback = fill_audio;   
	wanted_spec.userdata = pAudioCodecCtx;   

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

	int64_t in_channel_layout=av_get_default_channel_layout(pAudioCodecCtx->channels);  
	//Swr  

	au_convert_ctx = swr_alloc();  
	au_convert_ctx=swr_alloc_set_opts(au_convert_ctx,out_channel_layout, out_sample_fmt, out_sample_rate,  
		in_channel_layout,pAudioCodecCtx->sample_fmt , pAudioCodecCtx->sample_rate,0, NULL);  
	swr_init(au_convert_ctx);  
	return 0;
}
下面是视频播放函数

int video_player(void *opaque){

	AVFormatContext *pFormatCtx=(AVFormatContext *)opaque;
	AVCodecContext *pCodecCtx=pFormatCtx->streams[videoindex]->codec;  
	SDL_Rect sdlRect;  

	sdlRect.x = 0;      
	sdlRect.y = 0; 
	AVFrame *pFrame=av_frame_alloc();  
	AVFrame *pFrameYUV=av_frame_alloc(); 
	unsigned char *out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,  pCodecCtx->width, pCodecCtx->height,1));  
	av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize,out_buffer,  
		AV_PIX_FMT_YUV420P,pCodecCtx->width, pCodecCtx->height,1);  
	struct SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,   
		pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); 
	int screen_w,screen_h;  
	SDL_Window *screen;   
	SDL_Renderer* sdlRenderer;  
	SDL_Texture* sdlTexture;  
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
	screen_w = pCodecCtx->width;  
	screen_h = pCodecCtx->height;  
	screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,  
		screen_w, screen_h,  
		SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
	sdlRenderer = SDL_CreateRenderer(screen, -1, 0); 
	sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height);

	AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket)); 

	int got_picture,ret;
	int clicked=1;
	SDL_Event event;
	while(av_read_frame(pFormatCtx, packet)>=0){
				if(packet->stream_index==videoindex){  
					ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);  
					//int y_size=pCodecCtx->width*pCodecCtx->height;
					//fwrite(pFrameYUV->data[0],1,y_size,fp_yuv);    //Y   
					//         fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv);  //U  
					//         fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);  //V 
					if(got_picture){
						sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,   
							pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
						SDL_UpdateTexture( sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0] );  

						/*	sdlRect.w = screen_w;      
						sdlRect.h = screen_h; 
						*/
						SDL_RenderClear( sdlRenderer );    
						SDL_RenderCopy( sdlRenderer, sdlTexture,  NULL, NULL);    
						SDL_RenderPresent( sdlRenderer );       
						SDL_Delay(40);
					}
				}
				av_free_packet(packet);
	}
	sws_freeContext(img_convert_ctx);

	//--------------
	av_frame_free(&pFrameYUV);
	av_frame_free(&pFrame);
	avcodec_close(pCodecCtx);
	av_free(out_buffer);  

	return 0;
}

下面是音频播放函数:

int audio_player(void *opaque){

	AVFormatContext *pFormatCtx=(AVFormatContext *)opaque;
	AVFrame *pAudioFrame =av_frame_alloc(); 
	uint8_t *out_buffer_audio=(uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE*2);  
	AVCodecContext *pAudioCodecCtx=pFormatCtx->streams[audioindex]->codec;  

	//Play  
	SDL_PauseAudio(0);  
	int index = 0; 
	AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));  
	int ret,got_picture;
	SDL_Event event;
	while(av_read_frame(pFormatCtx, packet)>=0){
				if(packet->stream_index==audioindex){
					ret = avcodec_decode_audio4( pAudioCodecCtx, pAudioFrame,&got_picture, packet);  
					if ( ret < 0 ) {  
						printf("Error in decoding audio frame.\n");  
						return -1;  
					}  
					if (got_picture > 0 ){  
						swr_convert(au_convert_ctx,&out_buffer_audio, MAX_AUDIO_FRAME_SIZE,(const uint8_t **)pAudioFrame->data , pAudioFrame->nb_samples);  
						//printf("index:%5d\t pts:%lld\t packet size:%d\n",index,packet->pts,packet->size);  
						index++;  
					}  
					while(audio_len>0)//Wait until finish  
						SDL_Delay(1);   
					//Set audio buffer (PCM data)  
					audio_chunk = (Uint8 *) out_buffer_audio;   
					//Audio buffer length  
					audio_len =out_buffer_size;  
					audio_pos = audio_chunk;  
				}
				av_free_packet(packet);
	}
	swr_free(&au_convert_ctx);  
	av_free(out_buffer_audio);
	SDL_CloseAudio();//Close SDL  
	av_frame_free(&pAudioFrame);
	avcodec_close(pAudioCodecCtx);
	//SDL_Quit();
	return 0;
}

主函数:

int main(int argc, char* argv[]){

	AVFormatContext *pFormatCtx; 
	AVFormatContext *pFormatCtx2; 

	av_register_all();
	avformat_network_init();
	pFormatCtx=avformat_alloc_context();
	pFormatCtx2=avformat_alloc_context();
	
	
	char filepath[]="E:\\workspace\\c_primer\\小学期课程资料 - 基于FFmpeg+SDL的视频播放器的制作\\工具\\testvideo\\ds.mov";  
	//音频播放线程

	avformat_open_input(&pFormatCtx,filepath,NULL,NULL);
	avformat_find_stream_info(pFormatCtx,NULL);
	audio_set(pFormatCtx);
	SDL_Thread *audio_thread = SDL_CreateThread(audio_player,NULL,pFormatCtx);

	//视频播放线程

	avformat_open_input(&pFormatCtx2,filepath,NULL,NULL);
	avformat_find_stream_info(pFormatCtx2,NULL);
	video_set(pFormatCtx2);
	video_player(pFormatCtx2);
	SDL_Thread *video_thread = SDL_CreateThread(video_player,NULL,pFormatCtx2);
	
	
	SDL_WaitThread(video_thread,NULL);
	SDL_WaitThread(audio_thread,NULL);


	avformat_close_input(&pFormatCtx);
	avformat_close_input(&pFormatCtx2);
	SDL_Quit();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值