zoukankan      html  css  js  c++  java
  • FFmpeg音视频编解码实践总结

    PS:由于目前开发RTSP服务器传输模块时用到了h264文件,所以攻了一段时间去实现h264的视频编解码,借用FFmpeg SDK实现了任意文件格式之间的转换,并实现了流媒体实时播放,目前音视频同步需要稍加完善,视频编码代码已成功移植到Visual Stdio平台,如有需要的留下邮箱

    以下文档来自FFmpeg工程组(http://www.ffmpeg.com.cn/index.php开发事例)

    实现转码一个普通视频文件为视频mpeg4,音频mp3的功能的程序

    本程序源引自FFmpeg工程组,实现转码一个普通视频文件为视频mpeg4,音频mp3的功能

    复制代码
    #include <avcodec.h>
    #include <avformat.h>
    #include <stdio.h>
    #include <avutil.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    main(int argc,char **argv)
    {
    const char *input_file_name="/root/movies/ddh1.mpg";
    av_register_all();//注册库中所有可用的文件格式和编码器
    AVFormatContext *ic;
    //输入文件处理部分
    ic=av_alloc_format_context();
    if(av_open_input_file(&ic,input_file_name,NULL,0,NULL)!=0)
    {
    printf("can't open the file %s ",input_file_name);
    exit(1);
    }//打开输入文件
    if(av_find_stream_info(ic)<0)
    {
    printf("can't find suitable codec parameters ");
    exit(1);
    }//取出流信息
    dump_format(ic,0,input_file_name,0);//列出输入文件的相关流信息
    int i;
    int videoindex=-1;int audioindex=-1;
    for(i=0;i<ic->nb_streams;i++)
    {
    if(ic->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
    {
    videoindex=i;
    //printf("video ");
    }
    else if(ic->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO)
    {
    //printf("audio ");
    audioindex=i;
    }
    }
    if(videoindex==-1)
    {
    printf("can't find video stream ");
    exit(1);
    }//没有找到视频流
    AVCodecContext *vCodecCtx;
    vCodecCtx=ic->streams[videoindex]->codec;//取得视频流编码上下文指针
    AVCodec *vCodec;
    vCodec=avcodec_find_decoder(vCodecCtx->codec_id);
    if(vCodec==NULL)
    {
    printf("can't find suitable video decoder ");
    exit(1);
    }//找到合适的视频解码器
    if(avcodec_open(vCodecCtx,vCodec)<0)
    {
    printf("can't open the video decoder ");
    exit(1);
    }//打开该视频解码器
    if(audioindex==-1)
    {
    printf("can't find audio stream ");
    exit(1);
    }//没有找到音频流
    AVCodecContext *aCodecCtx;
    aCodecCtx=ic->streams[audioindex]->codec;
    AVCodec *aCodec;
    aCodec=avcodec_find_decoder(aCodecCtx->codec_id);
    if(aCodec==NULL)
    {
    printf("can't find suitable audio decoder ");
    exit(1);
    }//找到合适的音频解码器
    if(avcodec_open(aCodecCtx,aCodec)<0)
    {
    printf("can't open the audio decoder ");
    exit(1);
    }//打开该音频解码器
    //下面为输出文件处理部分
    const char *output_file_name="/root/123.avi";
    AVOutputFormat *fmt;
    AVFormatContext *oc;
    AVCodecContext *oVcc,*oAcc;
    AVCodec *oVc,*oAc;
    AVStream *video_st,*audio_st;
    AVFrame *oVFrame,*oAFrame;
    double video_pts;
    oVFrame=avcodec_alloc_frame();
    fmt=guess_format(NULL,output_file_name,NULL);
    if(!fmt)
    {
    printf("could not deduce output format from outfile extension ");
    exit(0);
    }//判断是否可以判断输出文件的编码格式
    oc=av_alloc_format_context();
    if(!oc)
    {
    printf("Memory error ");
    exit(0);
    }
    oc->oformat=fmt;
    pstrcpy(oc->filename,sizeof(oc->filename),output_file_name);
    video_st=av_new_stream(oc,0);
    if(!video_st)
    {
    printf("could not alloc video stream ");
    exit(0);
    }
    oVcc=avcodec_alloc_context();
    oVcc=video_st->codec;
    oVcc->codec_id=CODEC_ID_MPEG4;
    oVcc->codec_type=CODEC_TYPE_VIDEO;
    oVcc->bit_rate=2500000;
    oVcc->width=704;
    oVcc->height=480;
    oVcc->time_base=vCodecCtx->time_base;
    oVcc->gop_size=vCodecCtx->gop_size;
    //oVcc->pix_fmt=vCodecCtx->pix_fmt;
    oVcc->pix_fmt=vCodecCtx->pix_fmt;
    oVcc->max_b_frames=vCodecCtx->max_b_frames;
    video_st->r_frame_rate=ic->streams[videoindex]->r_frame_rate;
    audio_st=av_new_stream(oc,oc->nb_streams);
    if(!audio_st)
    {
    printf("could not alloc audio stream ");
    exit(0);
    }
    avcodec_get_context_defaults2(audio_st->codec,CODEC_TYPE_AUDIO);
    oAcc=avcodec_alloc_context();
    oAcc=audio_st->codec;
    oAcc->codec_id=CODEC_ID_MP3;
    oAcc->codec_type=CODEC_TYPE_AUDIO;
    oAcc->bit_rate=aCodecCtx->bit_rate;
    oAcc->sample_rate=aCodecCtx->sample_rate;
    oAcc->channels=2;
    if (av_set_parameters(oc, NULL) < 0)
    {
    printf( "Invalid output format parameters ");
    exit(0);
    }//设置必要的输出参数
    strcpy(oc->title,ic->title);
    strcpy(oc->author,ic->author);
    strcpy(oc->copyright,ic->copyright);
    strcpy(oc->comment,ic->comment);
    strcpy(oc->album,ic->album);
    oc->year=ic->year;
    oc->track=ic->track;
    strcpy(oc->genre,ic->genre);
    dump_format(oc,0,output_file_name,1);//列出输出文件的相关流信息
    oVc=avcodec_find_encoder(CODEC_ID_MPEG4);
    if(!oVc)
    {
    printf("can't find suitable video encoder ");
    exit(0);
    }//找到合适的视频编码器
    if(avcodec_open(oVcc,oVc)<0)
    {
    printf("can't open the output video codec ");
    exit(0);
    }//打开视频编码器
    oAc=avcodec_find_encoder(CODEC_ID_MP3);
    if(!oAc)
    {
    printf("can't find suitable audio encoder ");
    exit(0);
    }//找到合适的音频编码器
    if(avcodec_open(oAcc,oAc)<0)
    {
    printf("can't open the output audio codec");
    exit(0);
    }//打开音频编码器
    /*if(url_exist(output_file_name))
    {
    printf("the output file name %s has exist,please select other ",output_file_name);
    exit(0);
    }//判断该输出文件是否已经存在
    */
    if (!(oc->flags & AVFMT_NOFILE))
    {
    if(url_fopen(&oc->pb,output_file_name,URL_WRONLY)<0)
    {
    printf("can't open the output file %s ",output_file_name);
    exit(0);
    }//打开输出文件
    }
    if(!oc->nb_streams)
    {
    fprintf(stderr,"output file dose not contain any stream ");
    exit(0);
    }//查看输出文件是否含有流信息
    if(av_write_header(oc)<0)
    {
    fprintf(stderr, "Could not write header for output file ");
    exit(1);
    }[/i][/i]
    AVPacket packet;
    uint8_t *ptr,*out_buf;
    int out_size;
    static short *samples=NULL;
    static unsigned int samples_size=0;
    uint8_t *video_outbuf,*audio_outbuf;int video_outbuf_size,audio_outbuf_size;
    video_outbuf_size=400000;
    video_outbuf= (unsigned char *) malloc(video_outbuf_size);
    audio_outbuf_size = 10000;
    audio_outbuf = av_malloc(audio_outbuf_size);
    int flag;int frameFinished;int len;int frame_index=0,ret;
    while(av_read_frame(ic,&packet)>=0)//从输入文件中读取一个包
    {
    if(packet.stream_index==videoindex)//判断是否为当前视频流中的包
    {
    len=avcodec_decode_video(vCodecCtx,oVFrame,&frameFinished,packet.data,packet.size);//若为视频包,解码该视频包
    if(len<0)
    {
    printf("Error while decoding ");
    exit(0);
    }
    if(frameFinished)//判断视频祯是否读完
    {
    fflush(stdout);
    oVFrame->pts=av_rescale(frame_index,AV_TIME_BASE*(int64_t)oVcc->time_base.num,oVcc->time_base.den);
    oVFrame->pict_type=0;
    out_size = avcodec_encode_video(oVcc, video_outbuf, video_outbuf_size, oVFrame);
    if (out_size > 0)
    {
    AVPacket pkt;
    av_init_packet(&pkt);
    if(oVcc->coded_frame && oVcc->coded_frame->key_frame)
    pkt.flags |= PKT_FLAG_KEY;
    pkt.flags = packet.flags;
    pkt.stream_index= video_st->index;
    pkt.data= video_outbuf;
    pkt.size= out_size;
    ret=av_write_frame(oc, &pkt);
    }
    frame_index++;
    }
    else
    ret=av_write_frame(oc, &packet);
    //img_convert((AVPicture *)vFrame, PIX_FMT_RGB24, (AVPicture*)oVFrame, oVcc->pix_fmt,oVcc->width,oVcc-
    >height);
    //SaveFrame(vFrame,oVcc->width,oVcc->height,frame_index);
    if(ret!=0)
    {
    printf("while write video frame error ");
    exit(0);
    }
    }
    else if(packet.stream_index==audioindex)
    {
    len=packet.size;
    ptr=packet.data;
    int ret=0;
    while(len>0)
    {
    out_buf=NULL;
    out_size=0;
    if(&packet)
    samples=av_fast_realloc(samples,&samples_size,FFMAX(packet.size*sizeof
    (*samples),AVCODEC_MAX_AUDIO_FRAME_SIZE));
    out_size=samples_size;
    ret=avcodec_decode_audio(aCodecCtx,samples,&out_size,ptr,len);//若为音频包,解码该音频包
    if(ret<0)
    {
    printf("while decode audio failure ");
    exit(0);
    }
    fflush(stdout);
    ptr+=ret;
    len-=ret;
    if(out_size<=0)
    continue;
    out_buf=(uint8_t *)samples;
    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.size= avcodec_encode_audio(oAcc, audio_outbuf, audio_outbuf_size, out_buf);
    pkt.pts= av_rescale_q(oAcc->coded_frame->pts, oAcc->time_base, audio_st->time_base);
    pkt.flags |= PKT_FLAG_KEY;
    pkt.stream_index= audioindex;
    pkt.data= audio_outbuf;
    if (av_write_frame(oc, &pkt) != 0)
    {
    fprintf(stderr, "Error while writing audio frame ");
    exit(1);
    }
    }
    }
    av_free_packet(&packet);
    }
    av_write_trailer(oc);
    for(i = 0; i < oc->nb_streams; i++)
    {
    av_freep(&oc->streams[i]->codec);
    av_freep(&oc->streams[i]);
    }
    url_fclose(oc);
    av_free(oc);
    av_free(oVFrame);
    av_free(out_buf);
    avcodec_close(vCodecCtx);
    avcodec_close(aCodecCtx);
    av_close_input_file(ic);
    }
    复制代码
    最近一直很忙  花时间整理了一份  希望大家多多交流ffmpeg视频编解码方面的知识  接下来会抽时间总结一篇RTP传输协议的文章  好了  废话不说  附上链接自己下载
    source download:  https://files.cnblogs.com/msopengl/ffmpegh264codec.rar

    
    
    作者:jemmyLiu
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
    一些接口已经老到已经很多事情记不清了,只记得那年中国队勇夺世界杯:
     
     
     
    更新下:
    27:av_alloc_format_context -> avformat_alloc_context
    28:if(av_open_input_file(&ic,input_file_name,NULL,0,NULL)!=0) -> if(avformat_open_input(&ic, input_file_name, NULL, NULL) !=0 )
    33: if(av_find_stream_info(ic)<0) -> if(avformat_find_stream_info(ic,NULL)<0)
    38:dump_format(ic,0,input_file_name,0) -> av_dump_format(ic,0,input_file_name,0)
    43: CODEC_TYPE_VIDEO -> AVMEDIA_TYPE_VIDEO
    48: CODEC_TYPE_AUDIO -> AVMEDIA_TYPE_AUDIO
    68: if(avcodec_open(vCodecCtx,vCodec)<0) -> if(avcodec_open2(vCodecCtx,vCodec,NULL)<0)
    87: if(avcodec_open(aCodecCtx,aCodec)<0) -> if(avcodec_open2(aCodecCtx,aCodec,NULL)<0)
    101: oVFrame=avcodec_alloc_frame() -> oVFrame=av_frame_alloc()
    102: guess_format -> av_guess_format
    108: av_alloc_format_context -> avformat_alloc_context
    116: video_st=av_new_stream(oc,0) -> video_st=avformat_new_stream(oc,oVc)
    122: oVcc=avcodec_alloc_context() -> oVcc=avcodec_alloc_context3(oVc)
    124: CODEC_ID_H264 -> AV_CODEC_ID_H264
    125: CODEC_TYPE_VIDEO -> AVMEDIA_TYPE_VIDEO
    135: audio_st=av_new_stream(oc,oc->nb_streams) -> audio_st=avformat_new_stream(oc,oAc)
    141: avcodec_get_context_defaults2(audio_st->codec,CODEC_TYPE_AUDIO) -> avcodec_get_context_defaults3(audio_st->codec,oAc)
    142: oAcc=avcodec_alloc_context() -> oAcc=avcodec_alloc_context3(oAc)
    144: CODEC_ID_MP3 -> AV_CODEC_ID_AAC (这种自己选择)
    145: CODEC_TYPE_AUDIO ->AVMEDIA_TYPE_AUDIO
    146: …………
     
  • 相关阅读:
    Java的Socket通信----通过 Socket 实现 TCP 编程之多线程demo(2)
    MySQL 数据备份与还原
    java实现时钟方法汇总
    java实现二叉树demo
    java实现心型、99乘法demo
    显示本月日历demo
    打开图片并显示在面板上demo
    ArraySort--冒泡排序、选择排序、插入排序工具类demo
    类的实例化顺序
    StringsUtil字符串工具类---灵活截取
  • 原文地址:https://www.cnblogs.com/youngt/p/3732048.html
Copyright © 2011-2022 走看看