๊ธ€ ์ž‘์„ฑ์ž: ์ด์ง€์›๐ŸŒฉ๏ธ

๐Ÿ’ก ์ดˆ๊ธฐ ์„ค์ •(OS ์„ค์น˜, ์„ค์ • ๋“ฑ)์€ ๋˜์–ด ์žˆ๋‹ค๋Š” ๊ฐ€์ • ํ•˜์— ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

์ค€๋น„๋ฌผ

  1. ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด3 B+
  2. ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ํ˜ธํ™˜ ์นด๋ฉ”๋ผ ๋ชจ๋“ˆ (5MP ์‚ฌ์šฉ)
  3. Android Studio
  4. (์„ ํƒ) ํ…Œ์ŠคํŠธ ๊ธฐ๊ธฐ

 

๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ์นด๋ฉ”๋ผ ์„ค์ •


pi@raspberrypi:~ $ sudo raspi-config

5 Interfacing Options ์„ ํƒ

P1 Camera > enable ๋กœ ์„ค์ •ํ–ˆ๋‹ค๋ฉด ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด๋ฅผ ์žฌ๋ถ€ํŒ…ํ•œ๋‹ค.

pi@raspberrypi:~ $ sudo reboot

์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ์ด ์ œ๋Œ€๋กœ ๋˜์–ด์žˆ๋Š” ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

pi@raspberrypi:~ $ vcgencmd get_camera

# ์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ๋ถˆ๋Ÿ‰
supported=1 detected=0 

# ์นด๋ฉ”๋ผ ์—ฐ๊ฒฐ ์„ฑ๊ณต
supported=1 detected=1

์นด๋ฉ”๋ผ๋ฅผ ํ†ตํ•ด ์‚ฌ์ง„์„ ์ฐ์œผ๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ˜„์žฌ ํ„ฐ๋ฏธ๋„์ด ์œ„์น˜ํ•œ ๊ฒฝ๋กœ์— screen.jpg ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์บก์ณ๋ฅผ ํ•œ๋‹ค.

pi@raspberrypi:~ $ raspistill -o screen.jpg

์นด๋ฉ”๋ผ๊ฐ€ ์ •์ƒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค. ์ด์ œ mjpg-streamer ๋ฅผ ์ด์šฉํ•ด ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด์— ์—ฐ๊ฒฐ๋œ ์นด๋ฉ”๋ผ ์˜์ƒ์„ ์›น์—์„œ ์ŠคํŠธ๋ฆฌ๋ฐํ•  ๊ฒƒ์ด๋‹ค.

 

mjpg-streamer ์„ค์ •


๋จผ์ € mjpg-streamer ๋ฅผ ์„ค์น˜ํ•˜๊ธฐ ์œ„ํ•ด git ์„ ์„ค์น˜ํ•ด์•ผํ•œ๋‹ค.

pi@raspberrypi:~ $ sudo apt-get install git

pi@raspberrypi:~ $ git clone https://github.com/jacksonliam/mjpg-streamer.git

pi@raspberrypi:~ $ sudo apt-get install cmake python-pil libjpeg-dev build-essential

โ“ ๋Œ€๋ถ€๋ถ„์˜ ๋ธ”๋กœ๊ทธ์—์„œ๋Š” python-imaging ์„ ์„ค์น˜ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋˜‘๊ฐ™์ด ๋”ฐ๋ผ์„œ ํ•ด๋ดค๋Š”๋ฐ python-pil ๋กœ ๋Œ€์ฒด๋˜์–ด์„œ ์„ค์น˜๊ฐ€ ์•ˆ๋œ๋‹ค๋Š” ๋ฌธ๊ตฌ๊ฐ€ ๋–ด๋‹ค. ๋‹นํ™ฉํ•˜์ง€ ๋ง๊ณ  python-pil๋กœ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค.

 

ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์ „๋ถ€ ๋‹ค์šด ๋ฐ›์•˜๋‹ค๋ฉด mjpg-streamer๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

pi@raspberrypi:~ $ cd mjpg-streamer/mjpg-streamer-experimental

pi@raspberrypi:~/mjpg-streamer/mjpg-streamer-experimental $ make

pi@raspberrypi:~ $ sudo make install

ํ™ˆ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋Œ์•„๊ฐ€ ๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค๋ฉด

http://localhost:8090 ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (ํ˜น์€ localhost ๋Œ€์‹  ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ์•„์ดํ”ผ๋กœ ์ ‘์†)

pi@raspberrypi:~ $ mjpg_streamer -i "input_raspicam.so -vf" -o "output_http.so -p 8090 -w /usr/local/share/mjpg-streamer/www/"

์ฐธ๊ณ : https://webnautes.tistory.com/1261

์—ฌ๊ธฐ๊นŒ์ง€ ๋˜์—ˆ๋‹ค๋ฉด ์ด์ œ ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ WebView๋ฅผ ํ†ตํ•ด ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด๋ฅผ CCTV๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์•ˆ๋“œ๋กœ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ


in Android Studio

  1. ์ƒˆ๋กœ์šด ์•กํ‹ฐ๋น„ํ‹ฐ ์ƒ์„ฑ
  2. Empty Activity๋ฅผ ์„ ํƒ (CameraActivity)
  3. activity_camera.xml์— WebView๋ฅผ ์ถ”๊ฐ€
  4. CameraActivity.java์— ์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€
  5. ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ์•„์ดํ”ผ ์ž‘์„ฑ
     import androidx.appcompat.app.AppCompatActivity;
    
     import android.os.Bundle;
     import android.webkit.WebSettings;
     import android.webkit.WebView;
     import android.webkit.WebViewClient;
    
     public class CameraActivity extends AppCompatActivity {
    
         private WebView mWebView; // ์›น๋ทฐ ์„ ์–ธ
         private WebSettings mWebSettings; //์›น๋ทฐ์„ธํŒ…
    
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_camera);
    
             mWebView = (WebView) findViewById(R.id.webView);
    
             mWebView.setWebViewClient(new WebViewClient()); // ํด๋ฆญ์‹œ ์ƒˆ์ฐฝ ์•ˆ๋œจ๊ฒŒ
             mWebSettings = mWebView.getSettings(); //์„ธ๋ถ€ ์„ธํŒ… ๋“ฑ๋ก
             mWebSettings.setJavaScriptEnabled(true); // ์›นํŽ˜์ด์ง€ ์ž๋ฐ”์Šคํด๋น„ํŠธ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setSupportMultipleWindows(false); // ์ƒˆ์ฐฝ ๋„์šฐ๊ธฐ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setJavaScriptCanOpenWindowsAutomatically(false); // ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ƒˆ์ฐฝ ๋„์šฐ๊ธฐ(๋ฉ€ํ‹ฐ๋ทฐ) ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setLoadWithOverviewMode(true); // ๋ฉ”ํƒ€ํƒœ๊ทธ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setUseWideViewPort(true); // ํ™”๋ฉด ์‚ฌ์ด์ฆˆ ๋งž์ถ”๊ธฐ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setSupportZoom(false); // ํ™”๋ฉด ์คŒ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setBuiltInZoomControls(false); // ํ™”๋ฉด ํ™•๋Œ€ ์ถ•์†Œ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); // ์ปจํ…์ธ  ์‚ฌ์ด์ฆˆ ๋งž์ถ”๊ธฐ
             mWebSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); // ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ํ—ˆ์šฉ ์—ฌ๋ถ€
             mWebSettings.setDomStorageEnabled(true); // ๋กœ์ปฌ์ €์žฅ์†Œ ํ—ˆ์šฉ ์—ฌ๋ถ€
    
             mWebView.loadUrl("http://localhost:8090/?action=stream"); // ์›น๋ทฐ์— ํ‘œ์‹œํ•  ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด ์ฃผ์†Œ, ์›น๋ทฐ ์‹œ์ž‘
         }
     }
    ์ถœ์ฒ˜: https://web-inf.tistory.com/34
  6. ์™ธ๋ถ€์—์„œ(๋™์ผํ•œ ์ธํ„ฐ๋„ท์ด ์•„๋‹Œ ๊ฒฝ์šฐ) ๋ณด๋ ค๋ฉด ๋ผ์ฆˆ๋ฒ ๋ฆฌํŒŒ์ด์— ๊ณ ์ •IP๋ฅผ ํ• ๋‹นํ•ด์ฃผ๊ณ  ์•„๋ž˜ ์ฝ”๋“œ ๊ฐ€์žฅ ํ•˜๋‹จ์— localhost ๋Œ€์‹  ์™ธ๋ถ€IP๋ฅผ ๊ธฐ์ž…ํ•˜๋ฉด ๋œ๋‹ค.

ํฌ๊ฒŒ ๊ฑด๋“ค์ผ ๊ฒŒ ์—†๋Š” ์„ธํŒ…์ด๋ผ ๊ทธ๋ƒฅ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ ์•ˆ๋“œ๋กœ์ด๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ†ตํ•ด ์ธํ„ฐ๋„ท์„ ์ ‘์†ํ•˜๋ ค๋ฉด Manifest ํŒŒ์ผ์—์„œ ๊ถŒํ•œ์„ ์š”์ฒญํ•ด์•ผํ•œ๋‹ค. Manifest ํŒŒ์ผ์„ ์—ด์–ด ๋‹ค์Œ์˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ž.

 

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.INTERNET" />

 

-

์ž‘๋…„์— ๋…ธ์…˜์œผ๋กœ ์ž‘์„ฑํ–ˆ๋˜ ๋ฌธ์„œ๋ฅผ ๋ธ”๋กœ๊ทธ๋กœ ์˜ฎ๊น€.

๋ฐ˜์‘ํ˜•