WEB/Backend

[Firebase] storage에 비디오 영상 넣고 가져오기 (with flask)

Jerry_K 2024. 5. 25. 23:39

🔍Storage에 비디오 영상 넣고 가져오기 

Firebase에  Realtime base를 이용하여 데이터 넣는 방법은 예전 포스팅에서 한 적이 있다.

(만일 Firebase에 대해 모른다면 아래 포스팅부터 보는 것을 추천한다.)

 

[Python] Firebase 시작하기

🙄 Firebase란 ? 구글이 소유하고 있는 모발일 애플리케이션 개발 플랫폼으로,개발자가 모바일 및 웹 애플리케이션을 모두 쉽게 생성,실행 및 확장 할  수  있도록 한다. (데이터 저장은 NoSQL 문

fishking.tistory.com

 

Realtime base 같은 경우 단순 text 에 적합하지, 영상이나 사진같이 큰 용량의 데이터에는 적합하지 않다.

 

영상이나 사진을 보관하기위해서는 Storage가 적합하고, 해당 저장 링크를 통해 html에 나타내는게 효율적이다.

따라서 이번 포스팅에는 영상을 저장하고, html에 나타내는 부분까지 할 예정이다.


📚 Storage 시작

Realtime base 블로그 포스팅을 봤다는 전제로 한다.

 

 

지난 포스팅에서 만든 프로젝트에서 "Storage" 부분에 들어간다.

 

 

 

 Storage에서 "시작하기"를 누르고, 기본 디폴트 값으로 진행하면 된다.

 

 

 

읽고 쓰기를 자유롭게 하기위해 ,  "규칙"에 들어가서 read와 write를 허용 해준다 (9번 줄 코드처럼 하면 됨)

 

 

 

그 후 "프로젝트 설정"  ->  "서비스 계정"에 들어간 후,

python의 "새 비공개 키 생성"으로 key를 다운받아준다.

 

해당키는 servicekey로 json 형태로 저장되어 비디오 read / wirte에 필수이다.

해당 json 파일은 내 프로젝트 폴더에 잘 저장한다.

(지난 포스팅 realtimebase에서 만든 auth 폴더에 같이 보관하는게 좋음)

 

 


📚 Video Storage Read / Write 

 

📑 Video Storage class 준비

firebase_recode.py 파일을 새호 만들어  class를 만들어 줄 예정이다.  (파일명은 자유롭게 해도 된다.)

 

import firebase_admin
from firebase_admin import credentials, storage
import pyrebase
import json
from datetime import datetime, timedelta
class Storage :
    def __init__(self):
        if not firebase_admin._apps:
            cred = credentials.Certificate("./auth/serviceAccountKey.json")
            firebase_admin.initialize_app(cred, {
              'storageBucket': 'emergencyresponse-b8c54.appspot.com',
              'databaseURL': 'https://emergencyresponse-b8c54-default-rtdb.firebaseio.com/'  # Firebase Realtime Database URL
            })
        
        with open("./auth/firebaseAuth.json") as f:
            config = json.load(f)
        self.firebase = pyrebase.initialize_app(config)
        self.storage = self.firebase.storage()

 

"Firebase Admin SDK"는 서버 사이드에서 Firebase 서비스를 사용하기 위해 Admin SDK를 초기화하고,

다양한 Firebase 기능에 접근 가능

 

"Pyrebase"는 클라이언트 사이드에서 REST API를 사용하여 사용자 인증 및 데이터베이스 작업에 사용

 

해당 코드에서 각각의 initialize_app은 다른 목적으로 사용된다.

Firebase Admin SDK 같은 경우 애플리케이션 당 한 번만 초기화 가능하기 때문에 if 문으로 제어했다.

 

("./auth/serviceAccountKey.json"  이 부분 같은 경우, 아까 "새 비공개 키 생성" 부분에서 저장한 key 경로)

("./auth/firebaseAuth.json"  이 부분 같은 경우, 이전 포스팅에서 저장한 key 경로)

 

 

 

'storageBucket' 부분과 'databaseURL' 부분에서는  Storage에 해당 URL만 복사 붙여 넣으면 되고,

나머지 뒷 부분은 그대로 쓰면 된다.

 

여기까지 했으면, 준비가 다 된 상태이다. 

 

 

📑 Video Storage 에 넣기

def video_save(self) :
    self.storage.child("Video/recode/1.mp4").put("1.mp4","jerry")
    return 0

 

child("저장하고 싶은 경로")

put("저장하려는 파일 경로" , "UID")  형식으로 넣어주면 된다.

 

 

 

Storage 클래스에서 video_save함수를 실행 시키고,

저장된 것을 확인해보면 Video/recode에  원하는 영상이 잘 저장 된 것을 확인 할 수 있다. 

 

 

 

[Python] 비디오 녹화 및 코덱 H.264 변환 (with opencv / flask)

🔍 비디오 녹화 및 코덱 변환지금 캡스톤 프로젝트를 진행하는데, 비디오 녹화 기능이 필요하다.녹화 기능은 한번도 안해봐서 좀 걱정했는데, 다행히 어렵지는 않았다. 비디오 녹화는 opencv 라

fishking.tistory.com

만일 storage에 영상이 잘 재생이 안되면, 바로 위의 포스팅을 참고하자. 

대부분 코덱 변환의 문제이다.

 

 

📑 Storage에서 Video 꺼내오기

 def video_getUrl(self):
    bucket = storage.bucket()
    blobs = bucket.list_blobs(prefix="Video/recode")         
    urls = []
    for blob in blobs:
        url = blob.generate_signed_url(timedelta(seconds=300))  # URL 생성
        urls.append(url)
    return urls

 

storage에 저장된 video를 가져오기위해 url을 통해 가져오는게 효과적이다. 

 

bucket() 함수와 blobs 함수를 통해서 원하는 링크를 가져올 수 있다.

가져온 링크들은 urls 리스트에 넣어주고  urls 리스트를 반환 해준다.

 

 

 

지금 현재 Storage에 저장되어있는 파일은 3개이다. (2개 추가함)

 

 

 

Storage 클래스에서 video_getUrl함수를 실행 시켜보면,

3개 비디오에 대한 url이 뜨는 것을 확인 할 수 있다.

 

 

📚 Storage Video  HTML에 올리기

 

📑 Flask 서버 사이드

영상을 저장하고 꺼내는 것은 할 줄 알게되었다.

이제 Storage에 저장된 영상을 html에 게시하는 것을 해보자.

 

app = Flask( __name__ )
DB = DBModule()
STORAGE = Storage()

@app.route("/")
def index():    
    return render_template("index.html")
    
#-------------------firebase storage -------------------
@app.route('/video-urls', methods=['GET'])
def video_urls():
    urls = STORAGE.video_getUrl()
    return jsonify(urls)

 

flask 서버 기반으로  할 예정이다.  (flask 기초 설명 X / flask 같은 경우 templates 구조 필요)

 

라우팅 할 video_urls 을 GET 형식으로 만들어 주었다. 

해당 url은 video_getUrl에서 전달받은 urls 리스트들을  json형태로 반환해주는게 전부이다.

 

http://192.168.0.20:1500/video-urls

 

사실 서버 사이드 쪽은 이게 전부이다 .

 

📑 Frontend 사이드

<h1>Video Gallery</h1>
<div id="video-gallery">
    <!-- 비디오 썸네일이 여기에 동적으로 추가. -->
</div>
<div class="video-player" id="video-player">
    <video id="video" controls>
        <source id="video-source" src="" type="video/mp4">
        Your browser does not support the video tag.
    </video>
</div>

 

div "id = video-gallery" 태그에서 Strorage의 영상들을 동적으로 담을 예정이다.

 

div "class = video-play" 태그는 선택한 비디오를 재생할 비디오 플레이어이다.  

source 태그에 비디오 url을 설정하고 controls 속성으로 기본 컨트롤을 추가한다.

 

 

<style>
    .video-thumbnail {
        width: 200px;
        height: 150px;
        display: inline-block;
        margin: 10px;
        cursor: pointer;
        background-color: #ccc;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: bold;
    }

    .video-player {
        display: none;
        width: 640px;
        height: 360px;
        margin-top: 20px;
    }
</style>

 

이것은 css적인 요소인데, video-thumbnail과 video-player를 어떤식으로 꾸밀지를 나타냈다.

(video-thumbnail는 Storage와의 통신을 통해서 만들어지는 요소의 class 이다.  (밑에서 나올 예정) )

 

 

  <script>
        // 서버에서 비디오 URL 받아오기
        fetch('/video-urls')
            .then(response => response.json())
            .then(videoUrls => {
                console.log('Fetched video URLs:', videoUrls); // 디버깅용 콘솔 로그
                if (Array.isArray(videoUrls)) { // videoUrls가 배열인지 확인
                    const gallery = document.getElementById('video-gallery');
                    videoUrls.forEach((url, index) => {
                        const thumbnail = document.createElement('div');
                        thumbnail.className = 'video-thumbnail';
                        thumbnail.innerText = `Video ${index + 1}`;
                        thumbnail.addEventListener('click', () => playVideo(url));
                        gallery.appendChild(thumbnail);
                    });
                } else {
                    console.error('Fetched data is not an array:', videoUrls);
                }
            })
            .catch(error => {
                console.error('Error fetching video URLs:', error); // 에러 디버깅용 콘솔 로그
            });

        // 비디오 재생 함수
        function playVideo(url) {
            const videoPlayer = document.getElementById('video-player');
            const video = document.getElementById('video');
            const videoSource = document.getElementById('video-source');
            videoSource.src = url;
            video.load();
            videoPlayer.style.display = 'block';
        }
    </script>

 

그 다음 js적인 요소 설명이다. 

 

우선 fetch 방식으로 비동기적으로 서버와 통신을 한다.  

서버와 통신에 성공하면, 서버에서는 urls (Storage 링크 배열)을 넘겨 준다. ( 위에 내용 참고)

 

if문에서는 배열이 맞는지를 확인하고,

배열이 맞으면, 그 크기만큼 반복문을 돌리고 thumnail을 나타낼 div 요소를 만들어준다.

그리고 class와 innerText 값을 주어주고, 만일 thumnail 이 클릭 된 경우 playVideo 함수를 실행하고,

video-gallery에 해당 요소를 넣어준다.

 

playVideo 함수는 url값을 전달 받고, vidooSource src에 해당 url을 넣어주고, 비디오를 로드하여 재생한다.  

(해당 video-player 요소는 display가 none에서 block 처리됨)

 

 

📌 실행 결과

 

 

이제 내가 만들었던 flask 서버에 접속하고 썸네일을 누르면,

해당 영상이 웹페이지 내에서 잘 재생되고 있는 것을 확인 할 수 있다 .

 

우선 기능은 완성되었고,  디자인은 css로 쿰쩍쿰쩍 잘 하면 될 것이다...!