• 音频编码器的流程


    一 RGB------->YUV

      1.sws_getCachedContext : 像素格式转换上下文(大小也转化)

       sws_getCachedContext(struct  SwsContext *context  ,  int srcW , int srcH , enum AVPixelFormat srcFormat

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

       format : AV_PIX_FMT_YUV420P (连续存放YYYY UUVV)

       SwsContext : 如果为null 的时候,它会自动创建一个新的,如果不为空,它会根据你传入的数值是否和你配置一样.

             如果相同,直接返回内容,如果不同,清除掉你的配置的内容,并返回上下文

       flag : 对应图像算法的标志位   //SWS_BICUBIC (尺寸变化使用算法)

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

                            srcSilceY(从哪一个位置计算)  , srcSliceH(1280*720 H=720) , dst , dstStride) : 对每一帧数据进行转换

      

       输出数据结构

       //分配对象的空间

       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)

         输入数据结构

      uint_t  *indata[8] = {0};

      对于交错存放的数据格式  indata[0]  bgrbgrbgr

      对于planne(平面存放)的数据格式  indata[0] bbbbb  indata[1]ggggg indata[2] rrrrr

      indata[0] = frame.data(存放的数据格式RGB交错模式)

      int  inLineSize[8] = {0};

      //一行(宽)数据的字节数

      inLineSize[0] = frame.cols(列----->代表宽度) * (frame.elemSize()-----> 代表每一个像素的大小);  int  h = sws_scale(vsc , indata , inLineSize , 0 , frame.rows(行数--->代表就是高度) ,             yuv->data , yuv->inLineSize);

    二 H264编码

      1.找到编码器

       avcodec_find_encoder(......) : 通过ID找到编码器

       AVCodec  *codec = avcodec_find_encoder(AV_CODEC_ID_H264)

       avcodec_find_encodec_by_name(.....) :通过名字去找编码器

      2.编码上下文空间(为了编码可以缓存)

       AVCodecContext  *vc = accodec_alloc_context3((AVCodec * code:代表参数)  codec)   

      3. 配置编码器的参数

       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  //像素格式 

      4.打开编码器

       avcodec_open2(vc , 0 , 0);

      5.H264的编码

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

       avcodec_send_frame(vc , yuv);              //AVFrame  *yuv = av_frame_alloc();

       

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

       avcodec_receive_packet(vc , &pack);      //下次调用会自动清理缓存    //AVPacket *pkt = av_packet_alloc();

        

       6.封装器和视频流配置

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

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

        (2)添加相应的数据

         AVStream *vs = avformat_new_stream(ic , NULL);

         vs->codercpar->codec_tag = 0;

         //从编码器复制到流的属性里面

         avcodec_parameters_from_context(vs->codeccpar , vc);  

         av_dump_format(ic ,  0 , "推送到网址" ,1(代表输出   0:代表不输出))

       7.打开网络协议

        1).打开rtmp 的输出网络IO口

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

        

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

         avformat_write_header(ic , NULL);

        

    三 推流

      av_read_frame()

      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)

  • 相关阅读:
    0209利用innobackupex进行简单数据库的备份
    0208如何利用federated配置远程的数据库和本地数据相互交互
    0208MySQL5.7之Group Replication
    解决问题的方法
    0123简单配置LNMP
    0120Keeplived实现自动切换Mysql服务
    0116MySql主从复制监控
    大数据导入EXCEL
    OSI结构和TCP/IP模型
    ORA-12154 TNS无法解析指定的连接标识符
  • 原文地址:https://www.cnblogs.com/liunx1109/p/9328466.html
Copyright © 2020-2023  润新知