2016年6月30日 星期四


/drivers/media/video/uvc/uvcvideo.c


/drivers/media/video/uvc/uvc_ctrl.c

line 789:

case VIDIOC_S_FMT:
  {
    800                 struct uvc_streaming_control probe;
    801
    802                 return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
    803         }


加了一些printk... 然後按下 dmesg...  得到這個訊息

 uvcvideo: Failed to set UVC probe control : -110 (exp. 26).


google  uvcvideo: Failed to set UVC probe control : -110 (exp. 26).

這是因為  uvc_v4l2_try_format() 裡面的

 ret = uvc_probe_video(stream, probe);


uvc_video.c  line  300

int uvc_probe_video(struct uvc_streaming *stream,
301         struct uvc_streaming_control *probe)
302 {
303         struct uvc_streaming_control probe_min, probe_max;
304         __u16 bandwidth;
305         unsigned int i;
306         int ret;
307 
308         /* Perform probing. The device should adjust the requested values
309          * according to its capabilities. However, some devices, namely the
310          * first generation UVC Logitech webcams, don't implement the Video
311          * Probe control properly, and just return the needed bandwidth. For
312          * that reason, if the needed bandwidth exceeds the maximum available
313          * bandwidth, try to lower the quality.
314          */
315         ret = uvc_set_video_ctrl(stream, probe, 1);
316         if (ret < 0)
317                 goto done;


然後再呼叫  ret = uvc_set_video_ctrl(stream, probe, 1);


uvc_video.c  line 254 

static int uvc_set_video_ctrl(struct uvc_streaming *stream,
255         struct uvc_streaming_control *ctrl, int probe)
256 {
257         __u8 *data;
258         __u16 size;
259         int ret;
260 
261         size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
262         data = kzalloc(size, GFP_KERNEL);
263         if (data == NULL)
264                 return -ENOMEM;
265 
266         *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
267         data[2] = ctrl->bFormatIndex;
268         data[3] = ctrl->bFrameIndex;
269         *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
270         *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
271         *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
272         *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
273         *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
274         *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
275         put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
276         put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
277 
278         if (size == 34) {
279                 put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
280                 data[30] = ctrl->bmFramingInfo;
281                 data[31] = ctrl->bPreferedVersion;
282                 data[32] = ctrl->bMinVersion;
283                 data[33] = ctrl->bMaxVersion;
284         }
285 
286         ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
287                 probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
288                 size, uvc_timeout_param);
289         if (ret != size) {
290                 uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
291                         "%d (exp. %u).\n", probe ? "probe" : "commit",
292                         ret, size);
293                 ret = -EIO;
294         }
295 
296         kfree(data);
297         return ret;
298 }


就發出 error message....




Logitech webcam not working


苦主的linux 版本是
Uname: Linux 3.5.0-1-generic i686

Joseph Salisbury (jsalisbury) wrote : 回說

Can you test the latest mainline kernel, to see if the bug is already fixed upstream? The latest mainline kernel is available at:
http://kernel.ubuntu.com/~kernel-ppa/mainline/v3.5-rc4-quantal/
You will need to install both the linux-image and linux-image-extra .deb packages.
Thanks in advance!
Changed in linux (Ubuntu):
importance:Undecided → Medium
tags:added: kernel-da-key
Changed in linux (Ubuntu):
status:New → Confirmed


目前的linux kernel 版本是  3.0.15
Linux localhost 3.0.15-Dmatek #202 SMP PREEMPT Fri Jul 1 13:28:07 CST 2016 armv7l GNU/Linux


usb wem cam flow-chart 筆記



step 1:  startCamera

進入點:   WebcamManager  的 onCreate()   :    WebcamManager.cpp


public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service starting");
      mWebcam = new NativeWebcam("/dev/video4");
     }

====================================================
NativeWebcam 建構子  就會呼叫    connect()    :  NativeWebcam .cpp


 public NativeWebcam(String deviceName, int width, int height) {
        mWidth = width;
        mHeight = height;
        mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
        connect(deviceName, mWidth, mHeight);
    }


NativeWebcam   的 connect() check "/dev/video4" ok後會呼叫   startCamera()

private void connect(String deviceName, int width, int height) {
        boolean deviceReady = true;

        File deviceFile = new File(deviceName);
        if(deviceFile.exists()) {
            if(!deviceFile.canRead()) {
                Log.d(TAG, "Insufficient permissions on " + deviceName +
                        " -- does the app have the CAMERA permission?");
                deviceReady = false;
            }
        } else {
            Log.w(TAG, deviceName + " does not exist");
            deviceReady = false;
        }

        if(deviceReady) {
            Log.i(TAG, "Preparing camera with device name " + deviceName);
            startCamera(deviceName, width, height);
            
        //    controlBrightnessContrass(10, 10 );
        }
    }

又    startCamera 的實作在   webcam.c 裡面...透過jni 的方式連結上來

 private native int startCamera(String deviceName, int width, int height);

check webcam.c

Java_com_example_robortbead_Bead_startCamera():

step 1 : 呼叫  open_device()
int result = open_device(dev_name, &DEVICE_DESCRIPTOR);

step 2: 呼叫  init_device()

result = init_device(DEVICE_DESCRIPTOR, width, height);

step 3: 呼叫 start_capture()

result = start_capture(DEVICE_DESCRIPTOR);


Step 2:   getFrame

      呼叫   WebcamManager   的  getFrame()

      首先會先呼叫    mWebcam.isAttached() cehck

     然後  mWebcam.getFrame();

     public Bitmap getFrame() {
        if(!mWebcam.isAttached()) {
            stopSelf();
        }
        Bitmap bmp = mWebcam.getFrame();

      return bmp ;
     }
  ---------------------------------------------------------------
   mWebcam 的  isAttached function :

     public boolean isAttached() {
        return cameraAttached();
    }

   又  cameraAttached 是 jni 的 c code

    private native boolean cameraAttached();

   cameraAttached() 的實作相當簡單..只需要查看剛剛開的file 是不是NULL 即可

jboolean Java_com_example_robortbead_Bead_cameraAttached(JNIEnv* env,
        jobject thiz) {
    return DEVICE_DESCRIPTOR != -1;
}

-----------------------------------------------------------------
 再回來看    mWebcam.getFrame();

  其實就是call  loadNextFrame(mBitmap);

   public Bitmap getFrame() {
        loadNextFrame(mBitmap);
        return mBitmap;
    }

  又 loadNextFrame 是jni 的 c code....

  private native void loadNextFrame(Bitmap bitmap);

  step 1:        先得到  bmp file header
 if((result = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed, error=%d", result);
        return;
    }

    如果不是   RGBA888 就return... 也就是傳進來的BMP 一定要是 RGBA8888
if(info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888 !");
        return;
    }
   
  step 2:        配置 bmp color buffer 的記憶體,   得到 colors array

  int* colors;
    if((result = AndroidBitmap_lockPixels(env, bitmap, (void*)&colors)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed, error=%d", result);
    }

   

    if(!RGB_BUFFER || !Y_BUFFER) {
        LOGE("Unable to load frame, buffers not initialized");
        return;
    }

step 3:  呼叫   process_camera() 

  process_camera(DEVICE_DESCRIPTOR, FRAME_BUFFERS, info.width, info.height,
            RGB_BUFFER, Y_BUFFER);

   //  把RGB_BUFFER 的data copy 到  colors array
    int *lrgb = &RGB_BUFFER[0];
    int i;
    //for(int i = 0; i < info.width * info.height; i++) {
    for(i = 0; i < info.width * info.height; i++) {
        *colors++ = *lrgb++;
    }

    //   release  temp buffer
    AndroidBitmap_unlockPixels(env, bitmap);

  接下來看   process_camera()     :   capture.c

     利用select function 去 check status
    當 result 為 -1...  繼續讀
    當 result 為 0...  time out ...繼續讀
    則代表正常...可以抓資料了

   

  for(;;) {
        fd_set fds;
        FD_ZERO(&fds);
        FD_SET(fd, &fds);

        struct timeval tv;
        tv.tv_sec = 2;
        tv.tv_usec = 0;

        int result = select(fd + 1, &fds, NULL, NULL, &tv);
        if(-1 == result) {
            if(EINTR == errno) {
                continue;
            }
            errnoexit("select");
        } else if(0 == result) {
            LOGE("select timeout");
        }

   if(read_frame(fd, frame_buffers, width, height, rgb_buffer, ybuf) == 1) {
            break;   // 跳出迴圈
        }

   接下來看   read_frame()

   一開始先用   xioctl(fd, VIDIOC_DQBUF, &buf)  把資料抓到   buf array
 
   然後呼叫   yuyv422_to_argb()  把 buf 從 yuyv 轉成rb 存放在 rgb_buffer

  最後再呼叫    xioctl(fd, VIDIOC_QBUF, &buf) 去release buf

int read_frame(int fd, buffer* frame_buffers, int width, int height,
        int* rgb_buffer, int* y_buffer)
  struct v4l2_buffer buf;
    CLEAR(buf);
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;

    if(-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
        switch(errno) {
            case EAGAIN:
                return 0;
            case EIO:
            default:
                return errnoexit("VIDIOC_DQBUF");
        }
    }

    assert(buf.index < BUFFER_COUNT);
    yuyv422_to_argb(frame_buffers[buf.index].start, width, height, rgb_buffer,
            y_buffer);

    if(-1 == xioctl(fd, VIDIOC_QBUF, &buf)) {
        return errnoexit("VIDIOC_QBUF");
    }

Step 3:  stopCamera


2016年6月29日 星期三

eclipse + ndk




Ref : https://magiclen.org/android-jni/

android imageview



再來是layout/main.xml
新增三個ImageView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:maxHeight="100dp"
        android:maxWidth="100dp"
        android:src="@drawable/ie" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:maxHeight="100dp"
        android:maxWidth="100dp"
        android:layout_below="@+id/imageView1"
        android:layout_marginTop="10dp" />

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:maxHeight="100dp"
        android:maxWidth="100dp"
        android:layout_below="@+id/imageView2"
        android:layout_marginTop="10dp" />

</RelativeLayout>


【第二種方式】
利用ImageView類別的方法
將res/drawable 中的圖片載入

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViews();
        secondImage.setImageResource(R.drawable.firefox);    
    }
    
    private ImageView secondImage;
    
    private void findViews() {
        secondImage = (ImageView) findViewById(R.id.imageView2);
    }
}


Ref : http://seanstar5317.pixnet.net/blog/post/29305261-%5Bandroid%5D%E5%88%A9%E7%94%A8imageview-%E5%9C%A8%E7%95%AB%E9%9D%A2%E4%B8%8A%E9%A1%AF%E7%A4%BA%E5%9C%96%E7%89%87

Android 執行序 Runnable 和 Handler


Ref :  http://andcooker.blogspot.tw/2012/09/android-runnable-handler.html


Android 執行緒 - Runnable 與 Handler

Android 提供了很多執行緒的方法,在本部落格中也可以參考 Thread 與 AsyncTask,在不同的情境我們可以使用不同的方法,此篇我們介紹 Handler 如何操作 Runnable。將  Handler 想像為處理器,而 Runnable 為被處理的事件,所以一個處理器可以處理很多事件,那大略架構就會樣是:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MainActivity extends Activity {
    Handler mHandler;
    TextView txtCount;
  
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         
        txtCount = (TextView) findViewById(R.id.txtCount);
         
        mHandler = new Handler();
        mHandler.post(runnable);
    }
     
    final Runnable runnable = new Runnable() {
        public void run() {
            // TODO Auto-generated method stub
            // 需要背景作的事
                  }
    };
}
接下來,一樣設計數到十的背景程序,但我們會有兩種作法,先看第一種作法,我們只執行一次 Runnable,利用 for 迴圈來達成: 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
final Runnable runnable = new Runnable() {
    public void run() {
        // TODO Auto-generated method stub
        // 需要背景作的事
                  try {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
     }
};
另一種是,不斷的調用 Runnable 但使用 postDelayed(runnable, 1000),每次都延後一秒來作,如此一來,作完十次不就是數完十秒了!
?
1
2
3
4
5
6
7
8
9
10
11
int count = 0;
final Runnable runnable = new Runnable() {
    public void run() {
        // TODO Auto-generated method stub
        // 需要背景作的事
                   if (count < 10) {
            count++;
            mHandler.postDelayed(runnable, 1000);
        }
    }
};
但是與 Thread 不同的是,我們可以在 Runnble 直接更新介面,所以可以直接寫成:
?
1
2
3
4
5
6
7
8
9
10
11
12
int count = 0;
final Runnable runnable = new Runnable() {
    public void run() {
        // TODO Auto-generated method stub
        // 需要背景作的事
                  if (count < 10) {
            txtCount.setText(Integer.toString(count+1));
            count++;
            mHandler.postDelayed(runnable, 1000);
        }
    }
};
我們仍然要妥善管理,所以在 Activity 被結束時,也請 Handler 把 Runnable 給停掉:
?
1
2
3
4
5
6
7
8
@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if (mHandler != null) {
        mHandler.removeCallbacks(runnable);
    }
}