使用七牛云存儲上傳android本地視頻并播放

項目最近又來了添加視頻的需求蟆沫,暫定存儲到七牛歉秫。具體步驟大致分為三步:
1:獲取本地視頻縮略圖展示蛾洛,當(dāng)用戶選擇某一段視頻時,拿到該視頻的地址端考。
2:通過七牛sdk雅潭,將該視頻地址傳入,上傳到七牛云存儲却特,然后獲取視頻videoUrl和videoThumail扶供。
3:通過視頻播放器播放視頻。

2017-06-21 20_59_30.gif

一:獲取視頻列表并在手機中展示裂明。

這里大致可以分為一下幾步:
1:由于獲取視頻列表需要查詢多媒體數(shù)據(jù)庫椿浓,因此我們創(chuàng)建一個線程。
2:當(dāng)查詢完畢闽晦,通過獲取DATA列的路徑扳碍,傳入Thumbnails中獲取視頻縮略圖
3:通過GridView 展示這些縮略圖,當(dāng)用戶點選某個視頻的時候仙蛉,拿到那個視頻的本地地址笋敞。

(1):創(chuàng)建handler代替線程,用來查詢多媒體數(shù)據(jù)庫
  Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            pictureAdapter.notifyDataSetChanged();
        }
    };

handler.post(new Runnable() {
            @Override
            public void run() {
                getThumbnail();
            }
        });

這里的getthumbnail就是我們要查詢多媒體數(shù)據(jù)庫荠瘪,獲取縮略圖的方法

(2):查詢視頻列表夯巷,獲取每個視頻縮略圖

在這個方法中我們構(gòu)造了一個構(gòu)造了一條查詢語句,查詢的是外部存儲卡中的視頻哀墓,以及按照日期倒序排列趁餐。然后通過游標的移動,獲取每條視頻的MediaStore.Video.Media.DATA代表路徑篮绰,以及MediaStore.Video.Media._ID代表唯一id后雷。當(dāng)我們拿到路徑和唯一id后,就可以通過系統(tǒng)工具類獲取視頻的縮略圖bitmap吠各,然后將其在一個數(shù)組中臀突,用來作為gridview的數(shù)據(jù)源。下面這個方法獲取視頻縮略圖耗時嚴重贾漏,可以參看博文更新解決辦法;

private void getThumbnail() {
        Cursor mCursor = mContentResolver.query(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                null, null, null,
                MediaStore.MediaColumns.DATE_ADDED + " DESC");
        if (mCursor.moveToFirst()) {
            int _date = mCursor.getColumnIndex(MediaStore.Video.Media.DATA);
            int columnIndex = mCursor.getColumnIndex(MediaStore.Video.Media._ID);

            do {
                //data 是數(shù)據(jù)的意思惧辈,獲取的就是文件數(shù)據(jù),也就是文件路徑磕瓷。
                String path = mCursor.getString(_date);
                int anInt = mCursor.getInt(columnIndex);
                DebugUtil.error("path:"+path);
                images.add(path);
                Bitmap bitmap= MediaStore.Video.Thumbnails.getThumbnail(mContentResolver,anInt, MediaStore.Video.Thumbnails.MINI_KIND,null);
                bitmapArrayList.add(bitmap);
            } while (mCursor.moveToNext());
        }
        mCursor.close();
        handler.sendEmptyMessage(0);
    }
(3):通過gridview展示縮略圖

在第二步中images.add(path)將每個視頻的地址保存在了一個指定的集合中,bitmapArrayList.add(bitmap)則將每個生成的視頻縮略圖放在了集合中。這里需要將生成縮略圖放在集合的方法遷移到展示的時候困食,不然太費內(nèi)存边翁。不過一個手機中的視頻文件肯定不多,因此生成的縮略圖也不會占用過多內(nèi)存硕盹。

  @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            ViewHolder holder = null;
            if (convertView == null) {
                convertView = View.inflate(context, R.layout.grid_item_picture,
                        null);
                holder = new ViewHolder();
                holder.iv = (ImageView) convertView.findViewById(R.id.iv);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            final String item = images.get(position);
             Bitmap bitmap = bitmapArrayList.get(position);
            holder.iv.setImageBitmap(bitmap);
            return convertView;

二:上傳七牛云

從七牛云存儲的上傳策略中可以看出符匾,我們將文件上傳到七牛云,不是安卓sdk一方面來完成的瘩例,是需要我們自己的業(yè)務(wù)服務(wù)器和客戶端配合來完成啊胶。上傳七牛云分為兩步:
1:通過訪問自己業(yè)務(wù)服務(wù)器的接口,來獲取上傳到七牛云的token垛贤。
2:使用skd中的upLoadManager中的put方法焰坪,上傳文件。通過回調(diào)獲取返回數(shù)據(jù)聘惦。
在第一步和第二步中獲得的返回數(shù)據(jù)某饰,都是自己業(yè)務(wù)服務(wù)器定義好的,在第二步中善绎,當(dāng)我們上傳成功黔漂,七牛服務(wù)器會回調(diào)自己的業(yè)務(wù)服務(wù)器,然后將需要返回的數(shù)據(jù)返回給客戶端禀酱。

(1):訪問業(yè)務(wù)服務(wù)器獲得上傳token

這里就是用七牛demo中的例子來說明一下炬守。新建一個訪問網(wǎng)絡(luò)的線程,然后構(gòu)造一個請求實例剂跟,然后開始請求减途,這里訪問的地址,其實就相當(dāng)于一個我們自己的業(yè)務(wù)服務(wù)器浩聋。訪問成功之后观蜗,拿到上傳需要的token。

  public void uploadFile(View view) {
    
        new Thread(new Runnable() {
            @Override
            public void run() {
                final OkHttpClient httpClient = new OkHttpClient();
                Request req = new Request.Builder()
.url(“https://api.qiniudemo.com/upload/api/quick_start/simple_video_example_token.php)
.method("GET", null).build();

                Response resp = null;
                try {
                    resp = httpClient.newCall(req).execute();
                    JSONObject jsonObject = new JSONObject(resp.body().string());
                    String uploadToken = jsonObject.getString("uptoken");
                    String domain = jsonObject.getString("domain");
                    upload(uploadToken, domain);
                } catch (Exception e) {
                  
                } finally {
                    if (resp != null) {
                        resp.body().close();
                    }
                }
            }
        }).start();
    }
(2):開始上傳文件衣洁。

上傳文件需要使用到兩個類墓捻,UploadOptions主要用來處理上傳進度;UploadManager則用來實現(xiàn)具體的上傳操作坊夫。還有一個上傳配置的類Configuration砖第,官方文檔也說可以使用默認設(shè)置。

image.png

下面就是官方demo的上傳代碼

 private void upload(final String uploadToken, final String domain) {
        File uploadFile = new File(this.uploadFilePath);
        UploadOptions uploadOptions = new UploadOptions(null, null, false,
                new UpProgressHandler() {
                    @Override
                    public void progress(String key, double percent) {
                        updateStatus(percent);
                    }
                }, null);
 
        this.uploadManager.put(uploadFile, null, uploadToken,
                new UpCompletionHandler() {
                    @Override
                    public void complete(String key, ResponseInfo respInfo,
                                         JSONObject jsonData) {

                        long lastMillis = System.currentTimeMillis()
                                - startTime;
                        if (respInfo.isOK()) {
                            try {
                                String fileKey = jsonData.getString("key");
                                final String persistentId = jsonData.getString("persistentId");
                             
                                final String videoUrl = domain + "/" + fileKey;

                                final com.pili.pldroid.player.widget.PLVideoView videoView = uploadResultVideoView;
                                if(Uri.parse(videoUrl)!=null){
                                    videoView.setVideoURI(Uri.parse(videoUrl));
                                }
                            } catch (JSONException e) {
                           
                            }
                        } else {
                           
                        }
                    }

                }, uploadOptions);
    }

其中updateStatus()就是用來更新上傳進度的方法环凿,而在UpCommpletionHandler的回調(diào)中梧兼,就是上傳結(jié)果的回調(diào),我們可以通過ResponseInfo中的isOk來判斷上傳是否成功智听,如果成功羽杰,就可以拿到自己業(yè)務(wù)服務(wù)器返回的數(shù)據(jù)渡紫,用來處理接下來的邏輯。

注意:七牛給的安卓Demo關(guān)于播放視頻的播放器存在一些問題考赛,我這里是與官方demo有出入惕澎。

三:上傳視頻持久化處理

七牛服務(wù)器給開發(fā)者提供了一些處理視頻的接口,我們上傳的視頻只是原文件颜骤,如果我們要對視頻做持久化的數(shù)據(jù)處理唧喉,那么可以采用下面兩種形式:
1:上傳資源成功后,自動觸發(fā)
2:已存在的資源忍抽,手動觸發(fā)
這兩種形式和圖片的縮略圖以及圖片水印還不一樣八孝,圖片的處理是可以通過在訪問資源時制定一定的數(shù)據(jù)處理指令轉(zhuǎn)換為url,已直接獲取處理結(jié)果鸠项,當(dāng)然圖片也能通過持久化處理來完成縮略圖以及水印干跛。

(1):上傳資源成功后自動觸發(fā)

這個觸發(fā)條件,需要在構(gòu)造上傳憑證時在上傳策略中設(shè)置 persistentOps 和 persistentNotifyUrl 兩個字段锈锤。

image.png

比如我這里上傳了一個視頻驯鳖,可以通過下面的地址來查詢進度

http://api.qiniu.com/status/get/prefop?id=z0.594b333045a2650c99a40cde
image.png
(2):已有資源手動觸發(fā)


其實這個預(yù)處理持久化的操作,應(yīng)該是由我們的業(yè)務(wù)服務(wù)器來完成的操作久免,客戶端不用考慮過多浅辙,只負責(zé)上傳原文件,在上傳完成后按照業(yè)務(wù)服務(wù)器的要求阎姥,來配合完成即可记舆。

四:本地視頻編碼壓縮

如果本地視頻不進行編碼壓縮,那么視頻文件就會超大呼巴。當(dāng)然android手機里面的視頻來源有很多種泽腮,如果是通過手機攝像頭拍攝的話,最好是先進行編碼壓縮衣赶,然后再上傳服務(wù)器诊赊,比如我用華為FRD_AL00拍攝一段十秒鐘的視頻就有22M大小。府瞄。如果是通過電腦下載的一些已經(jīng)壓縮好的mp4碧磅,文件已經(jīng)比較小了,然后再發(fā)送到手機上遵馆,這個時候選擇的這些視頻鲸郊,就可以視情況而定,是否需要再次壓縮货邓。本地視頻編碼壓縮秆撮,實際上就是通過手機執(zhí)行ffmpeg的編碼命令。對視頻編碼一般是使用libx264换况,對音頻編碼一般使用libfdk_aac就足夠了职辨。如何編譯在android中可執(zhí)行命令的ffmpeg呢盗蟆?可以參考這篇博客編譯Android下可執(zhí)行命令的FFmpeg,以及github上的這個開源項目FFMPEG-ANDROID-JAVA

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拨匆,一起剝皮案震驚了整個濱河市姆涩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惭每,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亏栈,死亡現(xiàn)場離奇詭異台腥,居然都是意外死亡,警方通過查閱死者的電腦和手機绒北,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門黎侈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人闷游,你說我怎么就攤上這事峻汉。” “怎么了脐往?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵休吠,是天一觀的道長。 經(jīng)常有香客問我业簿,道長瘤礁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任梅尤,我火速辦了婚禮柜思,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巷燥。我一直安慰自己赡盘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布缰揪。 她就那樣靜靜地躺著陨享,像睡著了一般。 火紅的嫁衣襯著肌膚如雪邀跃。 梳的紋絲不亂的頭發(fā)上霉咨,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音拍屑,去河邊找鬼途戒。 笑死,一個胖子當(dāng)著我的面吹牛僵驰,可吹牛的內(nèi)容都是我干的喷斋。 我是一名探鬼主播唁毒,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼星爪!你這毒婦竟也來了浆西?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤顽腾,失蹤者是張志新(化名)和其女友劉穎近零,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抄肖,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡久信,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了漓摩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裙士。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖管毙,靈堂內(nèi)的尸體忽然破棺而出腿椎,到底是詐尸還是另有隱情,我是刑警寧澤夭咬,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布啃炸,位于F島的核電站,受9級特大地震影響皱埠,放射性物質(zhì)發(fā)生泄漏肮帐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一边器、第九天 我趴在偏房一處隱蔽的房頂上張望训枢。 院中可真熱鬧,春花似錦忘巧、人聲如沸恒界。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽十酣。三九已至,卻和暖如春际长,著一層夾襖步出監(jiān)牢的瞬間耸采,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工工育, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留虾宇,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓如绸,卻偏偏與公主長得像嘱朽,于是被迫代替她去往敵國和親旭贬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容