ffmpeg 分离音频 保存

来源:互联网 发布:陕西省家长网络学校 编辑:程序博客网 时间:2024/05/19 17:24
<h1 class="postTitle" style="margin: 0px 0px 10px; padding: 0px 15px; font-size: 12px; font-weight: normal; background-image: url(http://www.cnblogs.com/skins/iMetro_HD/images/logo.png); font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 18px; background-position: -10px 0px; background-repeat: no-repeat repeat;"><a target=_blank id="cb_post_title_url" class="postTitle2" href="http://www.cnblogs.com/xuanyuanchen/p/3161203.html" style="margin: 0px; padding: 0px; font-size: 24px; color: rgb(0, 0, 0); text-decoration: none;">Windwos平台上ffmpeg解码音频并且保存到wav文件中</a></h1>
#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 4typedef 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_AVFILTERstatic 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\n",filename);        return 0;    }    if(av_find_stream_info(pFormatCtx)<0)    {        printf("Could not find stream information\n");    }    //输出文件的音视频流信息    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.\n");        return 1;    }    printf("\tbit_rate=%d\n \    bytes_per_secondes=%d\n \    sample_rate=%d\n \    channels=%d\n \    codec_name=%s\n",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\n");        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\n");                    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;}

0 0
原创粉丝点击