根据ffmpeg的简单解码器

ffmpeg是比较好的开源解码器。提供相应的开发库,很容易根据其提供的函数做一个简单的音频解码器。下面是我根据网上的一些相关信息,自己写的一个音频解码器。

/***************************************************************************
 *            mokemar_ffmpeg_player.c
 *
 *  Copyright  2008
 *  Author mokemars
 *  QQ:263542344
 ****************************************************************************/

#include <avcodec.h>
#include <avformat.h>
#include <avutil.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.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 false 0
#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, false);
    #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 ==
            CODEC_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/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);
  
}
如果想解码视频文件可以参考ffmpeg源码中的ffplayer.c.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值