ffmpeg + sdl -03 简单音频播放器实现
没办法,工作中遇到了问题。
目前NEC EMMA的架构如下:
从USB读入文件 -> 文件分析并提取Packet中的Payload Data -> NEC HANDLE AVTransfer -> NEC HANDLE WMV -> AUDIO OUTPUT
按照驱动的API写好代码后却怎么也没有声音,所有API返回值均OK。
郁闷开始了。继续绝望中寻找希望。
为了对比调试,参考
http://blog.csdn.net/ashlingr/article/details/7791321
并做了一些ffmpeg版本升级修改。
修改前:
- len = avcodec_decode_audio (pAudioCodecCtx,
- (int16_t *)decompressed_audio_buf,
- &decompressed_audio_buf_size, // it is the decompressed frame in BYTES 解码后的数据大小,字节为单位;
- packet.data,
- packet.size );
修改后:
decompressed_audio_buf_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2; // 不加这一行,执行时会出错。
len = avcodec_decode_audio3 (pCodecCtx,
(int16_t *)decompressed_audio_buf,
&decompressed_audio_buf_size, // it is the decompressed frame in BYTES
&packet);
遇到的问题:
/dev/dsp 设备不存在
解决办法:
modprobe snd_pcm_oss (需要su到root用户)
完整代码如下:(基本来自http://bbs.chinavideo.org/viewthread.php?tid=1247&extra=page%3D1)
#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, " Can't 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){ 
         // Couldn't open file 
         fprintf (stderr, " Can't open %s!/n", file_name); 
         return -1;   
     }
// Retrieve stream information 
     if (av_find_stream_info (*pFormatCtx) < 0){ 
         // Couldn't find stream information 
         return -1;   
     } 
    
     #ifdef AV_DEBUG 
     // Dump information about file onto standard error 
     dump_format (*pFormatCtx, 0, file_name, 0); 
     #endif 
    
     // Find the first audio and video stream respectively 
     audioStream = -1; 
     for (i = 0; i < (*pFormatCtx)->nb_streams; i++){ 
         if ((*pFormatCtx)->streams[i]->codec->codec_type == 
             AVMEDIA_TYPE_AUDIO) 
         { 
             audioStream = i; 
         } 
     } 
    
     #ifdef AV_DEBUG 
     // dump_stream_info(pFormatCtx); 
     #endif 
    
     // exclude error 
     if (audioStream == -1){ 
         // Didn't 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 \n", 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数据; 
             decompressed_audio_buf_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
             len = avcodec_decode_audio3 (pCodecCtx, 
                             (int16_t *)decompressed_audio_buf, 
                             &decompressed_audio_buf_size,        // it is the decompressed frame in BYTES 
                             &packet); 
             // 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); 
    
 }
ffmpeg + sdl -03 简单音频播放器实现的更多相关文章
- ffmpeg+SDL2实现的音频播放器V2.0(无杂音)
		1. 前言 目前为止,学习了并记录了ffmpeg+SDL2显示视频以及事件(event)的内容. 这篇中记录ffmpeg+SDL2播放音频,没加入事件处理. 接下来加入事件处理并继续学习音视频同步,再 ... 
- IOS开发之简单音频播放器
		今天第一次接触IOS开发的UI部分,之前学OC的时候一直在模拟的使用Target-Action回调模式,今天算是真正的用了一次.为了熟悉一下基本控件的使用方法,和UI部分的回调,下面开发了一个特别简易 ... 
- WIN32下使用DirectSound接口的简单音频播放器(支持wav和mp3)
		刚好最近接触了一些DirectSound,就写了一个小程序练练手,可以用来添加播放基本的wav和mp3音频文件的播放器.界面只是简单的GDI,dxsdk只使用了DirectSound8相关的接口. D ... 
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)
		===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ... 
- 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)
		===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ... 
- H.264:FFMpeg 实现简单的播放器
		H.264:FFMpeg 实现简单的播放器 FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手.我刚接触FFMPEG的时候也感觉不知从何学起. 因此我 ... 
- [SimplePlayer] 实现一个简单的播放器
		简单的播放器需要实现一个最基本的功能:播放视频文件. 实现这个功能需要包含以下几个步骤: 从视频文件中提取视频图像 在屏幕上显示视频图像 视频帧的同步,也就是保证视频图像在合适的时间在屏幕上显示 从视 ... 
- 11.QT-ffmpeg+QAudioOutput实现音频播放器
		1.前言 由于QAudioOutput支持的输入数据必须是原始数据,所以播放mp3,WAV,AAC等格式文件,需要解封装后才能支持播放. 而在QT中,提供了QMediaPlayer ... 
- Android 实现简单音乐播放器(二)
		在Android 实现简单音乐播放器(一)中,我介绍了MusicPlayer的页面设计. 现在,我简单总结一些功能实现过程中的要点和有趣的细节,结合MainActivity.java代码进行说明(写出 ... 
随机推荐
- springmvc 基础
			在最简单的springmvc应用程序中,控制器是唯一需要在java web部署描述文件(web.xml)中配置的servlete(springmvc的控制器是Dispatcher Servlet).每 ... 
- 高性能Java Web 页面静态化技术
			package com.yancms.util; import java.io.*; import org.apache.commons.httpclient.*; import org.apache ... 
- JavaScript原型,原型链 !
			js原型 问题:什么是js原型? js每声明一个function,都有prototype原型,prototype原型是函数的一个默认属性,在函数的创建过程中由js编译器自动添加. 也就是说:当生产一个 ... 
- c - 比较字符串的大小
			c的标准库中当然有现成的比较字符串的函数<string.h>中的 strcmp int __cdecl strcmp(_In_z_ const char * _Str1, _In_z_ c ... 
- javascript 倒计时跳转.
			<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ... 
- 2016年的个人计划-xiangjiejie
			过去一年,开发了angularjs的wap项目,appwap社区,忙忙碌碌不停的做各种活动. 职业目标 今年,要多看书,别总是被懒癌缠身. 多学习,过去半年很少看技术文章了吧,养成定期看文章的好习惯, ... 
- 关于curl_setopt参数的记录
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE) 其中true输出执行结果,false为不输出 fsockopen与curl_setopt请求的区别之一就是 ... 
- 万维网发布服务(w3svc)已停止,除非万维网发布服务(w3svc)正在运行。
			近来遇到一个IIS服务启动问题,重启服务器PC后,网站启动的时候,提示“ 万维网发布服务(w3svc)已停止,除非万维网发布服务(w3svc)正在运行”. 解决方法: 点击"开始" ... 
- Python学习笔记总结(二)函数和模块
			一.函数 函数的作用:可以计算出一个返回值,最大化代码重用,最小化代码冗余,流程的分解. 1.函数相关的语句和表达式 语句 例子 Calls myfunc(‘diege', ... 
- OCR中的倾斜矫正
			电面中被问到了做的LPR,简单的介绍了下后又问到了关于如何矫正倾斜角的问题.答得比较含糊,所以今天来补充一下. 倾斜矫正的方法有很多种,包括基于Hough变换的矫正,基于字符投影的倾角矫正,常规线性角 ... 
