sql >> Databáze >  >> RDS >> SQLite

Jak uložit video obsah v databázi SQLite (nikoli cestu videa)

Chci uložit video do databáze sqlite. P.S. Nechci ukládat cestu, ale skutečný obsah videa.

Pokud nejsou videa velmi krátká a nezabírají málo místa (řekněme až 200 000 každé, možná 1/10 sekundy, ale bude to záviset na formátu, ve kterém jsou uložena), pravděpodobně narazíte na problémy a výjimky/selhání.

  • Při použití telefonu zabraly přibližně 2 sekundy černé barvy 2,2 Mb, 2 sekundy skutečného záznamu videa zabraly 7 Mb.

Ačkoli SQLite má schopnost ukládat relativně velké objekty BLOB podle :-

  • Maximální délka řetězce nebo BLOB

    Maximální počet bajtů v řetězci nebo BLOB v SQLite je definován makrem preprocesoru SQLITE_MAX_LENGTH. Výchozí hodnota tohoto makra je 1 miliarda (1 tisíc milionů nebo 1 000 000 000). Tuto hodnotu můžete zvýšit nebo snížit během kompilace pomocí možnosti příkazového řádku, jako je tato:

    -DSQLITE_MAX_LENGTH=123456789 Aktuální implementace bude podporovat pouze řetězec nebo délku BLOB do 231-1 nebo 2147483647. A některé vestavěné funkce, jako je hex() mohou selhat dlouho před tímto bodem. U aplikací citlivých na zabezpečení je nejlepší nepokoušet se zvýšit maximální délku řetězce a blob. Ve skutečnosti by bylo dobré snížit maximální délku řetězce a blob na něco více v rozsahu několika milionů, pokud je to možné.

    Během části zpracování SQLite INSERT a SELECT je úplný obsah každého řádku v databázi zakódován jako jeden BLOB. Takže parametr SQLITE_MAX_LENGTH také určuje maximální počet bajtů v řádku.

    Maximální délku řetězce nebo BLOB lze za běhu snížit pomocí rozhraní sqlite3_limit(db,SQLITE_LIMIT_LENGTH,size). Limity v SQLite

CursorWindow sady Android SDK má omezení 2 Mb a to je pro všechny sloupce řádků if buffers. I když můžete úspěšně uložit videa, možná nebudete moci tato videa načíst.

Doporučený způsob je to, co nechcete, tedy uložit cestu k videu.

Pokud video uložím do svého interního/externího úložiště a místo něj uložím cestu, jak k němu budu mít přístup z jiného zařízení.

Stejný problém byste měli s databází protože jsou obvykle uloženy v datech aplikací, která jsou chráněna. Tedy pokud databáze není již existující databází (tj. naplněnou daty), v takovém případě je databáze distribuována s aplikací prostřednictvím souboru APK.

Pokud se jedná o již existující databázi distribuovanou prostřednictvím souboru APK, mohou být videa také distribuována jako součást souboru APK, a tudíž chráněna a zpřístupněna jako databáze.

Pokud je vaším záměrem distribuovat videa mezi zařízeními, která nejsou součástí APK, pak SQlite pravděpodobně není správné řešení, protože se jedná o vestavěnou databázi a nemá vestavěnou žádnou funkci klient/server.

Kromě toho, co když se moje zařízení zformátuje, ztratím všechna data.

V takovém scénáři by databáze byla stejně zranitelná jako jakákoli jiná data , protože to je vše, co databáze je, soubor, stejně jako video, textový dokument atd., které všechny potřebují vhodnou aplikaci pro zobrazení/změnu obsahu. Pokud je však databáze již existující databází, pak by jednoduchá přeinstalace aplikace obnovila databázi a další soubory z APK.

Pracovní příklad

Toto používá navrhovanou/doporučenou metodu za předpokladu, že videa mají být distribuována s APK.

  • Videa s laskavým svolením Ukázková videa

Po vytvoření nového projektu byla stažena 4 videa a zkopírována do složky res/raw (po vytvoření složky raw) podle :-

Database Helper (podtřída SQLiteOpenHelper) byla vytvořena pro 2 sloupcovou tabulku s- _id sloupec (poznámka s názvem _id pro použití s ​​SimpleCursorAdapter .- video_path pro uložení cesty/názvu videa (není to úplná cesta, ale dostačující k tomu, aby bylo možné určit cestu z uložených dat)- Poznámka:UNIQUE byl kódován tak, aby zabránil přidávání duplikátů.

S nějakou základní metodou umožňující přidávat a odstraňovat řádky a extrahovat všechny řádky (přes kurzor pro použití s ​​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);
    }
}

Docela složitá MainActivity.java (viz komentáře)

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

Výsledky

Při prvním spuštění (nic se nehraje) :-

Po dlouhém klikání na 1Mb video (smazání záznamu DB) :-

Po kliknutí na Video v seznamu :-



  1. Dynamický pivot T-SQL

  2. Vygenerujte třídu z databázové tabulky

  3. Chyba SQL Server JDBC v jazyce Java 8:Ovladač nemohl vytvořit zabezpečené připojení k serveru SQL pomocí šifrování Secure Sockets Layer (SSL)

  4. ALTER TABLE v MySQL:Přítel nebo nepřítel?