zoukankan      html  css  js  c++  java
  • 解码大致流程

     //注册FFMpeg

    av_register_all();

    //网络初始化
    avformat_network_init();

    //注册编解码器
    avcodec_register_all();


    //打开文件并且解析
    avformat_open_input(&ic, url, NULL, NULL); ------------------------->AVFormatContext(里面包含AVStream)


    //该函数可以读取一部分视音频数据并且获得一些相关的信息
    avformat_find_stream_info(ic, NULL); 


    //找到对应流的索引
    audioStream = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);


    //找到相应流的解码器
    AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);


    //解码器初上下文-------->解码器始化缓存空间
    AVCodecContext *vc = avcodec_alloc_context3(codec);

    //把对应流的一些属性复制给解码器的缓存空间,相当于配置解码器的一些信息:宽 高 帧率 采样格式
    avcodec_parameters_to_context(vc, ic->streams[videoStream]->codecpar);

    //打开解码器
    avcodec_open2(vc, 0, 0);


    //读取音视频信息 //AVFormatContext *ic = NULL
    av_read_frame(ic, pkt);            //AVPacket *pkt = av_packet_alloc();


    //把数据发送到数据空间缓冲区
    re = avcodec_send_packet(vc, pkt);

    //从数据空间缓冲区收到数据(这个就是原始数据)
    avcodec_receive_frame(vc, frame);

    //接收到原始数据后对视频进行转换

    //对数据格式进行转换(包括大小)
    sws_getCachedContext(struct  SwsContext *context  ,  int srcW , int srcH , enum AVPixelFormat srcFormat 

                    int dstW , int dst H , enum AVPixelFormat dstFormat , int flag)

     //对每一帧数据进行转换

     sws_scale(struct  SwsContext *context , srcSlice(高度 Slice[0]Slice[1]Slice[2]) , srcStride(对齐策略--->宽度) ,        

     srcSilceY(从哪一个位置计算)  , srcSliceH(1280*720 H=720) , dst , dstStride) 

     




    AVFormatContext(里面包含AVStream)------>AVCondecContext----------->AVPacket---------->AVFrame



    -----------------------华丽的分割线------------------------------------------

     //注册FFMpeg

    av_register_all();

    //网络初始化
    avformat_network_init();

    //注册编解码器
    avcodec_register_all();

    //YUV--->RGB
    sws_getCachedContext(struct  SwsContext *context  ,  int srcW , int srcH , enum AVPixelFormat srcFormat

                    int dstW , int dst H , enum AVPixelFormat dstFormat , int flag)------------>像素格式转换上下文(大小也转化)

       //配置YUV的一些属性(数据格式 宽 高 对齐方式)               

       AVFrame  *yuv = av_frame_alloc();                         

       yuv->format = AV_PIX_FMT_YUV420P                       

       yuv->width = inWidth                                 

       yuv->height = inHeight                             

       yuv->pts = 0                                   

       //分配yuv空间                                  

       av_frame_get_buffer(yuv , (alignment多少位作为对齐策略)32)            

                                        

     (AVFrame  *yuv = av_frame_alloc();

     pcm->format = outSampleFmt;                                                               //样本格式

     pcm->channels = channels;                   //通道数量

     pcm->channel_layout = av_get_default_channel_layout(channels);      //通道的格式

     pcm->nb_samples = 1024;                                                                    //一帧数量

     av_frame_get_buffer(pcm , (alignment多少位作为对齐策略)32)       //分配pcm的空间

    )


     //通过ID找到编码器

    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);


    //创造编码器的缓冲空间
    AVCodecContext  *vc = accodec_alloc_context3((AVCodec * code:代表参数)  codec)

    //为编码缓冲空间配置参数

       vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER  //全局参数

       vc->codec_id = codec->id

       vc->thread_count = 4 ;

       针对视频的参数的配置

       vc->bit_rate = 50*1024*8   (50KB) //码率, 压缩率 50*1024(kb)*8(字节数)

       vc->width = inWidth

       vc->height = inHight

       vc->time_base(时间基数单位是秒) = {1 , fps}---------> 1 / fps--------------------------------------------------->需要回来重点看看

       vc->time_framerate = {fps , 1}---------> fps / 1

       vc->gop_size = 50  //画面组的大小,多少帧为一个关键帧,越大压缩率越好,但是容易丢失

       vc->max_b_frames = 0;  //当B帧为0的时候 , pts和bts显示一致

       vc->pix_fmt = AV_PIX_FMT_YUV420P  //像素格式 

       共工配置:全局参数 线程数量 压缩率

      视频 : (数据格式 宽 高 时间基数 帧率 多少帧为一关键帧 B帧设置为0)
      
      音频 : (采样率 数据格式 通道数 通道格式)
      ac->bit_rate = 40000;
       ac->sample_rate = sampleRate;
       ac->sample_fmt = AV_SAMPLE_FMT_FLTP;
       ac->channels = channels;
       ac->channel_layout = av_get_default_channel_layout(channels);

       //打开编码器

       avcodec_open2(vc , 0 , 0);

      //把每一帧数据转换成功后发送到缓冲区

      sws_scale(struct  SwsContext *context , srcSlice(高度 Slice[0]Slice[1]Slice[2]) , srcStride(对齐策略--->宽度) ,

                    srcSilceY(从哪一个位置计算)  , srcSliceH(1280*720 H=720) , dst , dstStride) 

      //数据发送到编码器数据空间缓冲区    

      avcodec_send_frame(vc , yuv);  

      //AVPacket从编码器数据空间缓冲区收到数据    

      avcodec_receive_packet(vc , &pack); 

      //输出封装器的上下文(封装器的数据缓冲空间)

      avformat_alloc_output_context2(&ic , 0 ,"flv(封装格式)" , "推流到指定的地址");

      //首先创建AVStream,并从AVCodecContext获得数据

      AVStream *vs = avformat_new_stream(ic , NULL);

      avcodec_parameters_from_context(vs->codeccpar , vc);

      //打开rtmp 的输出网络IO口

      avio_open(&i->pb , "  " , AVIO_FLAG_WRITE(写入的方式:有读 有写 有读写))

      //写入封装头(它会 改变vs->timebase数值会被改掉,去取解码后的AVStream的timebase)

      avformat_write_header(ic , NULL);

          //推流

      pack->pts = av_rescale_q(pack.pts , vc->time_base , vs->time_base)

      pack->dts = av_rescale_q(pack.dts , vc->time_base , vs->time_base)

      av_interleaved_write_frame(ic , &pack)

     
    
    
    
    
     
    
    
     
     


     


     


  • 相关阅读:
    解决Hash冲突的几种方式
    深入理解JDK8中的HashMap
    JAVA中两个int类型的变量在不借助第三个变量的情况下完成值的互换
    Feign调用时读取超时(Read timed out executing GET)解决
    windows上Jenkins安装及其配置
    windows下查看端口被占用及处理
    flutter IOS模拟器无法弹出软键盘
    Android-ION内存管理简介
    移动GPU分类/百科
    ApiGen4.1 windows安装教程
  • 原文地址:https://www.cnblogs.com/liunx1109/p/9328470.html
Copyright © 2011-2022 走看看