• FFMPEG学习----使用SDL构建音频播放器


    ffmpeg版本:ffmpeg-20160413-git-0efafc5

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    extern "C"
    {
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libswresample/swresample.h"
    #include "SDL.h"
    };
    
    
    #define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
    
    
    
    Uint32  audio_len;//音频数据大小
    Uint8  *audio_pos;//指向音频数据的指针
    
    //回调函数
    void  fill_audio(void *userdata, Uint8 *stream, int len)
    {
    	//SDL 2.0
    	SDL_memset(stream, 0, len);
    	if (audio_len == 0)
    	{
    		return;
    	}
    
    	len = (len > audio_len ? audio_len : len);
    
    	SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME);
    	audio_pos += len;
    	audio_len -= len;
    }
    
    
    int main(int argc, char* argv[])
    {
    	//FFmpeg
    	AVFormatContext		*pFormatCtx;
    	AVCodecContext		*pCodecCtx;
    	AVCodec				*pCodec;
    	AVPacket			packet;
    	AVFrame				*pFrame;
    	struct SwrContext	*au_convert_ctx;
    	int					got_picture;
    	int					audioIndex;
    	
    	//SDL
    	uint8_t				*out_buffer;
    	SDL_AudioSpec		wanted_spec;
    	int					index = 0;
    	
    
    	char filepath[1024] = "";
    	printf("Usage: player.exe *.mp3
    ");
    	if (argc == 2)
    	{
    		strcpy(filepath, argv[1]);
    	}
    	else
    	{
    		printf("Could not find a audio file
    ");
    		return -1;
    	}
    
    
    	av_register_all();
    
    	pFormatCtx = avformat_alloc_context();
    	
    	if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)
    	{
    		printf("Couldn't open input stream.
    ");
    		return -1;
    	}
    	
    	if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
    	{
    		printf("Couldn't find stream information.
    ");
    		return -1;
    	}
    	
    	av_dump_format(pFormatCtx, -1, filepath, 0);
    
    	
    	audioIndex = -1;
    	for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
    	{
    		//AVStream->codec不推荐使用
    		if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
    		{
    			audioIndex = i;
    			break;
    		}
    	}
    	if (audioIndex == -1)
    	{
    		printf("Didn't find a audio stream.
    ");
    		return -1;
    	}
    
    	//------------------------------------------------
    	//新版本:分配、填充AVCodecContext
    	pCodecCtx = avcodec_alloc_context3(NULL);
    	if (pCodecCtx == NULL)
    	{
    		printf("Could not allocate AVCodecContext
    ");
    		return -1;
    	}
    
    	if (avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[audioIndex]->codecpar) < 0)
    	{
    		printf("Could not initialize AVCodecContext
    ");
    		return -1;
    	}
    	//------------------------------------------------
    
    	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    	if (pCodec == NULL)
    	{
    		printf("Codec not found.
    ");
    		return -1;
    	}
    
    	if (avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    	{
    		printf("Could not open codec.
    ");
    		return -1;
    	}
    
    
    
    	//Out Audio Param
    	uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
    	//nb_samples: AAC-1024 MP3-1152
    	int out_nb_samples = pCodecCtx->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
    	int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
    
    	out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
    	pFrame = av_frame_alloc();
    
    
    	//Init
    	if (SDL_Init(SDL_INIT_AUDIO)) 
    	{
    		printf("Could not initialize SDL - %s
    ", SDL_GetError());
    		return -1;
    	}
    	//SDL_AudioSpec
    	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 = pCodecCtx;
    
    	if (SDL_OpenAudio(&wanted_spec, NULL) < 0)
    	{
    		printf("can't open audio.
    ");
    		return -1;
    	}
    
    
    	au_convert_ctx = swr_alloc();
    	au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,
    		pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);
    	swr_init(au_convert_ctx);
    
    	//Play
    	SDL_PauseAudio(0);
    
    	while (av_read_frame(pFormatCtx, &packet) >= 0)
    	{
    		if (packet.stream_index == audioIndex)
    		{
    			if (avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, &packet) < 0)
    			{
    				printf("Error in decoding audio frame.
    ");
    				return -1;
    			}
    			if (got_picture)
    			{
    				swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame->data, pFrame->nb_samples);
    				printf("index:%5d	 pts:%lld	 packet size:%d
    ", index, packet.pts, packet.size);
    				index++;
    			}
    
    
    			while (audio_len > 0)//Wait until finish
    			{
    				SDL_Delay(1);
    			}
    
    			//Audio buffer length
    			audio_len = out_buffer_size;
    			audio_pos = (Uint8 *)out_buffer;
    
    		}
    		av_packet_unref(&packet);
    	}
    
    	swr_free(&au_convert_ctx);
    	SDL_CloseAudio();//Close SDL
    	SDL_Quit();
    	av_free(out_buffer);
    	avcodec_free_context(&pCodecCtx);
    	avformat_close_input(&pFormatCtx);
    	return 0;
    }


    Keep it simple!
    作者:N3verL4nd
    知识共享,欢迎转载。
  • 相关阅读:
    php查看网页源代码的方法
    php阻止网页被用户频繁刷新
    php实现只保留mysql中最新1000条记录
    php限定时间内同一ip只能访问一次
    emmet插件快捷键:
    抓包工具--Fiddler
    HTTP版本进化过程
    ECMAScript6的Promise对象
    H5、CSS3属性的支持性以及flex
    关于未来前端的规划
  • 原文地址:https://www.cnblogs.com/lgh1992314/p/5834633.html
Copyright © 2020-2023  润新知