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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

android 学习随笔二十(多媒体编程 )

發布時間:2025/3/21 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 学习随笔二十(多媒体编程 ) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、圖片處理

  • 加載大圖片
    • 圖片大小的計算

圖片大小 = 圖片的總像素 * 每個像素占用的大小

* 單色圖:每個像素占用1/8個字節
* 16色圖:每個像素占用1/2個字節
* 256色圖:每個像素占用1個字節
* 24位圖:每個像素占用3個字節

?

* 圖片總大小 = 圖片總像素 * 每個像素的大小
* 單色:只能表示兩種顏色,只需要使用兩個數字即可,0和1表示黑白
* 每個像素需要使用一個長度為1的二進制數字表示顏色
* 每個像素占用1/8個字節
* 16色:能表示16種顏色,需要16個數字
* 0 - 15,二進制表示:0000 - 1111
* 每個像素需要一個長度為4的二進制數字表示顏色信息
* 每個像素占用1/2個字節
* 256色:能表示256種顏色,需要256個數字
* 0 - 255,二進制表示:0000 0000 - 1111 1111
* 每個像素需要長度為8的二進制數字
* 每個像素占用1個字節
* 24位色:能表示一千六百七十七萬多種顏色
* 每個像素占用3個字節
* R:0-255,占用1個字節
* G:同上
* B:同上

Android系統以ARGB表示每個像素,所以每個像素占用4個字節,很容易內存溢出。

  • 對圖片進行縮放

* 獲取屏幕寬高

Display dp = getWindowManager().getDefaultDisplay();
int screenWidth = dp.getWidth();
int screenHeight = dp.getHeight();
* 獲取圖片寬高

Options opts = new Options();
//請求圖片屬性但不申請內存
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
int imageWidth = opts.outWidth;
int imageHeight = opts.outHeight;
* 圖片的寬高除以屏幕寬高,算出寬和高的縮放比例,取較大值作為圖片的縮放比例

int scale = 1;
int scaleX = imageWidth / screenWidth;
int scaleY = imageHeight / screenHeight;
if(scaleX >= scaleY && scaleX > 1){
scale = scaleX;
}
else if(scaleY > scaleX && scaleY > 1){
scale = scaleY;
}
* 按縮放比例加載圖片

//設置縮放比例
opts.inSampleSize = scale;
//為圖片申請內存
opts.inJustDecodeBounds = false;
Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts);
iv.setImageBitmap(bm);//如果不壓縮,在加載圖片時(所有圖片格式),會分析像素,每個像素會占用4個字節(ARGB),A代表透明度。1.73M的JPG文件,加載時會占用20多M的內存解析。

  • 在內存中創建圖片的副本

直接加載的bitmap對象是只讀的,無法修改,要修改圖片只能在內存中創建出一個一模一樣的bitmap副本,然后修改副本

//加載原圖

Bitmap srcBm = BitmapFactory.decodeResource(getResource(),R.drawable.photo3);
//Bitmap srcBm = BitmapFactory.decodeFile("sdcard/photo3.jpg");
iv_src.setImageBitmap(srcBm);

//創建與原圖大小一致的空白bitmap
Bitmap copyBm = Bitmap.createBitmap(srcBm.getWidth(), srcBm.getHeight(), srcBm.getConfig());
//定義畫筆
Paint paint = new Paint();
//把紙鋪在畫版上
Canvas canvas = new Canvas(copyBm);
//把srcBm的內容繪制在copyBm上
canvas.drawBitmap(srcBm, new Matrix(), paint);

iv_copy.setImageBitmap(copyBm);

  • 對圖片進行特效處理

* 首先定義一個矩陣對象

Matrix mt = new Matrix();
* 縮放效果

//x軸縮放1倍,y軸縮放0.5倍
mt.setScale(1, 0.5f);

* 旋轉效果

//以copyBm.getWidth() / 2, copyBm.getHeight() / 2點為軸點,順時旋轉30度
mt.setRotate(30, copyBm.getWidth() / 2, copyBm.getHeight() / 2);
* 平移

//x軸坐標+10,y軸坐標+20
mt.setTranslate(10, 20);
* 鏡面

//把X坐標都變成負數
mt.setScale(-1, 1);
//圖片整體向右移
mt.postTranslate(copyBm.getWidth(), 0);
* 倒影

//把Y坐標都變成負數
mt.setScale(1, -1);
//圖片整體向下移
mt.postTranslate(0, copyBm.getHeight());//不能用setTranslate,不用重復用set,再次set時,先復原再設置

  • 畫畫板

記錄用戶觸摸事件的XY坐標,繪制直線
* 給ImageView設置觸摸偵聽,得到用戶的觸摸事件,并獲知用戶觸摸ImageView的坐標

iv.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
//觸摸屏幕
case MotionEvent.ACTION_DOWN:
//得到觸摸屏幕時手指的坐標
startX = (int) event.getX();
startY = (int) event.getY();
break;
//在屏幕上滑動
case MotionEvent.ACTION_MOVE:
//用戶滑動手指,坐標不斷的改變,獲取最新坐標
int newX = (int) event.getX();
int newY = (int) event.getY();
//用上次onTouch方法得到的坐標和本次得到的坐標繪制直線
canvas.drawLine(startX, startY, newX, newY, paint);
iv.setImageBitmap(copyBm);
startX = newX;
startY = newY;
break;

}
return true;
}
});
* 刷子效果,加粗畫筆

paint.setStrokeWidth(8);
* 調色板,改變畫筆顏色

paint.setColor(Color.GREEN);
* 保存圖片至SD卡

FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("sdcard/dazuo.png"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//保存圖片
copyBm.compress(CompressFormat.PNG, 100, fos);// 有可能打開SD卡,找不到圖片(圖片已經在SD卡中,但圖庫中沒有)。

圖片在sd卡中,但是圖庫沒有
* 系統每次遍歷sd卡時,會把sd卡中的所有多媒體文件(圖片、音頻、視頻)都在MediaStore數據庫中保存一個索引,這個索引包含的字段有文件名、文件保存路徑、標題、藝術家、持續時間
* 每次啟動圖庫時,圖庫應用并不會去遍歷sd卡,檢測圖片文件,而是直接從MediaStore數據庫讀取圖片的索引,從而讀取到這張圖片


* 系統每次收到SD卡就緒廣播時,都會去遍歷sd卡的所有文件和文件夾,把遍歷到的所有多媒體文件都在MediaStore數據庫保存一個索引,這個索引包含多媒體文件的文件名、路徑、大小
* 系統開機或者點擊加載sd卡按鈕時,系統會發送sd卡就緒廣播,我們也可以手動發送就緒廣播

Intent intent = new Intent();
intent.setAction(Intent.ACTION_MEDIA_MOUNTED);
intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));
sendBroadcast(intent);

----------------------------------------------------------------------------------------------

撕衣服
* 原理:把穿內衣和穿外衣的照片重疊顯示,內衣照在下面,用戶滑動屏幕時,觸摸的是外衣照,把手指經過的像素都置為透明,內衣照就顯示出來了,如果圖片大于屏幕(但加載不會內存溢出),圖片是被壓縮顯示在屏幕,在屏幕上滑行得到的坐標,與圖片上坐標不對應,會出現坐標偏移。需要計算出圖片和屏幕的縮放比例。

屏幕高/圖片高=滑動坐標/得出需要的值;

iv.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
int newX = (int) event.getX();
int newY = (int) event.getY();
//把指定的像素變成透明
copyBm.setPixel(newX, newY, Color.TRANSPARENT);
iv.setImageBitmap(copyBm);
break;

}
return true;
}
});
* 每次只設置一個像素點太慢,以觸摸的像素為圓心,半徑為5畫圓,圓內的像素全部置為透明

for (int i = -5; i < 6; i++) {
for (int j = -5; j < 6; j++) {
if(Math.sqrt(i * i + j * j) <= 5)

if(newX + i < copyBm.getWidth() & newY+j < compBm.getHeight()

&& newX + i >=0 &&?newY + j >= 0?)

copyBm.setPixel(newX + i, newY + j, Color.TRANSPARENT);
}
}

2、音頻處理

?

  • 播放服務

* 播放音頻的代碼應該運行在服務中,定義一個播放服務MusicService
* 服務里定義play、stop、pause、continuePlay等方法

private void play() {
// TODO Auto-generated method stub
player.reset();
try {
player.setDataSource("sdcard/bzj.mp3");
player.prepare();

player.start();

//在線播放

//player.setDataSource("http://192.168.0.1/music/bzj.mp3");
//player.prepareAsync();

// player.setOnPreparedListener(new OnPrepareListener(){

@override

//public void onPrepared(MediaPlayer mp)

//{

//player.start();

//}

//}

//);


} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
private void pause() {
player.pause();
}
private void stop() {
player.stop();
}
private void continuePlay() {
player.start();
}
* 把這幾個方法抽取成一個接口MusicInterface
* 定義一個中間人類,繼承Binder,實現MusicInterface
* 先start啟動MusicService,再bind

Intent intent = new Intent(this, MusicService.class);
startService(intent);
bindService(intent, conn, BIND_AUTO_CREATE);

  • 根據播放進度設置進度條

* 獲取當前的播放時間和當前音頻的最長時間

int currentPosition = player.getCurrentPosition();
int duration = player.getDuration();
* 播放進度需要不停的獲取,不停的刷新進度條,使用計時器每500毫秒獲取一次播放進度
* 發消息至Handler,把播放進度放進Message對象中,在Handler中更新SeekBar的進度,可以拖動的進度條

if(timer == null){//避免重發創建

timer = new Timer();//在onDestroy中調用timer.cancel();取消計時器。并且銷毀player. ?player.release();
timer.schedule(new TimerTask() {

@Override
public void run() {
int currentPosition = player.getCurrentPosition();
int duration = player.getDuration();
Message msg = Message.obtain();
//把播放進度存入Message中
Bundle data = new Bundle();
data.putInt("currentPosition", currentPosition);
data.putInt("duration", duration);
msg.setData(data);
MainActivity.handler.sendMessage(msg);
}
}, 5, 500);//計時任務開始5毫秒后,RUN方法執行,每500毫秒執行一次
* 在Activity中定義Handler

static Handler handler = new Handler(){//設置為靜態,在整個項目中都可以訪問(包括服務),并且谷歌提示靜態不會發生內存溢出。
public void handleMessage(android.os.Message msg) {
//取出消息攜帶的數據
Bundle data = msg.getData();
int currentPosition = data.getInt("currentPosition");
int duration = data.getInt("duration");

//設置播放進度
sb.setMax(duration);
sb.setProgress(currentPosition);
};
};

  • 拖動進度條改變播放進度

//給sb設置一個拖動偵聽
sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
//停止拖動時調用
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
int progress = seekBar.getProgress();
mi.seekTo(progress);//在接口和服務中定義seekTo方法
}
//開始拖動時調用
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub

}
//拖動的時候不斷調用
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub

}
});

3、視頻處理

  • ?SurfaceView

* 對畫面的實時更新要求較高
* 雙緩沖技術:內存中有兩個畫布,A畫布顯示至屏幕,B畫布在內存中繪制下一幀畫面,繪制完畢后B顯示至屏幕,A在內存中繼續繪制下一幀畫面
* 播放視頻也是用MediaPlayer,不過跟音頻不同,要設置顯示在哪個SurfaceView

*?VideoView(視頻播放組件,應用更簡單,且支持多種格式)

VideoView vv = (VideoView)findViewById(R.id.vv);

vv.setVideoPath("sdcard/2.3gp");

vv.start();

*?第三方架構:FFMPEG:開源免費音視頻編解碼器(c++)

* 第三方架構:vitamio(java)

SurfaceView sv = (SurfaceView) findViewById(R.id.sv);
SurfaceHolder sh = sv.getHolder();

MediaPlayer player = new MediaPlayer();
player.reset();
try {
player.setDataSource("sdcard/2.3gp");
player.setDisplay(sh);
player.prepare();

player.start();
} catch (Exception e) {
e.printStackTrace();
}

* SurfaceView是重量級組件,可見時才會創建
* 給SurfaceHolder設置CallBack,類似于偵聽,可以知道SurfaceView的狀態

sh.addCallback(new Callback() {
//SurfaceView銷毀時調用
@Override
public void surfaceDestroyed(SurfaceHolder holder) {

if(player != null){

progress = player.getCurrentPosition();//定義全局變量progress保存進度
player.stop();

player.release();
player = null;

}
}
//SurfaceView創建時調用
@Override
public void surfaceCreated(SurfaceHolder holder) {

if(player == null){

player = new MediaPlayer();

player.reset();
try {
player.setDataSource("sdcard/2.3gp");
player.setDisplay(sh);
player.prepare();

player.seekTo(progress);

player.start();
} catch (Exception e) {
e.printStackTrace();
}

}}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {


}
});
* SurfaceView一旦不可見,就會被銷毀,一旦可見,就會被創建,銷毀時停止播放,再次創建時再開始播放

4、攝像頭

?

* 啟動系統提供的拍照程序

//隱式啟動系統提供的拍照Activity
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//設置照片的保存路徑
File file = new File(Environment.getExternalStorageDirectory(), "haha.jpg");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
startActivityForResult(intent, 0);
* 啟動系統提供的攝像程序

Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);

File file = new File(Environment.getExternalStorageDirectory(), "haha.3gp");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
//設置保存視頻文件的質量
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent, 0);

?

創建自定義相機可參照幫助文檔:?develop->API Guid -> Camera

-------------------------------------------------------------------------------------------

1 package com.itheima.cameraapp; 2 3 import java.io.IOException; 4 5 import android.content.Context; 6 import android.hardware.Camera; 7 import android.util.Log; 8 import android.view.SurfaceHolder; 9 import android.view.SurfaceView; 10 11 /** 預覽類 */ 12 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 13 public static final String TAG = "camera"; 14 private SurfaceHolder mHolder; 15 private Camera mCamera; 16 17 public CameraPreview(Context context, Camera camera) { 18 super(context); 19 mCamera = camera; 20 21 // Install a SurfaceHolder.Callback so we get notified when the 22 // underlying surface is created and destroyed. 23 //獲取surfaceview的控制器 24 mHolder = getHolder(); 25 //設置偵聽 26 mHolder.addCallback(this); 27 // deprecated setting, but required on Android versions prior to 3.0 28 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 29 } 30 31 public void surfaceCreated(SurfaceHolder holder) { 32 // The Surface has been created, now tell the camera where to draw the preview. 33 try { 34 //設置攝像頭的預覽界面顯示在holder對應的那個surfaceview 35 mCamera.setPreviewDisplay(holder); 36 //開始預覽 37 mCamera.startPreview(); 38 } catch (IOException e) { 39 Log.d(TAG, "Error setting camera preview: " + e.getMessage()); 40 } 41 } 42 43 public void surfaceDestroyed(SurfaceHolder holder) { 44 // empty. Take care of releasing the Camera preview in your activity. 45 } 46 47 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 48 // If your preview can change or rotate, take care of those events here. 49 // Make sure to stop the preview before resizing or reformatting it. 50 51 if (mHolder.getSurface() == null){ 52 // preview surface does not exist 53 return; 54 } 55 56 // 在對surfaceview做改變前,先停止預覽 57 try { 58 mCamera.stopPreview(); 59 } catch (Exception e){ 60 // ignore: tried to stop a non-existent preview 61 } 62 63 // set preview size and make any resize, rotate or 64 // reformatting changes here 65 66 // 設置改變完后,重新開始預覽 67 try { 68 mCamera.setPreviewDisplay(mHolder); 69 mCamera.startPreview(); 70 71 } catch (Exception e){ 72 Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 73 } 74 } 75 } CameraPreview 1 package com.itheima.cameraapp; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 8 import android.app.Activity; 9 import android.content.Context; 10 import android.content.pm.PackageManager; 11 import android.hardware.Camera; 12 import android.hardware.Camera.AutoFocusCallback; 13 import android.hardware.Camera.PictureCallback; 14 import android.os.Bundle; 15 import android.util.Log; 16 import android.view.View; 17 import android.widget.Button; 18 import android.widget.FrameLayout; 19 20 public class MainActivity extends Activity { 21 22 private Camera mCamera; 23 private CameraPreview mPreview; 24 25 @Override 26 public void onCreate(Bundle savedInstanceState) { 27 super.onCreate(savedInstanceState); 28 setContentView(R.layout.activity_main); 29 30 if(checkCameraHardware(this)){ 31 // 創建攝像頭實例 32 mCamera = getCameraInstance(); 33 } 34 else{ 35 return; 36 } 37 //創建預覽類的對象 38 mPreview = new CameraPreview(this, mCamera); 39 FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); 40 //把預覽類設置為幀布局的子節點 41 preview.addView(mPreview); 42 43 44 // 給按鈕設置點擊偵聽 45 Button captureButton = (Button) findViewById(R.id.button_capture); 46 captureButton.setOnClickListener( 47 new View.OnClickListener() { 48 @Override 49 public void onClick(View v) { 50 //自動聚焦 51 mCamera.autoFocus(new AutoFocusCallback() { 52 53 //聚焦完成調用 54 @Override 55 public void onAutoFocus(boolean success, Camera camera) { 56 // 拍照 57 mCamera.takePicture(null, null, mPicture); 58 59 } 60 }); 61 62 } 63 } 64 ); 65 } 66 67 68 /** 檢測手機是否有攝像頭 */ 69 private boolean checkCameraHardware(Context context) { 70 //檢測手機是否安裝有攝像頭應用 71 if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){ 72 // this device has a camera 73 return true; 74 } else { 75 // no camera on this device 76 return false; 77 } 78 } 79 80 /** 一個獲取攝像頭實例的安全途徑 */ 81 public static Camera getCameraInstance(){ 82 Camera c = null; 83 try { 84 c = Camera.open(); // 獲取第一個后置攝像頭的實例 85 } 86 catch (Exception e){ 87 // Camera is not available (in use or does not exist) 88 } 89 return c; // returns null if camera is unavailable 90 } 91 92 93 private PictureCallback mPicture = new PictureCallback() { 94 95 //拍照會調用此方法 96 //data:照片的字節數組 97 @Override 98 public void onPictureTaken(byte[] data, Camera camera) { 99 try { 100 File pictureFile = new File("sdcard/mrplus.jpg"); 101 FileOutputStream fos = new FileOutputStream(pictureFile); 102 fos.write(data); 103 fos.close(); 104 } catch (FileNotFoundException e) { 105 Log.d(CameraPreview.TAG, "File not found: " + e.getMessage()); 106 } catch (IOException e) { 107 Log.d(CameraPreview.TAG, "Error accessing file: " + e.getMessage()); 108 } finally{ 109 //拍照完成后重新進入預覽 110 camera.startPreview(); 111 } 112 } 113 }; 114 115 } MainActivity 1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.itheima.cameraapp" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="8" 9 android:targetSdkVersion="17" /> 10 <uses-permission android:name="android.permission.CAMERA" /> 11 12 <uses-feature android:name="android.hardware.camera" /> 13 14 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 15 <application 16 android:allowBackup="true" 17 android:icon="@drawable/ic_launcher" 18 android:label="@string/app_name" 19 android:theme="@style/AppTheme" > 20 <activity 21 android:name="com.itheima.cameraapp.MainActivity" 22 android:label="@string/app_name" 23 android:screenOrientation="landscape" 24 > 25 <intent-filter> 26 <action android:name="android.intent.action.MAIN" /> 27 28 <category android:name="android.intent.category.LAUNCHER" /> 29 </intent-filter> 30 </activity> 31 </application> 32 33 </manifest> AndroidManifest 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="horizontal" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 > 7 <FrameLayout 8 android:id="@+id/camera_preview" 9 android:layout_width="fill_parent" 10 android:layout_height="fill_parent" 11 android:layout_weight="1" 12 android:visibility="invisible" 13 /> 14 15 <Button 16 android:id="@+id/button_capture" 17 android:text="Capture" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" 20 android:layout_gravity="center" 21 /> 22 </LinearLayout> activity_main

?

轉載于:https://www.cnblogs.com/ecollab/p/5919953.html

總結

以上是生活随笔為你收集整理的android 学习随笔二十(多媒体编程 )的全部內容,希望文章能夠幫你解決所遇到的問題。

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