Android 多媒体编程笔记

加载大图片

图片在计算机中的大小=图片的总像素 * 每个像素占用的大小。
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的状态图
这里写图片描述

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是以一个工程模块的方式提供给我们使用。

这里写图片描述

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

这里写图片描述

下面就是使用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));
    }
}

工程源码地址

点击查看源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值