sql >> データベース >  >> RDS >> SQLite

ビデオコンテンツをSQLiteデータベース(ビデオパスではなく)に保存する方法

    ビデオをsqliteデータベースに保存したい。 P.S.パスではなく実際のビデオコンテンツを保存したい。

    ビデオが非常に短く、スペースをほとんどとらない場合(たとえば、それぞれ最大200k、おそらく1/10秒ですが、保存されている形式によって異なります)、問題や例外/クラッシュが発生する可能性があります。

    >
    • 電話を使用すると、約2秒の黒が2.2Mbを消費し、実際にビデオを録画する2秒は7Mbを消費しました。

    SQLiteには、次のように比較的大きなBLOBを格納する機能があります:-

    • 文字列またはBLOBの最大長

      SQLiteの文字列またはBLOBの最大バイト数は、プリプロセッサマクロSQLITE_MAX_LENGTHによって定義されます。 thismacroのデフォルト値は10億(1億または10億)です。次のようなコマンドラインオプションを使用して、コンパイル時にこの値を増減できます。

      -DSQLITE_MAX_LENGTH =123456789現在の実装は、231-1または2147483647までの文字列またはBLOBの長さのみをサポートします。また、hex()などの一部の組み込み関数は、その時点よりかなり前に失敗する可能性があります。セキュリティに敏感なアプリケーションでは、文字列とBLOBの最大長を増やそうとしないことをお勧めします。実際、可能であれば、文字列とBLOBの最大長を数百万の範囲に下げるとよいでしょう。

      SQLiteのINSERTおよびSELECT処理の一部で、データベースの各行の完全なコンテンツが単一のBLOBとしてエンコードされます。したがって、SQLITE_MAX_LENGTHパラメータは、行の最大バイト数も決定します。

      最大文字列またはBLOBの長さは、sqlite3_limit(db、SQLITE_LIMIT_LENGTH、size)インターフェイスを使用して実行時に減らすことができます。SQLiteの制限

    AndroidSDKのCursorWindow 2Mbの制限があり、これは、バッファの場合、行のすべての列に適用されます。そのため、動画を正常に保存できたとしても、それらの動画を取得できない場合があります。

    推奨される方法は、ビデオへのパスを保存することです。

    ビデオを内部/外部ストレージに保存し、代わりにパスを保存した場合、他のデバイスから同じものにアクセスするにはどうすればよいですか。

    データベースでも同じ問題が発生します 通常、保護されているアプリケーションデータ内に保存されるためです。これは、データベースが既存のデータベースである(つまり、データが入力されている)場合を除きます。この場合、データベースはAPKを介してアプリとともに配布されます。

    後者の場合、APKを介して配布される既存のデータベースの場合、ビデオはAPKの一部として配布することもできるため、データベースと同じように保護され、公開可能です。

    APKの一部ではないデバイス間でビデオを配信することを意図している場合、SQliteは組み込みデータベースであり、クライアント/サーバー機能が組み込まれていないため、おそらく正しいソリューションではありません。

    デバイスがフォーマットされると、すべてのデータが失われます。

    このようなシナリオでは、データベースは他のデータと同じくらい脆弱になります 、データベースはすべて、ビデオやワードドキュメントなどのファイルであり、コンテンツを表示/変更するには適切なアプリケーションが必要です。ただし、データベースが既存のデータベースである場合は、アプリを再インストールするだけで、データベースとその他のファイルがAPKから復元されます。

    実例

    これは、動画がAPKと一緒に配信されることを前提として、推奨/推奨される方法を使用します。

    • メモ動画サンプル動画

    新しいプロジェクトを作成した後、次のように4つのビデオがダウンロードされ、res / rawフォルダーにコピーされました(rawフォルダーの作成後):-

    データベースヘルパー(SQLiteOpenHelperのサブクラス)は、 _idを使用して2列のテーブル用に作成されました。 列( _idという名前のメモ SimpleCursorAdapterで使用するため ).-ビデオのパス/名前を保存するためのvideo_path(フルパスではありませんが、保存されたデータからパスを判別するのに十分です)-重複が追加されないようにUNIQUEがコーディングされていることに注意してください。

    行の追加と削除、およびすべての行の抽出を可能にするいくつかの基本的な方法を使用します(SimpleCursorAdapterで使用するカーソルを使用)。

    DBHelper.java

    public class DBHelper extends SQLiteOpenHelper {
    
        public static final String DBNAME = "myvideos";
        public static final int DBVERSION = 1;
    
        public static final String TBL_VIDEO = "video";
    
        public static final String COL_VIDEO_ID = BaseColumns._ID;
        public static final String COL_VIDEO_PATH = "video_path";
    
    
        SQLiteDatabase mDB;
    
        public DBHelper(Context context) {
            super(context, DBNAME, null, DBVERSION);
            mDB = this.getWritableDatabase();
        }
    
    
        @Override
        public void onCreate(SQLiteDatabase db) {
    
            String crt_video_table = "CREATE TABLE IF NOT EXISTS " + TBL_VIDEO + "(" +
                    COL_VIDEO_ID + " INTEGER PRIMARY KEY," +
                    COL_VIDEO_PATH + " TEXT UNIQUE" +
                    ")";
            db.execSQL(crt_video_table);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    
        }
    
        public long addVideo(String path) {
            ContentValues cv = new ContentValues();
            cv.put(COL_VIDEO_PATH,path);
            return mDB.insert(TBL_VIDEO,null,cv);
        }
    
        public Cursor getVideos() {
            return mDB.query(TBL_VIDEO,null,null,null,null,null,null);
        }
    
        public int deleteVideoFromDB(long id) {
            String whereclause = COL_VIDEO_ID + "=?";
            String[] whereargs = new String[]{String.valueOf(id)};
            return mDB.delete(TBL_VIDEO,whereclause,whereargs);
        }
    }
    

    かなり単純なMainActivity.java (コメントを参照)

    public class MainActivity extends AppCompatActivity {
    
        TextView mMyTextView;
        ListView mVideoList;
        VideoView mVideoViewer;
        DBHelper mDBHlpr;
        Cursor mCsr;
        SimpleCursorAdapter mSCA;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mMyTextView =  this.findViewById(R.id.mytext);
            mVideoList = this.findViewById(R.id.videolist);
            mVideoViewer = this.findViewById(R.id.videoviewer);
    
            mDBHlpr = new DBHelper(this);
            addVideosFromRawResourceToDB();
        }
    
        @Override
        protected void onDestroy() {
            mCsr.close(); //<<<<<<<<<< clear up the Cursor
            super.onDestroy();
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            manageListView(); //<<<<<<<<<< rebuild and redisplay the List of Videos (in case they have changed) 
        }
    
        /**
         *  Setup or Refresh the ListView adding the OnItemClick and OnItemLongClick listeners
         */
        private void manageListView() {
            mCsr = mDBHlpr.getVideos();
    
            // Not setup so set it up
            if (mSCA == null) {
                // Instantiate the SimpleCursorAdapter
                mSCA = new SimpleCursorAdapter(
                        this,
                        android.R.layout.simple_list_item_1, // Use stock layout
                        mCsr, // The Cursor with the list of videos
                        new String[]{DBHelper.COL_VIDEO_PATH}, // the column (columns)
                        new int[]{android.R.id.text1}, // the view id(s) into which the column(s) data will be placed
                        0 
                );
                mVideoList.setAdapter(mSCA); // Set the adpater for the ListView
                /**
                 * Add The Long Click Listener (will delete the video row from the DB (NOT the video))
                 */
                mVideoList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                    @Override
                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                        mDBHlpr.deleteVideoFromDB(id);
                        manageListView(); // <<<<<<<<<< refresh the ListView as data has changed
                        return true;
                    }
                });
                /**
                 * Play the respective video when the item is clicked
                 * Note Cursor should be at the correct position so data can be extracted directly from the Cursor
                 */
                mVideoList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        setCurrentVideo(mCsr.getString(mCsr.getColumnIndex(DBHelper.COL_VIDEO_PATH)));
                    }
                });
            } else {
                mSCA.swapCursor(mCsr); //<<<<<<<<<< apply the changed Cursor
            }
        }
    
        /**
         * Set the currrent video and play it
         * @param path the path (resource name of the video)
         */
        private void setCurrentVideo(String path) {
    
            mVideoViewer.setVideoURI(
                    Uri.parse(
                           "android.resource://" + getPackageName() + "/" + String.valueOf(
                                   getResources().getIdentifier(
                                           path,
                                   "raw",
                                   getPackageName())
                           )
                    )
            );
            mVideoViewer.start();
        }
    
        /**
         *  Look at all the resources in the res/raw folder and add the to the DB (not if they are duplicates due to UNQIUE)
         */
        private void addVideosFromRawResourceToDB() {
                Field[] fields=R.raw.class.getFields();
                for(int count=0; count < fields.length; count++){
                    Log.i("Raw Asset: ", fields[count].getName());
                    mDBHlpr.addVideo(fields[count].getName());
                }
        }
    }
    

    結果

    最初に開始したとき(何も再生されません):-

    1Mbビデオを長くクリックした後(DBエントリを削除):-

    リスト内のビデオをクリックした後:-



    1. PostgreSQLでデータベースとテーブルを作成および削除する方法

    2. グループごとに1列の最大値を持つ行を返します

    3. Java 9のカスタムランタイムイメージとは何ですか?

    4. SQLiteのGROUP_CONCAT