functional::Video transcode()

in vireo/tools/transcode/main.cpp [429:533]


functional::Video<encode::Sample> transcode(const functional::Video<decode::Sample> track,
                                            const float fps,
                                            const vector<common::EditBox> &edit_boxes,
                                            const Config config,
                                            FirstPtsAndTimescale &first_pts_and_timescale,
                                            const bool print_info) {
  settings::Video video_settings = track.settings();
  THROW_IF(video_settings.codec != settings::Video::Codec::H264, Unsupported);

  const uint16_t in_width = video_settings.width;
  const uint16_t in_height = video_settings.height;
  const settings::Video::Orientation in_orientation = video_settings.orientation;
  auto resolution = out_resolution(in_width, in_height, in_orientation, config.height, config.square);
  const uint16_t out_width = resolution.width;
  const uint16_t out_height = resolution.height;

  if (print_info) {
    cout << "Video resolution " << out_width << "x" << out_height;
    if (out_width != in_width || out_height != in_height) {
      cout << ", resized from " << in_width << "x" << in_height;
    }
    cout << endl << "video framerate = " << fps << "fps";
    cout << endl << "Optimization = " << config.optimization;
    if (config.outfile_type == MP4 || config.outfile_type == MP2TS) {
      if (config.rc_method == vireo::encode::RCMethod::CRF) {
        cout << ", CRF = " << config.crf  << ", number of b-frames = " << config.bframes;
      } else {
        cout << ", bitrate = " << config.video_bitrate;
      }
    } else {
      cout << ", Quantizer = " << config.quantizer;
    }

    if (config.max_video_bitrate) {
      cout << ", max bitrate = " << config.max_video_bitrate;
    }
    cout << endl << "Threads = " << config.decoder_threads << " (decoder)";
    if (config.outfile_type == MP4 || config.outfile_type == MP2TS) {
      cout << ", " << config.encoder_threads;
    } else {
      cout << ", 1";
    }
    cout << " (encoder)" << endl;
    cout << "Video Profile = " << vireo::encode::kVideoProfileTypeToString[config.vprofile] << endl;
    cout << "Output type = " << kFileTypeToString[config.outfile_type];
    if (config.dash_init) {
      cout << ", dash_init" << endl;
    } else if (config.dash_data) {
      cout << ", dash_data" << endl;
    } else {
      cout << endl;
    }
  }

  auto crop_scale_rotate = [](frame::Frame frame, uint16_t in_width, uint16_t in_height, settings::Video::Orientation orientation, uint16_t out_width, uint16_t out_height) -> frame::Frame {
    return (frame::Frame){ frame.pts, [in_width, in_height, orientation, out_width, out_height, yuv_func = frame.yuv]() {
      // crop - if necessary
      const bool square = (out_width == out_height);
      const uint16_t min_dim = min(in_width, in_height);
      const uint16_t crop_x_offset = square ? (in_width - min_dim) / 2 : 0;
      const uint16_t crop_y_offset = square ? (in_height - min_dim) / 2 : 0;
      auto yuv_cropped_func = (crop_x_offset == 0 && crop_y_offset == 0) ? yuv_func : [crop_x_offset, crop_y_offset, min_dim, &yuv_func](){
        return yuv_func().crop(crop_x_offset, crop_y_offset, min_dim, min_dim);
      };
      const uint16_t cropped_width = in_width - 2 * crop_x_offset;
      const uint16_t cropped_height = in_height - 2 * crop_y_offset;
      // scale - if necessary
      const bool is_portrait = orientation % 2;
      const uint16_t real_height = is_portrait ? cropped_width : cropped_height;
      auto yuv_scaled_func = (real_height == out_height) ? yuv_cropped_func : [real_height, out_height, &yuv_cropped_func](){
        return yuv_cropped_func().scale(out_height, real_height);
      };
      // rotate - if necessary
      auto yuv_rotated_func = (orientation == settings::Video::Landscape) ? yuv_scaled_func : [orientation, &yuv_scaled_func](){
        return yuv_scaled_func().rotate((frame::Rotation)orientation);
      };
      return yuv_rotated_func();
    }};
  };

  auto decoder = decode::Video(track, config.decoder_threads).filter(
    [&edit_boxes, timescale = video_settings.timescale, start = config.start, duration = config.duration, &first_pts_and_timescale](const frame::Frame& frame) {
      return include_pts(frame.pts, timescale, edit_boxes, start, duration, first_pts_and_timescale);
    }
  ).transform<frame::Frame>(
    [&edit_boxes, timescale = video_settings.timescale, &first_pts_and_timescale, &crop_scale_rotate, in_width, in_height, in_orientation, out_width, out_height](const frame::Frame& frame) {
      int64_t first_pts = first_pts_and_timescale.first_pts;
      CHECK(first_pts >= 0);
      int64_t scaled_first_pts = first_pts * timescale / first_pts_and_timescale.timescale;
      return crop_scale_rotate(frame.adjust_pts(edit_boxes).shift_pts(-scaled_first_pts), in_width, in_height, in_orientation, out_width, out_height);
    }
  );

  auto output_video_settings = settings::Settings<SampleType::Video>(decoder.settings().codec, out_width, out_height, video_settings.timescale, settings::Video::Landscape, decoder.settings().sps_pps);

  if (config.outfile_type == MP4 || config.outfile_type == MP2TS) {
    auto computation = encode::H264Params::ComputationalParams(config.optimization, config.encoder_threads);
    auto rc = encode::H264Params::RateControlParams(config.rc_method, config.crf, config.max_video_bitrate, config.video_bitrate, config.buffer_size, config.buffer_init, config.rc_look_ahead, config.is_second_pass, config.rc_b_mb_tree, config.aq_mode, config.qp_min, config.stats_log_path, config.mixed_refs, config.trellis, config.me_method, config.subpel_refine);
    auto gop = encode::H264Params::GopParams(config.bframes, config.pyramid_mode, config.keyint_max, config.keyint_min, config.frame_references);
    encode::H264Params params(computation, rc, gop, config.vprofile, fps);
    return encode::H264(functional::Video<frame::Frame>(decoder, output_video_settings), params);
  } else {
    return encode::VP8(functional::Video<frame::Frame>(decoder, output_video_settings), config.quantizer, config.optimization, fps, config.max_video_bitrate);
  }
};