您好,登錄后才能下訂單哦!
PhotoMovie (https://github.com/yellowcath/PhotoMovie) 可輕松實(shí)現(xiàn)類似抖音、微視、美拍的照片電影功能。
效果如下
濾鏡效果
轉(zhuǎn)場(chǎng)效果
使用
首先在項(xiàng)目根目錄的build.gradle文件里添加maven庫(kù)
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,photoPath2,PhotoData.STATE_LOCAL)); ... photoDataList.add(new SimplePhotoData(context,photoPathN,PhotoData.STATE_LOCAL)); //生成圖片源 PhotoSource photoSource = new PhotoSource(photoDataList); //生成照片電影(使用預(yù)定義的水平轉(zhuǎn)場(chǎng)動(dòng)畫) PhotoMovie photoMovie = PhotoMovieFactory.generatePhotoMovie(photoSource, PhotoMovieFactory.PhotoMovieType.HORIZONTAL_TRANS); //生成負(fù)責(zé)繪制電影內(nèi)容的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();
輕松擴(kuò)展
PhotoMovie使用模塊化的設(shè)計(jì),每個(gè)部分都可以自定義然后替換,
擴(kuò)展電影類型
目前內(nèi)置了6種類型,后兩種即是抖音的左右切換和上下切換,Thaw和WINDOW仿自美拍
public enum PhotoMovieType { THAW, //融雪 SCALE, //縮放 SCALE_TRANS, //縮放 & 平移 WINDOW, //窗扉 HORIZONTAL_TRANS,//橫向平移 VERTICAL_TRANS//縱向平移 }
這里以微視的漸變特效為例展示如何擴(kuò)展
分析得出,漸變特效首先圖片居中放置,然后全程做一個(gè)微弱的放大動(dòng)畫,后半部分同時(shí)透明度變化消失
可見需要兩個(gè)不同的片段類型
首先創(chuàng)建FitCenterScaleSegment,繼承FitCenterSegment,實(shí)現(xiàn)單張圖片的放大動(dòng)畫
public class FitCenterScaleSegment extends FitCenterSegment { /** * 縮放動(dòng)畫范圍 */ private float mScaleFrom; private float mScaleTo; private float mProgress; /** * @param duration 片段時(shí)長(zhǎng) * @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已經(jīng)具有縮放能力,這里傳縮放值即可 drawContent(canvas, scale); } //提升這兩個(gè)函數(shù)的訪問(wèn)權(quán)限,供轉(zhuǎn)場(chǎng)時(shí)使用 @Override public void drawContent(GLESCanvas canvas, float scale) { super.drawContent(canvas, scale); } @Override public void drawBackground(GLESCanvas canvas) { super.drawBackground(canvas); } }
然后創(chuàng)建轉(zhuǎn)場(chǎng)片段GradientTransferSegment,其父類TransitionSegment同時(shí)持有上一個(gè)與下一個(gè)片段,可以在其基礎(chǔ)上實(shí)現(xiàn)任意轉(zhuǎn)場(chǎng)功能
public class GradientTransferSegment extends TransitionSegment<FitCenterScaleSegment, FitCenterScaleSegment> { /** * 縮放動(dòng)畫范圍 */ 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) { //下一個(gè)片段開始放大 float nextScale = mNextScaleFrom + (mNextScaleTo - mNextScaleFrom) * segmentProgress; mNextSegment.drawContent(canvas, nextScale); //上一個(gè)片段繼續(xù)放大同時(shí)變透明 float preScale = mPreScaleFrom + (mPreScaleTo - mPreScaleFrom) * segmentProgress; float alpha = 1 - segmentProgress; mPreSegment.drawBackground(canvas); canvas.save(); canvas.setAlpha(alpha); mPreSegment.drawContent(canvas, preScale); canvas.restore(); }
創(chuàng)建照片電影
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); }
然后將這個(gè)PhotoMovie正常播放即可,效果如下
擴(kuò)展濾鏡
目前內(nèi)置了9個(gè)濾鏡
public enum FilterType { NONE, CAMEO,//浮雕 GRAY,//黑白 KUWAHARA,//水彩 SNOW,//飄雪(動(dòng)態(tài)) LUT1, LUT2, LUT3, LUT4, LUT5, }
先看IMovieFilter
public interface IMovieFilter { void doFilter(PhotoMovie photoMovie,int elapsedTime, FboTexture inputTexture, FboTexture outputTexture); void release(); }
外部會(huì)提供一個(gè)輸入紋理,然后由IMovieFilter處理之后繪制到輸出紋理上,即實(shí)現(xiàn)了濾鏡效果
BaseMovieFilter已經(jīng)實(shí)現(xiàn)了基本的輸入輸出流程,例如要做最基本的黑白濾鏡,只需更換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); } }
同時(shí)PhotoMovie提供了對(duì)Lut濾鏡的支持
Lut其實(shí)就是Lookup Table(顏色查找表),根據(jù)原圖的RGB值去相應(yīng)的lut圖里面查找對(duì)應(yīng)轉(zhuǎn)換后的RGB值,從而實(shí)現(xiàn)各種濾鏡效果
lut(原圖)
lut_2.jpg
原圖
濾鏡效果圖
public class LutMovieFilter extends TwoTextureMovieFilter { public LutMovieFilter(Bitmap lutBitmap){ super(loadShaderFromAssets("shader/two_vertex.glsl"),loadShaderFromAssets("shader/lut.glsl")); setBitmap(lutBitmap); } }
在LutMovieFilter的構(gòu)造函數(shù)傳入上面表格里的lut圖,即可實(shí)現(xiàn)相應(yīng)的濾鏡效果,前面提到的黑白濾鏡也可用這個(gè)方式實(shí)現(xiàn)
錄制功能
GLMovieRecorder 提供了將照片電影錄制為mp4的功能
可參照 DemoPresenter 的saveVideo()函數(shù)
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) { ...... } });
背景音樂(lè)
mPhotoMoviePlayer.setMusic(context, mMusicUri);
PhotoMovie只提供了播放背景音樂(lè)的功能,錄制完成之后需自行合成,Demo里使用了
VideoProcessor 進(jìn)行合成
VideoProcessor.mixAudioTrack(context, videPath, audioPath,outputPath, null, null, 0,100, 1f, 1f);
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。