哈尔滨网站备案,哪些网站可以免费推广,注册公司需要钱吗?多少费用,做ps图标什么网站最好ffmpeg提取音频播放器总结#xff1b; 一#xff1a;简介 从编写音频播放器代码到完成播放器编写#xff0c;测试#xff0c;整整5天的时间#xff0c;这时间还不算之前对 ffmpeg熟悉的时间#xff0c;可以说是历经千辛万苦#xff0c;终于搞出来了#xff0c;虽然最…ffmpeg提取音频播放器总结 一简介 从编写音频播放器代码到完成播放器编写测试整整5天的时间这时间还不算之前对 ffmpeg熟悉的时间可以说是历经千辛万苦终于搞出来了虽然最终效果还不是很理想但是已经可以很流畅的播放某些歌曲了说是某些歌曲是因为还有些歌曲播放效果不是很好有些许杂音至于那些歌曲能够顺利播放那些不能够我现在也摸不准是什么原因导致的有待进一步钻研等啥时候调好了就用自己的这个播放器听歌曲了嘿嘿 a插播 这一部分属于插播内容就不用看了 tv视频播放 采用img_convert时是转换成24RGB快呢还是32RGB快呢可能前者快吧似乎用qimage的话只能转换成32RGB了因为它只有三种颜色深度1-p, 8-p, 32-p所以只能选择32-p了 下面是AVFrame的结构具体可以看这里 http://cekirdek.pardus.org.tr/~ismail/ffmpeg-docs/avcodec_8h-source.html#l00424 就是一个宏定义咳。。。 二音频播放器原理 音频播放器过程如下所示 打开文件分析文件格式打开对应解码器读取一音频帧解码音频帧音频数据写入音频设备循环读取音频帧再解码。。。如此循环下去 整个播放器实现原理详细说明为采用ffmpeg提供的API函数先用av_open_input_file打开音频文件分析文件得到格式信息然后识别格式并查找对应的解码器再得到针对此音频文件的解码器之后用av_read_frame从音频文件中读取一帧然后对其用 avcodec_decode_audio函数进行解码在将解码之后的PCM音频数据直接写到audio设备devdsp上根据linux音频设备的原理此时你就应该听到悦耳的歌声了 三重点要点说明 在这个过程当中有几处需要特别注意下面详细说明一下 1、不同音频文件格式对音频压缩率不同导致对于同一个音频包你解压出来的音频数据大小也是不一样的这一点无需惊奇但是对于这些解压出来的音频数据一定要保证全部写到声卡当中去这样才能够作为你能听到悦耳歌声的基础这里留意一下这只是一个基础要想完全实现好此播放器下一点更是不可或缺的我之前之所以在调试时总是听到声音很杂乱或者带有金属声就是因为声音没有全部写到音频设备中去当然可能或多或少也有一些写音频数据的太快的原故 2、在确认了解码后的数据是完整的之后可以将数据写入到音频设备当中了/dev/dsp这里很关键的一点就是要对音频设备进行设置否则你也听不到你想听到的声音 对音频设备的设置主要是四个方面这不代表其他方面不设置哦 设置采样率有关音频采样率在我blog前面的文章当中有说明一般有44100hz48000hz22050不记得了你查看我blog中前面的文章吧嘿嘿 ioctl (fd, SNDCTL_DSP_SPEED, (pCodecCtx-sample_rate)); 设置音频声道数这个很好理解一般都是立体声了 // set channels; i pCodecCtx-channels; #ifdef AUDIO_DEBUG printf (pCodecCtx-channels:%d\n, pCodecCtx-channels); #endif if ((ioctl (fd, SNDCTL_DSP_CHANNELS, i)) -1) { fprintf (stderr, Set Audio Channels %d failed:%s\n, i, strerror (errno)); return (-1); } 这里需要说明的一点是如果是立体声则此处i应该等于2而不是1网上很多文章这里都说明的不正确我之前就一直以为立体声为1单声道为0总是不出声音后来一狠心改为2尽然okfaint 结论网上的东西啊不可全信之。。。。。。。。。。。。。。。。。。。。。。。。。。。 设置量化位数这个量化位数是指对声音的振幅进行采样的位数以前一般是8位现在以16位居多更高位数对于普通用户用不着只能在专业音乐中才有价值 i AFMT_S16_LE; 16位小端存储也即intel的倒序数据存储 ioctl (fd, SNDCTL_DSP_SETFMT, i); 设置音频驱动级缓存 i (0x0004 16) 0x000b; // four 2kb buffer;你看着对应改就行了这里是四个2kb缓存 ioctl (fd, SNDCTL_DSP_SETFRAGMENT, i); 这里也可以不设置用系统默认自定义也可 另外有一个疑问也顺带解决了 Q播放音频和pts有关系么需要他来调整播放的快慢么就像视频那样 A基本没有关系至少我目前没有用到这个咚咚pts应该实在视频当中采用到的pts是显示时间戳dts是解码时间戳以后搞到视频再详细说明啦不需要对于写音频数据系统或者更准确的说驱动会自动调整写得快他会阻塞你的写写的慢你的机器该换了嘿嘿玩笑一个。。。增加缓存可以解决慢的问题 Q如何调试音频播放器 这里需要注意两点一点是你要保证解码后的数据确实是PCM数据第二点是你要确定数据准确无误全部写入音频文件否则会出现各种各样的暴音啊之类的事情不可预测 有关这两点你可以分别调试第一点可以将解码后的数据写入一个文件当中然后利用一些音频分析软件能够分析PCM数据播放即可看你解码的数据是否正确完整如果没有问题那这一步就完成了我在这里没有卡壳直接过下一步我是扔进去很多时间由于我的指针使用不当导致总是漏写数据我在下面也会把我的错误代码贴出来以做对比大家也都可以来看看这一点我想经常和指针打交道的就肯定没问题了的 这里向大家推荐windows下的cooledit软件不用找注册码反正能试用没问题功能绝对够用而且分析声音频播非常形象郑重推荐虽然windows和linux切换麻烦了点嘿嘿不过如果你有两台电脑另说啦。。。 下面将这个音频播放器的源代码贴出来以便大家互相学习 我的编译环境是 osNeoshine linux 2.6.14-1.1644_dt_5 硬件普通pc机 /*************************************************************************** * main.cc * * Thu Nov 9 20:47:33 2006 * Copyright 2006 * Email lsosa.BIT * Author lsosa.BIT ****************************************************************************/ #include avcodec.h #include avformat.h #include avutil.h #include assert.h #include stdio.h #include stdlib.h #include X11/Xlib.h #include sys/soundcard.h #include sys/stat.h #include fcntl.h #include sys/ioctl.h #include unistd.h #include errno.h #include string.h #include sched.h #define ALL_DEBUG #ifdef ALL_DEBUG #define AV_DEBUG #define AUDIO_DEBUG #endif //------------------------------------------------------------------------------ // manipulations for file int open_file (char *file_name, int mode) { // open file file_name and return the file descriptor; int fd; if ((fd open (file_name, mode)) 0) { fprintf (stderr, Cant open %s!\n, file_name); exit (-1); } return fd; } int set_audio (int fd, AVCodecContext * pCodecCtx) { // set the properties of audio device with pCodecCtx; int i, err; /* 设置适当的参数使得声音设备工作正常 */ /* 详细情况请参考Linux关于声卡编程的文档 */ i 0; ioctl (fd, SNDCTL_DSP_RESET, i); i 0; ioctl (fd, SNDCTL_DSP_SYNC, i); i 1; ioctl (fd, SNDCTL_DSP_NONBLOCK, i); // set sample rate; #ifdef AUDIO_DEBUG printf (pCodecCtx-sample_rate:%d\n, pCodecCtx-sample_rate); #endif i pCodecCtx-sample_rate; if (ioctl (fd, SNDCTL_DSP_SPEED, i) -1) { fprintf (stderr, Set speed to %d failed:%s\n, i, strerror (errno)); return (-1); } if (i ! pCodecCtx-sample_rate) { fprintf (stderr, do not support speed %d,supported is %d\n, pCodecCtx-sample_rate, i); return (-1); } // set channels; i pCodecCtx-channels; #ifdef AUDIO_DEBUG printf (pCodecCtx-channels:%d\n, pCodecCtx-channels); #endif if ((ioctl (fd, SNDCTL_DSP_CHANNELS, i)) -1) { fprintf (stderr, Set Audio Channels %d failed:%s\n, i, strerror (errno)); return (-1); } if (i ! pCodecCtx-channels) { fprintf (stderr, do not support channel %d,supported %d\n, pCodecCtx-channels, i); return (-1); } // set bit format; i AFMT_S16_LE; if (ioctl (fd, SNDCTL_DSP_SETFMT, i) -1) { fprintf (stderr, Set fmt to bit %d failed:%s\n, i, strerror (errno)); return (-1); } if (i ! AFMT_S16_LE) { fprintf (stderr, do not support bit %d, supported %d\n, AFMT_S16_LE, i); return (-1); } // set application buffer size; // i (0x00032 16) 0x000c; // 32 4kb buffer; // ioctl (fd, SNDCTL_DSP_SETFRAGMENT, i); i 1; ioctl (fd, SNDCTL_DSP_PROFILE, i); return 0; } void close_file (int fd) { // close the file pointed by file descriptor fd; close (fd); } //------------------------------------------------------------------------------ // handle audio; void display_AVCodecContext(AVCodecContext *pCodecCtx){ // #define STDOUT stderr fprintf(STDOUT, pCodecCtx-bit_rate:%d\n, pCodecCtx-bit_rate); fprintf(STDOUT, pCodecCtx-sample_rate:%d\n, pCodecCtx-sample_rate); fprintf(STDOUT, pCodecCtx-channels:%d\n, pCodecCtx-channels); fprintf(STDOUT, pCodecCtx-frame_size:%d\n, pCodecCtx-frame_size); fprintf(STDOUT, pCodecCtx-frame_number:%d\n, pCodecCtx-frame_number); fprintf(STDOUT, pCodecCtx-delay:%d\n, pCodecCtx-delay); fprintf(STDOUT, pCodecCtx-frame_bits:%d\n, pCodecCtx-frame_bits); } // error if return -1; // success if return 0; // 这里要用到指向指针的指针否则传不到值 int av_init (char *file_name, AVFormatContext ** pFormatCtx, AVCodecContext ** pCodecCtx, int *p_audioStream) { // init the codec and format of input file file_name; int audioStream, i; AVCodec *pCodec; // catch error assert(file_name ! NULL); assert(*pFormatCtx ! NULL); assert(*pCodecCtx ! NULL); // Register all formats and codecs av_register_all (); // open file if (av_open_input_file (pFormatCtx, file_name, NULL, 0, NULL) ! 0){ // Couldnt open file fprintf (stderr, Cant open %s!\n, file_name); return -1; } // Retrieve stream information if (av_find_stream_info (*pFormatCtx) 0){ // Couldnt find stream information return -1; } #ifdef AV_DEBUG // Dump information about file onto standard error dump_format (*pFormatCtx, 0, file_name, false); #endif // Find the first audio and video stream respectively audioStream -1; for (i 0; i (*pFormatCtx)-nb_streams; i){ if ((*pFormatCtx)-streams-codec-codec_type CODEC_TYPE_AUDIO) { audioStream i; } } #ifdef AV_DEBUG // dump_stream_info(pFormatCtx); #endif // exclude error if (audioStream -1){ // Didnt find a audio or video stream return -1; } // Get a pointer to the codec context for the audio stream *pCodecCtx (*pFormatCtx)-streams[audioStream]-codec; // Find the decoder for the audio stream pCodec avcodec_find_decoder ((*pCodecCtx)-codec_id); if (pCodec NULL) return -1; // Codec not found // Open codec if (avcodec_open ((*pCodecCtx), pCodec) 0){ return -1; // Could not open codec } #ifdef AUDIO_DEBUG // printf (pCodecCtx-sample_rate:%d, audioStream:%d\n, (*pCodecCtx)-sample_rate, audioStream); // display_AVCodecContext(*pCodecCtx); #endif *p_audioStream audioStream; return 0; } void av_play (AVFormatContext * pFormatCtx, AVCodecContext * pCodecCtx, int audioStream) { // which was read from one frame; AVPacket packet; uint32_t len; uint8_t decompressed_audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; int decompressed_audio_buf_size; uint8_t * p_decompressed_audio_buf; int fd -1; // audio file or test file? char filename[64] /dev/dsp; int mode O_WRONLY; // // open audio file or written file // printf(fd:%d, fd); fd open_file(filename, mode); // printf(fd:%d, fd); // set_audio(fd, pCodecCtx); // printf((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2%d\n, (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2); printf(AVCODEC_MAX_AUDIO_FRAME_SIZE%d\n, AVCODEC_MAX_AUDIO_FRAME_SIZE); // for a test // char test_file[256] my_pcm.pcm; // fd open_file(test_file, mode); #ifdef AV_DEBUG static int size 0; #endif // // set the sched priority // 这是为了提高音频优先级不晓得起作用没 int policy SCHED_FIFO; sched_setscheduler(0, policy, NULL); int write_buf_size 4196; int written_size; while (av_read_frame (pFormatCtx, packet) 0) { // Is this a packet from the audio stream? // 判断是否音频帧 if (packet.stream_index audioStream) { // Decode audio frame // 解码音频数据为pcm数据 len avcodec_decode_audio (pCodecCtx, (int16_t *)decompressed_audio_buf, decompressed_audio_buf_size, // it is the decompressed frame in BYTES 解码后的数据大小字节为单位 packet.data, packet.size ); // printf(len:%d, packet.size:%d\n, len, packet.size); if ( len 0 ){ // if error len -1 printf(----- error in decoding audio frame\n); // exit(0); } // test lsosa // printf(size %d\n, size); //****************************************************************** // 重点是这一部分使用oss播放的代码之前的数据写是否完整的问题就是出在这里或者是前面的set_audio函数设置不正确 // audio_buf_info info; p_decompressed_audio_buf decompressed_audio_buf; while ( decompressed_audio_buf_size 0 ){ // 解码后数据不为零则播放之为零则 written_size write(fd, p_decompressed_audio_buf, decompressed_audio_buf_size); if ( written_size -1 ){ // printf(error:decompressed_audio_buf_size:%d, decompressed_audio_buf_size:%d, %s\n, \ decompressed_audio_buf_size, decompressed_audio_buf_size,strerror(errno)); // usleep(100); continue; } // printf(decompressed_audio_buf_size:%d, written_size:%d\n, \ decompressed_audio_buf_size, written_size); decompressed_audio_buf_size - written_size; p_decompressed_audio_buf written_size; }// end while //****************************************************************** } else { printf(----- this is not audio frame\n); }// end if // Free the packet that was allocated by av_read_frame av_free_packet (packet); }// end while of reading one frame; close_file(fd); } void av_close (AVFormatContext * pFormatCtx, AVCodecContext * pCodecCtx) { // close the file and codec // Close the codec avcodec_close (pCodecCtx); // Close the video file av_close_input_file (pFormatCtx); } //------------------------------------------------------------------------------ int main (int argc, char **argv){ // AVFormatContext *pFormatCtx; int audioStream -1; AVCodecContext *pCodecCtx; // exclude the error about args; if ( argc ! 2 ){ printf(please give a file name\n); exit(0); } // 注意这里要用到指向指针的指针是因为这个初始化函数需要对指针的地址进行改动 // 所以只有这么做才能达到目的 if ( av_init(argv[1], pFormatCtx, pCodecCtx, audioStream) 0 ){ // fprintf(stderr, error when av_init\n); } // play the audio file av_play(pFormatCtx, pCodecCtx, audioStream); // close all the opend files av_close(pFormatCtx, pCodecCtx); } http://weiyuhu.iteye.com/blog/576610 ffmpeg提取音频播放器总结