How can I record a Video in my Android App.?

后端 未结 10 1588
后悔当初
后悔当初 2020-11-22 11:34

How can I capture a video recording on Android?

相关标签:
10条回答
  • 2020-11-22 12:15

    Check out this Sample Camera Preview code, CameraPreview. This would help you in devloping video recording code for video preview, create MediaRecorder object, and set video recording parameters.

    0 讨论(0)
  • 2020-11-22 12:15

    As of December 2017, there have been some updates, e.g. the usage of android.hardware.Camera is deprecated now. While the newer android.hardware.camera2 comes with handy things like a CameraManager.

    I personally like this example a lot, which makes use of this current API and works like a charm: https://github.com/googlesamples/android-Camera2Video

    It also includes asking the user for the required permissions at start and features video preview before starting the video recording.

    (In addition, I find the code really beautiful (and this is very rare for me ^^), but that's just my subjective opinion.)

    0 讨论(0)
  • 2020-11-22 12:20

    For the benefit of searchers, this example will give you an active preview, with a start/stop button for recording. It was modified from this android blog and seems fairly reliable.

    java class (VideoWithSurfaceVw)

    package <<your packagename here>>;
    
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import android.app.Activity;
    import android.content.Context;
    import android.hardware.Camera;
    import android.media.CamcorderProfile;
    import android.media.MediaRecorder;
    import android.os.Bundle;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.widget.Button;
    import android.widget.FrameLayout;
    import android.widget.Toast;
    
    public class VideoWithSurfaceVw extends Activity{
    
        // Adapted from http://sandyandroidtutorials.blogspot.co.uk/2013/05/android-video-capture-tutorial.html
    
    
        private Camera myCamera;
        private MyCameraSurfaceView myCameraSurfaceView;
        private MediaRecorder mediaRecorder;
    
        Button myButton;
        SurfaceHolder surfaceHolder;
        boolean recording;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            recording = false;
    
            setContentView(R.layout.activity_video_with_surface_vw);
    
            //Get Camera for preview
            myCamera = getCameraInstance();
            if(myCamera == null){
                Toast.makeText(VideoWithSurfaceVw.this,
                        "Fail to get Camera",
                        Toast.LENGTH_LONG).show();
            }
    
            myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
            FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview);
            myCameraPreview.addView(myCameraSurfaceView);
    
            myButton = (Button)findViewById(R.id.mybutton);
            myButton.setOnClickListener(myButtonOnClickListener);
        }
    
        Button.OnClickListener myButtonOnClickListener
                = new Button.OnClickListener(){
    
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
    
                try{
                    if(recording){
                        // stop recording and release camera
                        mediaRecorder.stop();  // stop the recording
                        releaseMediaRecorder(); // release the MediaRecorder object
    
                        //Exit after saved
                        //finish();
                        myButton.setText("REC");
                        recording = false;
                    }else{
    
                        //Release Camera before MediaRecorder start
                        releaseCamera();
    
                        if(!prepareMediaRecorder()){
                            Toast.makeText(VideoWithSurfaceVw.this,
                                    "Fail in prepareMediaRecorder()!\n - Ended -",
                                    Toast.LENGTH_LONG).show();
                            finish();
                        }
    
                        mediaRecorder.start();
                        recording = true;
                        myButton.setText("STOP");
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }};
    
        private Camera getCameraInstance(){
            // TODO Auto-generated method stub
            Camera c = null;
            try {
                c = Camera.open(); // attempt to get a Camera instance
            }
            catch (Exception e){
                // Camera is not available (in use or does not exist)
            }
            return c; // returns null if camera is unavailable
        }
    
        private String getFileName_CustomFormat() {
            SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH_mm_ss");
            Date now = new Date();
            String strDate = sdfDate.format(now);
            return strDate;
        }
    
    
        private boolean prepareMediaRecorder(){
            myCamera = getCameraInstance();
            mediaRecorder = new MediaRecorder();
    
            myCamera.unlock();
            mediaRecorder.setCamera(myCamera);
    
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    
            mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
    
    
    
            mediaRecorder.setOutputFile("/sdcard/" + getFileName_CustomFormat() + ".mp4");
            //mediaRecorder.setOutputFile("/sdcard/myvideo1.mp4");
            mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
            mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M
    
            mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());
    
            try {
                mediaRecorder.prepare();
            } catch (IllegalStateException e) {
                releaseMediaRecorder();
                return false;
            } catch (IOException e) {
                releaseMediaRecorder();
                return false;
            }
            return true;
    
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            releaseMediaRecorder();       // if you are using MediaRecorder, release it first
            releaseCamera();              // release the camera immediately on pause event
        }
    
        private void releaseMediaRecorder(){
            if (mediaRecorder != null) {
                mediaRecorder.reset();   // clear recorder configuration
                mediaRecorder.release(); // release the recorder object
                mediaRecorder = new MediaRecorder();
                myCamera.lock();           // lock camera for later use
            }
        }
    
        private void releaseCamera(){
            if (myCamera != null){
                myCamera.release();        // release the camera for other applications
                myCamera = null;
            }
        }
    
        public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
    
            private SurfaceHolder mHolder;
            private Camera mCamera;
    
            public MyCameraSurfaceView(Context context, Camera camera) {
                super(context);
                mCamera = camera;
    
                // Install a SurfaceHolder.Callback so we get notified when the
                // underlying surface is created and destroyed.
                mHolder = getHolder();
                mHolder.addCallback(this);
                // deprecated setting, but required on Android versions prior to 3.0
                mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int weight,
                                       int height) {
                // If your preview can change or rotate, take care of those events here.
                // Make sure to stop the preview before resizing or reformatting it.
    
                if (mHolder.getSurface() == null){
                    // preview surface does not exist
                    return;
                }
    
                // stop preview before making changes
                try {
                    mCamera.stopPreview();
                } catch (Exception e){
                    // ignore: tried to stop a non-existent preview
                }
    
                // make any resize, rotate or reformatting changes here
    
                // start preview with new settings
                try {
                    mCamera.setPreviewDisplay(mHolder);
                    mCamera.startPreview();
    
                } catch (Exception e){
                }
            }
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                // TODO Auto-generated method stub
                // The Surface has been created, now tell the camera where to draw the preview.
                try {
                    mCamera.setPreviewDisplay(holder);
                    mCamera.startPreview();
                } catch (IOException e) {
                }
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // TODO Auto-generated method stub
    
            }
        }
    }
    

    activity (activity_video_with_surface_vw)

    <RelativeLayout android:id="@+id/surface_camera"     
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_centerInParent="true"
    android:layout_weight="1"
    >
    
    <RelativeLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <FrameLayout
            android:id="@+id/videoview"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
        <Button
            android:id="@+id/mybutton"
            android:layout_width="100dp"
            android:layout_height="50dp"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            android:text="REC"
            android:textSize="12dp"/>
    </RelativeLayout>
    
    </RelativeLayout>
    
    0 讨论(0)
  • 2020-11-22 12:22

    As a side note - there seems to be a bug in the Android API or faulty documentation or maybe I am just plain stupid. The google docs clearly states the following:

    Note: Starting with Android 4.0 (API level 14), the Camera.lock() and Camera.unlock() calls are managed for you automatically.

    See: http://developer.android.com/guide/topics/media/camera.html

    This does not seem to be the case!

    After batteling for literaly days without any success and many little problems like "failed to start" kinda errors I decided to manually implement the locking and BAM! everything worked fine.

    Im using the genymotion emulator for a 4.1.1 device with a min sdk of 14.

    0 讨论(0)
  • 2020-11-22 12:25

    Here is a simple video recording example using the MediaRecorder:

    public class VideoCapture extends Activity implements OnClickListener, SurfaceHolder.Callback {
        MediaRecorder recorder;
        SurfaceHolder holder;
        boolean recording = false;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    
            recorder = new MediaRecorder();
            initRecorder();
            setContentView(R.layout.main);
    
            SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView);
            holder = cameraView.getHolder();
            holder.addCallback(this);
            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
            cameraView.setClickable(true);
            cameraView.setOnClickListener(this);
        }
    
        private void initRecorder() {
            recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
            recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
    
            CamcorderProfile cpHigh = CamcorderProfile
                    .get(CamcorderProfile.QUALITY_HIGH);
            recorder.setProfile(cpHigh);
            recorder.setOutputFile("/sdcard/videocapture_example.mp4");
            recorder.setMaxDuration(50000); // 50 seconds
            recorder.setMaxFileSize(5000000); // Approximately 5 megabytes
        }
    
        private void prepareRecorder() {
            recorder.setPreviewDisplay(holder.getSurface());
    
            try {
                recorder.prepare();
            } catch (IllegalStateException e) {
                e.printStackTrace();
                finish();
            } catch (IOException e) {
                e.printStackTrace();
                finish();
            }
        }
    
        public void onClick(View v) {
            if (recording) {
                recorder.stop();
                recording = false;
    
                // Let's initRecorder so we can record again
                initRecorder();
                prepareRecorder();
            } else {
                recording = true;
                recorder.start();
            }
        }
    
        public void surfaceCreated(SurfaceHolder holder) {
            prepareRecorder();
        }
    
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
        }
    
        public void surfaceDestroyed(SurfaceHolder holder) {
            if (recording) {
                recorder.stop();
                recording = false;
            }
            recorder.release();
            finish();
        }
    }
    

    It's from my book: Pro Android Media: Developing Graphics, Music, Video, and Rich Media Apps for Smartphones and Tablets

    Also, do not forget to include these permissions in manifest:

    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    0 讨论(0)
  • 2020-11-22 12:25

    This demo will helpful for you....

    video.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
    <ToggleButton
        android:id="@+id/toggleRecordingButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true" />
    
    <SurfaceView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/surface_camera"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_centerInParent="true"
        android:layout_weight="1" >
    </SurfaceView>
    

    Your Main Activity: Video.java

     public class Video extends Activity implements OnClickListener,
        SurfaceHolder.Callback {
    
    private static final String TAG = "CAMERA_TUTORIAL";
    
    private SurfaceView mSurfaceView;
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private boolean previewRunning;
    private MediaRecorder mMediaRecorder;
    private final int maxDurationInMs = 20000;
    private final long maxFileSizeInBytes = 500000;
    private final int videoFramesPerSecond = 20;
    Button btn_record;
    boolean mInitSuccesful = false;
    File file;
    ToggleButton mToggleButton;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.video);
    
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    
        mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
        mToggleButton = (ToggleButton) findViewById(R.id.toggleRecordingButton);
        mToggleButton.setOnClickListener(new OnClickListener() {
            @Override
            // toggle video recording
            public void onClick(View v) {
                if (((ToggleButton) v).isChecked())
                    mMediaRecorder.start();
                else {
                    mMediaRecorder.stop();
                    mMediaRecorder.reset();
                    try {
                        initRecorder(mHolder.getSurface());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
    
    private void initRecorder(Surface surface) throws IOException {
        // It is very important to unlock the camera before doing setCamera
        // or it will results in a black preview
        if (mCamera == null) 
        {
            mCamera = Camera.open();
            mCamera.unlock();
        }
    
        if (mMediaRecorder == null)
            mMediaRecorder = new MediaRecorder();
    
        mMediaRecorder.setPreviewDisplay(surface);
        mMediaRecorder.setCamera(mCamera);
    
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
    
        mMediaRecorder.setOutputFile(this.initFile().getAbsolutePath());
    
        // No limit. Don't forget to check the space on disk.
        mMediaRecorder.setMaxDuration(50000);
        mMediaRecorder.setVideoFrameRate(24);
        mMediaRecorder.setVideoSize(1280, 720);
        mMediaRecorder.setVideoEncodingBitRate(3000000);
        mMediaRecorder.setAudioEncodingBitRate(8000);
    
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            // This is thrown if the previous calls are not called with the
            // proper order
            e.printStackTrace();
        }
    
        mInitSuccesful = true;
    }
    
    private File initFile() {
        // File dir = new
        // File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),
        // this
        File dir = new File(Environment.getExternalStorageDirectory(), this
                .getClass().getPackage().getName());
    
    
        if (!dir.exists() && !dir.mkdirs()) {
            Log.wtf(TAG,
                    "Failed to create storage directory: "
                            + dir.getAbsolutePath());
            Toast.makeText(Video.this, "not record", Toast.LENGTH_SHORT);
            file = null;
        } else {
            file = new File(dir.getAbsolutePath(), new SimpleDateFormat(
                    "'IMG_'yyyyMMddHHmmss'.mp4'").format(new Date()));
        }
        return file;
    }
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            if (!mInitSuccesful)
                initRecorder(mHolder.getSurface());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    private void shutdown() {
        // Release MediaRecorder and especially the Camera as it's a shared
        // object that can be used by other applications
        mMediaRecorder.reset();
        mMediaRecorder.release();
        mCamera.release();
    
        // once the objects have been released they can't be reused
        mMediaRecorder = null;
        mCamera = null;
    }
    
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        shutdown();
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
    
    }
    
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
    
    }
    
    }
    

    MediaMetadataRetriever Class

    public class MediaMetadataRetriever {
    
     static {
            System.loadLibrary("media_jni");
            native_init();
        }
    
        // The field below is accessed by native methods
        @SuppressWarnings("unused")
        private int mNativeContext;
    
        public MediaMetadataRetriever() {
            native_setup();
        }
    
        /**
         * Call this method before setDataSource() so that the mode becomes
         * effective for subsequent operations. This method can be called only once
         * at the beginning if the intended mode of operation for a
         * MediaMetadataRetriever object remains the same for its whole lifetime,
         * and thus it is unnecessary to call this method each time setDataSource()
         * is called. If this is not never called (which is allowed), by default the
         * intended mode of operation is to both capture frame and retrieve meta
         * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY).
         * Often, this may not be what one wants, since doing this has negative
         * performance impact on execution time of a call to setDataSource(), since
         * both types of operations may be time consuming.
         * 
         * @param mode The intended mode of operation. Can be any combination of 
         * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY:
         * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: 
         *    For neither frame capture nor meta data retrieval
         * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only
         * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only
         * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: 
         *    For both frame capture and meta data retrieval
         */
        public native void setMode(int mode);
    
        /**
         * @return the current mode of operation. A negative return value indicates
         * some runtime error has occurred.
         */
        public native int getMode();
    
        /**
         * Sets the data source (file pathname) to use. Call this
         * method before the rest of the methods in this class. This method may be
         * time-consuming.
         * 
         * @param path The path of the input media file.
         * @throws IllegalArgumentException If the path is invalid.
         */
        public native void setDataSource(String path) throws IllegalArgumentException;
    
        /**
         * Sets the data source (FileDescriptor) to use.  It is the caller's
         * responsibility to close the file descriptor. It is safe to do so as soon
         * as this call returns. Call this method before the rest of the methods in
         * this class. This method may be time-consuming.
         * 
         * @param fd the FileDescriptor for the file you want to play
         * @param offset the offset into the file where the data to be played starts,
         * in bytes. It must be non-negative
         * @param length the length in bytes of the data to be played. It must be
         * non-negative.
         * @throws IllegalArgumentException if the arguments are invalid
         */
        public native void setDataSource(FileDescriptor fd, long offset, long length)
                throws IllegalArgumentException;
    
        /**
         * Sets the data source (FileDescriptor) to use. It is the caller's
         * responsibility to close the file descriptor. It is safe to do so as soon
         * as this call returns. Call this method before the rest of the methods in
         * this class. This method may be time-consuming.
         * 
         * @param fd the FileDescriptor for the file you want to play
         * @throws IllegalArgumentException if the FileDescriptor is invalid
         */
        public void setDataSource(FileDescriptor fd)
                throws IllegalArgumentException {
            // intentionally less than LONG_MAX
            setDataSource(fd, 0, 0x7ffffffffffffffL);
        }
    
        /**
         * Sets the data source as a content Uri. Call this method before 
         * the rest of the methods in this class. This method may be time-consuming.
         * 
         * @param context the Context to use when resolving the Uri
         * @param uri the Content URI of the data you want to play
         * @throws IllegalArgumentException if the Uri is invalid
         * @throws SecurityException if the Uri cannot be used due to lack of
         * permission.
         */
        public void setDataSource(Context context, Uri uri)
            throws IllegalArgumentException, SecurityException {
            if (uri == null) {
                throw new IllegalArgumentException();
            }
    
            String scheme = uri.getScheme();
            if(scheme == null || scheme.equals("file")) {
                setDataSource(uri.getPath());
                return;
            }
    
            AssetFileDescriptor fd = null;
            try {
                ContentResolver resolver = context.getContentResolver();
                try {
                    fd = resolver.openAssetFileDescriptor(uri, "r");
                } catch(FileNotFoundException e) {
                    throw new IllegalArgumentException();
                }
                if (fd == null) {
                    throw new IllegalArgumentException();
                }
                FileDescriptor descriptor = fd.getFileDescriptor();
                if (!descriptor.valid()) {
                    throw new IllegalArgumentException();
                }
                // Note: using getDeclaredLength so that our behavior is the same
                // as previous versions when the content provider is returning
                // a full file.
                if (fd.getDeclaredLength() < 0) {
                    setDataSource(descriptor);
                } else {
                    setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
                }
                return;
            } catch (SecurityException ex) {
            } finally {
                try {
                    if (fd != null) {
                        fd.close();
                    }
                } catch(IOException ioEx) {
                }
            }
            setDataSource(uri.toString());
        }
    
        /**
         * Call this method after setDataSource(). This method retrieves the 
         * meta data value associated with the keyCode.
         * 
         * The keyCode currently supported is listed below as METADATA_XXX
         * constants. With any other value, it returns a null pointer.
         * 
         * @param keyCode One of the constants listed below at the end of the class.
         * @return The meta data value associate with the given keyCode on success; 
         * null on failure.
         */
        public native String extractMetadata(int keyCode);
    
        /**
         * Call this method after setDataSource(). This method finds a
         * representative frame if successful and returns it as a bitmap. This is
         * useful for generating a thumbnail for an input media source.
         * 
         * @return A Bitmap containing a representative video frame, which 
         *         can be null, if such a frame cannot be retrieved.
         */
        public native Bitmap captureFrame();
    
        /**
         * Call this method after setDataSource(). This method finds the optional
         * graphic or album art associated (embedded or external url linked) the 
         * related data source.
         * 
         * @return null if no such graphic is found.
         */
        public native byte[] extractAlbumArt();
    
        /**
         * Call it when one is done with the object. This method releases the memory
         * allocated internally.
         */
        public native void release();
        private native void native_setup();
        private static native void native_init();
    
        private native final void native_finalize();
    
        @Override
        protected void finalize() throws Throwable {
            try {
                native_finalize();
            } finally {
                super.finalize();
            }
        }
    
        public static final int MODE_GET_METADATA_ONLY  = 0x01;
        public static final int MODE_CAPTURE_FRAME_ONLY = 0x02;
    
        /*
         * Do not change these values without updating their counterparts
         * in include/media/mediametadataretriever.h!
         */
        public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
        public static final int METADATA_KEY_ALBUM           = 1;
        public static final int METADATA_KEY_ARTIST          = 2;
        public static final int METADATA_KEY_AUTHOR          = 3;
        public static final int METADATA_KEY_COMPOSER        = 4;
        public static final int METADATA_KEY_DATE            = 5;
        public static final int METADATA_KEY_GENRE           = 6;
        public static final int METADATA_KEY_TITLE           = 7;
        public static final int METADATA_KEY_YEAR            = 8;
        public static final int METADATA_KEY_DURATION        = 9;
        public static final int METADATA_KEY_NUM_TRACKS      = 10;
        public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11;
        public static final int METADATA_KEY_CODEC           = 12;
        public static final int METADATA_KEY_RATING          = 13;
        public static final int METADATA_KEY_COMMENT         = 14;
        public static final int METADATA_KEY_COPYRIGHT       = 15;
        public static final int METADATA_KEY_BIT_RATE        = 16;
        public static final int METADATA_KEY_FRAME_RATE      = 17;
        public static final int METADATA_KEY_VIDEO_FORMAT    = 18;
        public static final int METADATA_KEY_VIDEO_HEIGHT    = 19;
        public static final int METADATA_KEY_VIDEO_WIDTH     = 20;
        public static final int METADATA_KEY_WRITER          = 21;
        // Add more here...
    }
    
    0 讨论(0)
提交回复
热议问题