安卓基础干货(十):安卓多媒体编程的学习


多媒体编程

1、什么是多媒体?

多种媒体的综合。图片、音乐、视频。

计算机表示图形的方式

1、bmp 以高质量保存所有类型的图片,用于计算机。 计算机使用像素点表示图形,每个像素点都是一个颜色,24位深度(24bit)。 每个像素点的颜色是一个RGB,使用6个十六进制的数值来表示。 文件头信息占用的数据大小。 体积比较大。

2、jpg 以良好的质量保存图片,用于计算机、电子邮件或网络。 jpg 工业图形的压缩算法,类似rar的算法。人眼识别精度有限,把相邻空间内类似的颜色使用同一个颜色来表示。 体积减小,失真。

3、png 203.2k 255*340 以高质量保存图片或者绘图,用于计算机或网络。

加载大图片的OOM异常

java.lang.OutOfMemoryError 

堆内存空间:给类实例、数组分配内存空间的。 RGB ARGB 32

应用程序在启动时系统为它创建一个进程,系统为每个进程创建dalvik虚拟机(模拟器设置的VM Heap),当图片的大小大于虚拟机的堆内存空间时,就内存溢出(内存泄露);

解决办法:缩放图片加载到内存

步骤:

1、获得设备屏幕的分辨率; 2、得到原图的分辨率; 3、通过比较得到一个合适的比例值; 4、按照比例值缩放图片 5、把图片显示在imageview

缩放图片并加载到内存中

解决办法:

缩放图片加载到内存 步骤: 1、获得设备屏幕的分辨率; 2、得到原图的分辨率; 3、通过比较得到一个合适的比例值; 4、按照比例值缩放图片 5、把图片显示在imageview

代码:

package com.itheima.loadbigpic;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.Bundle;
import android.os.Environment;
import android.view.Display;
import android.view.WindowManager;
import android.widget.ImageView;

public class MainActivity extends Activity {

  private ImageView iv;

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

     iv = (ImageView) findViewById(R.id.iv);

   //1、获得设备屏幕的分辨率;
   //通过服务获得窗口管理器
   WindowManager  wm =  (WindowManager) getSystemService(WINDOW_SERVICE);
    //获得设备分辨率对象
   Display display = wm.getDefaultDisplay();

   //api13之前使用这个两个方法,13之后置为过期
    int screenWidth = display.getWidth();
   int screenHeight = display.getHeight();

   //2、得到原图的分辨率;
   Options opts = new Options();
   opts.inJustDecodeBounds = true;
   //opts为null 可以返回一个图片对象,如果不为null ,就会返回null
   BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/lp.jpg", opts);
    //得到原图的宽和高
    int srcWidth = opts.outWidth;
   int srcHeight = opts.outHeight;       

   //3、通过比较得到一个合适的比例值;
   //3000/320 = 9 2262/480 =5
    int sx = srcWidth/screenWidth;
    int sy = srcHeight/screenHeight;
    int scale = 0;
    if(sx >= 1 && sx > sy){
     scale = sx;
   }else if(sy >= 1 && sy > sx){
     scale = sy;
   }
   //4、按照比例值缩放图片
   opts.inJustDecodeBounds = false;
    opts.inSampleSize = scale; // 1/scale * 1/scale
   Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/lp.jpg", opts);

    //5、把图片显示在imageview

    iv.setImageBitmap(bm);
    }
}

在内存中创建原图的副本(重点)

步骤: 1、得到原图; 2、创建一个空白的纸张,参考原图; 3、创建一个画板,参考空白纸张; 4、创建一个画笔; 5、在画板上画画;

代码:

package com.itheima.copypic;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends Activity {

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

    iv = (ImageView) findViewById(R.id.iv);

    //1、得到原图;
   Bitmap srcPic = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);

    //config 包括位深度
    //2、创建一个空白的纸张,参考原图;
   Bitmap copyPic = Bitmap.createBitmap(srcPic.getWidth(), srcPic.getHeight(), srcPic.getConfig());  
    //3、创建一个画板,参考空白纸张;
    Canvas canvas = new Canvas(copyPic);

    //4、创建一个画笔;
   Paint paint = new Paint();
    paint.setColor(Color.BLACK);//默认是使用黑色,后面会根据原图的颜色画画
    //5、在画板上画画;
   canvas.drawBitmap(srcPic, new Matrix(), paint);   
    iv.setImageBitmap(copyPic);
 }
}

计算机图形处理的API(重点)

* 旋转
* 缩放
* 平移
* 镜面倒影
* 修改颜色
ColorMatrix cm = new ColorMatrix();
 cm.set(new float[] {
      1, 0, 0, 0, 0,  //red
     0, 1, 0, 0, 0,  //green
     0, 0, 1, 0, 0,  //blue
      0, 0, 0, 1, 0   //透明度
 });

paint.setColorFilter(new ColorMatrixColorFilter(cm));

微信画画板

package com.itheima.painter;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class MainActivity extends Activity {

 private ImageView iv;
 private Bitmap srcPic;
  private Bitmap copyPic;
 private Canvas canvas;
  private Paint paint;
  @Override
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

    iv  = (ImageView) findViewById(R.id.iv);

    srcPic = BitmapFactory.decodeResource(getResources(), R.drawable.bg);

    copyPic = Bitmap.createBitmap(srcPic.getWidth(), srcPic.getHeight(), srcPic.getConfig());
   canvas = new Canvas(copyPic);

   paint = new Paint();
    paint.setColor(Color.BLACK);//默认是使用黑色,后面会根据原图的颜色画画
    //5、在画板上画画;

    Matrix matrix = new Matrix();

    canvas.drawBitmap(srcPic, matrix, paint);
   iv.setImageBitmap(copyPic);

    iv.setOnTouchListener(new OnTouchListener(){

      int startX ;
      int startY;

     @Override
     public boolean onTouch(View v, MotionEvent event) {
       int type = event.getAction();   
        switch (type) {
       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();

          canvas.drawLine(startX, startY, newX, newY, paint);

          iv.setImageBitmap(copyPic);

          //得到新的开始坐标点
          startX = (int) event.getX();

           startY = (int) event.getY();
         break;
        }

        //消费掉当前的监听器
       return true;
      }

   });

  }
}

视频播放器videoview(重点)

代码:

package com.itheima.videoview;

import android.app.Activity;
import android.os.Bundle;
import android.widget.VideoView;

public class MainActivity extends Activity {

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

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

    vv.setVideoPath("http://192.168.22.136:8080/11.mp4");

    vv.start(); 
  }
}

视频播放器surfaceview(重点)

surfaceview表面视图

双缓冲区:使用两个线程协调工作;

surfaceview 重量级空间,当画面可见时,双缓冲器被创建,占用较高的cpu和内存资源。

当界面不可见时,双缓冲器占用释放。

音乐播放器API

package com.itheima.surfaceview;

import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MainActivity extends Activity {

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

    sv = (SurfaceView) findViewById(R.id.sv);

    SurfaceHolder holder = sv.getHolder();
    //推送缓冲数据,api 13之前的版本上必须执行这行代码,13版本之后,播放器可以自动把
   //数据加载到缓冲区
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    holder.addCallback(new Callback() {

      private MediaPlayer mediaPlay;

      @Override
     public void surfaceCreated(SurfaceHolder holder) {
        try {
         mediaPlay = new MediaPlayer();

          mediaPlay.setDataSource("http://192.168.22.136:8080/11.mp4");
         mediaPlay.setAudioStreamType(AudioManager.STREAM_MUSIC);

          mediaPlay.setDisplay(holder);

          //使用阻塞式准备方法,等待数据资源准备完成后才开始播放,用于播放本地的音视频文件
         //mediaPlay.prepare(); 
         //使用异步式准备方法,使用子线程等待数据资源准备完成后才开始播放,用于播放网络上的音视频文件
         mediaPlay.prepareAsync();

          mediaPlay.setOnPreparedListener(new OnPreparedListener() {

            @Override
           public void onPrepared(MediaPlayer mp) {

              mediaPlay.start();
            }
         });

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

      }

      @Override
     public void surfaceDestroyed(SurfaceHolder holder) {
        if(mediaPlay != null && mediaPlay.isPlaying()){
         mediaPlay.stop();

          mediaPlay.release();

          mediaPlay = null;

          //mediaPlay.seekTo(msec);

        }
     }   

      @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width,
         int height) {
       // TODO Auto-generated method stub

      }
   });
 }
}

vitamio框架的使用

1 引入vitamio框架 以library形式引入

2 在布局中定义VideoView

<io.vov.vitamio.widget.VideoView 
 android:id="@+id/vv"
  android:layout_width="match_parent"
 android:layout_height="match_parent"/>

3 mainactivity代码

插件vitamio框架检查是否可用
if (!LibsChecker.checkVitamioLibs(this)) {
 return;
}

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

vv.setVideoPath("http://192.168.1.1:8080/haha.avi");
vv.setOnPreparedListener(new OnPreparedListener() {

  @Override
 public void onPrepared(MediaPlayer mp) {
    vv.start();
 }
});
//设置video的控制器
vv.setMediaController(new MediaController(this));

4 一定要在清单文件初始化InitActivity

<activity android:name="io.vov.vitamio.activity.InitActivity"></activity>

照相机拍照

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 

file = new File(Environment.getExternalStorageDirectory()+"/123.jpg");

intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));

startActivityForResult(intent, 0);

录机应用

Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); 

file = new File(Environment.getExternalStorageDirectory()+"/123.3gp");

intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));

startActivityForResult(intent, 0);