JACKY_ZZ[猫猫爱吃鱼]

春风拂面两颊红,秋叶洒地一片金。 夏荷摇曳一身轻,冬雪覆盖大地银。
posts - 30, comments - 123, trackbacks - 0, articles - 0
无法在XP下运行。
re: 音频文件频谱[未登录] jacky_zz 2012-03-09 18:02
@tfzxyinhao,spek就是开源的啊,vala+GTK开发
re: ffmpeg小试[未登录] jacky_zz 2011-12-26 15:34
@glueless lace wigs
不是,要是有那本事,就不玩了。
是实时频谱分析仪
提个建议啊,能把bin下的那个wmv换掉吗??太大了!!!!
又有新版本发布了,持续关注ing。
第一次看到,我也有过类似经历。
哦,期待ing。
更新到x-framework的svn了吗?
又出新作品了?
代码生成选项选择多线程版本噻,就不需要DLL了
re: 基于mplayer的开发 jacky_zz 2011-02-11 11:04
spectrum_analyzer.dll不开源
re: 基于mplayer的开发 jacky_zz 2011-01-18 17:55
to chris:
我下载了mplayer-ww的源码,但是编译不成mplayer-ww的发布版本,无奈下自己做了自己的界面。
re: 基于mplayer的开发 jacky_zz 2011-01-18 17:53
to gaimor:
我的QQ是59502553
使用什么不重要,而是你能从中得到什么,每个人的侧重点不一样,选择的方向就不一样,得到的结果就不一样,但有一样是相同的,No Pains, No Gains.
TO欣萌:没啊,别人怎么评论那是他的想法,我坚持走自己的路。
其实我发布这个程序不是为了吸引网友的眼球,更多的是为了记录自己在学习过程中的一点心得,以便过了N年后回过头来看看自己曾经走过的路,我选择的更多的是默默的去探索,而不愿去更多的争辩,于事无补。
非得自己写解码器才叫有技术含量?
Show一个来看看你所谓的技术含量?
你做了这方面的工作了吗?
经测试,4608这个值是不会出现overrun的,我参看了很多开源的winamp插件,这个值出现的频率很高。
PS:你提到的这个方案我原来也考虑过,好像效果并不是很好,显示的频谱与当前播放好像不符合。用waveOut呢,延时比较大;用DirectSound,采用通知点的方式呢,也不是最好的处理办法。如果能计算出playback的数值,那就是最准确的了。不知你有何更好的办法??
我的QQ是59502553,交流下?
re: ffmpeg_play on ubuntu 9.10 jacky_zz 2009-12-14 22:26
你好,我现在都不想自己去写具体格式的音频解码代码了,我想采用ffmpeg作为解码后台,这样做有几个好处:一是可以把程序开发的重点从解码转移到程序架构的设计上来;二是ffmpeg支持的格式也比较多,这样一来程序就可以播放多种格式的音频文件了,我现在测试了aac,ape,flac,mp3,mp4,mpc,ogg,wma,wav,效果还不错;三是编写几个封装DLL,用于ffmpeg和DirectSound操作的封装,这样就越发模块化了。呵呵,这个只是我的一个初步的想法,等封装完成,那么剩下的工作就是界面编程了,有兴趣的话,一起来整整?
PS:最近几天准备用VC6来开发程序,在多个系统上测试,包括Ubuntu(9.10,Wine v1.01)。
我的QQ是:59502553。
re: ffmpeg_play on ubuntu 9.10 jacky_zz 2009-12-14 15:09
你提到的这个问题,在codeproject有例子的,无非需要做的自己开发一个Filter,并注册到系统,以便系统能以你开发的Filter来解码输入的文件,并将解码数据返回给应用程序进行播放。
例子的地址为:http://www.codeproject.com/KB/audio-video/PeakMeterCS.aspx
re: ffmpeg小试 jacky_zz 2009-11-25 11:03
找到不能播放aac和ogg的问题了,原因是在ffmpeg里分配内存需要用av_malloc,释放内存要用av_free,因为windows和linux下内存分配存在不同,而ffmpeg在解码的时候是要检查内存是否对齐(内存对齐可以加快CPU的处理速度),所以在程序里在window环境下通过malloc或者通过数组的方式分配的内存不完全是内存对齐的,所以在遇到aac和ogg这种帧长度与其它音频格式帧长度不一致时,就有可能在运行时出错。修改后的代码如下,读者参照着自己修改即可。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <mmsystem.h>

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

#ifdef __cplusplus
extern "C" {
#endif

#include "./include/avcodec.h"
#include "./include/avformat.h"
#include "./include/avutil.h"
#include "./include/mem.h"

#ifdef __cplusplus
}
#endif

#define BLOCK_SIZE 4608
#define BLOCK_COUNT 20

HWAVEOUT hWaveOut = NULL;

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

static CRITICAL_SECTION waveCriticalSection;
static WAVEHDR* waveBlocks;
static volatile unsigned int waveFreeBlockCount;
static int waveCurrentBlock;

typedef struct AudioState {
AVFormatContext* pFmtCtx;
AVCodecContext* pCodecCtx;
AVCodec* pCodec;
//uint8_t* audio_buf1[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
uint8_t* audio_buf1;
uint8_t* audio_buf;
unsigned int audio_buf_size; /* in bytes */
unsigned int buffer_size;
int audio_buf_index; /* in bytes */
AVPacket audio_pkt_temp;
AVPacket audio_pkt;
uint8_t* audio_pkt_data;
int audio_pkt_size;

int stream_index;
} AudioState;

int audio_decode_frame(AudioState* pState) {

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

for( ; ; ) {
while (pkt_temp->size > 0) {
// data_size = sizeof(pState->audio_buf1);
data_size = pState->buffer_size;
len = avcodec_decode_audio3(dec, (int16_t*)pState->audio_buf1, &data_size, pkt_temp);
if (len < 0) {
pkt_temp->size = 0;
break;
}

pkt_temp->data += len;
pkt_temp->size -= len;

if (data_size <= 0)
continue;

pState->audio_buf = pState->audio_buf1;
return data_size;
}

if (pkt->data)
av_free_packet(pkt);

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

pkt_temp->data = pkt->data;
pkt_temp->size = pkt->size;
}

return -1;
}

int main(int argc, char* argv[]) {
int err = 0;
AudioState audio_state = {0};
unsigned int i = 0;
unsigned int ready = 0;

OPENFILENAME ofn = {0};
char filename[MAX_PATH];
WAVEFORMATEX wfx = {0};
uint8_t buffer[BLOCK_SIZE];
uint8_t* pbuffer = buffer;
AVInputFormat* iformat = NULL;

int audio_size = 0, data_size = 0;
int len = 0, len1 = 0, eof = 0, size = 0;

memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = GetDesktopWindow();
ofn.lpstrFile = filename;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(filename) / sizeof(filename[0]);
ofn.lpstrFilter = _TEXT("All support files\0*.aac;*.ape;*.flac;*.mp3;*.mp4;*.mpc;*.ogg;*.tta;*.wma;*.wav\0");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

if (GetOpenFileName(&ofn) == FALSE)
return 0;

av_register_all();

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

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

for(i = 0; i < audio_state.pFmtCtx->nb_streams; i++) {
if(audio_state.pFmtCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
audio_state.pCodecCtx = audio_state.pFmtCtx->streams[i]->codec;
audio_state.stream_index = i;
ready = 1;
break;
}
}

if(!ready)
return -1;

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

wfx.nSamplesPerSec = audio_state.pCodecCtx->sample_rate;
switch(audio_state.pCodecCtx->sample_fmt)
{
case SAMPLE_FMT_U8:
wfx.wBitsPerSample = 8;
break;
case SAMPLE_FMT_S16:
wfx.wBitsPerSample = 16;
break;
case SAMPLE_FMT_S32:
wfx.wBitsPerSample = 32;
break;
case SAMPLE_FMT_FLT:
wfx.wBitsPerSample = sizeof(double) * 8;
break;
default:
wfx.wBitsPerSample = 0;
break;
}

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

waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
waveFreeBlockCount = BLOCK_COUNT;
waveCurrentBlock = 0;

InitializeCriticalSection(&waveCriticalSection);

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

// allocate memory
audio_state.audio_buf1 =(uint8_t*)av_malloc(buffer_size);
audio_state.buffer_size = buffer_size;

// play loop
for( ; ; ) {

len = BLOCK_SIZE;
size = 0;
pbuffer = buffer;

if(eof)
break;

while(len > 0) {
if(audio_state.audio_buf_index >= (int)audio_state.audio_buf_size) {
audio_size = audio_decode_frame(&audio_state);
if(audio_size < 0) {
if(size > 0)
break;

eof = 1;
break;
}

audio_state.audio_buf_size = audio_size;
audio_state.audio_buf_index = 0;
}

len1 = audio_state.audio_buf_size - audio_state.audio_buf_index;
if(len1 > len)
len1 = len;

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

len -= len1;
pbuffer += len1;
size += len1;
audio_state.audio_buf_index += len1;
}

writeAudio(hWaveOut, (char*)buffer, size);
}

// free allocated memory
av_free(audio_state.audio_buf1);
audio_state.audio_buf1 = NULL;

// wait for complete
for( ; ; ) {
if(waveFreeBlockCount >= BLOCK_COUNT)
break;

Sleep(10);
}

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

DeleteCriticalSection(&waveCriticalSection);
freeBlocks(waveBlocks);
waveOutClose(hWaveOut);

avcodec_close(audio_state.pCodecCtx);

system("pause");
return 0;
}

static void writeAudio(HWAVEOUT hWaveOut, LPSTR data, int size)
{
WAVEHDR* current;
int remain;

current = &waveBlocks[waveCurrentBlock];

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

if(size < (int)(BLOCK_SIZE - current->dwUser)) {
memcpy(current->lpData + current->dwUser, data, size);
current->dwUser += size;
break;
}

remain = BLOCK_SIZE - current->dwUser;
memcpy(current->lpData + current->dwUser, data, remain);
size -= remain;
data += remain;
current->dwBufferLength = BLOCK_SIZE;

waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));

EnterCriticalSection(&waveCriticalSection);
waveFreeBlockCount--;
LeaveCriticalSection(&waveCriticalSection);

/*
* wait for a block to become free
*/
while(!waveFreeBlockCount)
Sleep(10);

/*
* point to the next block
*/
waveCurrentBlock++;
waveCurrentBlock %= BLOCK_COUNT;

current = &waveBlocks[waveCurrentBlock];
current->dwUser = 0;
}
}

static WAVEHDR* allocateBlocks(int size, int count)
{
char* buffer;
int i;
WAVEHDR* blocks;
DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;

/*
* allocate memory for the entire set in one go
*/
if((buffer = (char*)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
totalBufferSize
)) == NULL) {
fprintf(stderr, "Memory allocation error\n");
ExitProcess(1);
}

/*
* and set up the pointers to each bit
*/
blocks = (WAVEHDR*)buffer;
buffer += sizeof(WAVEHDR) * count;
for(i = 0; i < count; i++) {
blocks[i].dwBufferLength = size;
blocks[i].lpData = buffer;
buffer += size;
}

return blocks;
}

static void freeBlocks(WAVEHDR* blockArray)
{
/*
* and this is why allocateBlocks works the way it does
*/
HeapFree(GetProcessHeap(), 0, blockArray);
}

static void CALLBACK waveOutProc(
HWAVEOUT hWaveOut,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
)
{
int* freeBlockCounter = (int*)dwInstance;
/*
* ignore calls that occur due to opening and closing the
* device.
*/
if(uMsg != WOM_DONE)
return;

EnterCriticalSection(&waveCriticalSection);
(*freeBlockCounter)++;
LeaveCriticalSection(&waveCriticalSection);
}
re: ffmpeg小试 jacky_zz 2009-11-24 21:02
和我的程序有关系吗?况且我的这个程序附带了源码,虽然简单。
流程:
(1)从文件读取pcm数据;
(2)将pcm数据写入到播放设备(waveOut或DirectSound);
(3)将pcm数据同步到DSP(FFT,绘图)。
其中:第一步,读取的数据不能太大,这个将直接影响后面2步的延时时间,延时时间越大,就不“实时”了,我在网上查的数据量大小是4608字节;第二步是标准操作,没有什么特别的;第三步,包含的工作有对pcm数据的FFT计算,以及频谱绘图。
唉……是啊,最近还忙,只有慢慢的靠着回忆来完善了。
TO ALL:
近期硬盘分区表损坏,所有数据全部丢失(损失惨重)!!!包括AudioPlayer的源码,现在仅存的源码在www.codeproject.com上可以下载,感谢网友一直以来对此程序的关心,本打算公开,现在却因为硬盘问题而无法实现,深表歉意。

jacky_zz
2009-09-18
TO lyon:
嗯,这个只能是慢慢的去实验才能得到最终的效果。
PS:通过QQ可以和我联系,59502553。
DSound的缓冲区大小与读写缓冲区大小无关,读写缓冲区越大,解码耗费的时间就多,反之就小。而DSound的缓冲区一般都设置为两秒的数据量。而频谱分析,在我的实例里我从环形缓冲区(我设置为1秒的数据量)获取512字节的数据,通过FFT,再对前256(也就是总数据量512的一半)个数据分析,绘图。
TO lyon:
获取数据的原理,我在文章里已提到,我在google上查到一篇文章,是原Winamp的作者写的,他提到,做实时频谱分析,首先需要通过FFT转换,而FFT转换的计算量与传入的数据长度成正比,也就是说你传入的数据越多,计算量就越大,继而花费CPU的时间就越多,为了减少因为FFT的计算量,就需要减少传入的数据量,但使用waveOutXXX或DirectSound输出时,PCM数据量太少的话,是会出现断音的,经过作者不断的测试,终于找到一个合适的数值,就是4608。也就是你每次先获取4608个PCM数据,先将PCM数据输出到waveOutXXX或DirectSound,然后通过线程同步的方式将PCM数据传入到频谱分析线程,此线程负责FFT计算,然后绘图。
To lyon:
你好,我现在的实现在实时性上是达到了目的,但现在我现在的这个实现也存在一定的问题:在单CPU的计算机上,播放线程和频谱线程CPU占用率较高,15~30%之间;在双CPU的计算机上(我的)测试呢,没有启动QQ2009的情况呢,CPU占用率在0~3%之间,一旦启动QQ2009,一下子就飚升上去了,在10~25%之间。

我把获取实时的代码贴在这里:
===========System.h===========
#pragma once

#ifndef INCLUDE_SYSTEM
#define INCLUDE_SYSTEM

typedef __int64 jlong;
typedef unsigned int juint;
typedef unsigned __int64 julong;
typedef long jint;
typedef signed char jbyte;

#define CONST64(x) (x ## LL)
#define NANOS_PER_SEC CONST64(1000000000)
#define NANOS_PER_MILLISEC 1000000

jlong as_long(LARGE_INTEGER x);
void set_high(jlong* value, jint high);
void set_low(jlong* value, jint low);

class System
{
private:
static jlong frequency;
static int ready;

static void init()
{
LARGE_INTEGER liFrequency = {0};
QueryPerformanceFrequency(&liFrequency);
frequency = as_long(liFrequency);
ready = 1;
}
public:
static jlong nanoTime()
{
if(ready != 1)
init();

LARGE_INTEGER liCounter = {0};
QueryPerformanceCounter(&liCounter);
double current = as_long(liCounter);
double freq = frequency;
return (jlong)((current / freq) * NANOS_PER_SEC);
}
};

#endif

===========System.cpp===========
#include "System.h"

inline void set_low(jlong* value, jint low)
{
*value &= (jlong)0xffffffff << 32;
*value |= (jlong)(julong)(juint)low;
}

inline void set_high(jlong* value, jint high)
{
*value &= (jlong)(julong)(juint)0xffffffff;
*value |= (jlong)high << 32;
}

jlong as_long(LARGE_INTEGER x) {
jlong result = 0; // initialization to avoid warning
set_high(&result, x.HighPart);
set_low(&result, x.LowPart);
return result;
}

LARGE_INTEGER liFrequency = {0};
BOOL gSupportPerformanceFrequency = QueryPerformanceFrequency(&liFrequency);
jlong System::frequency = as_long(liFrequency);
int System::ready = 1;
re: union再探 jacky_zz 2009-07-13 11:30
可以不加&符号的,可能在VC6里需要加。
用事件来控制。
这个版本支持wma的解码嘛,只不过是使用COM接口的方式。DMO没有试过,但流程差不多一样吧,都是获取PCM格式的数据,然后播放。
没有安装libmad,或没有找到libmad位置
TO audioer,QQ:59502553
在VS2008里编译,需要有Windows Media Format 9以上的支持。
PS:这个程序很大程度上参考了YoYoPlayer(Java开发),有兴趣的话可以参考以下地址:
http://www.blogjava.net/hadeslee/archive/2008/07/29/218161.html
哦,是吗,你对频谱处理有独到的见解?有机会交流一下?
我的QQ:59502553
哇,好久没有看到你冒泡了,呵呵,支持一下。
用FireFox3的插件Galdder就可以访问
re: 回武汉咯[未登录] jacky_zz 2008-03-03 17:42
祝答辩顺利通过,且好运!
re: Go On[未登录] jacky_zz 2007-08-15 16:45
么么,太漂亮了!
re: 无题 jacky_zz 2007-07-27 17:42
没有下载的吗??
re: 我把初恋搞丢了(原创) jacky_zz 2007-05-15 14:43
在程序员的眼里,代码就是他最好的女朋友,甚至是老婆。我不知道你是否是这样想的,但这是我经历了类似你这样的两次得出的结论。我也是转行到计算机里的,也经过了类似你那样努力学习技术的过程,只是我一开始学的不是C++,而是Basic,经历了很多次的计划才正式的开始学习C++,而此前一直都在和Java打交道。初恋是美好的,但最终都将成为回忆,过去的事情仅供以后生活的参考和借鉴,而不是将来。