Sunday, October 13, 2013

Android Thumbnail From Video

Video Thumbnails Using the MediaStore        

We could, starting with Android 2.0 (API Level 5), pull out the thumbnails associated with
each video file from within the loop. We need the ID of the video file that is in our list of
columns to select (MediaStore.Video.Media._ID), which we can then use in the “where”
clause of the managedQuery.

int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));
String[] thumbColumns = { MediaStore.Video.Thumbnails.DATA,
MediaStore.Video.Thumbnails.VIDEO_ID};
Cursor thumbCursor = managedQuery(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
thumbColumns, MediaStore.Video.Thumbnails.VIDEO_ID + "=" + id, null, null);
if (thumbCursor.moveToFirst()) {
       Log.v("VideoGallery",thumbCursor.getColumnIndex(MediaStore.Video.Thumbnails.DATA));
}

Full Source Code Here

Full MediaStore Video Example

Here is a full example that retrieves all of the available video files from the MediaStore
and displays each of their thumbnail images and titles. This example uses the MediaStore.Video.Thumbnails class which is available in Android 2.0 (API Level 5) and above.

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class VideoGallery extends Activity implements OnItemClickListener {

Cursor cursor;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

We’ll use a ListView to display the list of videos.

ListView listView = (ListView) this.findViewById(R.id.ListView);

Next is the list of columns we want from the MediaStore.Video.Thumbnails queries.

String[] thumbColumns = {
MediaStore.Video.Thumbnails.DATA,
MediaStore.Video.Thumbnails.VIDEO_ID
};

Then comes the list of columns we want from the MediaStore.Video.Media query.

String[] mediaColumns = {
    MediaStore.Video.Media._ID,
    MediaStore.Video.Media.DATA,
    MediaStore.Video.Media.TITLE,
    MediaStore.Video.Media.MIME_TYPE
};

In the main query, we’ll select all of the videos that are represented in the

MediaStore.cursor = managedQuery(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
mediaColumns, null, null, null);

Each row returned by the query will create an item in the following ArrayList. Each item
will be a VideoViewInfo object, which is a class defined here specifically to hold
information about a video for use in this activity.

ArrayList<VideoViewInfo> videoRows = new ArrayList<VideoViewInfo>();

Here we loop through the data contained in the Cursor object, creating a VideoViewInfo
object for each row and adding it to our ArrayList.

if (cursor.moveToFirst())

We are using a do while loop as we want it to run through the first row of data before
moving to the next row. The do portion happens before the while clause is
tested/executed. In our loop, we’ll create a new VideoViewInfo object for each row of
data returned.

do {
    VideoViewInfo newVVI = new VideoViewInfo();

We can then pull out all of the relevant data from the Cursor. As just described, we’ll
also make another query to pull out a thumbnail image for each video. Each of these
pieces of data will be stored in the VideoViewInfo object.

int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));
Cursor thumbCursor = managedQuery(MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
thumbColumns, MediaStore.Video.Thumbnails.VIDEO_ID + "=" + id, null, null);

if (thumbCursor.moveToFirst())
{
         newVVI.thumbPath = thumbCursor.getString(
         thumbCursor.getColumnIndex(MediaStore.Video.Thumbnails.DATA));
         Log.v("VideoGallery","Thumb " + newVVI.thumbPath);
}

newVVI.filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA));
newVVI.title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE));
Log.v("VideoGallery","Title " + newVVI.title);
newVVI.mimeType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.MIME_TYPE));
Log.v("VideoGallery","Mime " + newVVI.mimeType);

Finally, we add the VideoViewInfo to the videoRows ArrayList.

             videoRows.add(newVVI);
     } while (cursor.moveToNext());
}

Once we are done getting all of the videos, we can continue on. We’ll set the adapter of
the ListView object to be a new instance of VideoGalleryAdapter, which is an inner
class defined here. We’ll also set this activity to be the OnItemClickListener for the
 
          ListView.listView.setAdapter(new VideoGalleryAdapter(this,videoRows));      
          listView.setOnItemClickListener(this);
 }

When an item in the ListView is clicked, the onItemClick method will be called. In this
method, we extract the data we need from the Cursor and create an intent to launch the
default media player application on the device to play back the video. We could have
created our own MediaPlayer or used the VideoView class here instead.

public void onItemClick(AdapterView<?> l, View v, int position, long id) {
   if (cursor.moveToPosition(position)) {
   int fileColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
   int mimeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.MIME_TYPE);
   String videoFilePath = cursor.getString(fileColumn);
   String mimeType = cursor.getString(mimeColumn);
   Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
   File newFile = new File(videoFilePath);
   intent.setDataAndType(Uri.fromFile(newFile), mimeType);
   startActivity(intent);
     }
}

What follows is the very basic VideoViewInfo class, which is used to hold information about each video returned.

class VideoViewInfo
{
    String filePath;
    String mimeType;
    String thumbPath;
    String title;
}

Since we are using a ListView in our activity to display each of the videos returned from the MediaStore query, we’ll be using the ListView to display both the title of the video and a thumbnail. In order to hand the data to the ListView, we need to construct anAdapter. Next, we create an Adapter, VideoGalleryAdapter, which extends BaseAdapter. When this class is constructed, it gets passed the ArrayList that holds all of the videos returned from the MediaStore query.

BaseAdapter is an abstract class, so in order to extend it, we need to implement several methods. Most of them are straightforward and just operate on the ArrayList we passed in, such as getCount and getItem. The method that requires the most attention is the getView method.

class VideoGalleryAdapter extends BaseAdapter
{
      private Context context;
      private List<VideoViewInfo> videoItems;
      LayoutInflater inflater;
      public VideoGalleryAdapter(Context _context, ArrayList<VideoViewInfo> _items) {
          context = _context;
          videoItems = _items;
          inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public int getCount() {
      return videoItems.size();
}
public Object getItem(int position) {
      return videoItems.get(position);
}
public long getItemId(int position) {
      return position;
}

The getView method is used to return the view for each row represented in the ListView. It is passed in the position that is meant to be returned (along with a View object representing the current View and an object that represents the parent ViewGroup).

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

To construct the View to be returned, we need to inflate the layout that we are using for
each row. In this case, we are using a layout defined in list_item.xml (shown here).

View videoRow = inflater.inflate(R.layout.list_item, null);

After the layout is inflated, we can get at the individual Views that are defined and use the data from the ArrayList of VideoViewInfo objects to define what to display. Here is how that is done for the ImageView that is used to display each video’s thumbnail.

ImageView videoThumb = (ImageView) videoRow.findViewById(R.id.ImageView);

if (videoItems.get(position).thumbPath != null) {
           videoThumb.setImageURI(Uri.parse(videoItems.get(position).thumbPath));
}

Here we obtain a reference to the TextView for the video title and set the text according to the data in the ArrayList of VideoViewInfo object.

TextView videoTitle = (TextView) videoRow.findViewById(R.id.TextView);
videoTitle.setText(videoItems.get(position).title);

Finally, we return the newly constructed View.
          return videoRow;
        }
    }
}

Here is the main.xml file defining the layout for the activity.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
>
<ListView android:layout_width="wrap_content" android:layout_height="wrap_content"
         android:id="@+id/ListView"></ListView>
</LinearLayout>

Here is the list_item.xml file that is used to define the layout for each row of the ListView.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

<ImageView android:id="@+id/ImageView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content">
</ImageView>
<TextView
       android:text="@+id/TextView01"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/TextView">
</TextView>
</LinearLayout>

1 comment: