这是一个基于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 源码2 源码3
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))
主程序代码如下:
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 }
由于是新近开发,代码注释不多,敬请原谅。
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