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 \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)