首页 > 系统 > Android > 正文

Android高仿抖音照片电影功能的实现代码

2019-10-21 21:38:46
字体:
来源:转载
供稿:网友

PhotoMovie (https://github.com/yellowcath/PhotoMovie) 可轻松实现类似抖音、微视、美拍的照片电影功能。

效果如下

滤镜效果

Android,仿抖音,照片电影,代码

转场效果

Android,仿抖音,照片电影,代码

使用

首先在项目根目录的build.gradle文件里添加maven库

allprojects {    repositories {      ...      maven { url 'https://www.jitpack.io' }    }  }

再在需要用的Module的build.gradle里添加依赖

dependencies {  compile 'com.github.yellowcath:PhotoMovie:1.5.0'}

基本用法

可参照 DemoPresenter

//添加图片    List<PhotoData> photoDataList = new LinkedList<PhotoData>();    photoDataList.add(new SimplePhotoData(context,photoPath1,PhotoData.STATE_LOCAL));    ...    photoDataList.add(new SimplePhotoData(context,photoPathN,PhotoData.STATE_LOCAL));    //生成图片源    PhotoSource photoSource = new PhotoSource(photoDataList);    //生成照片电影(使用预定义的水平转场动画)    PhotoMovie photoMovie = PhotoMovieFactory.generatePhotoMovie(photoSource, PhotoMovieFactory.PhotoMovieType.HORIZONTAL_TRANS);    //生成负责绘制电影内容的MovieRenderer    MovieRenderer movieRenderer = new GLTextureMovieRender(glTextureView);    /**     * OR MovieRenderer movieRenderer = new GLSurfaceMovieRenderer(glSurfaceView);     */    //照片电影播放器    PhotoMoviePlayer photoMoviePlayer = new PhotoMoviePlayer(context);    photoMoviePlayer.setMovieRenderer(mMovieRenderer);    photoMoviePlayer.setMovieListener(...);    photoMoviePlayer.setLoop(true);    photoMoviePlayer.setOnPreparedListener(new PhotoMoviePlayer.OnPreparedListener() {      @Override      public void onPreparing(PhotoMoviePlayer moviePlayer, float progress) {      }      @Override      public void onPrepared(PhotoMoviePlayer moviePlayer, int prepared, int total) {         mPhotoMoviePlayer.start();      }      @Override      public void onError(PhotoMoviePlayer moviePlayer) {      }    });    photoMoviePlayer.prepare();

轻松扩展

PhotoMovie使用模块化的设计,每个部分都可以自定义然后替换,

  • MovieSegment:电影片段,每个电影片段都有特定的时长,在这段时间之内以特定的方式播放图片,例如ScaleSegment会对图片做缩放动画、EndGaussianBlurSegment会对图片做从清晰到模糊的高斯模糊动画
  • PhotoMovie:核心类,代表照片电影本身,由图片源(PhotoSource)和若干电影片段(MovieSegment)组成一个完整的照片电影,图片通过PhotoAllocator分配给MovieSegment
  • MovieLayer:为MovieSegment扩展绘制多层特效的功能,例如SubtitleLayer提供字幕展示
  • IMovieFilter:为整个照片电影提供滤镜
  • MovieRenderer:负责把照片电影渲染到指定的输出界面,例如TextureView(GLTextureMovieRender)、GLSurfaceView(GLSurfaceMovieRenderer)
  • PhotoMoviePlayer:提供类似MediaPlayer的接口,负责播放照片电影,播放进度由IMovieTimer控制

扩展电影类型

目前内置了6种类型,后两种即是抖音的左右切换和上下切换,Thaw和WINDOW仿自美拍

public enum PhotoMovieType {    THAW, //融雪    SCALE, //缩放    SCALE_TRANS, //缩放 & 平移    WINDOW, //窗扉    HORIZONTAL_TRANS,//横向平移    VERTICAL_TRANS//纵向平移  }

这里以微视的渐变特效为例展示如何扩展

分析得出,渐变特效首先图片居中放置,然后全程做一个微弱的放大动画,后半部分同时透明度变化消失

可见需要两个不同的片段类型

首先创建FitCenterScaleSegment,继承FitCenterSegment,实现单张图片的放大动画

public class FitCenterScaleSegment extends FitCenterSegment {  /**   * 缩放动画范围   */  private float mScaleFrom;  private float mScaleTo;  private float mProgress;  /**   * @param duration 片段时长   * @param scaleFrom 缩放范围   * @param scaleTo  缩放范围   */  public FitCenterScaleSegment(int duration, float scaleFrom, float scaleTo) {    super(duration);    mScaleFrom = scaleFrom;    mScaleTo = scaleTo;  }  @Override  protected void onDataPrepared() {    super.onDataPrepared();  }  @Override  public void drawFrame(GLESCanvas canvas, float segmentProgress) {    mProgress = segmentProgress;    if (!mDataPrepared) {      return;    }    drawBackground(canvas);    float scale = mScaleFrom + (mScaleTo - mScaleFrom) * mProgress;    //FitCenterSegment已经具有缩放能力,这里传缩放值即可    drawContent(canvas, scale);  }  //提升这两个函数的访问权限,供转场时使用    @Override  public void drawContent(GLESCanvas canvas, float scale) {    super.drawContent(canvas, scale);  }  @Override  public void drawBackground(GLESCanvas canvas) {    super.drawBackground(canvas);  }}

然后创建转场片段GradientTransferSegment,其父类TransitionSegment同时持有上一个与下一个片段,可以在其基础上实现任意转场功能

public class GradientTransferSegment extends TransitionSegment<FitCenterScaleSegment, FitCenterScaleSegment> {  /**   * 缩放动画范围   */  private float mPreScaleFrom;  private float mPreScaleTo;  private float mNextScaleFrom;  private float mNextScaleTo;  public GradientTransferSegment(int duration,                  float preScaleFrom, float preScaleTo,                  float nextScaleFrom, float nextScaleTo) {    mPreScaleFrom = preScaleFrom;    mPreScaleTo = preScaleTo;    mNextScaleFrom = nextScaleFrom;    mNextScaleTo = nextScaleTo;    setDuration(duration);  }  @Override  protected void onDataPrepared() {  }  @Override  public void drawFrame(GLESCanvas canvas, float segmentProgress) {    //下一个片段开始放大    float nextScale = mNextScaleFrom + (mNextScaleTo - mNextScaleFrom) * segmentProgress;    mNextSegment.drawContent(canvas, nextScale);    //上一个片段继续放大同时变透明    float preScale = mPreScaleFrom + (mPreScaleTo - mPreScaleFrom) * segmentProgress;    float alpha = 1 - segmentProgress;    mPreSegment.drawBackground(canvas);    canvas.save();    canvas.setAlpha(alpha);    mPreSegment.drawContent(canvas, preScale);    canvas.restore();  }

创建照片电影

private static PhotoMovie initGradientPhotoMovie(PhotoSource photoSource) {    List<MovieSegment> segmentList = new ArrayList<>(photoSource.size());    for (int i = 0; i < photoSource.size(); i++) {      if (i == 0) {        segmentList.add(new FitCenterScaleSegment(1600, 1f, 1.1f));      } else {        segmentList.add(new FitCenterScaleSegment(1600, 1.05f, 1.1f));      }      if (i < photoSource.size() - 1) {        segmentList.add(new GradientTransferSegment(800, 1.1f, 1.15f, 1.0f, 1.05f));      }    }    return new PhotoMovie(photoSource, segmentList);  }

然后将这个PhotoMovie正常播放即可,效果如下

Android,仿抖音,照片电影,代码

扩展滤镜

目前内置了9个滤镜

public enum FilterType {  NONE,  CAMEO,//浮雕  GRAY,//黑白  KUWAHARA,//水彩  SNOW,//飘雪(动态)  LUT1,  LUT2,  LUT3,  LUT4,  LUT5,}

先看IMovieFilter

public interface IMovieFilter {  void doFilter(PhotoMovie photoMovie,int elapsedTime, FboTexture inputTexture, FboTexture outputTexture);  void release();}

外部会提供一个输入纹理,然后由IMovieFilter处理之后绘制到输出纹理上,即实现了滤镜效果

BaseMovieFilter已经实现了基本的输入输出流程,例如要做最基本的黑白滤镜,只需更换FRAGMENT_SHADER即可

public class GrayMovieFilter extends BaseMovieFilter {  protected static final String FRAGMENT_SHADER = "" +      "varying highp vec2 textureCoordinate;/n" +      " /n" +      "uniform sampler2D inputImageTexture;/n" +      " /n" +      "void main()/n" +      "{/n" +      "   mediump vec4 color = texture2D(inputImageTexture, textureCoordinate);/n" +      "   mediump float gray = color.r*0.3+color.g*0.59+color.b*0.11;/n"+      "   gl_FragColor = vec4(gray,gray,gray,1.0);/n"+      "}";  public GrayMovieFilter(){    super(VERTEX_SHADER,FRAGMENT_SHADER);  }}

同时PhotoMovie提供了对Lut滤镜的支持

Lut其实就是Lookup Table(颜色查找表),根据原图的RGB值去相应的lut图里面查找对应转换后的RGB值,从而实现各种滤镜效果

Android,仿抖音,照片电影,代码

lut(原图)

Android,仿抖音,照片电影,代码

lut_2.jpg

Android,仿抖音,照片电影,代码

原图

Android,仿抖音,照片电影,代码

滤镜效果图

public class LutMovieFilter extends TwoTextureMovieFilter {  public LutMovieFilter(Bitmap lutBitmap){    super(loadShaderFromAssets("shader/two_vertex.glsl"),loadShaderFromAssets("shader/lut.glsl"));    setBitmap(lutBitmap);  }}

在LutMovieFilter的构造函数传入上面表格里的lut图,即可实现相应的滤镜效果,前面提到的黑白滤镜也可用这个方式实现

录制功能

GLMovieRecorder 提供了将照片电影录制为mp4的功能

可参照 DemoPresenter 的saveVideo()函数

GLMovieRecorder recorder = new GLMovieRecorder();    recorder.configOutput(width, height(), bitrate,frameRate,iFrameInterval, outputPath);    recorder.setDataSource(movieRenderer);    recorder.startRecord(new GLMovieRecorder.OnRecordListener() {      @Override      public void onRecordFinish(boolean success) {        ......      }      @Override      public void onRecordProgress(int recordedDuration, int totalDuration) {        ......      }    });

背景音乐

 mPhotoMoviePlayer.setMusic(context, mMusicUri);

PhotoMovie只提供了播放背景音乐的功能,录制完成之后需自行合成,Demo里使用了

VideoProcessor 进行合成

 VideoProcessor.mixAudioTrack(context, videPath, audioPath,outputPath, null, null, 0,100, 1f, 1f);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表