美文网首页
Android 使用textureView加载视频,拍照及录制视

Android 使用textureView加载视频,拍照及录制视

作者: 怪咖小青年_56e8 | 来源:发表于2020-12-10 20:26 被阅读0次

需求是只拍照视频播放位置

/** 拍照视频播放位置* */

public static void getBitmap(Context context, TextureView vv){

public static String BASE_URL = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/";

 String mPath = Path.BASE_URL + System.currentTimeMillis() + ".jpg"; 

 Toast.makeText(context, "图片已保存到" + mPath, Toast.LENGTH_SHORT).show(); Bitmap bm = vv.getBitmap(); 

 if(bm == null) 

 Log.e(TAG,"bitmap is null");

 OutputStream fout = null;

 File imageFile = new File(mPath); 

 try { 

 fout = new FileOutputStream(imageFile); bm.compress(Bitmap.CompressFormat.JPEG, 90, fout);

 fout.flush();

 fout.close();

 } catch (FileNotFoundException e) { 

 Log.e(TAG, "FileNotFoundException"); e.printStackTrace(); 

 } catch (IOException e) { 

 Log.e(TAG, "IOException"); e.printStackTrace(); }

 //通知系統相冊刷新保持的錄屏,否则图库不会更新

 Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(new File(mPath))); context.sendBroadcast(intent);

}

由于录制视频需求是只录制展示视频的那个区域,实现了mediaRecorder录制全屏,mediaRecorder.setVideoSize(width, height);可以设置从屏幕左上角开始录制的宽高,但是状态栏也会录上,ffmpeg、OpenGL都可以实现,本人对底层不懂,视频功能我是用了图片合成MP4文件

implementation 'org.jcodec:jcodec-android:0.1.9'//图片合成视频


最终使用这个框架实现多张图片合成MP4视频

生成视频的图片和拍照的图片代码一样,只是换了不同目录

public static void Image2Mp4(Context context ,String videoName){

try {

Log.e("performJcodec: ","执行开始");

SequenceEncoderMp4 se  =null;

File   file =new File(Environment.getExternalStorageDirectory()

.getAbsolutePath() +"/wy/" +"pic/");

File fileout =new File(Path.BASE_URL);

if (!fileout.exists()) {

fileout.mkdir();

}

File out =new File(Path.BASE_URL, videoName +".mp4");

se =new SequenceEncoderMp4(out);

File[]files =file.listFiles();

for (int i =0; i

if (!files[i].exists()) {

break;

}

Bitmap frame =BitmapUtil.decodeSampledBitmapFromFile(files[i].getAbsolutePath() ,480 ,320);

se.encodeImage(frame);

Log.e("performJcodec: ","执行到的图片是 " + i);

}

se.finish();

Log.e("performJcodec: ","执行完成"+videoName+".mp4");

//发送广播通知挂载文件

        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(out)));

}catch (IOException e) {

Log.e("performJcodec: ","执行异常 " + e.toString());

}

//删除sdcard创建的临时文件

File imageFile =new File(Path.BASE_URL +"pic/");

PictureUtils.delete(imageFile);

}

public static void delete(File file) {

if (file.isDirectory()) {

File[]childFiles = file.listFiles();

//空文件夹直接删除

            if (childFiles ==null ||childFiles.length ==0) {

file.delete();

return;

}

//非空循环删除

            for (int i =0; i

deleteFile(childFiles[i]);

}

file.delete();

}

}

public static void deleteFile(File file) {

if (file.isFile()) {

file.delete();

return;

}

}

还有几个重要的类

public class SequenceEncoderMp4

        extends org.jcodec.api.android.SequenceEncoder {

/**

    * 控制帧率缩放,时间长度调整这个值

    * 值越小,生成视频时间越长

    * 如:timeScale = 50    一秒视屏采用50张图片

    */

    private int timeScale =10;

public SequenceEncoderMp4(File out)

throws IOException

    {

super(out);

this.ch =NIOUtils.writableFileChannel(out);

// Muxer that will store the encoded frames

        muxer =new MP4Muxer(ch,Brand.MP4);

// Add video track to muxer

        outTrack =muxer.addTrack(TrackType.VIDEO,timeScale);

// Allocate a buffer big enough to hold output frames

        _out =ByteBuffer.allocate(1920 *1080 *6);

// Create an instance of encoder

        encoder =new H264Encoder();

// Transform to convert between RGB and YUV

        transform =ColorUtil.getTransform(ColorSpace.RGB,encoder.getSupportedColorSpaces()[0]);

// Encoder extra data ( SPS, PPS ) to be stored in a special place of

// MP4

        spsList =new ArrayList();

ppsList =new ArrayList();

}

private SeekableByteChannel  ch;

private  Picture              toEncode;

private  Transform            transform;

private  H264Encoder          encoder;

private  ArrayListspsList;

private  ArrayListppsList;

private  FramesMP4MuxerTrack  outTrack;

private  ByteBuffer            _out;

private  int                  frameNo;

private  MP4Muxer              muxer;

public void encodeNativeFrame(Picture pic)throws IOException {

if (toEncode ==null) {

toEncode =Picture.create(pic.getWidth() , pic.getHeight() ,encoder.getSupportedColorSpaces()[0]);

}

// Perform conversion

        transform.transform(pic,toEncode);

// Encode image into H.264 frame, the result is stored in '_out' buffer

        _out.clear();

ByteBuffer result =encoder.encodeFrame(toEncode,_out);

// Based on the frame above form correct MP4 packet

        spsList.clear();

ppsList.clear();

H264Utils.wipePS(result,spsList,ppsList);

H264Utils.encodeMOVPacket(result);

// Add packet to video track

        outTrack.addFrame(new MP4Packet(result,frameNo,timeScale,1,frameNo,true,null,frameNo,0));

frameNo++;

}

public void finish()throws IOException {

// Push saved SPS/PPS to a special storage in MP4

        outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList,ppsList,4));

// Write MP4 header and finalize recording

        muxer.writeHeader();

NIOUtils.closeQuietly(ch);

}

}

public class BitmapUtil {

public static void checkArgs(String filePath){

BitmapFactory.Options options =new BitmapFactory.Options();

options.inJustDecodeBounds =true;

BitmapFactory.decodeFile(filePath,options);

int imageHeight =options.outHeight;

int imageWidth =options.outWidth;

String imageType =options.outMimeType;

}

public static int calculateInSampleSize(BitmapFactory.Options options,

int reqWidth,int reqHeight) {

// 源图片的高度和宽度

        final int height = options.outHeight;

final int width = options.outWidth;

int inSampleSize =1;

if (height > reqHeight ||width > reqWidth) {

// 计算出实际宽高和目标宽高的比率

            final int heightRatio =Math.round((float)height / (float) reqHeight);

final int widthRatio =Math.round((float)width / (float) reqWidth);

// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高

            // 一定都会大于等于目标的宽和高。

            inSampleSize =heightRatio

}

return inSampleSize;

}

public static Bitmap decodeSampledBitmapFromFile(String filePath,

int reqWidth,int reqHeight) {

// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小

        final BitmapFactory.Options options =new BitmapFactory.Options();

options.inJustDecodeBounds =true;

BitmapFactory.decodeFile(filePath,options);

// 调用上面定义的方法计算inSampleSize值

        options.inSampleSize =calculateInSampleSize(options, reqWidth, reqHeight);

// 使用获取到的inSampleSize值再次解析图片

        options.inJustDecodeBounds =false;

return BitmapFactory.decodeFile(filePath,options);

}

}

参考这个GitHub  https://github.com/ynztlxdeai/ImageToVideo

相关文章

网友评论

      本文标题:Android 使用textureView加载视频,拍照及录制视

      本文链接:https://www.haomeiwen.com/subject/tnirgktx.html