JACKY_ZZ[猫猫爱吃鱼]

春风拂面两颊红,秋叶洒地一片金。 夏荷摇曳一身轻,冬雪覆盖大地银。
posts - 30, comments - 123, trackbacks - 0, articles - 0
这是一个基于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, 00))
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       00320100, 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 = {0000};
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 + 430018, hMainWindow, NULL, hInstance, NULL);
269    SendMessage(hTrackBar, TBM_SETRANGE, (WPARAM)FALSE, (LPARAM) MAKELONG (0100));
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 + 11010018, 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, 00);
328                 }
329             }
330             break;
331         case ID_STOP:
332             {
333                 if(Playing == TRUE && hMainLoopThread && dwMainLoopThreadId)
334                     PostThreadMessage(dwMainLoopThreadId, TM_EOF, 00);
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, 00);
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, 00);
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, 00, 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, 0sizeof(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, 00, 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, 00);
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, 00);
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, 00);
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, 00);
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(001, 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                         0000);
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, 0sizeof(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, 00);
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                     0000);
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

Feedback

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)[未登录]  回复  更多评论   

2010-04-12 11:06 by tina
一直帮助猫猫测试着播放器,试着一个一个不断更新的版本,体验着一个一个不断增加的新功能,有时候偶尔提出一两个需求,可以说,见证了播放器的开发过程,见证了猫猫的心血。
不论怎么说,支持你!加油!

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-12 15:56 by 欣萌
用ffmpeg做的播放器。。。
有技术含量吗???

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-12 16:23 by jacky_zz
非得自己写解码器才叫有技术含量?
Show一个来看看你所谓的技术含量?

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-13 02:22 by 欲三更
@欣萌
难不成您想自己做个ffmpeg?

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-13 09:23 by 欣萌
其实不是说你做的不好。
我平时也用ffmpeg作很多东西,成功之后。总会觉得,真的很失败。自己做的很少。不过是因为这个库太强大。

我是做编解码器的。所以深刻知道,一个播放器哪里才是最有技术含量的。冒犯到你不好意思啊。

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-13 09:34 by 万连文
1、大音希声,大道无形,大智之人,不耽于形,不逐于力,不恃于技
2、用建议的方式而不是批评的方式对待他人的成果,这样会更好

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-13 14:30 by jacky_zz
其实我发布这个程序不是为了吸引网友的眼球,更多的是为了记录自己在学习过程中的一点心得,以便过了N年后回过头来看看自己曾经走过的路,我选择的更多的是默默的去探索,而不愿去更多的争辩,于事无补。

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-13 15:53 by 欲三更
@欣萌
啊哦, 有眼不识泰山, 真遇到做编解码器的了...

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-13 20:34 by 欣萌
@jacky_zz
没想到你居然很在意那条评论。实在对不起。

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-14 08:28 by jacky_zz
TO欣萌:没啊,别人怎么评论那是他的想法,我坚持走自己的路。

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-14 08:52 by ccsdu2009
从纯技术的观点说也许使用ffmpeg感觉没多大挑战性
但是从商业角度考虑 能复用别人的东西则更好
从非流媒体工程师而言 基于这些第三方库是最好的选择
我使用过vlc,ffmpeg

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-04-14 10:34 by jacky_zz
使用什么不重要,而是你能从中得到什么,每个人的侧重点不一样,选择的方向就不一样,得到的结果就不一样,但有一样是相同的,No Pains, No Gains.

# CodeProject一识博主,再在二相遇实属缘分  回复  更多评论   

2010-08-07 10:50 by hetao.su
首先说一下我的系统环境,XP SP3+VC6,Ffmpeg编译环境是SYS+MinGW,采用动态链接库的方式编译,我采用的是Ffmpeg0.5版本,博主可能是采用0.6吧,avcodec_decode_audio3 0.5版本没有这个函数,只有avcodec_decode_audio2。轻微修改一下博主的有关,Ffmpeg解码器的简单播放器的源代码,就可以在VC6上编译运行了,无非就是把修改一下头文件的一些lib,一些VC9的字符串操作换成VC6的,修改,long long 换成__int64,还有几个X##LL等等的这些宏定义。对于博主这种分享精神,我表示赞同,本着交流的心态,说一下我的愚见,我想这里存在一些设计的漏洞,如果单纯说实现播放音乐,是做到了。但是使用的填充解码DAUDIO_Write之后采用Sleep这种方式,估计是为了确保lock的时候可以lock在播放光标之前4608byte,不至于覆盖了播放光标前的数据,同时让解码器休息。本人愚见,为什么不采用ds的事件通知机制,虽然DirectSound控制单元来自jdk1.6源码看似使用很方便,稍稍看了一下他的封装,在DS_createSoundBuffer创建dsbuffer的时候他只简单的传入DSBCAPS_GETCURRENTPOSITION2,DSBCAPS_GLOBALFOCUS两种参数,也就是说他没有实现事件通知。为了说明问题,我在创建dsbuffer的函数createSoundBuffer中加入DSBCAPS_CTRLFREQUENCY参数,表示可以修改频率(播放速度),好啦。然后在MainLoopThreadProc的if(Playing == TRUE && info != NULL)之后也就是真正播放的地方,加个调用info->playBuffer->SetFrequency(2*samplerate);//两倍速播放。这个时候找个窗体复杂的软件,不停的最小化和放大它,造成xp的消息队列比较繁琐,嘿嘿,效果就出来了。或者再快一点info->playBuffer->SetFrequency(4*samplerate);//四倍 我想肯定不能播放了。完全可以放弃jdk1.6的DS控制单元,自己实现一个DS的操作类,实现通知机制,这样子就灵活多了。只是实现事件通知的方式,我就不在这里复述,网上多的是例子。

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2010-09-21 17:41 by metaza
都是牛人

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)[未登录]  回复  更多评论   

2010-11-08 16:27 by tj
您好,可否将您的源代码给我一份。。。貌似给的源码压缩包损坏了。。。谢谢

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)[未登录]  回复  更多评论   

2010-11-08 16:28 by tj
我的邮箱是xiaozhu_tc@yeah.net

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2011-01-15 12:36 by longyaner
ad as

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2011-03-21 12:16 by ffmpeg
好像编译不了,楼主确定吗

# re: 基于Ffmpeg解码器的简单播放器(a simple audio player based on Ffmpeg)  回复  更多评论   

2013-03-16 09:04 by 陈阿铭
TO 欣萌

真不知道这有什么好炫耀的,又没有什么好处,做人不能谦虚一点嘛?难道稻米不是亲自收成的你就不吃饭啦?

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理