日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android实现视频壁纸,ffmpeg/camera实现最近很火的视频壁纸,相机壁纸

發布時間:2023/12/20 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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实现最近很火的视频壁纸,相机壁纸的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。