这是一个基于Ffmpeg解码器的简单播放器,怎么在Windows上编译Ffmpeg可以在网上找到很多,开发环境是Windows XP SP3+VS2008,其中DirectSound控制单元来自jdk1.6源码。我的Ffmpeg编译环境是MSYS+MinGW,GCC版本为4.4.0,采取静态无DEBUG方式编译,得到libavcodec.a、libavformat.a和libavutil.a三个静态库,将静态库引入工程,代码如下:
1 #pragma once
2
3 #define WIN32_LEAN_AND_MEAN
4
5 #include "targetver.h"
6 #include <windows.h>
7 #include <commdlg.h>
8
9 #include <stdlib.h>
10 #include <malloc.h>
11 #include <memory.h>
12 #include <tchar.h>
13 #include <math.h>
14 #include <mmsystem.h>
15 #include <dsound.h>
16 #include <commctrl.h>
17
18 #include <list>
19 #include <vector>
20 using namespace std;
21
22 #pragma comment(lib, "winmm.lib")
23 #pragma comment(lib, "dsound.lib")
24 #pragma comment(lib, "msimg32.lib")
25 #pragma comment(lib, "wsock32.lib")
26 #pragma comment(lib, "comctl32.lib")
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 #pragma warning(disable : 4005)
33 #pragma warning(disable : 4049)
34
35 #include "./include/avcodec.h"
36 #include "./include/avformat.h"
37 #include "./include/avutil.h"
38 #include "./include/mem.h"
39
40 #pragma comment(lib, "./lib/libgcc.a")
41 #pragma comment(lib, "./lib/libmingwex.a")
42 #pragma comment(lib, "./lib/libcoldname.a")
43
44 #pragma comment(lib, "./lib/libavcodec.a")
45 #pragma comment(lib, "./lib/libavformat.a")
46 #pragma comment(lib, "./lib/libavutil.a")
47
48
49 #ifdef __cplusplus
50 }
51 #endif
52
53 #define USE_DAUDIO TRUE
54 #define round(a) ((long)floor((a) + 0.5f))
主程序代码如下:
1 #include "stdafx.h"
2 #include "SimpleFfmpegPlayer.h"
3 #include "DirectSound.h"
4
5 #define MAX_LOADSTRING 100
6 #define BLOCK_SIZE 4608
7
8 // Thread Message Define Here
9 #define TM_PLAY 0
10 #define TM_PAUSE 1
11 #define TM_RESUME 2
12 #define TM_SEEK 3
13 #define TM_STOP 4
14 #define TM_OPENFILE 5
15 #define TM_PREVIOUS 6
16 #define TM_NEXT 7
17 #define TM_EOF 8
18 #define TM_PLAYITEM 9
19
20 struct StartParameter
21 {
22 HWND hMainWnd;
23 HANDLE hThreadReadyEvent;
24 };
25
26 HINSTANCE hInst;
27 TCHAR szTitle[MAX_LOADSTRING];
28 TCHAR szWindowClass[MAX_LOADSTRING];
29 HWND hMainWindow = NULL;
30 HWND hTrackBar = NULL;
31 HWND hStatic = NULL;
32
33 DWORD dwMainLoopThreadId = 0;
34 HANDLE hMainLoopThread = NULL;
35
36 BOOL Playing = FALSE;
37
38 TCHAR szFileName[MAX_PATH];
39 int gTotalSeconds;
40 int gCurPlaySeconds;
41 int gPosition;
42
43 HFONT hFont;
44
45 ATOM MyRegisterClass(HINSTANCE hInstance);
46 BOOL InitInstance(HINSTANCE, int);
47 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
48 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
49 DWORD WINAPI MainLoopThreadProc(VOID*);
50 LRESULT CALLBACK StaticWndProc(HWND, UINT, WPARAM, LPARAM);
51
52 #define SUPPORT_FILTER _TEXT("All supported files\0*.aac;*.ape;*.flac;*.mp3;*.mpc;*.ogg;*.tta;*.wav;*.wma;*.wv\0") \
53 _TEXT("AAC files(*.aac)\0*.aac\0") \
54 _TEXT("APE files(*.ape)\0*.ape\0") \
55 _TEXT("FLAC files(*.flac)\0*.flac\0") \
56 _TEXT("MP3 files(*.mp3)\0*.mp3\0") \
57 _TEXT("MPC files(*.mpc)\0*.mpc\0") \
58 _TEXT("Ogg vorbis files(*.ogg)\0*.ogg\0") \
59 _TEXT("TTA files(*.tta)\0*.tta\0") \
60 _TEXT("Wave files(*.wav)\0*.wav\0") \
61 _TEXT("WMA files(*.wma)\0*.wma\0") \
62 _TEXT("Wavpack files(*.wv)\0*.wv\0") \
63 _TEXT("All files(*.*)\0*.*\0")
64
65 typedef struct AudioState
66 {
67 AVFormatContext* pFmtCtx;
68 AVCodecContext* pCodecCtx;
69 AVCodec* pCodec;
70
71 #ifdef OUTPUT_INFORMATS
72 AVInputFormat* ifmt;
73 #endif
74
75 uint8_t* audio_buf1;
76 uint8_t* audio_buf;
77 unsigned int audio_buf_size;
78 unsigned int buffer_size;
79 int audio_buf_index;
80 AVPacket audio_pkt_temp;
81 AVPacket audio_pkt;
82 uint8_t* audio_pkt_data;
83 int audio_pkt_size;
84 int stream_index;
85 } AudioState;
86
87 long align(long bytes, int blockSize) {
88 // prevent null pointers
89 if (blockSize <= 1)
90 return bytes;
91
92 return bytes - (bytes % blockSize);
93 }
94
95 long millis2bytes(int samplerate, long millis, int frameSize)
96 {
97 long result = (long) (millis * samplerate / 1000.0f * frameSize);
98 return align(result, frameSize);
99 }
100
101 long bytes2millis(int samplerate, long bytes, int frameSize) {
102 return (long) (bytes / samplerate * 1000.0f / frameSize);
103 }
104
105 int audio_decode_frame(AudioState* pState)
106 {
107
108 AVPacket* pkt_temp = &pState->audio_pkt_temp;
109 AVPacket* pkt = &pState->audio_pkt;
110 AVCodecContext* dec= pState->pCodecCtx;
111 int len = 0, data_size = sizeof(pState->audio_buf1);
112 int err = 0;
113
114 for( ; ; )
115 {
116 while (pkt_temp->size > 0)
117 {
118 data_size = pState->buffer_size;
119 len = avcodec_decode_audio3(dec, (int16_t*)pState->audio_buf1, &data_size, pkt_temp);
120 if (len < 0)
121 {
122 /* if error, we skip the frame */
123 pkt_temp->size = 0;
124 break;
125 }
126
127 pkt_temp->data += len;
128 pkt_temp->size -= len;
129
130 if (data_size <= 0)
131 continue;
132
133 pState->audio_buf = pState->audio_buf1;
134 return data_size;
135 }
136
137 if (pkt->data)
138 av_free_packet(pkt);
139
140 if((err = av_read_frame(pState->pFmtCtx, pkt)) < 0)
141 return -1;
142
143 pkt_temp->data = pkt->data;
144 pkt_temp->size = pkt->size;
145 }
146
147 return -1;
148 }
149
150 int read_buffer(AudioState* pState, void* buffer, int buf_size)
151 {
152 int len = buf_size;
153 uint8_t* pbuffer = (uint8_t*)buffer;
154 int audio_size = 0;
155 int len1 = 0;
156 int size = 0;
157
158 while(len > 0)
159 {
160 if(pState->audio_buf_index >= (int)pState->audio_buf_size)
161 {
162 audio_size = audio_decode_frame(pState);
163 if(audio_size < 0)
164 return (size > 0) ? size : -1;
165
166 pState->audio_buf_size = audio_size;
167 pState->audio_buf_index = 0;
168 }
169
170 len1 = pState->audio_buf_size - pState->audio_buf_index;
171 if(len1 > len)
172 len1 = len;
173
174 memcpy(pbuffer, (uint8_t *)pState->audio_buf + pState->audio_buf_index, len1);
175
176 len -= len1;
177 pbuffer += len1;
178 size += len1;
179 pState->audio_buf_index += len1;
180 }
181
182 return size;
183 }
184
185 int APIENTRY _tWinMain(HINSTANCE hInstance,
186 HINSTANCE hPrevInstance,
187 LPTSTR lpCmdLine,
188 int nCmdShow)
189 {
190 UNREFERENCED_PARAMETER(hPrevInstance);
191 UNREFERENCED_PARAMETER(lpCmdLine);
192
193 MSG msg;
194 HACCEL hAccelTable;
195
196 INITCOMMONCONTROLSEX cex = {sizeof(INITCOMMONCONTROLSEX),
197 ICC_BAR_CLASSES | ICC_PROGRESS_CLASS};
198 BOOL ret = InitCommonControlsEx(&cex);
199
200 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
201 LoadString(hInstance, IDC_SIMPLEFFMPEGPLAYER, szWindowClass, MAX_LOADSTRING);
202 MyRegisterClass(hInstance);
203
204 if (!InitInstance (hInstance, nCmdShow))
205 {
206 return FALSE;
207 }
208
209 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SIMPLEFFMPEGPLAYER));
210
211 while (GetMessage(&msg, NULL, 0, 0))
212 {
213 if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
214 {
215 TranslateMessage(&msg);
216 DispatchMessage(&msg);
217 }
218 }
219
220 return (int) msg.wParam;
221 }
222
223 ATOM MyRegisterClass(HINSTANCE hInstance)
224 {
225 WNDCLASSEX wcex;
226
227 wcex.cbSize = sizeof(WNDCLASSEX);
228
229 wcex.style = CS_HREDRAW | CS_VREDRAW;
230 wcex.lpfnWndProc = WndProc;
231 wcex.cbClsExtra = 0;
232 wcex.cbWndExtra = 0;
233 wcex.hInstance = hInstance;
234 wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SIMPLEFFMPEGPLAYER));
235 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
236 wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
237 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_SIMPLEFFMPEGPLAYER);
238 wcex.lpszClassName = szWindowClass;
239 wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
240
241 return RegisterClassEx(&wcex);
242 }
243
244 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
245 {
246 HWND hWnd;
247
248 hInst = hInstance;
249
250 DWORD dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
251 hWnd = CreateWindow(szWindowClass, szTitle, dwStyle,
252 0, 0, 320, 100, NULL, NULL, hInstance, NULL);
253
254 if (!hWnd)
255 {
256 return FALSE;
257 }
258
259 hMainWindow = hWnd;
260
261 hFont = CreateFont(18,0,0,0,FW_BLACK,FALSE,FALSE,FALSE,
262 GB2312_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
263 DEFAULT_QUALITY,FIXED_PITCH | FF_MODERN,_T("Tahoma"));
264
265 RECT r = {0, 0, 0, 0};
266 GetWindowRect(hMainWindow, &r);
267 hTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, _T(""), WS_CHILD | WS_VISIBLE | TBS_BOTH | TBS_NOTICKS,
268 r.left + 4, (r.bottom - r.top) / 6 + 4, 300, 18, hMainWindow, NULL, hInstance, NULL);
269 SendMessage(hTrackBar, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM) MAKELONG (0, 100));
270 SendMessage(hTrackBar, TBM_SETLINESIZE, (WPARAM)0, (LPARAM)5);
271 SendMessage(hTrackBar, TBM_SETPAGESIZE, (WPARAM)0, (LPARAM)5);
272
273 GetClientRect(hMainWindow, &r);
274 hStatic = CreateWindowEx(0, WC_STATIC, _T("00:00/00:00"), WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | SS_CENTER | SS_LEFT,
275 (r.right - r.left) / 4 + 11, 0, 100, 18, hMainWindow, NULL, hInstance, NULL);
276
277 SetWindowLong(hStatic, GWL_WNDPROC, (LONG)StaticWndProc);
278
279 ShowWindow(hWnd, nCmdShow);
280 UpdateWindow(hWnd);
281
282 return TRUE;
283 }
284
285 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
286 {
287 int wmId, wmEvent;
288 PAINTSTRUCT ps;
289 HDC hdc;
290 TCHAR buffer[128] = {0};
291
292 switch (message)
293 {
294 case WM_COMMAND:
295 wmId = LOWORD(wParam);
296 wmEvent = HIWORD(wParam);
297
298 switch (wmId)
299 {
300 case IDM_ABOUT:
301 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
302 break;
303 case IDM_EXIT:
304 DestroyWindow(hWnd);
305 break;
306 case ID_PLAY:
307 {
308 if(Playing == TRUE)
309 break;
310
311 OPENFILENAME ofn = {0};
312 ofn.lStructSize = sizeof(ofn);
313 ofn.hwndOwner = hMainWindow;
314 ofn.lpstrFile = szFileName;
315 ofn.lpstrFile[0] = _T('\0');
316 ofn.nMaxFile = sizeof(szFileName) / sizeof(szFileName[0]);
317 ofn.lpstrFilter = SUPPORT_FILTER;
318 ofn.nFilterIndex = 1;
319 ofn.lpstrFileTitle = NULL;
320 ofn.nMaxFileTitle = 0;
321 ofn.lpstrInitialDir = NULL;
322 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
323
324 if(GetOpenFileName(&ofn) == TRUE)
325 {
326 if(hMainLoopThread && dwMainLoopThreadId && Playing == FALSE)
327 PostThreadMessage(dwMainLoopThreadId, TM_PLAY, 0, 0);
328 }
329 }
330 break;
331 case ID_STOP:
332 {
333 if(Playing == TRUE && hMainLoopThread && dwMainLoopThreadId)
334 PostThreadMessage(dwMainLoopThreadId, TM_EOF, 0, 0);
335 }
336 break;
337 default:
338 return DefWindowProc(hWnd, message, wParam, lParam);
339 }
340 break;
341 case WM_PAINT:
342 hdc = BeginPaint(hWnd, &ps);
343
344 EndPaint(hWnd, &ps);
345 break;
346 case WM_DESTROY:
347 if(hMainLoopThread && dwMainLoopThreadId)
348 {
349 PostThreadMessage(dwMainLoopThreadId, TM_STOP, 0, 0);
350
351 CloseHandle(hMainLoopThread);
352 hMainLoopThread = NULL;
353 }
354
355 DeleteObject(hFont);
356 DestroyWindow(hTrackBar);
357 DestroyWindow(hStatic);
358 PostQuitMessage(0);
359 break;
360 case WM_NOTIFY:
361 {
362 NMHDR* pNMHDR = (NMHDR*)lParam;
363 if(pNMHDR->hwndFrom == hTrackBar)
364 {
365 LRESULT ret = SendMessage(hTrackBar, TBM_GETPOS, 0, 0);
366 if( ret != gPosition && Playing)
367 PostThreadMessage(dwMainLoopThreadId, TM_SEEK, (WPARAM)ret, 0);
368 }
369 }
370 break;
371 case WM_CREATE:
372 {
373 // start main play loop thread
374 HANDLE hThreadReadyEvent = CreateEvent(NULL, TRUE, FALSE, _T("ThreadReadyEvent"));
375
376 StartParameter startParam = {hWnd, hThreadReadyEvent};
377
378 dwMainLoopThreadId = 0;
379 hMainLoopThread = CreateThread(NULL, 0, MainLoopThreadProc, &startParam,
380 CREATE_SUSPENDED, &dwMainLoopThreadId);
381
382 ResumeThread(hMainLoopThread);
383 WaitForSingleObject(hThreadReadyEvent, INFINITE);
384
385 CloseHandle(hThreadReadyEvent);
386 hThreadReadyEvent = NULL;
387 }
388 break;
389 default:
390 return DefWindowProc(hWnd, message, wParam, lParam);
391 }
392 return 0;
393 }
394
395 LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
396 {
397 PAINTSTRUCT ps;
398 HDC hdc;
399 HFONT holdfont;
400 TCHAR buffer[MAX_PATH] = {0};
401 RECT r = {0};
402
403 switch(message)
404 {
405 case WM_PAINT :
406 {
407 hdc = BeginPaint(hWnd, &ps);
408
409 GetClientRect(hWnd, &r);
410 FillRect(hdc, &r, (HBRUSH)(COLOR_BTNFACE+1));
411
412 SetBkMode(hdc, TRANSPARENT);
413
414 GetWindowText(hWnd, buffer, MAX_PATH);
415 holdfont = (HFONT)SelectObject(hdc, hFont);
416 TextOut(hdc, 0, 0, buffer, _tcslen(buffer));
417 SelectObject(hdc, holdfont);
418
419 EndPaint(hWnd, &ps);
420 }
421 break;
422 case WM_ERASEBKGND:
423 return 1;
424 default:
425 return DefWindowProc(hWnd, message, wParam, lParam);
426 }
427
428 return 0;
429 }
430
431 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
432 {
433 UNREFERENCED_PARAMETER(lParam);
434 switch (message)
435 {
436 case WM_INITDIALOG:
437 return (INT_PTR)TRUE;
438
439 case WM_COMMAND:
440 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
441 {
442 EndDialog(hDlg, LOWORD(wParam));
443 return (INT_PTR)TRUE;
444 }
445 break;
446 }
447 return (INT_PTR)FALSE;
448 }
449
450 DWORD WINAPI MainLoopThreadProc(VOID* pParam)
451 {
452 StartParameter* pStartParam = (StartParameter*)pParam;
453 BOOL bTerminateThread = FALSE;
454
455 // register all codecs.
456 av_register_all();
457 SetEvent(pStartParam->hThreadReadyEvent);
458
459 AudioState state = {0};
460 int buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
461 memset(&state, 0, sizeof(AudioState));
462
463 int err = 0;
464 char filepath[MAX_PATH] = {0};
465
466 __int64 duration = 0;
467 int totalSeconds = 0;
468 int minute = 0;
469 int second = 0;
470 int totalMinute = 0;
471 int totalSecond = 0;
472
473 int channels = 0;
474 int samplerate = 0;
475 int bitpersample = 16;
476
477 DS_Info* info = NULL;
478 int frameSize = 0;
479 long bufferSize = 0;
480 int bytesPerSec = 0;
481 long waitTime = 0;
482 int deviceCount = 0;
483
484 DWORD readBytes = 0;
485 char input_buffer[BLOCK_SIZE] = {0};
486 TCHAR szTime[20] = {0};
487 TCHAR szPosition[10] = {0};
488
489 do
490 {
491 MSG msg = {0};
492 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
493 {
494 switch(msg.message)
495 {
496 case TM_PLAY:
497 {
498
499 #ifdef _UNICODE
500 WideCharToMultiByte(CP_ACP, 0, szFileName, -1, filepath, sizeof(filepath) / sizeof(char), NULL, NULL);
501 #else
502 memcpy(filepath, szFileName, sizeof(filepath) / sizeof(char));
503 #endif
504
505 err = av_open_input_file(&state.pFmtCtx, filepath, NULL, 0, NULL);
506 if(err < 0)
507 {
508 TCHAR buffer[2*MAX_PATH];
509 _stprintf_s(buffer, sizeof(TCHAR) * (2 * MAX_PATH), _T("can not open file %s."), filepath);
510 MessageBox(hMainWindow, buffer, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
511
512 Playing = FALSE;
513
514 if(hMainLoopThread && dwMainLoopThreadId)
515 PostThreadMessage(dwMainLoopThreadId, TM_EOF, 0, 0);
516
517 break;
518 }
519
520 err = av_find_stream_info(state.pFmtCtx);
521 if(err < 0)
522 {
523 TCHAR buffer[2*MAX_PATH];
524 _stprintf_s(buffer, sizeof(TCHAR) * (2 * MAX_PATH), _T("can not find stream info of file %s."), filepath);
525 MessageBox(hMainWindow, buffer, _T("Error"), MB_OK | MB_ICONEXCLAMATION);
526
527 Playing = FALSE;
528
529 if(hMainLoopThread && dwMainLoopThreadId)
530 PostThreadMessage(dwMainLoopThreadId, TM_EOF, 0, 0);
531
532 break;
533 }
534
535 int index = -1;
536 for(unsigned int i = 0; i < state.pFmtCtx->nb_streams; i++)
537 {
538 if(state.pFmtCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
539 {
540 state.pCodecCtx = state.pFmtCtx->streams[i]->codec;
541 index = i;
542 state.stream_index = i;
543 break;
544 }
545 }
546
547 if(!state.pCodecCtx)
548 {
549 MessageBox(hMainWindow, _T("can not get codec context."), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
550 av_close_input_file(state.pFmtCtx);
551
552 Playing = FALSE;
553
554 if(hMainLoopThread && dwMainLoopThreadId)
555 PostThreadMessage(dwMainLoopThreadId, TM_EOF, 0, 0);
556
557 break;
558 }
559
560 state.pCodec = avcodec_find_decoder(state.pCodecCtx->codec_id);
561 if(!state.pCodec || avcodec_open(state.pCodecCtx, state.pCodec) < 0)
562 {
563 MessageBox(hMainWindow, _T("can not open codec."), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
564 av_close_input_file(state.pFmtCtx);
565
566 Playing = FALSE;
567
568 if(hMainLoopThread && dwMainLoopThreadId)
569 PostThreadMessage(dwMainLoopThreadId, TM_EOF, 0, 0);
570
571 break;
572 }
573
574 duration = state.pFmtCtx->duration;
575 totalSeconds = (int)(duration / 1000000L);
576 gTotalSeconds = totalSeconds;
577 totalMinute = (int)(totalSeconds / 60);
578 totalSecond = (int)(totalSeconds % 60);
579
580 state.audio_buf1 = (uint8_t*)av_mallocz(buffer_size);
581 state.buffer_size = buffer_size;
582
583 channels = state.pCodecCtx->channels;
584 samplerate = state.pCodecCtx->sample_rate;
585
586 bitpersample = 16;
587 switch(state.pCodecCtx->sample_fmt)
588 {
589 case SAMPLE_FMT_U8:
590 bitpersample = 8;
591 break;
592 case SAMPLE_FMT_S16:
593 bitpersample = 16;
594 break;
595 case SAMPLE_FMT_S32:
596 bitpersample = 32;
597 break;
598 case SAMPLE_FMT_FLT:
599 bitpersample = sizeof(double) * 8;
600 break;
601 default:
602 bitpersample = 0;
603 break;
604 }
605
606 frameSize = (channels == 1) ? 2 : 4;
607 bufferSize = millis2bytes(samplerate, 500, frameSize);
608 bytesPerSec = samplerate * frameSize;
609
610 waitTime = bytes2millis(samplerate, bufferSize, frameSize) / 4;
611 if(waitTime < 10) waitTime = 1;
612 if(waitTime > 1000) waitTime = 1000;
613
614 deviceCount = DAUDIO_GetDirectAudioDeviceCount();
615 info = (DS_Info*)DAUDIO_Open(0, 0, 1, DAUDIO_PCM, (float)samplerate,
616 bitpersample, frameSize, channels, TRUE, FALSE, bufferSize);
617
618 if(info != NULL && DAUDIO_Start((void*)info, TRUE))
619 {
620 Playing = TRUE;
621 PostMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
622 }
623 }
624 break;
625 case TM_STOP:
626 {
627 if(info)
628 {
629 DAUDIO_Stop((void*)info, TRUE);
630 DAUDIO_Close((void*)info, TRUE);
631 info = NULL;
632
633 av_free(state.audio_buf1);
634 state.audio_buf1 = NULL;
635
636 avcodec_close(state.pCodecCtx);
637 av_close_input_file(state.pFmtCtx);
638 }
639
640 Playing = FALSE;
641 bTerminateThread = TRUE;
642 }
643 break;
644 case TM_EOF:
645 {
646 if(info)
647 {
648 DAUDIO_Stop((void*)info, TRUE);
649 DAUDIO_Close((void*)info, TRUE);
650 info = NULL;
651
652 av_free(state.audio_buf1);
653 state.audio_buf1 = NULL;
654
655 avcodec_close(state.pCodecCtx);
656 av_close_input_file(state.pFmtCtx);
657 }
658
659 SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
660
661 _stprintf_s(szTime, sizeof(szTime)/sizeof(szTime[0]), _T("%02d:%02d/%02d:%02d"),
662 0, 0, 0, 0);
663 SendMessage(hStatic, WM_SETTEXT, (WPARAM)0, (LPARAM)szTime);
664
665 RECT r = {0};
666 GetClientRect(hStatic, &r);
667 InvalidateRect(hStatic, &r, FALSE);
668
669 Playing = FALSE;
670 }
671 break;
672 case TM_SEEK:
673 {
674 if(Playing == TRUE && info != NULL)
675 {
676 MSG msg2;
677 if (PeekMessage(&msg2, NULL, TM_SEEK, TM_SEEK, PM_NOREMOVE) == FALSE)
678 {
679 int seekPosition = (int)msg.wParam;
680 int timestamp = (int)(gTotalSeconds * (float)seekPosition/100);
681 int ret = av_seek_frame(state.pFmtCtx, -1, timestamp * AV_TIME_BASE, 0);
682 avcodec_flush_buffers(state.pCodecCtx);
683 info->bytesPos = timestamp * bytesPerSec;
684 DAUDIO_Flush((void*)info, TRUE);
685 }
686 }
687 }
688 break;
689 default:
690 break;
691 }
692 }
693
694 if(bTerminateThread == TRUE)
695 break;
696
697 if(Playing == TRUE && info != NULL)
698 {
699 memset(input_buffer, 0, sizeof(input_buffer));
700 readBytes = 0;
701
702 readBytes = read_buffer(&state, input_buffer, BLOCK_SIZE);
703 if(readBytes == -1)
704 {
705 Sleep(250);
706 Playing = FALSE;
707
708 if(hMainLoopThread && dwMainLoopThreadId)
709 PostThreadMessage(dwMainLoopThreadId, TM_EOF, 0, 0);
710
711 SendMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
712
713 _stprintf_s(szTime, sizeof(szTime)/sizeof(szTime[0]), _T("%02d:%02d/%02d:%02d"),
714 0, 0, 0, 0);
715 SendMessage(hStatic, WM_SETTEXT, (WPARAM)0, (LPARAM)szTime);
716
717 RECT r = {0};
718 GetClientRect(hStatic, &r);
719 InvalidateRect(hStatic, &r, FALSE);
720
721 goto NextLoop;
722 }
723
724 DWORD len = readBytes;
725 DWORD offset = 0;
726 DWORD written = 0;
727
728 for( ; ; )
729 {
730 int thisWritten = DAUDIO_Write((void*)info, input_buffer+offset, len);
731 if(thisWritten < 0)
732 break;
733
734 len -= thisWritten;
735 written += thisWritten;
736 if(len > 0)
737 {
738 offset += thisWritten;
739 Sleep(waitTime);
740 }
741 else break;
742 }
743
744 // update progress
745 {
746 __int64 wFp = DAUDIO_GetLongFramePosition((void*)info, TRUE);
747 __int64 byteLen = wFp * frameSize;
748 gCurPlaySeconds = (int)byteLen / bytesPerSec;
749
750 int seconds = (int)byteLen / bytesPerSec;
751 minute = (int)(seconds / 60);
752 second = (int)(seconds % 60);
753
754 _stprintf_s(szTime, sizeof(szTime)/sizeof(szTime[0]), _T("%02d:%02d/%02d:%02d"),
755 minute, second, totalMinute, totalSecond);
756 SendMessage(hStatic, WM_SETTEXT, (WPARAM)0, (LPARAM)szTime);
757
758 RECT r = {0};
759 GetClientRect(hStatic, &r);
760 InvalidateRect(hStatic, &r, FALSE);
761
762 float percent = (float)seconds / totalSeconds;
763 int position = round(percent * 100);
764 if(position >= 100)
765 position = 100;
766
767 gPosition = position;
768 PostMessage(hTrackBar, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)position);
769
770 // _stprintf_s(szPosition, 10, _T("%02d\n"), position);
771 // OutputDebugString(szPosition);
772 }
773 }
774 else
775 {
776 WaitMessage();
777 }
778
779 NextLoop:
780 ;
781 } while (bTerminateThread == FALSE);
782
783 return 0;
784 }
由于是新近开发,代码注释不多,敬请原谅。
源码下载:
源码1 源码2 源码3