ffmpeg-3.1.5音频播放代码

本文代码在雷博的基础上进行了略微修改,实现播放音频的功能。

使用ffmpeg-3.1.5 + SDL2

雷博的代码链接:http://blog.csdn.net/leixiaohua1020/article/details/38979615

修改了两个地方:(1)使用了新版本的ffmpeg API。(2)更改了部分变量的赋值,使程序能够适应各种音频序列。

代码还不是完全理解,先记录下来。

/*
*实现音频解码和播放
*/

#include "stdafx.h"
#include <stdio.h>
#include <iostream>
using namespace std;
extern "C"
{
#include "include\libavcodec\avcodec.h"
#include "include\libavformat\avformat.h"
#include "include\libswresample\swresample.h"
#include "include\SDL2\SDL.h"
};

#define __STDC_CONSTANT_MACROS 

#define OUTPUT_PCM 0

//Buffer
static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;

//callback func
void  fill_audio(void *udata, Uint8 *stream, int len){
	SDL_memset(stream, 0, len);
	if (audio_len == 0)        /*  Only  play  if  we  have  data  left  */
		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;
}

int _tmain(int argc, _TCHAR* argv[])
{
	AVFormatContext *pFormatCtx;
	AVCodecContext *pCodecCtx;
	AVCodec *pCodec;
	int audioStreamIndex;

	//input audio
	char url[] = "test.mp3";

#if OUTPUT_PCM
	//output file
	FILE *outputFile = NULL;
	char *outputFileName = "output.aac";
	fopen_s(&outputFile, outputFileName, "wb");
#endif

	//init ffmpeg
	av_register_all();
	avformat_network_init();
	pFormatCtx = avformat_alloc_context();

	//open input audio
	if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0){
		cout << "could not open input stream." << endl;
		return -1;
	}
	if (avformat_find_stream_info(pFormatCtx,NULL) < 0){
		cout << "could not find stream information." << endl;
		return -1;
	}

	//print input audio info
	cout << "--------------------- audio info ---------------------" << endl;
	av_dump_format(pFormatCtx, 0, url, false);
	cout << "------------------------------------------------------" << endl;

	//find audioStreamIndex
	audioStreamIndex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, NULL);
	if (audioStreamIndex < 0){
		cout << "could not found a audio stream." << endl;
		return -1;
	}

	//find codec
	pCodecCtx = avcodec_alloc_context3(NULL);
	if (pCodecCtx == NULL){
		cout << "could not allocate audio AVCCodecContext." << endl;
		return -1;
	}
	avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[audioStreamIndex]->codecpar);
	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
	if (pCodec == NULL){
		cout << "Codec not found." << endl;
		return -1;
	}

	//open codec
	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){
		cout << "could not open codec." << endl;
		return -1;
	}

	//out audio param
	uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
	int out_nb_samples = pCodecCtx->frame_size;//number of samples per channels in an audio frame
	AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
	int out_sample_rate = pCodecCtx->sample_rate;
	int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);//the number of channels

	//out buffer size
	int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
	uint8_t *out_buffer = (uint8_t *)av_malloc(out_buffer_size);


	//SDL
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){
		cout << "could not initialize SDL - " << SDL_GetError << endl;
		return -1;
	}
	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 = pCodecCtx;

	//open the audio device with the desired parameters
	if (SDL_OpenAudio(&wanted_spec, NULL) < 0){
		cout << "could not open audio." << endl;
		return -1;
	}

	printf("Bitrate:\t %3d\n", pFormatCtx->bit_rate);
	printf("Decoder Name:\t %s\n", pCodecCtx->codec->long_name);
	printf("Channels:\t %d\n", pCodecCtx->channels);
	printf("Sample per Second\t %d \n", pCodecCtx->sample_rate);

	
	//FIX:some codec's context information is missing
	int64_t in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);
	//Swr  
	struct SwrContext *au_convert_ctx;
	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, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);
	swr_init(au_convert_ctx);

	//pre decode
	AVPacket *packet = (AVPacket*)malloc(sizeof(AVPacket));
	av_init_packet(packet);
	AVFrame *pFrame;
	pFrame = av_frame_alloc();


	//Play  
	SDL_PauseAudio(0);

	int index = 0;
	while (av_read_frame(pFormatCtx, packet) >= 0){
		if (packet->stream_index == audioStreamIndex){
			if (avcodec_send_packet(pCodecCtx, packet) != 0){
				printf("input AVPacket to audio decoder failed!\n");
				return -1;
			}
			while (0 == avcodec_receive_frame(pCodecCtx, pFrame)){
				swr_convert(au_convert_ctx, &out_buffer, out_buffer_size, (const uint8_t **)pFrame->data, pFrame->nb_samples);
				printf("index:%5d\t pts:%lld\t packet size:%d\n", index, packet->pts, packet->size);
				index++;

				audio_chunk = (Uint8*)out_buffer;
				audio_len = out_buffer_size;
				audio_pos = audio_chunk;
				while (audio_len > 0)
					SDL_Delay(1);
#if OUTPUT_PCM
				//wirte file
				fwrite(out_buffer, 1, out_buffer_size, outputFile);
#endif OUTPUT_PCM	
			}
		}
		av_packet_unref(packet);
	}

	//free
	swr_free(&au_convert_ctx);
	SDL_CloseAudio();
	SDL_Quit();
	av_free(out_buffer);
	avcodec_close(pCodecCtx);
	avformat_close_input(&pFormatCtx);
#if OUTPUT_PCM
	fclose(outputFile);
#endif
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值