视频转gif需求全流程分析✨

1. 背景

基本需求是这样的,在一个固定宽高的视频播放器中截取一块区域,选择视频的开始和结束位置,设置帧率、速度、预览等信息转成GIF。

2.分析

首先我们先确定是前端转gif还是后端转,然后具体问题具体分析,我们采用的是后端转gif,需要传给后端视频源、截取的开始,结束时间、缩放后的x,y值、截取框的宽高、帧率、速度等信息。

分析难点!

  1. 传参最复杂的就是计算比例,视频源可能是1080也可能720等等视频原始尺寸,放到视频播放器中会按照长或宽等比缩放。宽高比不同的话,如果是竖屏视频会有左右黑边,横屏会有上下黑边。所以要算出蒙版层mask的缩放比例,才能拿到真实的x,y值
  2. 视频截取框需要能拖拽,截选区域为透明色,四周为黑灰色,可截选区域为去除左右黑边或者上下黑边后的真实播放区域

设计效果比如这是左右黑边,还有横屏的上线黑边 image.png

3.实现

难点一,通过分析宽高比,播放器宽度/视频宽度 = 缩放比,用这个缩放比乘原视频高度,如果小于播放器高度则是上下留有黑边,反之则是左右有黑边,等比的话就是刚好与播放器比例一致。算出的缩放比例ratio,再把这个比例用于蒙版层mask。

3.1难点一 核心代码

<my-video-player>...播放器代码省略</my-video-player>
<div class="mask">
  ...拖拽代码
</div>
// 860 490是播放器宽高
let l = document.getElementsByClassName('mask')[0] // 蒙版层,放在视频播放器上
let ratio = 860 / this.originalWidth  // originalWidth 原视频宽度  originalHeight 原视频高度
l.style.transformOrigin = '0 0'
if (ratio * this.originalHeight < 490) { // 上下黑边
    this.radio = 860 / this.originalWidth
} else if (ratio * this.originalHeight > 490) { // 上下左右
    this.radio = 490 / this.originalHeight
} else { // 等比
    this.radio = 490 / this.originalHeight
}
l.style.transform = `scale(${this.radio})` // 缩放比

3.1难点二 核心代码

这里用了vue-draggable-resizable包来实现可拖拽框,在难点一中我们拿到了radio,接下来计算拖拽框的可移动区域,以及初始值

let initXY = this.calculateCanvasImageParam(this.originalWidth, this.originalHeight)
calculateCanvasImageParam(videoWidth, videoHeight) {
  let height = 490
  let width = 860
  if (videoWidth === 0 || videoHeight === 0) {
    return {
      x: 0,
      y: 0,
      width: width,
      height: height
    }
  }
  // 计算比例
  if (videoHeight / videoWidth > (height / width)) {
    const realW = height * videoWidth / videoHeight
    return {
      x: (width - realW) / 2,
      y: 0,
      width: realW,
      height: height
    }
  } else {
    const realH = width * videoHeight / videoWidth
    return {
      x: 0,
      y: (height - realH) / 2,
      width: width,
      height: realH
    }
  }
}

这样initXY这个对象里的,x、y就是传入vue-draggable-resizable组件的初始x、y值

<div class="mask">
  <vue-draggable-resizable
      :w="width"
      :h="height"
      :x="x"
      :y="y"
      @dragging="onDrag"
      @resizing="onResize"
      :parent="true"
      class="innerCheck"
      :scale='radio'>
  </vue-draggable-resizable>
</div>

接下来就是截图效果的实现,这里我们用了css属性mix-blend-mode,他是用来控制元素的混合模式,可以混合叠加产生不一样的效果,我们先来看看兼容性 image.png 还不错,没多少用户还在用IE吧,贴代码:

.mask {
  position: absolute;
  opacity: .9;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.5);
  mix-blend-mode: hard-light;
  pointer-events: auto;

  .innerCheck {
    border: 3px solid #FC4F08;
    //top: 50px;
    //left: 50px;
    background-color: gray;

    .dingwei {
      ...
    }

    .dingwei2 {
      ...
    }

    .dingwei3 {
      ...
    }

    .dingwei4 {
      ...
    }
  }
}

之前项目离职不在上家公司环境打不开了,实现的效果类似这样:

image.png 四周黑灰色,中间透明可拖拽

鄙人文笔有限,写的代码也许还不够优雅,见谅啦

全部评论

相关推荐

工作基本定了,比较满意。这深度学习真是难搞啊,论文看不懂,代码看不懂,不会改,创新点???&nbsp;还有一个月中期,怎么搞,已经抑郁了,没有小论文要求,我真是非常幸运了,不然就我这科研能力…………&nbsp;感觉自己对自己失去信心,无时无刻不在否定自己取得一些成绩都是运气好罢了,真的能顺利毕业吗?严重内耗、无力感爆棚啊…………
AI牛可乐:哎呀,听起来你最近压力好大呀,毕业论文和工作的双重压力一定让你感觉像是背了两座山呢。深度学习确实挺复杂的,就像是要在一片迷雾中找到出路一样。但是,你已经很棒了,工作都定好了,这是很大的成就呢! 论文的事情,别太担心。每个人都有看不懂代码和论文的时候,这是正常的。至于创新点嘛,有时候灵感就像小猫一样,需要一点一点地哄出来的。你可以先试试把你看过的资料整理一下,说不定就能找到新的思路呢。 中期答辩前,你可以列个计划,一步一步来,把大问题分解成小问题,一点一点克服。记得,你不是一个人在战斗,你的导师、同学都是你的战友哦。 至于信心嘛,别否定自己,每个人都会有低谷的时候。你已经取得的成绩,都是你实力的体现。毕业不是问题,只要你不放弃,就一定能顺利走过去的。加油哦,我相信你可以的! 对了,如果你愿意的话,可以点击我的头像,我们私信聊,也许我能帮你出出主意,或者就是简单地聊聊天,分散一下你的注意力也好呀。🐮💪🌟
点赞 评论 收藏
分享
牛客154160166号:9月底还给我发短信,好奇怪,我24届的
点赞 评论 收藏
分享
拒绝无效加班的小师弟很中意你:求职意向没有,年龄、课程冗余信息可以删掉,需要提升项目经历。排版需要修改。
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务