Android拍摄视频流的格式转换(YUV --- RGB) 怎么从网络获取流转换成视频

本文主要是介绍Android拍摄视频流的格式转换(YUV --- RGB) 怎么从网络获取流转换成视频,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android允许用户实时捕获摄像头的视频流,这在利用摄像头的AR应用中非常有用。可以利用摄像流实时做画面图像的分析,并做出许多有用的应用。比如人脸识别,条码识别,特定图像替换等等,不过大多数图像处理软件在处理时是需要RGB格式的图像,而默认的视频流是压缩的YUV格式,Android下是YUV420SP,这个格式,虽然可以在程序中修改,但是修改后好像不起作用,也就是说只能得到编码为YUV420SP的视频流,这就需要把YUV420SP的视频流转换成RGB格式的图像,用于图像识别。特贴一个格式转换函数,方便大家使用。

java 代码:

    static public void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
if (rgbBuf == null)
throw new NullPointerException("buffer 'rgbBuf' is null");
if (rgbBuf.length < frameSize * 3)
throw new IllegalArgumentException("buffer 'rgbBuf' size "
+ rgbBuf.length + " < minimum " + frameSize * 3);
if (yuv420sp == null)
throw new NullPointerException("buffer 'yuv420sp' is null");
if (yuv420sp.length < frameSize * 3 / 2)
throw new IllegalArgumentException("buffer 'yuv420sp' size " + yuv420sp.length
+ " < minimum " + frameSize * 3 / 2);
int i = 0, y = 0;
int uvp = 0, u = 0, v = 0;
int y1192 = 0, r = 0, g = 0, b = 0;
for (int j = 0, yp = 0; j < height; j++) {
uvp = frameSize + (j >> 1) * width;
u = 0;
v = 0;
for (i = 0; i < width; i++, yp++) {
y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
y1192 = 1192 * y;
r = (y1192 + 1634 * v);
g = (y1192 - 833 * v - 400 * u);
b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
rgbBuf[yp * 3] = (byte)(r >> 10);
rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
rgbBuf[yp * 3 + 2] = (byte)(b >> 10);
}
}
}


在Android的拍照视频预览时就可以截取视频数据。每获得一帧就调用一下接口函数。
我的开发平台是Android 1.5,这个程序实现视频流的获取,程序简单地在第20帧到来的时候,写入到文件中。这样就可以拿到电脑上进行分析。

参考代码:

package com.sunshine;
import java.io.File;
import java.io.RandomAccessFile;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
public class AndroidVideo extends Activity implements Callback,
Camera.PictureCallback {
private SurfaceView mSurfaceView = null;
private SurfaceHolder mSurfaceHolder = null;
private Camera mCamera = null;
private boolean mPreviewRunning = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
mSurfaceView = (SurfaceView) this.findViewById(R.id.surface_camera);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
Log.v("System.out", "get it!");
File file = new File("/sdcard/camera.jpg");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.write(data);
raf.close();
} catch (Exception ex) {
Log.v("System.out", ex.toString());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if (mPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(width, height);
mCamera.setPreviewCallback(new StreamIt());
mCamera.setParameters(p);
try {
mCamera.setPreviewDisplay(holder);
} catch (Exception ex) {
}
mCamera.startPreview();
mPreviewRunning = true;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
try {
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
}
} catch (Exception ex) {
}
}
}
class StreamIt implements Camera.PreviewCallback {
private int tick = 1;
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
if (tick == 20) {
System.out.println("data len: " + data.length);
try {
File file = new File("/sdcard/pal.pal");
if (!file.exists())
file.createNewFile();
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.write(data);
raf.close();
tick++;
} catch (Exception ex) {
Log.v("System.out", ex.toString());
}
}
tick++;
}
}


xml 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<SurfaceView android:id="@+id/surface_camera"
android:layout_width="fill_parent" android:layout_height="fill_parent">
</SurfaceView>
</LinearLayout>


注意在项目配置文件中还要加上访问权限
<uses-permission android:name="android.permission.CAMERA" />
通过查资料发现,Android每帧的数据流的格式是YUV420

YUV420转成RGB的函数,见第一部分

 

Android 端

package com.sunshine;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class AndroidVideo extends Activity implements Callback,OnClickListener{
private SurfaceView mSurfaceView = null;
private SurfaceHolder mSurfaceHolder = null;
private Camera mCamera = null;
private boolean mPreviewRunning = false;
//连接相关
private EditText remoteIP=null;
private Button connect=null;
private String remoteIPStr=null;
//视频数据
private StreamIt streamIt=null;
public static  Kit kit=null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
mSurfaceView = (SurfaceView) this.findViewById(R.id.surface_camera);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
remoteIP=(EditText)this.findViewById(R.id.remoteIP);
connect=(Button)this.findViewById(R.id.connect);
connect.setOnClickListener(this);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if (mPreviewRunning) {
mCamera.stopPreview();
}
Camera.Parameters p = mCamera.getParameters();
p.setPreviewSize(width, height);
streamIt=new StreamIt();
kit=new Kit();
mCamera.setPreviewCallback(streamIt);
mCamera.setParameters(p);
try {
mCamera.setPreviewDisplay(holder);
} catch (Exception ex) {
}
mCamera.startPreview();
mPreviewRunning = true;
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera.release();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
try {
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
}
} catch (Exception ex) {
}
}
class Kit implements Runnable {
private boolean run=true;
//        private final int dataLen=57600; //307200 OR 230400 76800 OR 57600
private final int tt=28800;
public void run() {
// TODO Auto-generated method stub
try {
Socket socket = new Socket(remoteIPStr, 8899);
DataOutputStream dos = new DataOutputStream(socket
.getOutputStream());
DataInputStream dis = new DataInputStream(socket
.getInputStream());
while (run) {
dos.write(streamIt.yuv420sp, 0, 28800);
dos.write(streamIt.yuv420sp, 28800, 28800);
dis.readBoolean();
Thread.sleep(155);
}
} catch (Exception ex) {
run=false;
ex.printStackTrace();
}
}
}
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
if(view==connect){//连接函数
remoteIPStr=remoteIP.getText().toString();
new Thread(AndroidVideo.kit).start();
}
}
}
class StreamIt implements Camera.PreviewCallback {
public byte[] yuv420sp =null;
private boolean t=true;
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
//        if(t){
//            t=false;
//            new Thread(AndroidVideo.kit).start();
//        }
yuv420sp=data;
}
}


pc端:

 

import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class FlushMe extends Frame {
private static final long serialVersionUID = 1L;
private BufferedImage im;
// 图像信息
//    private final int width = 480;
//    private final int height = 320;
private static final int width = 240;
private static final int height = 160;
private static final int numBands = 3;
private static final int dataLen = 57600;//307200 OR 230400//57600 76800
private static final int tt = 28800;//14400;//28800;
// 图像数组
private byte[] byteArray = new byte[width * height * numBands];// 图像RGB数组
private byte[] yuv420sp = new byte[dataLen];// 图像YUV数组
private static final int[] bandOffsets = new int[] { 0, 1, 2 };
private static final SampleModel sampleModel = new PixelInterleavedSampleModel(
DataBuffer.TYPE_BYTE, width, height, 3, width * 3,
bandOffsets);
// ColorModel
private static final ColorSpace cs=ColorSpace.getInstance(ColorSpace.CS_sRGB);
private static final ComponentColorModel cm=new ComponentColorModel(cs, false, false,
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
public FlushMe() {
super("Flushing");
updateIM();
setSize(480, 320);
// 窗口关闭方法
this.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent e) {
System.exit(0);
}
});
// 窗口居中
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setVisible(true);
this.getData();
}
public void update(Graphics g){
paint(g);
}
public void paint(Graphics g) {
g.drawImage(im, 0, 0, 480, 320, this);
}
public void getData() {
try {
ServerSocket server = new ServerSocket(8899);
Socket socket = server.accept();
DataInputStream dis = new DataInputStream(socket.getInputStream());
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
while (true) {
for (int i = 0; i < dataLen / tt; i++) {
dis.read(yuv420sp, i * tt, tt);
}
// 得到数据之后立即更新显示
updateIM();
im.flush();
repaint();
dos.writeBoolean(true);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void updateIM() {
try {
// 解析YUV成RGB格式
decodeYUV420SP(byteArray, yuv420sp, width, height);
DataBuffer dataBuffer = new DataBufferByte(byteArray, numBands);
WritableRaster wr = Raster.createWritableRaster(sampleModel,
dataBuffer, new Point(0, 0));
im = new BufferedImage(cm, wr, false, null);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp,
int width, int height) {
final int frameSize = width * height;
if (rgbBuf == null)
throw new NullPointerException("buffer 'rgbBuf' is null");
if (rgbBuf.length < frameSize * 3)
throw new IllegalArgumentException("buffer 'rgbBuf' size "
+ rgbBuf.length + " < minimum " + frameSize * 3);
if (yuv420sp == null)
throw new NullPointerException("buffer 'yuv420sp' is null");
if (yuv420sp.length < frameSize * 3 / 2)
throw new IllegalArgumentException("buffer 'yuv420sp' size "
+ yuv420sp.length + " < minimum " + frameSize * 3 / 2);
int i = 0, y = 0;
int uvp = 0, u = 0, v = 0;
int y1192 = 0, r = 0, g = 0, b = 0;
for (int j = 0, yp = 0; j < height; j++) {
uvp = frameSize + (j >> 1) * width;
u = 0;
v = 0;
for (i = 0; i < width; i++, yp++) {
y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
y1192 = 1192 * y;
r = (y1192 + 1634 * v);
g = (y1192 - 833 * v - 400 * u);
b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgbBuf[yp * 3] = (byte) (r >> 10);
rgbBuf[yp * 3 + 1] = (byte) (g >> 10);
rgbBuf[yp * 3 + 2] = (byte) (b >> 10);
}
}
}
public static void main(String[] args) {
Frame f = new FlushMe();
}
}


网络上获取了一段RGB格式的byte数组,但是,在android上显示出来,并且不保存在手机上,只是显示一下

 

 

是RBG格式的String吗?原格式?
要是这样的话可以这样
String s1=new String(b);//b就是byte[]
不过一般网上回来的是inputstream,要是inputstream的话,可以用下面的代码
/**
* InputStream转为String
* 
* @param is
* @return
*/
public static String InputStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
} 


 


这篇关于Android拍摄视频流的格式转换(YUV --- RGB) 怎么从网络获取流转换成视频的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/870482

相关文章

[职场] 护理专业简历怎么写 #经验分享#微信

护理专业简历怎么写   很多想成为一名护理方面的从业者,但是又不知道应该怎么制作一份简历,现在这里分享了一份护理方面的简历模板供大家参考。   蓝山山   年龄:24   号码:12345678910   地址:上海市 邮箱:jianli@jianli.com   教育背景   时间:2011-09到2015-06   学校:蓝山大学   专业:护理学   学历:本科

LangChain转换链:让数据处理更精准

1. 转换链的概念 在开发AI Agent(智能体)时,我们经常需要对输入数据进行预处理,这样可以更好地利用LLM。LangChain提供了一个强大的工具——转换链(TransformChain),它可以帮我们轻松实现这一任务。 转换链(TransformChain)主要是将 给定的数据 按照某个函数进行转换,再将 转换后的结果 输出给LLM。 所以转换链的核心是:根据业务逻辑编写合适的转换函

hevc和H.264格式的区别

HEVC(High Efficiency Video Coding)和H.264(也称为Advanced Video Coding,AVC)都是视频压缩标准,但它们之间存在一些显著的区别,主要集中在压缩效率、资源需求和兼容性方面。 压缩效率 HEVC,也被称为H.265,提供了比H.264更高的压缩效率。这意味着在相同的视频质量下,HEVC能够以大约一半的比特率进行编码,从而减少存储空间需求和

【Altium】查找PCB上未连接的网络

【更多软件使用问题请点击亿道电子官方网站】 1、文档目标: PCB设计后期检查中找出没有连接的网络 应用场景:PCB设计后期,需要检查是否所有网络都已连接布线。虽然未连接的网络会有飞线显示,但是由于布线后期整板布线密度较高,虚连,断连的网络用肉眼难以轻易发现。用DRC检查也可以找出未连接的网络,如果PCB中DRC问题较多,查找起来就不是很方便。使用PCB Filter面板来达成目的相比DRC

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

电脑不小心删除的文件怎么恢复?4个必备恢复方法!

“刚刚在对电脑里的某些垃圾文件进行清理时,我一不小心误删了比较重要的数据。这些误删的数据还有机会恢复吗?希望大家帮帮我,非常感谢!” 在这个数字化飞速发展的时代,电脑早已成为我们日常生活和工作中不可或缺的一部分。然而,就像生活中的小插曲一样,有时我们可能会在不经意间犯下一些小错误,比如不小心删除了重要的文件。 当那份文件消失在眼前,仿佛被时间吞噬,我们不禁会心生焦虑。但别担心,就像每个问题

通信系统网络架构_2.广域网网络架构

1.概述          通俗来讲,广域网是将分布于相比局域网络更广区域的计算机设备联接起来的网络。广域网由通信子网于资源子网组成。通信子网可以利用公用分组交换网、卫星通信网和无线分组交换网构建,将分布在不同地区的局域网或计算机系统互连起来,实现资源子网的共享。 2.网络组成          广域网属于多级网络,通常由骨干网、分布网、接入网组成。在网络规模较小时,可仅由骨干网和接入网组成

ABAP怎么把传入的参数刷新到内表里面呢?

1.在执行相关的功能操作之前,优先执行这一段代码,把输入的数据更新入内表里面 DATA: lo_guid TYPE REF TO cl_gui_alv_grid.CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'IMPORTINGe_grid = lo_guid.CALL METHOD lo_guid->check_changed_data.CALL M

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo