SQLite
 sql >> Baza danych >  >> RDS >> SQLite

Jak przechowywać zawartość wideo w bazie danych SQLite (nie w ścieżce wideo)

Chcę zapisać wideo w bazie danych sqlite. PS Nie chcę zapisywać ścieżki, ale rzeczywistą zawartość wideo.

O ile filmy nie są bardzo krótkie i zajmują mało miejsca (powiedzmy do 200 tys. każdy, być może 1/10 sekundy, ale zależy to od formatu, w jakim są zapisywane), prawdopodobnie napotkasz problemy i wyjątki/awarie.

  • Korzystanie z telefonu przez około 2 sekundy czerni zajęło 2,2 Mb, 2 sekundy faktycznego nagrania wideo zajęły 7 Mb.

Chociaż SQLite ma możliwość przechowywania stosunkowo dużych BLOBów zgodnie z :-

  • Maksymalna długość ciągu lub BLOB

    Maksymalna liczba bajtów w ciągu lub BLOB w SQLite jest zdefiniowana przez makro preprocesora SQLITE_MAX_LENGTH. Domyślna wartość tego makra to 1 miliard (1 tysiąc milionów lub 1 000 000 000). Możesz podnieść lub obniżyć tę wartość w czasie kompilacji za pomocą opcji wiersza poleceń, takiej jak ta:

    -DSQLITE_MAX_LENGTH=123456789 Obecna implementacja będzie obsługiwać tylko ciąg znaków lub BLOB o długości do 231-1 lub 2147483647. Niektóre wbudowane funkcje, takie jak hex(), mogą zawieść na długo przed tym punktem. W przypadku aplikacji wrażliwych na brak bezpieczeństwa najlepiej nie próbować zwiększać maksymalnej długości łańcucha i obiektu BLOB. W rzeczywistości dobrze byłoby obniżyć maksymalną długość łańcucha i blobu do wartości w zakresie kilku milionów, jeśli jest to możliwe.

    Podczas części przetwarzania INSERT i SELECT w SQLite kompletna zawartość każdego wiersza w bazie danych jest kodowana jako pojedynczy BLOB. Tak więc parametr SQLITE_MAX_LENGTH określa również maksymalną liczbę bajtów w rzędzie.

    Maksymalna długość ciągu lub BLOB może zostać zmniejszona w czasie wykonywania za pomocą interfejsu sqlite3_limit(db,SQLITE_LIMIT_LENGTH,rozmiar). Ograniczenia w SQLite

CursorWindow w Android SDK ma ograniczenie do 2 MB i dotyczy to wszystkich kolumn wiersza (wierszy) w przypadku buforów. W związku z tym, nawet jeśli możesz pomyślnie przechowywać filmy wideo, możesz nie być w stanie ich odzyskać.

Zalecany sposób to to, czego nie chcesz, czyli przechowywanie ścieżki do filmu.

Jeśli przechowuję wideo w mojej wewnętrznej/zewnętrznej pamięci i zamiast tego przechowuję ścieżkę, w jaki sposób będę mógł uzyskać do niej dostęp z innego urządzenia.

Mógłbyś mieć ten sam problem z bazą danych ponieważ jest zwykle przechowywany w chronionych danych aplikacji. To znaczy, chyba że baza danych jest wcześniej istniejącą bazą danych (tj. wypełnioną danymi), w którym to przypadku baza danych jest dystrybuowana z aplikacją za pośrednictwem APK.

Jeśli to drugie, to istniejąca wcześniej baza danych dystrybuowana za pośrednictwem APK, wówczas filmy mogą być również dystrybuowane jako część APK, a zatem tak chronione i udostępniane jak baza danych.

Jeśli Twoim zamiarem jest dystrybucja filmów między urządzeniami, które nie są częścią APK, SQlite prawdopodobnie nie jest właściwym rozwiązaniem, ponieważ jest to wbudowana baza danych i nie ma wbudowanej funkcji klient/serwer.

Poza tym co, jeśli moje urządzenie zostanie sformatowane, stracę wszystkie dane.

W takim scenariuszu baza danych byłaby tak samo podatna na zagrożenia, jak wszelkie inne dane , ponieważ to wszystko, co jest bazą danych, plik, taki jak wideo, dokument tekstowy itp., które wymagają odpowiedniej aplikacji do przeglądania/zmiany zawartości. Jeśli jednak baza danych jest już istniejącą bazą danych, po prostu ponowna instalacja aplikacji przywróci bazę danych i inne pliki z APK.

Przykład pracy

Wykorzystywana jest metoda sugerowana/zalecana, zakładając, że filmy mają być rozpowszechniane z APK.

  • Uwaga filmy wideo dzięki uprzejmości przykładowych filmów wideo

Po utworzeniu nowego projektu pobrano 4 filmy i skopiowano je do folderu res/raw (po utworzeniu folderu raw) zgodnie z :-

Pomocnik bazy danych (podklasa SQLiteOpenHelper) został utworzony dla dwukolumnowej tabeli z _id kolumna (uwaga o nazwie _id do użytku z SimpleCursorAdapter ).- ścieżka_wideo do przechowywania ścieżki/nazwy wideo (nie pełna ścieżka, ale wystarczająca do określenia ścieżki na podstawie zapisanych danych)- Uwaga UNIKALNE zostało zakodowane, aby zatrzymać dodawanie duplikatów.

Z podstawową metodą umożliwiającą dodawanie i usuwanie wierszy oraz wyodrębnianie wszystkich wierszy (za pomocą kursora do użytku z 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);
    }
}

Dość prostolinijny MainActivity.java (patrz komentarze)

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

Wyniki

Przy pierwszym uruchomieniu (nic nie odtwarza) :-

Po długim kliknięciu filmu 1Mb (usunięcie wpisu DB) :-

Po kliknięciu Wideo na liście:-



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Znajdź naruszenia kluczy obcych w SQLite

  2. Jak działa funkcja JulianDay() w SQLite

  3. Jak używać wyrażenia regularnego w sqlite

  4. Limit SQLite

  5. Suma nad wartościami według miesiąca w milisekundach