完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libavfilter/avfilter.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avutil.h"
#include "libavutil/fifo.h"
#include"sdl\SDL.h"
#include"libswresample/swresample.h"
}
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#define MAX_MUSIC_DATA 5
#pragma comment(lib, "swscale.lib")
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
//Buffer:
//|-----------|-------------|
//chunk-------pos---len-----|
typedef struct _AudioData
{
Uint8 *audio_chunk;
Uint32 audio_len;
Uint8 *audio_pos;
char filename[256];
int volume;
AVFormatContext *pFormatCtx;
int audioStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVPacket *packet;
uint8_t *out_buffer;
AVFrame *pFrame;
SDL_AudioSpec wanted_spec;
uint32_t len ;
int got_picture;
int index;
int64_t in_channel_layout;
struct SwrContext *au_convert_ctx;
int out_buffer_size;
}AudioData;
AudioData AData[2];
void fill_audio(void *udata, Uint8 *stream, int len) {
//SDL 2.0
SDL_memset(stream, 0, len);
for (int m = 0; m < 2; ++m)
{
if (AData[m].audio_len == 0)
continue;
len = (len>AData[m].audio_len ? AData[m].audio_len : len); /* Mix as much data as possible */
SDL_MixAudio(stream, AData[m].audio_pos, len, int(AData[m].volume*1.28));
AData[m].audio_pos += len;
AData[m].audio_len -= len;
}
}
//-----------------
int main(int argc, char* argv[])
{
av_register_all();
avformat_network_init();
int ret = 0;
memset(AData[0].filename, 0, 256);
strcpy(AData[0].filename, "003.mp3");
memset(AData[1].filename, 0, 256);
strcpy(AData[1].filename, "004.mp3");
AData[0].volume = 80;
AData[1].volume = 30;
for (int m = 0; m < 2; ++m)
{
AData[m].pFormatCtx = avformat_alloc_context();
//Open
if (avformat_open_input(&AData[m].pFormatCtx, AData[m].filename, NULL, NULL) != 0) {
printf("Couldn't open input stream.\n");
return -1;
}
// Retrieve stream information
if (avformat_find_stream_info(AData[m].pFormatCtx, NULL)<0) {
printf("Couldn't find stream information.\n");
return -1;
}
// Dump valid information onto standard error
av_dump_format(AData[m].pFormatCtx, 0, AData[m].filename, false);
// Find the first audio stream
AData[m].audioStream = -1;
for (int i = 0; i < AData[m].pFormatCtx->nb_streams; i++)
if (AData[m].pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
AData[m].audioStream = i;
break;
}
if (AData[m].audioStream == -1) {
printf("Didn't find a audio stream.\n");
return -1;
}
// Get a pointer to the codec context for the audio stream
AData[m].pCodecCtx = AData[m].pFormatCtx->streams[AData[m].audioStream]->codec;
// Find the decoder for the audio stream
AData[m].pCodec = avcodec_find_decoder(AData[m].pCodecCtx->codec_id);
if (AData[m].pCodec == NULL) {
printf("Codec not found.\n");
return -1;
}
// Open codec
if (avcodec_open2(AData[m].pCodecCtx, AData[m].pCodec, NULL)<0) {
printf("Could not open codec.\n");
return -1;
}
AData[m].packet = (AVPacket *)av_malloc(sizeof(AVPacket));
av_init_packet(AData[m].packet);
uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
//Out Audio Param
//nb_samples: AAC-1024 MP3-1152
int out_sample_rate = 44100;
int out_nb_samples = AData[m].pCodecCtx->frame_size;
AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
//Out Buffer Size
AData[m].out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
AData[m].out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
AData[m].pFrame = av_frame_alloc();
//SDL------------------
//Init
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
AData[m].in_channel_layout = av_get_default_channel_layout(AData[m].pCodecCtx->channels);
//Swr
AData[m].au_convert_ctx = swr_alloc();
AData[m].au_convert_ctx = swr_alloc_set_opts(AData[m].au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,
AData[m].in_channel_layout, AData[m].pCodecCtx->sample_fmt, AData[m].pCodecCtx->sample_rate, 0, NULL);
swr_init(AData[m].au_convert_ctx);
//Play
}
int m = 0;
uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
int out_sample_rate = 44100;
AData[m].wanted_spec.freq = out_sample_rate;
AData[m].wanted_spec.format = AUDIO_S16SYS;
AData[m].wanted_spec.channels = out_channels;
AData[m].wanted_spec.silence = 0;
AData[m].wanted_spec.samples = AData[m].pCodecCtx->frame_size;
AData[m].wanted_spec.callback = fill_audio;
AData[m].wanted_spec.userdata = AData[m].pCodecCtx;
if (SDL_OpenAudio(&AData[m].wanted_spec, NULL)<0) {
printf("can't open audio.\n");
return -1;
}
SDL_PauseAudio(0);
while (true)
{
for (int n = 0; n < 2; ++n)
{
if (av_read_frame(AData[n].pFormatCtx, AData[n].packet) >= 0)
{
if (AData[n].packet->stream_index == AData[n].audioStream)
{
ret = avcodec_decode_audio4(AData[n].pCodecCtx, AData[n].pFrame, &AData[n].got_picture, AData[n].packet);
if (ret < 0) {
printf("Error in decoding audio frame.\n");
return -1;
}
if (AData[n].got_picture > 0) {
swr_convert(AData[n].au_convert_ctx, &AData[n].out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)AData[n].pFrame->data, AData[n].pFrame->nb_samples);
}
while (AData[n].audio_len>0)//Wait until finish
SDL_Delay(1);
//Set audio buffer (PCM data)
AData[n].audio_chunk = (Uint8 *)AData[n].out_buffer;
//Audio buffer length
AData[n].audio_len = AData[n].out_buffer_size;
AData[n].audio_pos = AData[n].audio_chunk;
}
av_free_packet(AData[n].packet);
}
}
}
getchar();
for (int k = 0; k < 2; ++k)
{
swr_free(&AData[k].au_convert_ctx);
SDL_CloseAudio();//Close SDL
SDL_Quit();
av_free(AData[k].out_buffer);
avcodec_close(AData[k].pCodecCtx);
avformat_close_input(&AData[k].pFormatCtx);
}
return 0;
}
参考:http://blog.csdn.net/u013080313/article/details/50387244