USB摄像头视频相关ffmpeg,rtp,mjpg-streamer
一个哥们的思路,不错,值得参考:http://blog.csdn.net/sg131971/article/details/6932237
但觉得移植apche太大了,lite http比较适合。
http://blog.csdn.net/sg131971/article/details/6932742
Mini2440Activity.java
package sg131971.mini2440; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; public class Mini2440Activity extends Activity { private static int Connect_flag = 0; private static int AutoRefresh_flag = 0; private static int LED_flag[] = new int[4]; private Bitmap m_Bitmap; private ImageView myImageView; private Handler m_Handler = new Handler(); private String Board_IP; private EditText myEditText; private Button myButtonConnect; private Button myButton0; private Button myButton1; private Button myButton2; private Button myButton3; private Button myButtonStatus; private Button autoButton; private Button manualButton; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); myEditText = (EditText) findViewById(R.id.editText); myButtonConnect = (Button) findViewById(R.id.myButtonConnect); myButtonConnect.setOnClickListener(new ConnectListener()); myImageView = (ImageView) findViewById(R.id.imageView); autoButton = (Button) findViewById(R.id.autoButton); manualButton = (Button) findViewById(R.id.manualButton); myButton0 = (Button) findViewById(R.id.myButton0); myButton1 = (Button) findViewById(R.id.myButton1); myButton2 = (Button) findViewById(R.id.myButton2); myButton3 = (Button) findViewById(R.id.myButton3); myButtonStatus = (Button) findViewById(R.id.myButtonStatus); StopService(); } public boolean onKeyDown(int keyCode, KeyEvent msg) { if (keyCode == KeyEvent.KEYCODE_BACK) { finish(); System.exit(0); } return false; } private void StartService() { // TODO Auto-generated method stub m_Handler.postDelayed(m_RefreshImage, 0); myButton0.setOnClickListener(new LED0Listener()); myButton1.setOnClickListener(new LED1Listener()); myButton2.setOnClickListener(new LED2Listener()); myButton3.setOnClickListener(new LED3Listener()); myButtonStatus.setOnClickListener(new StatusListener()); autoButton.setOnClickListener(new AutoRefresh()); manualButton.setOnClickListener(new ManualRefresh()); } private void StopService() { // TODO Auto-generated method stub m_Handler.removeCallbacks(m_RefreshImage); myImageView.setImageResource(R.drawable.first); myButton0.setOnClickListener(new DefaultListener()); myButton1.setOnClickListener(new DefaultListener()); myButton2.setOnClickListener(new DefaultListener()); myButton3.setOnClickListener(new DefaultListener()); myButtonStatus.setOnClickListener(new DefaultListener()); autoButton.setOnClickListener(new DefaultListener()); manualButton.setOnClickListener(new DefaultListener()); } public class ConnectListener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub Board_IP = myEditText.getText().toString(); if (Connect_flag == 0) { Connect_flag = 1; StartService(); myButtonConnect.setText("Disconnect"); showMessage("已连接:" + Board_IP); } else { Connect_flag = 0; AutoRefresh_flag = 0; StopService(); myButtonConnect.setText("Connect"); showMessage("已断开:" + Board_IP); } } } public class DefaultListener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub showMessage("请先连接ARM板!"); } } public class ManualRefresh implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub if (AutoRefresh_flag == 1) AutoRefresh_flag = 0; m_Handler.postDelayed(m_RefreshImage, 0); showMessage("手动刷新成功!"); } } public class AutoRefresh implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub if (AutoRefresh_flag == 0) AutoRefresh_flag = 1; m_Handler.postDelayed(m_RefreshImage, 0); showMessage("自动刷新设置成功!"); } } private Runnable m_RefreshImage = new Runnable() { public void run() { // TODO Auto-generated method stub RefreshImage(); if (AutoRefresh_flag == 1) m_Handler.postDelayed(m_RefreshImage, 100); else m_Handler.removeCallbacks(m_RefreshImage); } private void RefreshImage() { // TODO Auto-generated method stub try { URL m_URL = new URL("http://" + Board_IP + ":8080/?action=snapshot"); URLConnection m_URL_Connection = m_URL.openConnection(); m_URL_Connection.connect(); InputStream m_InputStream = m_URL_Connection.getInputStream(); m_Bitmap = BitmapFactory.decodeStream(m_InputStream); myImageView.setImageBitmap(m_Bitmap); m_InputStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; public class LED0Listener implements OnClickListener { public void onClick(View arg0) { // TODO Auto-generated method stub LED_flag[0]++; if (LED_flag[0] % 2 == 1) { HttpSendCmd("58400F01"); showMessage("LED0已打开!"); } else { HttpSendCmd("58400F00"); showMessage("LED0已关闭!"); } } } public class LED1Listener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub LED_flag[1]++; if (LED_flag[1] % 2 == 1) { HttpSendCmd("58401F01"); showMessage("LED1已打开!"); } else { HttpSendCmd("58401F00"); showMessage("LED1已关闭!"); } } } public class LED2Listener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub LED_flag[2]++; if (LED_flag[2] % 2 == 1) { HttpSendCmd("58402F01"); showMessage("LED2已打开!"); } else { HttpSendCmd("58402F00"); showMessage("LED2已关闭!"); } } } public class LED3Listener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub LED_flag[3]++; if (LED_flag[3] % 2 == 1) { HttpSendCmd("58403F01"); showMessage("LED3已打开!"); } else { HttpSendCmd("58403F00"); showMessage("LED3已关闭!"); } } } public class StatusListener implements OnClickListener { public void onClick(View v) { // TODO Auto-generated method stub String display_info = ""; // 以后此处可以通过发送http请求查询硬件状态 HttpSendCmd("5840FFFF"); if (LED_flag[0] % 2 == 1) display_info += "LED0:开"; else display_info += "LED0:关"; display_info += " "; if (LED_flag[1] % 2 == 1) display_info += "LED1:开"; else display_info += "LED1:关"; display_info += " "; if (LED_flag[2] % 2 == 1) display_info += "LED2:开"; else display_info += "LED2:关"; display_info += " "; if (LED_flag[3] % 2 == 1) display_info += "LED3:开"; else display_info += "LED3:关"; showMessage(display_info); } } public void HttpSendCmd(String cmd) { // TODO Auto-generated method stub HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost("http://" + Board_IP + "/mjpg-streamer/post_data.php"); try { List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3); nameValuePairs.add(new BasicNameValuePair("user", "root")); nameValuePairs.add(new BasicNameValuePair("passwd", "shiguang")); nameValuePairs.add(new BasicNameValuePair("para", cmd)); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); HttpResponse response = httpclient.execute(httppost); String tmpString = EntityUtils.toString(response.getEntity()); System.out.println(tmpString); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void showMessage(String str) { Toast toast = Toast.makeText(this, str, Toast.LENGTH_SHORT); toast.setGravity(Gravity.TOP, 0, 550); toast.show(); } }
最终效果图:
/nfsroot/rootfs/usr/local/apache_arm/htdocs/mjpg-streamer/post_data.php
<?php @header("content-type:text/html; charset=utf-8"); error_reporting(E_ALL); set_time_limit(0); $user = $_REQUEST['user']; $passed = $_REQUEST['passwd']; $para = $_REQUEST['para']; $service_port = 9090; $address = "192.168.1.97"; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket < 0) { echo "socket_create() failed: reason: " . socket_strerror($socket) . "\n"; } $result = socket_connect($socket, $address, $service_port); if ($result < 0) { echo "socket_connect() failed: reason: " . socket_strerror($result) . "\n"; } $in = $user . $passed . $para; $result = socket_write($socket, $in, strlen($in)) ; if(!$result) { echo "socket_write() failed: reason: " . socket_strerror($socket) . "\n"; } /* while($out = socket_read($socket,256)) { echo $out; break; } */ socket_close($socket); ?>手机端控制测试:
OK!
现在,基本通路已经打通,剩下的就是简单的指令转换和设备控制了!
转一篇文章:http://blog.csdn.net/acanoe/article/details/7572836
USB 设备,是我刚刚开始学习的,完全搞不懂,玩这个USB摄像头淘宝上买的杂牌子,我在xp 下测试了一下,只能保证芯片是芯片是ZC0301PL。 其它都未知。
现在开始正文:( 博文来自CSDN Acanoe 的博客:http://blog.csdn.net/ACanoe
我的操作环境是、主机:xp + VMware ubuntu 10.10 。 开发板:OK6410 A板。 使用内核:Linux 2.6.36.2 。 使用软件: mjpg-streamer
1、配置内核支持 中微星的 ZC3XX 摄像头。
Device Drivers ->
Multimedia devices->
<*>video for linux
[*]video capture adapters->
[*]V4l USB devices ->
<*>USB video class (UVC)
[*] UVC input events device support
<*>GSPCA based webcams ->
<*>ZC3XX USB Camera Driver
配置好了以后编译内核,下载到开发板。
2、查看USB 摄像头接入开发板的打印信息,当然你的开发板首先需要先支持 USB-Host 。我的开发板串口打印信息是:
[root@FORLINX6410]# usb 1-1: new full speed USB device using s3c2410-ohci and ad
dress 4
usb 1-1: New USB device found, idVendor=0ac8, idProduct=301b
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1: Product: PC Camera
usb 1-1: Manufacturer: Vimicro Corp.
gspca: probing 0ac8:301b
zc3xx: probe sensor -> 000a
zc3xx: Find Sensor PB0330. Chip revision 0
input: zc3xx as /class/input/input2
gspca: video0 created
[root@FORLINX6410]#
释放 USB 摄像头 的打印信息是:
[root@FORLINX6410]# usb 1-1: USB disconnect, address 4
gspca: video0 disconnect
gspca: video0 released
[root@FORLINX6410]#
3、编译安装:mjpg-streamer
移植参考了百度文库的
一、环境
主机环境 :ubuntu 10.10
目标机 :FS2410(S3C2410)
主机工具链 :gcc-4.4.5
交叉工具链 :arm-none-linux-gnueabi-gcc-4.3.2
摄像头 :ZC301
二、移植过程
1、配置内核是内核支持芯片为ZC301的摄像头
Make menuconfig
Device Drivers --->
<*> Multimedia support --->
<*> Video For Linux
[*] Enable Video For Linux API 1 (DEPRECATED) (NEW)
[*] Video capture adapters (NEW) --->
[*] V4L USB devices (NEW) --->
<*> USB Video Class (UVC)
[*] UVC input events device support (NEW)
<*> USB ZC0301[P] webcam support (DEPRECATED)
2、重新编译内核
make zImage
通过上面两个步骤就可以驱动我们的摄像头了。但是这个驱动是基于V4l2的。以前基于 V4L的一些上层应用就不能用了,或需要做大量的修改!这里我们要实现网络视频的功能,以前都是用servfox这个网络视频服务器,但是这个服务器就是 基于V4L的,我们如果想用的话就得对servfox的源码进行修改。这里我们选用另外一种方案mjpg-stream。
3、mjpg-stream的移植
关于mjpg-stream的资料大家可以在下面这个网址查看:http://sourceforge.net/apps/mediawiki/mjpg-streamer/index.php?title=Main_Page
mjpg-stream的移植需要jpeg的库,所以我们先移植jpeg的库
(1)jpeg库的移植
1)jpeg源码包通过下面这个网址下载
http://www.ijg.org/files/jpegsrc.v8b.tar.gz
2)解压源码包
tar xvf jpegsrc.v8b.tar.gz
3)配置源码
cd jpeg-8b
./configure --prefix=/home/linux/s3c2410-2.6.35/video/jpeg --host=arm-none-linux-gnueabi
4)编译
make
5)安装
make install
6)拷贝库到文件系统中
cp //home/linux/s3c2410-2.6.35/video/jpeg /lib/libjpeg.so.8 /source/rootfs/lib
(2)mjpg-stream的移植
1)mjpg-stream源码包通过下面这个网址下载
http://sourceforge.net/projects/mjpg-streamer/
2)解压源码
tar xvf mjpg-streamer-r63.tar.gz
3)修改源码
cd mjpg-streamer-r63
修改顶层makefile及plugins目录中的各级makefile将所有
CC=gcc
修改为
CC=arm-none-linux-gnueabi-gcc
修改plugins/input_uvc/Makfile
修改
CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC
为
CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC -I/home/linux/s3c2410-2.6.35/video/jpeg/include
修改
$(CC) $(CFLAGS) -ljpeg -o $@ input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo
为
$(CC) $(CFLAGS) -ljpeg -L/home/linux/s3c2410-2.6.35/video/jpeg/lib -o $@ input_uvc.c v4l2uvc.lo jpeg_utils.lo dynctrl.lo
jpeg_utils.c:27: fatal error: jpeglib.h: No such file or directory
4)编译
make
5)测试
mkdir /source/rootfs/mjpg
cp *.so /source/rootfs/mjpg
cp mjpg-stream /source/rootfs/bin
打开开开发板运行
mjpg_streamer -i "/mjpg/input_uvc.so" -o "/mjpg/output_http.so -w /www"
在源码目录下有start.sh,这个脚本里有一些mjpg-stream的使用方法及说明
打开一个网页输入下面地址就能够看到一个视频(开发板的IP为192.168.1.202):
http://192.168.1.202:8080/?action=stream
打开一个网页输入下面地址就能够看到一个静态图片:
http://192.168.1.202:8080/?action=snapshot
6)在mjpg源码下有一个www的目录,这个一个网络使用mjpg的实例,结合web服务器(boa)可以实现一些其他相关功能。
http://blog.csdn.net/wavemcu/article/details/7795561
FFMPEG库裁剪
经过长期模式,测试,可以用以下方法缩小,在configure的时候加上类似如下的参数:
--disable-encoders --disable-decoders --enable-decoder=h264
解释
--disable-encoders 屏蔽所有编码器
--disable-decoders 屏蔽所有解码器
--enable-decoder=h264 启用h264解码器
由上面可以看出编码器也可以先屏蔽所有编码器,再启用某些编码器。
这样编译出来的 avcodec.dll就会变成 700多K左右,另外几个 avutil.dll、swscale.dll 等等,大小
不会变。它们也没有多大。