此代碼在vs2008下編譯,基于最新的ffmpeg版本(svn下載),搭建MSYS+MinGW編譯環境編譯,如何搭建,在google上能搜索到。 源碼可在此下載。
但除了aac和ogg格式播放出錯,其余格式正常,不知為何,有ffmpeg開發經驗的朋友請給予幫助,謝謝。代碼貼于下方。
但除了aac和ogg格式播放出錯,其余格式正常,不知為何,有ffmpeg開發經驗的朋友請給予幫助,謝謝。代碼貼于下方。
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <windows.h>
4
#include <mmsystem.h>
5
6
#pragma comment(lib, "winmm.lib")
7
8
#ifdef __cplusplus
9
extern "C" {
10
#endif
11
12
#include "./include/avcodec.h"
13
#include "./include/avformat.h"
14
#include "./include/avutil.h"
15
#include "./include/mem.h"
16
17
#ifdef __cplusplus
18
}
19
#endif
20
21
#define BLOCK_SIZE 4608
22
#define BLOCK_COUNT 20
23
24
HWAVEOUT hWaveOut = NULL;
25
26
static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD, DWORD, DWORD);
27
static WAVEHDR* allocateBlocks(int size, int count);
28
static void freeBlocks(WAVEHDR* blockArray);
29
static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size);
30
31
static CRITICAL_SECTION waveCriticalSection;
32
static WAVEHDR* waveBlocks;
33
static volatile unsigned int waveFreeBlockCount;
34
static int waveCurrentBlock;
35
36
typedef struct AudioState {
37
AVFormatContext* pFmtCtx;
38
AVCodecContext* pCodecCtx;
39
AVCodec* pCodec;
40
uint8_t audio_buf1[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
41
uint8_t* audio_buf;
42
unsigned int audio_buf_size;
43
int audio_buf_index;
44
AVPacket audio_pkt_temp;
45
AVPacket audio_pkt;
46
uint8_t* audio_pkt_data;
47
int audio_pkt_size;
48
int stream_index;
49
} AudioState;
50
51
int audio_decode_frame(AudioState* pState) {
52
53
AVPacket* pkt_temp = &pState->audio_pkt_temp;
54
AVPacket* pkt = &pState->audio_pkt;
55
AVCodecContext* dec= pState->pCodecCtx;
56
int len = 0, data_size = sizeof(pState->audio_buf1);
57
int err = 0;
58
59
for( ; ; ) {
60
while (pkt_temp->size > 0) {
61
data_size = sizeof(pState->audio_buf1);
62
len = avcodec_decode_audio3(dec, (int16_t*)pState->audio_buf1, &data_size, pkt_temp);
63
if (len < 0) {
64
pkt_temp->size = 0;
65
break;
66
}
67
68
pkt_temp->data += len;
69
pkt_temp->size -= len;
70
71
if (data_size <= 0)
72
continue;
73
74
pState->audio_buf = pState->audio_buf1;
75
return data_size;
76
}
77
78
if (pkt->data)
79
av_free_packet(pkt);
80
81
if((err = av_read_frame(pState->pFmtCtx, pkt)) < 0)
82
return -1;
83
84
pkt_temp->data = pkt->data;
85
pkt_temp->size = pkt->size;
86
}
87
88
return -1;
89
}
90
91
int main(int argc, char* argv[]) {
92
int err = 0;
93
AudioState audio_state = {0};
94
unsigned int i = 0;
95
unsigned int ready = 0;
96
97
OPENFILENAME ofn = {0};
98
char filename[MAX_PATH];
99
WAVEFORMATEX wfx = {0};
100
uint8_t buffer[BLOCK_SIZE];
101
uint8_t* pbuffer = buffer;
102
AVInputFormat* iformat = NULL;
103
104
int audio_size = 0, data_size = 0;
105
int len = 0, len1 = 0, eof = 0, size = 0;
106
107
memset(&ofn, 0, sizeof(OPENFILENAME));
108
ofn.lStructSize = sizeof(ofn);
109
ofn.hwndOwner = GetDesktopWindow();
110
ofn.lpstrFile = filename;
111
ofn.lpstrFile[0] = '\0';
112
ofn.nMaxFile = sizeof(filename) / sizeof(filename[0]);
113
ofn.lpstrFilter = _TEXT("All support files\0*.aac;*.ape;*.flac;*.mp3;*.mp4;*.mpc;*.ogg;*.tta;*.wma;*.wav\0");
114
ofn.nFilterIndex = 1;
115
ofn.lpstrFileTitle = NULL;
116
ofn.nMaxFileTitle = 0;
117
ofn.lpstrInitialDir = NULL;
118
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
119
120
if (GetOpenFileName(&ofn) == FALSE)
121
return 0;
122
123
av_register_all();
124
125
err = av_open_input_file(&audio_state.pFmtCtx, filename, NULL, 0, NULL);
126
if(err < 0) {
127
printf("can not open file %s.\n", filename);
128
return -1;
129
}
130
131
err = av_find_stream_info(audio_state.pFmtCtx);
132
if(err < 0) {
133
printf("can not find stream info of file %s.\n", filename);
134
return -1;
135
}
136
137
for(i = 0; i < audio_state.pFmtCtx->nb_streams; i++) {
138
if(audio_state.pFmtCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
139
audio_state.pCodecCtx = audio_state.pFmtCtx->streams[i]->codec;
140
audio_state.stream_index = i;
141
ready = 1;
142
break;
143
}
144
}
145
146
if(!ready)
147
return -1;
148
149
audio_state.pCodec = avcodec_find_decoder(audio_state.pCodecCtx->codec_id);
150
if(!audio_state.pCodec || avcodec_open(audio_state.pCodecCtx, audio_state.pCodec) < 0)
151
return -1;
152
153
wfx.nSamplesPerSec = audio_state.pCodecCtx->sample_rate;
154
switch(audio_state.pCodecCtx->sample_fmt)
155
{
156
case SAMPLE_FMT_U8:
157
wfx.wBitsPerSample = 8;
158
break;
159
case SAMPLE_FMT_S16:
160
wfx.wBitsPerSample = 16;
161
break;
162
case SAMPLE_FMT_S32:
163
wfx.wBitsPerSample = 32;
164
break;
165
case SAMPLE_FMT_FLT:
166
wfx.wBitsPerSample = sizeof(double) * 8;
167
break;
168
default:
169
wfx.wBitsPerSample = 0;
170
break;
171
}
172
173
wfx.nChannels = FFMIN(2, audio_state.pCodecCtx->channels);
174
wfx.cbSize = 0;
175
wfx.wFormatTag = WAVE_FORMAT_PCM;
176
wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;
177
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
178
179
waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
180
waveFreeBlockCount = BLOCK_COUNT;
181
waveCurrentBlock = 0;
182
183
InitializeCriticalSection(&waveCriticalSection);
184
185
// open wave out device
186
if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc,
187
(DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
188
fprintf(stderr, "%s: unable to open wave mapper device\n", argv[0]);
189
ExitProcess(1);
190
}
191
192
// play loop
193
for( ; ; ) {
194
195
len = BLOCK_SIZE;
196
size = 0;
197
pbuffer = buffer;
198
199
if(eof)
200
break;
201
202
while(len > 0) {
203
if(audio_state.audio_buf_index >= (int)audio_state.audio_buf_size) {
204
audio_size = audio_decode_frame(&audio_state);
205
if(audio_size < 0) {
206
if(size > 0)
207
break;
208
209
eof = 1;
210
break;
211
}
212
213
audio_state.audio_buf_size = audio_size;
214
audio_state.audio_buf_index = 0;
215
}
216
217
len1 = audio_state.audio_buf_size - audio_state.audio_buf_index;
218
if(len1 > len)
219
len1 = len;
220
221
memcpy(pbuffer, (uint8_t *)audio_state.audio_buf + audio_state.audio_buf_index, len1);
222
223
len -= len1;
224
pbuffer += len1;
225
size += len1;
226
audio_state.audio_buf_index += len1;
227
}
228
229
writeAudio(hWaveOut, (char*)buffer, size);
230
}
231
232
// wait for complete
233
for( ; ; ) {
234
if(waveFreeBlockCount >= BLOCK_COUNT)
235
break;
236
237
Sleep(10);
238
}
239
240
for(i = 0; i < waveFreeBlockCount; i++)
241
if(waveBlocks[i].dwFlags & WHDR_PREPARED)
242
waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));
243
244
DeleteCriticalSection(&waveCriticalSection);
245
freeBlocks(waveBlocks);
246
waveOutClose(hWaveOut);
247
248
avcodec_close(audio_state.pCodecCtx);
249
250
system("pause");
251
return 0;
252
}
253
254
static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size)
255
{
256
WAVEHDR* current;
257
int remain;
258
259
current = &waveBlocks[waveCurrentBlock];
260
261
while(size > 0) {
262
/*
263
* first make sure the header we're going to use is unprepared
264
*/
265
if(current->dwFlags & WHDR_PREPARED)
266
waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
267
268
if(size < (int)(BLOCK_SIZE - current->dwUser)) {
269
memcpy(current->lpData + current->dwUser, data, size);
270
current->dwUser += size;
271
break;
272
}
273
274
remain = BLOCK_SIZE - current->dwUser;
275
memcpy(current->lpData + current->dwUser, data, remain);
276
size -= remain;
277
data += remain;
278
current->dwBufferLength = BLOCK_SIZE;
279
280
waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
281
waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
282
283
EnterCriticalSection(&waveCriticalSection);
284
waveFreeBlockCount--;
285
LeaveCriticalSection(&waveCriticalSection);
286
287
/*
288
* wait for a block to become free
289
*/
290
while(!waveFreeBlockCount)
291
Sleep(10);
292
293
/*
294
* point to the next block
295
*/
296
waveCurrentBlock++;
297
waveCurrentBlock %= BLOCK_COUNT;
298
299
current = &waveBlocks[waveCurrentBlock];
300
current->dwUser = 0;
301
}
302
}
303
304
static WAVEHDR* allocateBlocks(int size, int count)
305
{
306
char* buffer;
307
int i;
308
WAVEHDR* blocks;
309
DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
310
311
/*
312
* allocate memory for the entire set in one go
313
*/
314
if((buffer = (char*)HeapAlloc(
315
GetProcessHeap(),
316
HEAP_ZERO_MEMORY,
317
totalBufferSize
318
)) == NULL) {
319
fprintf(stderr, "Memory allocation error\n");
320
ExitProcess(1);
321
}
322
323
/*
324
* and set up the pointers to each bit
325
*/
326
blocks = (WAVEHDR*)buffer;
327
buffer += sizeof(WAVEHDR) * count;
328
for(i = 0; i < count; i++) {
329
blocks[i].dwBufferLength = size;
330
blocks[i].lpData = buffer;
331
buffer += size;
332
}
333
334
return blocks;
335
}
336
337
static void freeBlocks(WAVEHDR* blockArray)
338
{
339
/*
340
* and this is why allocateBlocks works the way it does
341
*/
342
HeapFree(GetProcessHeap(), 0, blockArray);
343
}
344
345
static void CALLBACK waveOutProc(
346
HWAVEOUT hWaveOut,
347
UINT uMsg,
348
DWORD dwInstance,
349
DWORD dwParam1,
350
DWORD dwParam2
351
)
352
{
353
int* freeBlockCounter = (int*)dwInstance;
354
/*
355
* ignore calls that occur due to opening and closing the
356
* device.
357
*/
358
if(uMsg != WOM_DONE)
359
return;
360
361
EnterCriticalSection(&waveCriticalSection);
362
(*freeBlockCounter)++;
363
LeaveCriticalSection(&waveCriticalSection);
364
}
#include <stdio.h>2
#include <stdlib.h>3
#include <windows.h>4
#include <mmsystem.h>5

6
#pragma comment(lib, "winmm.lib")7

8
#ifdef __cplusplus9
extern "C" {10
#endif11

12
#include "./include/avcodec.h"13
#include "./include/avformat.h"14
#include "./include/avutil.h"15
#include "./include/mem.h"16

17
#ifdef __cplusplus18
}19
#endif20

21
#define BLOCK_SIZE 460822
#define BLOCK_COUNT 2023

24
HWAVEOUT hWaveOut = NULL;25

26
static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD, DWORD, DWORD);27
static WAVEHDR* allocateBlocks(int size, int count);28
static void freeBlocks(WAVEHDR* blockArray);29
static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size);30

31
static CRITICAL_SECTION waveCriticalSection;32
static WAVEHDR* waveBlocks;33
static volatile unsigned int waveFreeBlockCount;34
static int waveCurrentBlock;35

36
typedef struct AudioState {37
AVFormatContext* pFmtCtx;38
AVCodecContext* pCodecCtx;39
AVCodec* pCodec;40
uint8_t audio_buf1[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];41
uint8_t* audio_buf;42
unsigned int audio_buf_size;43
int audio_buf_index;44
AVPacket audio_pkt_temp;45
AVPacket audio_pkt;46
uint8_t* audio_pkt_data;47
int audio_pkt_size;48
int stream_index;49
} AudioState;50

51
int audio_decode_frame(AudioState* pState) {52

53
AVPacket* pkt_temp = &pState->audio_pkt_temp;54
AVPacket* pkt = &pState->audio_pkt;55
AVCodecContext* dec= pState->pCodecCtx;56
int len = 0, data_size = sizeof(pState->audio_buf1);57
int err = 0;58

59
for( ; ; ) {60
while (pkt_temp->size > 0) {61
data_size = sizeof(pState->audio_buf1);62
len = avcodec_decode_audio3(dec, (int16_t*)pState->audio_buf1, &data_size, pkt_temp);63
if (len < 0) {64
pkt_temp->size = 0;65
break;66
}67

68
pkt_temp->data += len;69
pkt_temp->size -= len;70

71
if (data_size <= 0)72
continue;73

74
pState->audio_buf = pState->audio_buf1;75
return data_size;76
}77

78
if (pkt->data)79
av_free_packet(pkt);80

81
if((err = av_read_frame(pState->pFmtCtx, pkt)) < 0)82
return -1;83

84
pkt_temp->data = pkt->data;85
pkt_temp->size = pkt->size;86
}87

88
return -1;89
}90

91
int main(int argc, char* argv[]) {92
int err = 0;93
AudioState audio_state = {0};94
unsigned int i = 0;95
unsigned int ready = 0;96

97
OPENFILENAME ofn = {0};98
char filename[MAX_PATH];99
WAVEFORMATEX wfx = {0};100
uint8_t buffer[BLOCK_SIZE];101
uint8_t* pbuffer = buffer;102
AVInputFormat* iformat = NULL;103
104
int audio_size = 0, data_size = 0;105
int len = 0, len1 = 0, eof = 0, size = 0;106

107
memset(&ofn, 0, sizeof(OPENFILENAME));108
ofn.lStructSize = sizeof(ofn);109
ofn.hwndOwner = GetDesktopWindow();110
ofn.lpstrFile = filename;111
ofn.lpstrFile[0] = '\0';112
ofn.nMaxFile = sizeof(filename) / sizeof(filename[0]);113
ofn.lpstrFilter = _TEXT("All support files\0*.aac;*.ape;*.flac;*.mp3;*.mp4;*.mpc;*.ogg;*.tta;*.wma;*.wav\0");114
ofn.nFilterIndex = 1;115
ofn.lpstrFileTitle = NULL;116
ofn.nMaxFileTitle = 0;117
ofn.lpstrInitialDir = NULL;118
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;119

120
if (GetOpenFileName(&ofn) == FALSE)121
return 0;122

123
av_register_all();124

125
err = av_open_input_file(&audio_state.pFmtCtx, filename, NULL, 0, NULL);126
if(err < 0) {127
printf("can not open file %s.\n", filename);128
return -1;129
}130

131
err = av_find_stream_info(audio_state.pFmtCtx);132
if(err < 0) {133
printf("can not find stream info of file %s.\n", filename);134
return -1;135
}136

137
for(i = 0; i < audio_state.pFmtCtx->nb_streams; i++) {138
if(audio_state.pFmtCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {139
audio_state.pCodecCtx = audio_state.pFmtCtx->streams[i]->codec;140
audio_state.stream_index = i;141
ready = 1;142
break;143
}144
}145

146
if(!ready)147
return -1;148

149
audio_state.pCodec = avcodec_find_decoder(audio_state.pCodecCtx->codec_id);150
if(!audio_state.pCodec || avcodec_open(audio_state.pCodecCtx, audio_state.pCodec) < 0)151
return -1;152

153
wfx.nSamplesPerSec = audio_state.pCodecCtx->sample_rate;154
switch(audio_state.pCodecCtx->sample_fmt)155
{156
case SAMPLE_FMT_U8:157
wfx.wBitsPerSample = 8;158
break;159
case SAMPLE_FMT_S16:160
wfx.wBitsPerSample = 16;161
break;162
case SAMPLE_FMT_S32:163
wfx.wBitsPerSample = 32;164
break;165
case SAMPLE_FMT_FLT:166
wfx.wBitsPerSample = sizeof(double) * 8;167
break;168
default:169
wfx.wBitsPerSample = 0;170
break;171
}172

173
wfx.nChannels = FFMIN(2, audio_state.pCodecCtx->channels);174
wfx.cbSize = 0;175
wfx.wFormatTag = WAVE_FORMAT_PCM;176
wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;177
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;178

179
waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);180
waveFreeBlockCount = BLOCK_COUNT;181
waveCurrentBlock = 0;182

183
InitializeCriticalSection(&waveCriticalSection);184

185
// open wave out device186
if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc, 187
(DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {188
fprintf(stderr, "%s: unable to open wave mapper device\n", argv[0]);189
ExitProcess(1);190
}191

192
// play loop193
for( ; ; ) {194

195
len = BLOCK_SIZE;196
size = 0;197
pbuffer = buffer;198

199
if(eof)200
break;201

202
while(len > 0) {203
if(audio_state.audio_buf_index >= (int)audio_state.audio_buf_size) {204
audio_size = audio_decode_frame(&audio_state);205
if(audio_size < 0) {206
if(size > 0)207
break;208

209
eof = 1;210
break;211
}212

213
audio_state.audio_buf_size = audio_size;214
audio_state.audio_buf_index = 0;215
}216

217
len1 = audio_state.audio_buf_size - audio_state.audio_buf_index;218
if(len1 > len)219
len1 = len;220

221
memcpy(pbuffer, (uint8_t *)audio_state.audio_buf + audio_state.audio_buf_index, len1);222

223
len -= len1;224
pbuffer += len1;225
size += len1;226
audio_state.audio_buf_index += len1;227
}228

229
writeAudio(hWaveOut, (char*)buffer, size);230
}231

232
// wait for complete233
for( ; ; ) {234
if(waveFreeBlockCount >= BLOCK_COUNT)235
break;236

237
Sleep(10);238
}239

240
for(i = 0; i < waveFreeBlockCount; i++)241
if(waveBlocks[i].dwFlags & WHDR_PREPARED)242
waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));243

244
DeleteCriticalSection(&waveCriticalSection);245
freeBlocks(waveBlocks);246
waveOutClose(hWaveOut);247

248
avcodec_close(audio_state.pCodecCtx);249

250
system("pause");251
return 0;252
}253

254
static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size)255
{256
WAVEHDR* current;257
int remain;258

259
current = &waveBlocks[waveCurrentBlock];260

261
while(size > 0) {262
/* 263
* first make sure the header we're going to use is unprepared264
*/265
if(current->dwFlags & WHDR_PREPARED)266
waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));267

268
if(size < (int)(BLOCK_SIZE - current->dwUser)) {269
memcpy(current->lpData + current->dwUser, data, size);270
current->dwUser += size;271
break;272
}273

274
remain = BLOCK_SIZE - current->dwUser;275
memcpy(current->lpData + current->dwUser, data, remain);276
size -= remain;277
data += remain;278
current->dwBufferLength = BLOCK_SIZE;279

280
waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));281
waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));282

283
EnterCriticalSection(&waveCriticalSection);284
waveFreeBlockCount--;285
LeaveCriticalSection(&waveCriticalSection);286

287
/*288
* wait for a block to become free289
*/290
while(!waveFreeBlockCount)291
Sleep(10);292

293
/*294
* point to the next block295
*/296
waveCurrentBlock++;297
waveCurrentBlock %= BLOCK_COUNT;298

299
current = &waveBlocks[waveCurrentBlock];300
current->dwUser = 0;301
}302
}303

304
static WAVEHDR* allocateBlocks(int size, int count)305
{306
char* buffer;307
int i;308
WAVEHDR* blocks;309
DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;310

311
/*312
* allocate memory for the entire set in one go313
*/314
if((buffer = (char*)HeapAlloc(315
GetProcessHeap(), 316
HEAP_ZERO_MEMORY, 317
totalBufferSize318
)) == NULL) {319
fprintf(stderr, "Memory allocation error\n");320
ExitProcess(1);321
}322

323
/*324
* and set up the pointers to each bit325
*/326
blocks = (WAVEHDR*)buffer;327
buffer += sizeof(WAVEHDR) * count;328
for(i = 0; i < count; i++) {329
blocks[i].dwBufferLength = size;330
blocks[i].lpData = buffer;331
buffer += size;332
}333

334
return blocks;335
}336

337
static void freeBlocks(WAVEHDR* blockArray)338
{339
/* 340
* and this is why allocateBlocks works the way it does341
*/ 342
HeapFree(GetProcessHeap(), 0, blockArray);343
}344

345
static void CALLBACK waveOutProc(346
HWAVEOUT hWaveOut, 347
UINT uMsg, 348
DWORD dwInstance, 349
DWORD dwParam1, 350
DWORD dwParam2 351
)352
{353
int* freeBlockCounter = (int*)dwInstance;354
/*355
* ignore calls that occur due to opening and closing the356
* device.357
*/358
if(uMsg != WOM_DONE)359
return;360

361
EnterCriticalSection(&waveCriticalSection);362
(*freeBlockCounter)++;363
LeaveCriticalSection(&waveCriticalSection);364
}



