zoukankan      html  css  js  c++  java
  • 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版本升级修改。

    修改前:

    1. len = avcodec_decode_audio (pAudioCodecCtx,    
    2.                             (int16_t *)decompressed_audio_buf,   
    3.                             &decompressed_audio_buf_size,        // it is the decompressed frame in BYTES 解码后的数据大小,字节为单位;  
    4.                             packet.data,   
    5.                             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 ", fd); 
        // 
        set_audio(fd, pCodecCtx); 
       
        // 
        printf("(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2=%d ", (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2); 
        printf("AVCODEC_MAX_AUDIO_FRAME_SIZE=%d ", 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 "); 
                    // 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 "); 
            exit(0); 
        } 
       
        // 注意:这里要用到指向指针的指针,是因为这个初始化函数需要对指针的地址进行改动, 
        // 所以,只有这么做,才能达到目的; 
        if ( av_init(argv[1], &pFormatCtx, &pCodecCtx, &audioStream) < 0 ){ 
            // 
            fprintf(stderr, "error when av_init "); 
        } 
       
        // play the audio file 
        av_play(pFormatCtx, pCodecCtx, audioStream); 
       
        // close all the opend files 
        av_close(pFormatCtx, pCodecCtx); 
       
    }

  • 相关阅读:
    你的代码真的很健壮吗
    GAE 博客——B3log Solo 0.1.1 发布预告
    GAE 博客——B3log Solo 0.1.1 发布了!
    GAE 博客——B3log Solo 0.1.1 发布了!
    使用logcxx库和boost库构建系统日志的格式化输出
    Simple Hierarchical clustering in Python 2.7 using SciPy
    将python3.1+pyqt4打包成exe
    Installation — SIP 4.14.2 Reference Guide
    PyQt 维基百科,自由的百科全书
    沙湖王 py行者
  • 原文地址:https://www.cnblogs.com/pangblog/p/3341695.html
Copyright © 2011-2022 走看看