<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      FFmpeg libswscale源碼分析3-scale濾鏡源碼分析

      本文為作者原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處:http://www.rzrgm.cn/leisure_chn/p/14355017.html

      libswscale 源碼分析系列文章:
      [1]. FFmpeg libswscale源碼分析1-API介紹
      [2]. FFmpeg libswscale源碼分析2-轉(zhuǎn)碼命令行與濾鏡圖
      [3]. FFmpeg libswscale源碼分析3-scale濾鏡源碼分析
      [4]. FFmpeg libswscale源碼分析4-libswscale源碼分析

      源碼分析基于 FFmpeg 4.1 版本。

      3. scale 濾鏡源碼分析

      scale 濾鏡調(diào)用 libswscale 庫(kù)來執(zhí)行像素格式轉(zhuǎn)換或圖像分辨率縮放工作。閱讀 scale 濾鏡代碼,可以了解 libswscale API 的詳細(xì)用法。

      3.1 scale 濾鏡對(duì) SwsContext 的初始化

      函數(shù)調(diào)用關(guān)系如下:

      config_props() -->
      sws_init_context() -->
      ff_get_unscaled_swscale() -->
      

      config_props() 函數(shù):

      static int config_props(AVFilterLink *outlink)
      {
          AVFilterContext *ctx = outlink->src;
          AVFilterLink *inlink0 = outlink->src->inputs[0];
          AVFilterLink *inlink  = ctx->filter == &ff_vf_scale2ref ?
                                  outlink->src->inputs[1] :
                                  outlink->src->inputs[0];
          enum AVPixelFormat outfmt = outlink->format;
          const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
          ScaleContext *scale = ctx->priv;
          ......
          if (inlink0->w == outlink->w &&
              inlink0->h == outlink->h &&
              !scale->out_color_matrix &&
              scale->in_range == scale->out_range &&
              inlink0->format == outlink->format)
              // 如果當(dāng)前 scale 濾鏡的輸入和輸出一樣,此處不作任何初始化動(dòng)作
              ;
          else {
              // scale->sws 用于一幀圖像,scale->isws[0] 隔行幀頂場(chǎng),scale->isws[1] 用于隔行幀底場(chǎng)
              struct SwsContext **swscs[3] = {&scale->sws, &scale->isws[0], &scale->isws[1]};
              int i;
      
              for (i = 0; i < 3; i++) {
                  int in_v_chr_pos = scale->in_v_chr_pos, out_v_chr_pos = scale->out_v_chr_pos;
                  struct SwsContext **s = swscs[i];
                  *s = sws_alloc_context();
                  if (!*s)
                      return AVERROR(ENOMEM);
                  
                  // 將 ffmpeg 命令行中傳入的參數(shù)(命令行未給出的參數(shù)取默認(rèn)值)設(shè)置到 SwsContext
                  av_opt_set_int(*s, "srcw", inlink0 ->w, 0);
                  av_opt_set_int(*s, "srch", inlink0 ->h >> !!i, 0);
                  av_opt_set_int(*s, "src_format", inlink0->format, 0);
                  av_opt_set_int(*s, "dstw", outlink->w, 0);
                  av_opt_set_int(*s, "dsth", outlink->h >> !!i, 0);
                  av_opt_set_int(*s, "dst_format", outfmt, 0);
                  av_opt_set_int(*s, "sws_flags", scale->flags, 0);
                  av_opt_set_int(*s, "param0", scale->param[0], 0);
                  av_opt_set_int(*s, "param1", scale->param[1], 0);
                  if (scale->in_range != AVCOL_RANGE_UNSPECIFIED)
                      av_opt_set_int(*s, "src_range",
                                     scale->in_range == AVCOL_RANGE_JPEG, 0);
                  if (scale->out_range != AVCOL_RANGE_UNSPECIFIED)
                      av_opt_set_int(*s, "dst_range",
                                     scale->out_range == AVCOL_RANGE_JPEG, 0);
      
                  if (scale->opts) {
                      AVDictionaryEntry *e = NULL;
                      while ((e = av_dict_get(scale->opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
                          if ((ret = av_opt_set(*s, e->key, e->value, 0)) < 0)
                              return ret;
                      }
                  }
                  /* Override yuv420p default settings to have the correct (MPEG-2) chroma positions
                   * MPEG-2 chroma positions are used by convention
                   * XXX: support other 4:2:0 pixel formats */
                  if (inlink0->format == AV_PIX_FMT_yuv420p && scale->in_v_chr_pos == -513) {
                      in_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192;
                  }
      
                  if (outlink->format == AV_PIX_FMT_yuv420p && scale->out_v_chr_pos == -513) {
                      out_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192;
                  }
      
                  av_opt_set_int(*s, "src_h_chr_pos", scale->in_h_chr_pos, 0);
                  av_opt_set_int(*s, "src_v_chr_pos", in_v_chr_pos, 0);
                  av_opt_set_int(*s, "dst_h_chr_pos", scale->out_h_chr_pos, 0);
                  av_opt_set_int(*s, "dst_v_chr_pos", out_v_chr_pos, 0);
                  
                  // 調(diào)用初始化函數(shù) sws_init_context()
                  if ((ret = sws_init_context(*s, NULL, NULL)) < 0)
                      return ret;
                  if (!scale->interlaced)    // 未啟用隔行標(biāo)志,則不處理 scale->isws[0] 和 scale->isws[1]
                      break;
              }
          }
      
          ......
      
          return 0;
      
      fail:
          return ret;
      }
      

      3.2 scale 濾鏡調(diào)用 sws_scale 函數(shù)

      只看 scale 濾鏡中對(duì)視頻幀進(jìn)行縮放或格式轉(zhuǎn)換的實(shí)現(xiàn)邏輯。

      scale 濾鏡的 filter_frame() 函數(shù)如下:

      static int filter_frame(AVFilterLink *link, AVFrame *in)
      {
          ScaleContext *scale = link->dst->priv;
          AVFilterLink *outlink = link->dst->outputs[0];
          AVFrame *out;
          const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
          
          ......
          
          // 1. 色度子采樣因子
          //    log2_chroma_w 指由一行亮度樣本數(shù)(luma width)右移多少位得到一行色度樣本數(shù)(chroma width)
          //    log2_chroma_h 指由亮度樣本行數(shù)(luma height)右移多少位得到色度樣本行數(shù)(chroma height)
          //    以 YUV410P像素格式為例,
          //    水平方向子采樣因子為 1/4,則 scale->hsub = desc->log2_chroma_w = 2
          //    垂直方向子采樣因子為 1/2,則 scale->vsub = desc->log2_chroma_h = 1
          scale->hsub = desc->log2_chroma_w;    // 水平方向
          scale->vsub = desc->log2_chroma_h;
      
          ......
          
          // 2. 拷貝幀屬性
          av_frame_copy_props(out, in);
      
          ......
          // 3. 調(diào)用 scale_slice() 函數(shù)執(zhí)行轉(zhuǎn)換,分三種情況:
          if(scale->interlaced>0 || (scale->interlaced<0 && in->interlaced_frame)){
              // 3.1 scale->interlaced 的值由 scale 濾鏡的 interl 參數(shù)確定,有三個(gè)值:
              //     1: 使能隔行縮放方式
              //     0:禁用隔行縮放方式
              //     -1: 根據(jù)源幀中的隔行/逐行標(biāo)志決定是使用隔行縮放還是逐行縮放
              //     此處 if 第一個(gè)分支,即進(jìn)行隔行縮放
              scale_slice(link, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0);
              scale_slice(link, out, in, scale->isws[1], 0,  link->h   /2, 2, 1);
          }else if (scale->nb_slices) {
              // 3.2 此處 if 的第二個(gè)分支,是逐行縮放,一個(gè)圖像幀有多個(gè) slice 的情況
              int i, slice_h, slice_start, slice_end = 0;
              const int nb_slices = FFMIN(scale->nb_slices, link->h);
              for (i = 0; i < nb_slices; i++) {
                  slice_start = slice_end;
                  slice_end   = (link->h * (i+1)) / nb_slices;
                  slice_h     = slice_end - slice_start;
                  scale_slice(link, out, in, scale->sws, slice_start, slice_h, 1, 0);
              }
          }else{
              // 3.3 此處 if 第三個(gè)分支,是逐行縮放,一個(gè)圖像幀只有一個(gè) slice 的情況
              scale_slice(link, out, in, scale->sws, 0, link->h, 1, 0);
          }
      
      
          return ff_filter_frame(outlink, out);
      }
      

      scale_slice() 是對(duì)一個(gè) slice 執(zhí)行縮放操作,最終會(huì)調(diào)用 sws_scale() 函數(shù)。可以在轉(zhuǎn)碼命令行中,將 scale 濾鏡的 nb_slices 選項(xiàng)參數(shù)設(shè)置為大于 1,在 scale_slice() 函數(shù)中打斷點(diǎn)調(diào)試,觀察各參數(shù)及變量的值。

      
      static int scale_slice(AVFilterLink *link, AVFrame *out_buf, AVFrame *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
      {
          ScaleContext *scale = link->dst->priv;
          const uint8_t *in[4];
          uint8_t *out[4];
          int in_stride[4],out_stride[4];
          int i;
      
          for(i=0; i<4; i++){
              int vsub= ((i+1)&2) ? scale->vsub : 0;
               in_stride[i] = cur_pic->linesize[i] * mul;
              out_stride[i] = out_buf->linesize[i] * mul;
               in[i] = cur_pic->data[i] + ((y>>vsub)+field) * cur_pic->linesize[i];
              out[i] = out_buf->data[i] +            field  * out_buf->linesize[i];
          }
          if(scale->input_is_pal)
               in[1] = cur_pic->data[1];
          if(scale->output_is_pal)
              out[1] = out_buf->data[1];
      
          return sws_scale(sws, in, in_stride, y/mul, h,
                               out,out_stride);
      }
      
      posted @ 2021-02-03 08:51  葉余  閱讀(1232)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 欧美黑人又粗又大又爽免费 | 亚洲人成电影在线天堂色| 在线a级毛片无码免费真人| 国产日韩综合av在线| 中文字幕av一区二区三区| 亚洲中文字幕无码一久久区| 国产欧美日韩亚洲一区二区三区| 特黄 做受又硬又粗又大视频| 热久久这里只有精品国产| 国产三级精品三级| 亚洲鸥美日韩精品久久| 粉嫩av国产一区二区三区| 久久久av男人的天堂| 亚欧成人精品一区二区乱| 男女啪啪18禁无遮挡激烈| 国产成人精品视频不卡| 色噜噜在线视频免费观看| av在线中文字幕不卡电影网| 国产乱码精品一区二区三| 大桥未久亚洲无av码在线| 精品久久久久久中文字幕202| 国产永久免费高清在线观看| 亚洲国产精品综合久久2007| 少妇被日自拍黄色三级网络| 国精品无码人妻一区二区三区| 国产精品成人一区二区三区| 日夜啪啪一区二区三区| 各种少妇wbb撒尿| 国产一区二区在线观看粉嫩| 青青热在线精品视频免费观看| 亚洲精品综合网二三区| 日本高清不卡一区二区三| 日韩人妻熟女中文字幕a美景之屋| 亚洲伊人久久综合成人| 国产区成人精品视频| 亚洲中文字幕av不卡无码| 一本一本久久a久久精品综合| 91人妻熟妇在线视频| 国产不卡av一区二区| 亚洲中文字幕无码av永久| 视频一区二区不中文字幕|