Android 多媒体编程笔记

时间:2021-04-14 20:35:04

加载大图片

图片在计算机中的大小=图片的总像素 * 每个像素占用的大小。
Android保存图片像素信息,是用ARGB保存,A表示alpha透明度。
下面是几种位图的说明:

  • 单色位图:只能表示2种颜色
    • 使用两个数字: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位位图:
    • 每个像素占用24位,也就是3个字节,所在叫24位位图
    • R:0-255,需要一个长度为8的二进制数字,占用1个字节
    • G:0-255,需要一个长度为8的二进制数字,占用1个字节
    • B:0-255,需要一个长度为8的二进制数字,占用1个字节

所以一张3200*4800的24位位图,在加载到Android中时占用的内存大小为3200*4800*(3+1)=61440个字节,60000k=58M,直接加载大图片会导致out of memory,所以我们需要加载缩小后的图片。

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

private int calculateScaleSize(int originalWidth, int originalHeight,
int destWidth, int destHeight) {
// 这里采用向上取整,比如如果图片是屏幕的1.5倍大,
// 如果取1的话还是可能会崩溃,所以此时应该向上取整为2
int scaleWidth = (int) Math.ceil(originalWidth * 1.0f / destWidth);
int scaleHeight = (int) Math.ceil(originalHeight * 1.0f / destHeight);
System.out.println(Math.max(scaleHeight, scaleWidth)+"");
return Math.max(scaleHeight, scaleWidth);
}

public void click(View v) {
// 获取图片的宽高,但是不解析图片
Options opt = new Options();
opt.inJustDecodeBounds = true;
// BitmapFactory.decodeFile("sdcard/dog.jpg", opt);
BitmapFactory.decodeResource(getResources(), R.drawable.dog, opt);
int imageWidth = opt.outWidth;
int imageHeight = opt.outHeight;

// 获取屏幕的宽高
Display dp = getWindowManager().getDefaultDisplay();
int screenWidth = dp.getWidth();
int screenHeight = dp.getHeight();

// 缩放图片
opt.inSampleSize = calculateScaleSize(imageWidth, imageHeight,
screenWidth, screenHeight);
opt.inJustDecodeBounds = false;
// Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opt);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.dog, opt);
// 使用缩放后的图片显示在屏幕上
ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageBitmap(bm);
}
}

制作图像的副本

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// 这个对象是只读的
Bitmap bmSrc = BitmapFactory.decodeFile("sdcard/photo3.jpg");

//创建图片的副本
//1.在内存中创建一个与原图大小一模一样的的bitmap对象
Bitmap bmCopy = Bitmap.createBitmap(bmSrc.getWidth(), bmSrc.getHeight(), bmSrc.getConfig());

//2.创建画笔对象
Paint paint = new Paint();

//3.创建画板对象,把白纸铺在画板上
Canvas canvas = new Canvas(bmCopy);

//4.开始作画
canvas.drawBitmap(bmSrc, new Matrix(), paint);

ImageView iv_src = (ImageView) findViewById(R.id.iv_src);
ImageView iv_copy = (ImageView) findViewById(R.id.iv_copy);
iv_src.setImageBitmap(bmSrc);
iv_copy.setImageBitmap(bmCopy);
}

MediaPlayer播放音频

下面是官方MediaPlayer的状态图
Android 多媒体编程笔记

public class MusicService extends Service {

MediaPlayer player;
private Timer timer;

@Override
public IBinder onBind(Intent intent) {
return new MusicController();
}

class MusicController extends Binder implements MusicInterface {

@Override
public void play() {
MusicService.this.play();
}

@Override
public void pause() {
MusicService.this.pause();
}

@Override
public void continuePlay() {
MusicService.this.continuePlay();
}

@Override
public void seekTo(int progress) {
MusicService.this.seekTo(progress);
}
}

@Override
public void onCreate() {
super.onCreate();
player = new MediaPlayer();
}

@Override
public void onDestroy() {
super.onDestroy();
player.stop();
player.release();
player = null;
if (timer != null) {
timer.cancel();
timer = null;
}
}

public void play() {
player.reset();
try {
player.setDataSource("sdcard/zxmzf.mp3");
// player.setDataSource("http://192.168.13.119:8080/bzj.mp3");
// player.prepare();
player.prepareAsync();
// player.start();
player.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
player.start();
addTimer();
}
});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void continuePlay() {
player.start();
}

public void pause() {
player.pause();
}

public void seekTo(int progress) {
player.seekTo(progress);
}

public void addTimer() {
if (timer == null) {
timer = new Timer();
timer.schedule(new TimerTask() {

@Override
public void run() {
int duration = player.getDuration();
int currentPosition = player.getCurrentPosition();
Message msg = MainActivity.handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("duration", duration);
bundle.putInt("currentPosition", currentPosition);
msg.setData(bundle);
MainActivity.handler.sendMessage(msg);
}
}, 5, 500);
}
}
}

MediaPlayer+SurfaceView播放视频

SurfaceView提供了双缓冲技术,是一个重量级的控件,会占用很多的内存,所以SurfaceView只要不可见,就不会创建,可见时,才会创建。从可见变成不可见时会销毁。

public class MainActivity extends Activity {
private MediaPlayer player;
static int currentPosition;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

SurfaceView sv = (SurfaceView) findViewById(R.id.sv);
final SurfaceHolder sh = sv.getHolder();
sh.addCallback(new Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (player != null) {
currentPosition = player.getCurrentPosition();
player.stop();
player.release();
player = null;
}
}

@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.start();
player.seekTo(currentPosition);
} catch (Exception e) {
e.printStackTrace();
}
}
}

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

使用vitamio播放视频

系统的MediaPlayer支持的音视频格式很有限,所以如果我们想要制作一个支持很多种格式的音视频播放器,一般会用FFMPEG来实现。
FFMPEG是一个开源的音视频编解码库,用c语言编写,已经有人封装了Android的API的库vitamio给我们使用。
vitamio是以一个工程模块的方式提供给我们使用。

Android 多媒体编程笔记

需要先导入eclipse,然后在我们自己的工程中链接这个库。

Android 多媒体编程笔记

下面就是使用vitamio的一个例子

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 检查库是否存在
if (!LibsChecker.checkVitamioLibs(this)) {return;}

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

vv.setVideoPath("sdcard/4.rmvb");
vv.start();

vv.setMediaController(new MediaController(this));
}
}

工程源码地址

点击查看源码