android实现视频壁纸,ffmpeg/camera实现最近很火的视频壁纸,相机壁纸
比較重要的部分首先是權限android:permission=”android.permission.BIND_WALLPAPER”;
其次service需要響應action:android:name=”android.service.wallpaper.WallpaperService;
接下來接收配置文件。首先在res文件夾下建立一個xml目錄,和寫appwidget一樣。在目錄下我們創建一個xml文件:
android:settingsActivity="LiveWallPreference"
android:thumbnail="@drawable/ic_launcher"
android:description="@string/wallpaper_description"
/>
然后啟動選擇壁紙的代碼是這樣的:final?Intent?pickWallpaper?=?new?Intent(Intent.ACTION_SET_WALLPAPER);Intent?chooser?=?Intent.createChooser(pickWallpaper,?getString(R.string.choose_wallpaper));startActivity(chooser);
2.相機壁紙:
下面是相機壁紙實現的源碼
最精華的一句: ?camera.setPreviewDisplay(getSurfaceHolder());
直接把相機預覽數據傳給WallpaperService。package?com.ws.ffmpegandroidwallpaper;import?android.hardware.Camera;import?android.service.wallpaper.WallpaperService;import?android.view.MotionEvent;import?android.view.SurfaceHolder;import?java.io.IOException;public?class?CameraLiveWallpaper?extends?WallpaperService?{public?Engine?onCreateEngine()?{return?new?CameraEngine();
}
class?CameraEngine?extends?Engine??{private?Camera?camera;@Overridepublic?void?onCreate(SurfaceHolder?surfaceHolder)?{super.onCreate(surfaceHolder);
startPreview();//?設置處理觸摸事件??setTouchEventsEnabled(true);
}@Overridepublic?void?onTouchEvent(MotionEvent?event)?{super.onTouchEvent(event);
}@Overridepublic?void?onDestroy()?{super.onDestroy();
stopPreview();
}@Overridepublic?void?onVisibilityChanged(boolean?visible)?{if?(visible)?{
startPreview();
}?else?{
stopPreview();
}
}/**
*?開始預覽
*/public?void?startPreview()?{
camera?=?Camera.open();
camera.setDisplayOrientation(90);try?{
camera.setPreviewDisplay(getSurfaceHolder());
}?catch?(IOException?e)?{
e.printStackTrace();
}
camera.startPreview();
}/**
*?停止預覽
*/public?void?stopPreview()?{if?(camera?!=?null)?{try?{
camera.stopPreview();
camera.setPreviewCallback(null);//?camera.lock();camera.release();
}?catch?(Exception?e)?{
e.printStackTrace();
}
camera?=?null;
}
}
}
}
視頻壁紙
實現視頻壁紙的時候本來打算用mediaplayer實現,后來發現mediaplayer實現在某些機型上報JNI層錯誤。
于是改用ffmpeg自己實現JNI層,當然這樣做的好處是可以更多的定制化,比如示例上的快速播放視頻。
主要就一個函數
即把WallpaperService 的Surface傳給native的play方法。package?com.ws.ffmpegandroidwallpaper;import?android.os.Handler;import?android.service.wallpaper.WallpaperService;import?android.view.MotionEvent;import?android.view.SurfaceHolder;public?class?VideoLiveWallpaper?extends?WallpaperService?{//?實現WallpaperService必須實現的抽象方法??public?Engine?onCreateEngine()?{return?new?VideoEngine();
}
class?VideoEngine?extends?Engine?{@Overridepublic?void?onCreate(SurfaceHolder?surfaceHolder)?{super.onCreate(surfaceHolder);
play(getSurfaceHolder().getSurface());//?設置處理觸摸事件??setTouchEventsEnabled(true);
}static?{
System.loadLibrary("native-lib");
}public?native?int?play(Object?surface);
}
然后JNI的play方法具體實現。
關鍵地方都有注釋,可以結合我之前分享的ffmpeg源碼看
ffmpeg源碼簡析(一)結構總覽 :http://blog.csdn.net/king1425/article/details/70597642JNIEXPORT?jint?JNICALL
Java_com_ws_ffmpegandroidwallpaper_VideoLiveWallpaper_play
(JNIEnv?*env,?jclass?clazz,?jobject?surface)?{
LOGD("play");//?sd卡中的視頻文件地址,可自行修改或者通過jni傳入//char?*file_name?=?"/storage/emulated/0/ws.mp4";char?*file_name?=?"/storage/emulated/0/video.avi";
av_register_all();
AVFormatContext?*pFormatCtx?=?avformat_alloc_context();//?Open?video?fileif?(avformat_open_input(&pFormatCtx,?file_name,?NULL,?NULL)?!=?0)?{
LOGD("Couldn't?open?file:%s
",?file_name);return?-1;?//?Couldn't?open?file}//?Retrieve?stream?informationif?(avformat_find_stream_info(pFormatCtx,?NULL)?
LOGD("Couldn't?find?stream?information.");return?-1;
}//?Find?the?first?video?streamint?videoStream?=?-1,?i;for?(i?=?0;?i?nb_streams;?i++)?{if?(pFormatCtx->streams[i]->codec->codec_type?==?AVMEDIA_TYPE_VIDEO
&&?videoStream?
videoStream?=?i;
}
}if?(videoStream?==?-1)?{
LOGD("Didn't?find?a?video?stream.");return?-1;?//?Didn't?find?a?video?stream}//?Get?a?pointer?to?the?codec?context?for?the?video?streamAVCodecContext?*pCodecCtx?=?pFormatCtx->streams[videoStream]->codec;//?Find?the?decoder?for?the?video?streamAVCodec?*pCodec?=?avcodec_find_decoder(pCodecCtx->codec_id);if?(pCodec?==?NULL)?{
LOGD("Codec?not?found.");return?-1;?//?Codec?not?found}if?(avcodec_open2(pCodecCtx,?pCodec,?NULL)?
LOGD("Could?not?open?codec.");return?-1;?//?Could?not?open?codec}//?獲取native?windowANativeWindow?*nativeWindow?=?ANativeWindow_fromSurface(env,?surface);//?獲取視頻寬高int?videoWidth?=?pCodecCtx->width;int?videoHeight?=?pCodecCtx->height;//?設置native?window的buffer大小,可自動拉伸ANativeWindow_setBuffersGeometry(nativeWindow,?videoWidth,?videoHeight,
WINDOW_FORMAT_RGBA_8888);
ANativeWindow_Buffer?windowBuffer;if?(avcodec_open2(pCodecCtx,?pCodec,?NULL)?
LOGD("Could?not?open?codec.");return?-1;?//?Could?not?open?codec}//?Allocate?video?frameAVFrame?*pFrame?=?av_frame_alloc();//?用于渲染AVFrame?*pFrameRGBA?=?av_frame_alloc();if?(pFrameRGBA?==?NULL?||?pFrame?==?NULL)?{
LOGD("Could?not?allocate?video?frame.");return?-1;
}//?Determine?required?buffer?size?and?allocate?buffer//?buffer中數據就是用于渲染的,且格式為RGBAint?numBytes?=?av_image_get_buffer_size(AV_PIX_FMT_RGBA,?pCodecCtx->width,?pCodecCtx->height,1);
uint8_t?*buffer?=?(uint8_t?*)?av_malloc(numBytes?*?sizeof(uint8_t));
av_image_fill_arrays(pFrameRGBA->data,?pFrameRGBA->linesize,?buffer,?AV_PIX_FMT_RGBA,
pCodecCtx->width,?pCodecCtx->height,?1);//?由于解碼出來的幀格式不是RGBA的,在渲染之前需要進行格式轉換struct?SwsContext?*sws_ctx?=?sws_getContext(pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
AV_PIX_FMT_RGBA,
SWS_BILINEAR,NULL,NULL,NULL);int?frameFinished;
AVPacket?packet;while?(av_read_frame(pFormatCtx,?&packet)?>=?0)?{//?Is?this?a?packet?from?the?video?stream?if?(packet.stream_index?==?videoStream)?{//?Decode?video?frameavcodec_decode_video2(pCodecCtx,?pFrame,?&frameFinished,?&packet);//?并不是decode一次就可解碼出一幀if?(frameFinished)?{//?lock?native?window?bufferANativeWindow_lock(nativeWindow,?&windowBuffer,?0);//?格式轉換sws_scale(sws_ctx,?(uint8_t?const?*const?*)?pFrame->data,
pFrame->linesize,?0,?pCodecCtx->height,
pFrameRGBA->data,?pFrameRGBA->linesize);//?獲取strideuint8_t?*dst?=?(uint8_t?*)?windowBuffer.bits;int?dstStride?=?windowBuffer.stride?*?4;
uint8_t?*src?=?(pFrameRGBA->data[0]);int?srcStride?=?pFrameRGBA->linesize[0];//?由于window的stride和幀的stride不同,因此需要逐行復制int?h;for?(h?=?0;?h?
memcpy(dst?+?h?*?dstStride,?src?+?h?*?srcStride,?srcStride);
}
ANativeWindow_unlockAndPost(nativeWindow);
}
}
av_packet_unref(&packet);
}
av_free(buffer);
av_free(pFrameRGBA);//?Free?the?YUV?frameav_free(pFrame);//?Close?the?codecsavcodec_close(pCodecCtx);//?Close?the?video?fileavformat_close_input(&pFormatCtx);return?0;
}
}
demo :https://github.com/WangShuo1143368701/FFmpegAndroid/tree/master/ffmpegandroidwallpaper
總結
以上是生活随笔為你收集整理的android实现视频壁纸,ffmpeg/camera实现最近很火的视频壁纸,相机壁纸的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消防给水及消火栓系统技术规范_消防给水及
- 下一篇: 蓝牙模块测试