没办法,工作中遇到了问题。


目前NEC EMMA的架构如下:

从USB读入文件 -> 文件分析并提取Packet中的Payload Data   -> NEC HANDLE AVTransfer  -> NEC HANDLE WMV -> AUDIO OUTPUT


按照驱动的API写好代码后却怎么也没有声音,所有API返回值均OK。

郁闷开始了。继续绝望中寻找希望。


为了对比调试,参考

 ​


并做了一些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用户)


                       

#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); 

   

}