zoukankan      html  css  js  c++  java
  • Windwos平台上ffmpeg解码音频并且保存到wav文件中

    先附上代码,测试通过

    #include <stdio.h>
    #include <math.h>
    #include "libavutil/avstring.h"
    //修改colorspace.h中的inline为__inline
    #include "libavutil/colorspace.h"
    #include "libavutil/pixdesc.h"
    #include "libavutil/imgutils.h"
    #include "libavutil/dict.h"
    #include "libavutil/parseutils.h"
    #include "libavutil/samplefmt.h"
    #include "libavutil/avassert.h"
    #include "libavformat/avformat.h"
    #include "libavdevice/avdevice.h"
    #include "libswscale/swscale.h"
    #include "libavcodec/audioconvert.h"
    #include "libavutil/opt.h"
    #include "libavcodec/avfft.h"
    #include "cmdutils.h"
    #include "pthread.h"
    
    static AVPacket flush_pkt;//暂时不知道flush_pkt有什么作用,暂时先放这里。
    
    
    //#define DEBUG_SYNC
    
    #define MAX_QUEUE_SIZE (15 * 1024 * 1024)
    #define MIN_AUDIOQ_SIZE (20 * 16 * 1024)
    #define MIN_FRAMES 5
    
    /* SDL audio buffer size, in samples. Should be small to have precise
       A/V sync as SDL does not have hardware buffer fullness info. */
    #define SDL_AUDIO_BUFFER_SIZE 1024
    
    /* no AV sync correction is done if below the AV sync threshold */
    #define AV_SYNC_THRESHOLD 0.01
    /* no AV correction is done if too big error */
    #define AV_NOSYNC_THRESHOLD 10.0
    
    #define FRAME_SKIP_FACTOR 0.05
    
    /* maximum audio speed change to get correct sync */
    #define SAMPLE_CORRECTION_PERCENT_MAX 10
    
    /* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
    #define AUDIO_DIFF_AVG_NB   20
    
    /* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
    #define SAMPLE_ARRAY_SIZE (2*65536)
    
    typedef struct PacketQueue {
        AVPacketList *first_pkt, *last_pkt;
        int nb_packets;
        int size;
        int abort_request;
        pthread_mutex_t *mutex;//互斥锁
        pthread_cond_t *cond;//条件变量
    } PacketQueue;
    
    #define VIDEO_PICTURE_QUEUE_SIZE 2
    #define SUBPICTURE_QUEUE_SIZE 4
    
    typedef struct VideoPicture {
        double pts;                                  ///<presentation time stamp for this picture
        double target_clock;                         ///<av_gettime() time at which this should be displayed ideally
        int64_t pos;                                 ///<byte position in file
    //    SDL_Overlay *bmp;
        int width, height; /* source height & width */
        int allocated;
        enum PixelFormat pix_fmt;
    
    #if CONFIG_AVFILTER
        AVFilterBufferRef *picref;
    #endif
    } VideoPicture;
    
    typedef struct SubPicture {
        double pts; /* presentation time stamp for this picture */
        AVSubtitle sub;
    } SubPicture;
    
    enum {
        AV_SYNC_AUDIO_MASTER, /* default choice */
        AV_SYNC_VIDEO_MASTER,
        AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
    };
    
    typedef struct VideoState {
        pthread_t *parse_tid;
        //SDL_Thread *parse_tid;
        pthread_t *video_tid;
        //SDL_Thread *video_tid;
        pthread_t *refresh_tid;
        //SDL_Thread *refresh_tid;
        AVInputFormat *iformat;
        int no_background;
        int abort_request;
        int paused;
        int last_paused;
        int seek_req;
        int seek_flags;
        int64_t seek_pos;
        int64_t seek_rel;
        int read_pause_return;
        AVFormatContext *ic;
        int dtg_active_format;
    
        int audio_stream;
    
        int av_sync_type;
        double external_clock; /* external clock base */
        int64_t external_clock_time;
    
        double audio_clock;
        double audio_diff_cum; /* used for AV difference average computation */
        double audio_diff_avg_coef;
        double audio_diff_threshold;
        int audio_diff_avg_count;
        AVStream *audio_st;
        PacketQueue audioq;
        int audio_hw_buf_size;
        /* samples output by the codec. we reserve more space for avsync
           compensation */
        DECLARE_ALIGNED(16,uint8_t,audio_buf1)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
        DECLARE_ALIGNED(16,uint8_t,audio_buf2)[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
        uint8_t *audio_buf;
        unsigned int audio_buf_size; /* in bytes */
        int audio_buf_index; /* in bytes */
        AVPacket audio_pkt_temp;
        AVPacket audio_pkt;
        enum AVSampleFormat audio_src_fmt;
        AVAudioConvert *reformat_ctx;
    
        enum ShowMode {
            SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
        } show_mode;
        int16_t sample_array[SAMPLE_ARRAY_SIZE];
        int sample_array_index;
        int last_i_start;
        RDFTContext *rdft;
        int rdft_bits;
        FFTSample *rdft_data;
        int xpos;
    
        pthread_t *subtitle_tid;
        //SDL_Thread *subtitle_tid;
        int subtitle_stream;
        int subtitle_stream_changed;
        AVStream *subtitle_st;
        PacketQueue subtitleq;
        SubPicture subpq[SUBPICTURE_QUEUE_SIZE];
        int subpq_size, subpq_rindex, subpq_windex;
    
        pthread_mutex_t *subpq_mutex;
        pthread_cond_t *subpq_cond;
        //SDL_mutex *subpq_mutex;
        //SDL_cond *subpq_cond;
    
        double frame_timer;
        double frame_last_pts;
        double frame_last_delay;
        double video_clock;                          ///<pts of last decoded frame / predicted pts of next decoded frame
        int video_stream;
        AVStream *video_st;
        PacketQueue videoq;
        double video_current_pts;                    ///<current displayed pts (different from video_clock if frame fifos are used)
        double video_current_pts_drift;              ///<video_current_pts - time (av_gettime) at which we updated video_current_pts - used to have running video pts
        int64_t video_current_pos;                   ///<current displayed file pos
        VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE];
        int pictq_size, pictq_rindex, pictq_windex;
        pthread_mutex_t *pictq_mutex;
        //SDL_mutex *pictq_mutex;
        pthread_cond_t *pictq_cond;
        //SDL_cond *pictq_cond;
    
        struct SwsContext *img_convert_ctx;
    
        //    QETimer *video_timer;
        char filename[1024];
        int width, height, xleft, ytop;
    
        //PtsCorrectionContext pts_ctx;
    
        float skip_frames;
        float skip_frames_index;
        int refresh;
    } VideoState;
    
    
    static int opt_help(const char *opt, const char *arg);
    
    /* options specified by the user */
    static AVInputFormat *file_iformat;
    static const char *input_filename;
    static const char *window_title;
    static int fs_screen_width;
    static int fs_screen_height;
    static int screen_width = 0;
    static int screen_height = 0;
    static int frame_width = 0;
    static int frame_height = 0;
    static enum PixelFormat frame_pix_fmt = PIX_FMT_NONE;
    static int audio_disable;
    static int video_disable;
    /*
    static int wanted_stream[AVMEDIA_TYPE_NB]={
        [AVMEDIA_TYPE_AUDIO]=-1,
        [AVMEDIA_TYPE_VIDEO]=-1,
        [AVMEDIA_TYPE_SUBTITLE]=-1,
    };
    */
    static int wanted_stream[AVMEDIA_TYPE_NB]={-1,-1,0,-1,0};
    static int seek_by_bytes=-1;
    static int display_disable;
    static int show_status = 1;
    static int av_sync_type = AV_SYNC_AUDIO_MASTER;
    static int64_t start_time = AV_NOPTS_VALUE;
    static int64_t duration = AV_NOPTS_VALUE;
    static int step = 0;
    static int thread_count = 1;
    static int workaround_bugs = 1;
    static int fast = 0;
    static int genpts = 0;
    static int lowres = 0;
    static int idct = FF_IDCT_AUTO;
    static enum AVDiscard skip_frame= AVDISCARD_DEFAULT;
    static enum AVDiscard skip_idct= AVDISCARD_DEFAULT;
    static enum AVDiscard skip_loop_filter= AVDISCARD_DEFAULT;
    static int error_recognition = FF_ER_CAREFUL;
    static int error_concealment = 3;
    static int decoder_reorder_pts= -1;
    static int autoexit;
    static int exit_on_keydown;
    static int exit_on_mousedown;
    static int loop=1;
    static int framedrop=-1;
    static enum ShowMode show_mode = SHOW_MODE_NONE;
    
    static int rdftspeed=20;
    #if CONFIG_AVFILTER
    static char *vfilters = NULL;
    #endif
    
    /* current context */
    static int is_full_screen;
    static VideoState *cur_stream;
    static int64_t audio_callback_time;
    static AVPacket flush_pkt;//暂时不知道flush_pkt有什么作用,暂时先放这里。
    
    static int packet_queue_put(PacketQueue *q, AVPacket *pkt);
    
    /* packet queue handling */
    //初始化队列
    static void packet_queue_init(PacketQueue *q)
    {
        memset(q, 0, sizeof(PacketQueue));
        pthread_mutex_init(q->mutex,NULL);
        pthread_cond_init(q->cond,NULL);
        //q->mutex = SDL_CreateMutex();
        //q->cond = SDL_CreateCond();
        packet_queue_put(q, &flush_pkt);
    }
    
    //清空队列
    static void packet_queue_flush(PacketQueue *q)
    {
        AVPacketList *pkt, *pkt1;
    
        pthread_mutex_lock(q->mutex);
        //SDL_LockMutex(q->mutex);
        for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
            pkt1 = pkt->next;
            av_free_packet(&pkt->pkt);
            av_freep(&pkt);
        }
        q->last_pkt = NULL;
        q->first_pkt = NULL;
        q->nb_packets = 0;
        q->size = 0;
        pthread_mutex_unlock(q->mutex);
        //SDL_UnlockMutex(q->mutex);
    }
    
    static void packet_queue_end(PacketQueue *q)
    {
        packet_queue_flush(q);
        pthread_mutex_destroy(q->mutex);
        pthread_cond_destroy(q->cond);
        //SDL_DestroyMutex(q->mutex);
        //SDL_DestroyCond(q->cond);
    }
    
    static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
    {
        AVPacketList *pkt1;
    
        /* duplicate the packet */
        if (pkt!=&flush_pkt && av_dup_packet(pkt) < 0)
            return -1;
    
        pkt1 = av_malloc(sizeof(AVPacketList));
        if (!pkt1)
            return -1;
        pkt1->pkt = *pkt;
        pkt1->next = NULL;
    
        pthread_mutex_lock(q->mutex);
    //    SDL_LockMutex(q->mutex);
    
        if (!q->last_pkt)
    
            q->first_pkt = pkt1;
        else
            q->last_pkt->next = pkt1;
        q->last_pkt = pkt1;
        q->nb_packets++;
        q->size += pkt1->pkt.size + sizeof(*pkt1);
        /* XXX: should duplicate packet data in DV case */
        pthread_cond_signal(q->cond);
    //    SDL_CondSignal(q->cond);
    
    //    SDL_UnlockMutex(q->mutex);
        pthread_mutex_unlock(q->mutex);
        return 0;
    }
    
    
    static void packet_queue_abort(PacketQueue *q)
    {
        pthread_mutex_lock(q->mutex);
        //SDL_LockMutex(q->mutex);
    
        q->abort_request = 1;
    
        pthread_cond_signal(q->cond);
        //SDL_CondSignal(q->cond);
    
        pthread_mutex_unlock(q->mutex);
        //SDL_UnlockMutex(q->mutex);
    }
    
    
    //packet_queue_get 函数被调用的地方是audio_decode_frame,subtitle_thread,get_video_frame中,
    //作用是从队列q中读取block(一般为)个packet,留待下一次进行解码
    //avcodec_decode_audio3,avcodec_decode_video2
    /* return < 0 if aborted, 0 if no packet and > 0 if packet.  */
    static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
    {
        AVPacketList *pkt1;
        int ret;
    
        pthread_mutex_lock(q->mutex);
        //SDL_LockMutex(q->mutex);
    
        for(;;) {
            if (q->abort_request) {
                ret = -1;
                break;
            }
    
            pkt1 = q->first_pkt;
            if (pkt1) {
                q->first_pkt = pkt1->next;
                if (!q->first_pkt)
                    q->last_pkt = NULL;
                q->nb_packets--;
                q->size -= pkt1->pkt.size + sizeof(*pkt1);
                *pkt = pkt1->pkt;
                av_free(pkt1);
                ret = 1;
                break;
            } else if (!block) {
                ret = 0;
                break;
            } else {
                pthread_cond_wait(q->cond,q->mutex);
                //SDL_CondWait(q->cond, q->mutex);
            }
        }
        pthread_mutex_unlock(q->mutex);
        //SDL_UnlockMutex(q->mutex);
        return ret;
    }
    
    
    
    //声明了一个内联函数,写wav头
    static __inline  void writeWavHeader(AVCodecContext *pCodecCtx,AVFormatContext *pFormatCtx,FILE *audioFile) {
        //wav文件有44字节的wav头,所以要写44字节的wav头
        int8_t *data;
        int32_t long_temp;
        int16_t short_temp;
        int16_t BlockAlign;
        int bits=16;
        int32_t fileSize;
        int32_t audioDataSize;
    
        switch(pCodecCtx->sample_fmt) {
            case AV_SAMPLE_FMT_S16:
                bits=16;
                break;
            case AV_SAMPLE_FMT_S32:
                bits=32;
                break;
            case AV_SAMPLE_FMT_U8:
                bits=8;
                break;
            default:
                bits=16;
                break;
        }
        audioDataSize=(pFormatCtx->duration)*(bits/8)*(pCodecCtx->sample_rate)*(pCodecCtx->channels);
        fileSize=audioDataSize+36;
        data="RIFF";
        fwrite(data,sizeof(char),4,audioFile);
        fwrite(&fileSize,sizeof(int32_t),1,audioFile);
    
        //"WAVE"
        data="WAVE";
        fwrite(data,sizeof(char),4,audioFile);
        data="fmt ";
        fwrite(data,sizeof(char),4,audioFile);
        long_temp=16;
        fwrite(&long_temp,sizeof(int32_t),1,audioFile);
        short_temp=0x01;
        fwrite(&short_temp,sizeof(int16_t),1,audioFile);
        short_temp=(pCodecCtx->channels);
        fwrite(&short_temp,sizeof(int16_t),1,audioFile);
        long_temp=(pCodecCtx->sample_rate);
        fwrite(&long_temp,sizeof(int32_t),1,audioFile);
        long_temp=(bits/8)*(pCodecCtx->channels)*(pCodecCtx->sample_rate);
        fwrite(&long_temp,sizeof(int32_t),1,audioFile);
        BlockAlign=(bits/8)*(pCodecCtx->channels);
        fwrite(&BlockAlign,sizeof(int16_t),1,audioFile);
        short_temp=(bits);
        fwrite(&short_temp,sizeof(int16_t),1,audioFile);
        data="data";
        fwrite(data,sizeof(char),4,audioFile);
        fwrite(&audioDataSize,sizeof(int32_t),1,audioFile);
    
        fseek(audioFile,44,SEEK_SET);
    
    }
    
    int main()
    {
    //    char *filename="rtsp://192.168.20.112/Love_You.mp4";
        //char *filename="E:\flv\3d.mp3";
        char *filename="E:\flv\MY.aac";
    //    char *filename="mms://mms.cnr.cn/cnr003";
    //    char *filename="mms://mms.cnr.cn/cnr001";
    //    char *filename="rtsp://livewm.orange.fr/live-multicanaux";
    //    char *filename="mms://211.167.102.66/ch-01";
        AVFormatContext *pFormatCtx;
        int audioStream=-1;
        int i;
        int iFrame=0;
        AVCodecContext *pCodecCtx;
        AVCodec *pCodec=NULL;
        static AVPacket packet;
        uint8_t *pktData=NULL;
        int pktSize;
        int outSize=AVCODEC_MAX_AUDIO_FRAME_SIZE;
    //    FILE *wavfile=NULL;
    
        //这里必须使用av_malloc
        uint8_t *inbuf=(uint8_t *)av_malloc(outSize);
    
        FILE *wavFile=NULL;
        int32_t audioFileSize=0;
    
        //注册所有的编解码器
        av_register_all();
    
        //打开文件
        if(av_open_input_file(&pFormatCtx,filename,NULL,0,NULL)!=0)
        {
            printf("Could not open input file %s
    ",filename);
            return 0;
        }
        if(av_find_stream_info(pFormatCtx)<0)
        {
            printf("Could not find stream information
    ");
        }
    
        //输出文件的音视频流信息
        av_dump_format(pFormatCtx,0,filename,0);
    
        //找到音频流
        for(i=0;i<pFormatCtx->nb_streams;i++) {
            if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
                audioStream=i;
                break;
            }
        }
    
        //找到解码器
        pCodecCtx=pFormatCtx->streams[audioStream]->codec;
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    
    
        //打开解码器
        if(avcodec_open(pCodecCtx,pCodec)<0) {
            printf("Error avcodec_open failed.
    ");
            return 1;
        }
    
        printf("	bit_rate=%d
     
        bytes_per_secondes=%d
     
        sample_rate=%d
     
        channels=%d
     
        codec_name=%s
    ",pCodecCtx->bit_rate,(pCodecCtx->codec_id==CODEC_ID_PCM_U8)?8:16,
        pCodecCtx->sample_rate,pCodecCtx->channels,pCodecCtx->codec->name);
    
        //wavFile=fopen("E:\flv\saveWav.wav","wb");
        wavFile=fopen("E:\flv\MY.wav","wb");
        //wavFile=fopen("E:\flv\test.wav","wb");
        if (wavFile==NULL)
        {
            printf("open error
    ");
            return 1;
        }
    
        //写入wav文件头
        writeWavHeader(pCodecCtx,pFormatCtx,wavFile);
    
        //开始解码音频流
        av_free_packet(&packet);
        while(av_read_frame(pFormatCtx,&packet)>=0) {
            if(packet.stream_index==audioStream) {
                int len=0;
                if((iFrame++)>=4000)
                    break;
                pktData=packet.data;
                pktSize=packet.size;
                while(pktSize>0) {
                    outSize=AVCODEC_MAX_AUDIO_FRAME_SIZE;
                    len=avcodec_decode_audio3(pCodecCtx,(short *)inbuf,&outSize,&packet);
                    if(len<0){
                        printf("Error while decoding
    ");
                        break;
                    }
                    if(outSize>0) {
                        audioFileSize+=outSize;
                        fwrite(inbuf,1,outSize,wavFile);
                        fflush(wavFile);
                    }
                    pktSize-=len;
                    pktData+=len;
                }
            }
            av_free_packet(&packet);
        }
    
        //wav文件的第40个字节开始的4个字节存放的是wav文件的有效数据长度
        fseek(wavFile,40,SEEK_SET);
        fwrite(&audioFileSize,1,sizeof(int32_t),wavFile);
        //wav文件的第4个字节开始的4个字节存放的是wav文件的文件长度(audioFileSize+44-8),44表示44个字节的头,8表示"RIFF"和"WAVE"
        audioFileSize+=36;
        fseek(wavFile,4,SEEK_SET);
        fwrite(&audioFileSize,1,sizeof(int32_t),wavFile);
    
        //关闭文件
        fclose(wavFile);
    
        //释放内存
        av_free(inbuf);
        if(pCodecCtx!=NULL){
            avcodec_close(pCodecCtx);
        }
        av_close_input_file(pFormatCtx);
        return 0;
    }

    需要用到的音视频解码静态库文件包括以下几个:

    avcodec-53.lib,avdevice-53.lib,avfilter-2.lib,avformat-53.lib,avutil-51.lib,pthreadVC2.lib,swscale-2.lib

  • 相关阅读:
    vue table 固定首列和首行
    手机号隐藏中间4位变成****
    微信小程序填坑之page[pages/XXX/XXX] not found.May be caused by
    table表格固定前几列,其余的滚动
    大文件切片功能
    js如何判断数字是否有小数
    获取当前时间前后6个月的时间数组
    为你的mail server增加SPF记录
    给hmailserver添加DKIM签名
    HttpWatch工具简介及使用技巧
  • 原文地址:https://www.cnblogs.com/xuanyuanchen/p/3161203.html
Copyright © 2011-2022 走看看