SQLite
 sql >> Database >  >> RDS >> SQLite

Come archiviare contenuti video nel database SQLite (non nel percorso video)

Voglio archiviare un video nel database sqlite. PS Non voglio memorizzare il percorso ma i contenuti video veri e propri.

A meno che i video non siano molto brevi e occupino poco spazio (diciamo fino a 200.000 ciascuno, forse 1/10 di secondo, ma dipenderebbe dal formato in cui sono salvati), è probabile che si verifichino problemi ed eccezioni/crash.

  • L'utilizzo di un telefono per circa 2 secondi di nero ha richiesto 2,2 Mb, 2 secondi di registrazione di un video effettivamente hanno richiesto 7 Mb.

Sebbene SQLite abbia la capacità di memorizzare BLOB di dimensioni relativamente grandi come da :-

  • Lunghezza massima di una stringa o BLOB

    Il numero massimo di byte in una stringa o BLOB in SQLite è definito dalla macro del preprocessore SQLITE_MAX_LENGTH. Il valore predefinito di questa macro è 1 miliardo (1 miliardo o 1.000.000.000). Puoi aumentare o diminuire questo valore in fase di compilazione usando un'opzione della riga di comando come questa:

    -DSQLITE_MAX_LENGTH=123456789 L'implementazione corrente supporterà solo una stringa o una lunghezza BLOB fino a 231-1 o 2147483647. E alcune funzioni integrate come hex() potrebbero fallire ben prima di quel punto. Per le applicazioni sensibili all'insicurezza è meglio non cercare di aumentare la lunghezza massima della stringa e del BLOB. In effetti, potresti fare bene a ridurre la lunghezza massima della stringa e del BLOB a qualcosa di più nell'intervallo di qualche milione, se possibile.

    Durante parte dell'elaborazione INSERT e SELECT di SQLite, il contenuto completo di ogni riga nel database viene codificato come un singolo BLOB. Quindi il parametro SQLITE_MAX_LENGTH determina anche il numero massimo di byte in una riga.

    La lunghezza massima della stringa o del BLOB può essere ridotta in fase di esecuzione utilizzando l'interfaccia sqlite3_limit(db,SQLITE_LIMIT_LENGTH,size). Limiti in SQLite

CursorWindow dell'SDK Android ha un limite di 2Mb e cioè per tutte le colonne delle righe se buffer. Pertanto, anche se riesci a memorizzare i video correttamente, potresti non essere in grado di recuperare quei video.

Il modo consigliato è quello che non vuoi, ovvero memorizzare il percorso del video.

Se memorizzo il video nella mia memoria interna/esterna e memorizzo invece il percorso, come potrò accedere allo stesso da qualche altro dispositivo.

Avresti lo stesso problema con il database poiché in genere viene archiviato all'interno dei dati delle applicazioni che sono protetti. Questo a meno che il database non sia un database preesistente (ovvero popolato di dati), nel qual caso il database viene distribuito con l'App tramite l'APK.

Se quest'ultimo, un database preesistente distribuito tramite l'APK, i video possono anche essere distribuiti come parte dell'APK e quindi protetti ed esponibili come il database.

Se la tua intenzione è quella di distribuire video tra dispositivi che non fanno parte dell'APK, SQlite probabilmente non è la soluzione corretta in quanto è un database incorporato e non ha funzionalità client/server integrate.

Inoltre, se il mio dispositivo viene formattato, perderò tutti i dati.

In uno scenario del genere, il database sarebbe vulnerabile come qualsiasi altro dato , poiché questo è tutto ciò che il database è, un file, proprio come un video, un documento Word ecc. Che necessitano tutti di un'applicazione adatta per visualizzare/cambiare il contenuto. Tuttavia, se il database è un database preesistente, la semplice reinstallazione dell'app ripristinerà il database e altri file dall'APK.

Esempio di lavoro

Questo utilizza il metodo consigliato/consigliato presupponendo che i video debbano essere distribuiti con l'APK.

  • Video di note per gentile concessione di Video di esempio

Dopo aver creato il nuovo progetto sono stati scaricati 4 video e copiati nella cartella res/raw (dopo aver creato la cartella raw) come da :-

Il Database Helper (sottoclasse di SQLiteOpenHelper) è stato creato per una tabella a 2 colonne con _id colonna (nota denominata _id da utilizzare con SimpleCursorAdapter .- video_path per memorizzare il percorso/nome del video (non il percorso completo ma sufficiente per poter determinare il percorso dai dati memorizzati)- Nota UNIQUE è stato codificato per impedire l'aggiunta di duplicati.

Con alcuni metodi di base per consentire l'aggiunta e l'eliminazione di righe e per l'estrazione di tutte le righe (tramite un cursore da utilizzare con 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);
    }
}

Un MainActivity.java piuttosto semplice (vedi commenti)

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());
            }
    }
}

Risultati

Al primo avvio (non viene riprodotto nulla) :-

Dopo aver cliccato a lungo sul video da 1Mb (eliminando la voce DB) :-

Dopo aver fatto clic su Un video nell'elenco :-