android播放外接U盤(OTG)中的視頻音頻文件(使用vlc)

之前一直想寫這篇文章奈何沒什么時間(注:本文需要您有一定的JNI基礎(chǔ)衷模,C/C++基礎(chǔ)梗掰,以及在Linux環(huán)境下編譯vlc的so文件的能力),做的一個關(guān)于U盤掛載然后播放里面的視頻文件(視頻文件經(jīng)過特定的編碼處理,所以我們這邊的播放器也是定制,使用的是vlc),其中一個比較蛋疼的地方就是拿到U盤中某個文件的真實(shí)路徑,然后傳入vlc播放,但是現(xiàn)在的廠商的ROM啊................雖然通過判斷各種掛載信息有可能拿到真實(shí)路徑,但是不怎么準(zhǔn)確,我這里使用了一個第三方的項(xiàng)目來獲取U盤的文件信息以及能夠拿到文件流

compile 'com.github.mjdev:libaums:+'

網(wǎng)上也有比較多關(guān)于這個庫的使用,我就不做贅述了
在U盤插入拔出的時候加個廣播然后開始使用這個庫讀取文件的操作

   private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            switch (action) {
                case ACTION_USB_PERMISSION://接受到自定義廣播
                    UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {  //允許權(quán)限申請
                        if (usbDevice != null) {  //Do something
                            Toast.makeText(OtgActivity.this,"用戶已授權(quán)檀葛,可以進(jìn)行讀取操作",Toast.LENGTH_SHORT).show();
                            readDevice(getUsbMass(usbDevice));
                        } else {
                            Toast.makeText(OtgActivity.this,"未獲取到設(shè)備信息",Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(OtgActivity.this,"用戶未授權(quán),讀取失敗",Toast.LENGTH_SHORT).show();
                    }
                    break;
                case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到存儲設(shè)備插入廣播
                    UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device_add != null) {
                        Toast.makeText(OtgActivity.this,"存儲設(shè)備已插入铐达,嘗試讀取",Toast.LENGTH_SHORT).show();
                        redDeviceList();
                    }
                    break;
                case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到存儲設(shè)備拔出廣播
                    UsbDevice device_remove = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device_remove != null) {
                        Toast.makeText(OtgActivity.this,"存儲設(shè)備已拔出",Toast.LENGTH_SHORT).show();
                        usbFiles.clear();
                        adapter.notifyDataSetChanged();
                        cFolder = null;
                    }
                    break;
            }
        }
    };

跑題了,跑題了,接下來是我要表達(dá)的重點(diǎn)...就是vlcjni中只提供了傳入流的地址和文件的地址,而我們要播放U盤中的視頻只能夠拿到流(當(dāng)然你也可以復(fù)制到SD卡里面去播放,幾個G的視頻那...)的情況下有兩個思路去播放@1我們將手機(jī)自己作為一個服務(wù)器,然后拿到地址傳到vlc(可以用netty),第二個思路就是播放器播放的時候拿到不也是個流然后進(jìn)行解封裝解碼來播放,按照這個思路我們可以進(jìn)行如下操作...
先定義一個FileRead的文件讀取類供jni調(diào)用,實(shí)際上是vlc里面播放的時候要用,這個后面會說到

public class FileRead {
    public static UsbFileInputStream ins = null;
    public static UsbFile usbFile = null;
    public static RandomAccessFile randomFile = null;

    public static void initFile(UsbFile file, int configLength) {
        usbFile = file;
        ins = new UsbFileInputStream(file);
    }

    public static int open(String spath) {

        return 0;
    }

    public static long FileSize() {
        return usbFile.getLength();
    }

    public static long seek(long offset) {
        try {
            if (ins != null) {
                ins.close();
                ins = new UsbFileInputStream(usbFile);
                ins.skip(offset);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static int read(byte[] buffer, long offset, int len) {
        int result = 0;
        try {
            if (ins != null) {
                result = ins.read(buffer);
                if (result <= 0) result = 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    public static void close() {
        try {
            if (ins != null) {
                ins.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

我是直接用的vlc自帶的lib庫,所以加的jni代碼也是在原基礎(chǔ)上加的,我這里偷懶直接把我們注冊方法寫入到他原有的方法里面了,懶得去一個一個寫注冊了.一步一步來
第一我們要注冊聲明我們類文件實(shí)際上這里也是用的反射獲取的

void initClassHelper(JNIEnv *env, const char *path, jobject *objptr) {
    jclass cls = (*env)->FindClass(env,path);
    if(!cls) {
        LOGE("initClassHelper: failed to get %s class reference", path);
        return;
    }
    jmethodID constr = (*env)->GetMethodID(env,cls, "<init>", "()V");
    if(!constr) {
        LOGE("initClassHelper: failed to get %s constructor", path);
        return;
    }
    jobject obj = (*env)->NewObject(env,cls, constr);
    if(!obj) {
        LOGE("initClassHelper: failed to create a %s object", path);
        return;
    }
    (*objptr) = (*env)->NewGlobalRef(env,obj);
}

第二步就是我們vlc里面要調(diào)用的方法我這里定義為了

    libvlc_set_file_callback(vlc_f_open, vlc_f_read, vlc_f_seek, vlc_f_close, vlc_f_length);//這個方法是我們vlc要調(diào)用的

第三步就是vlc中各個方法的具體對應(yīng)調(diào)用我們的java方法了

int64_t* vlc_f_open(int64_t *fsize,const char* spath){
    JNIEnv* env = jni_get_env("open");
    jclass cls = (*env)->GetObjectClass(env,gInterfaceObject);
    if (cls != 0)
    {
        jmethodID mid = (*env)->GetStaticMethodID(env, cls, "open", "(Ljava/lang/String;)I");
        if (mid != 0)
        {
            int result = (*env)->CallStaticIntMethod(env, cls, mid,(*env)->NewStringUTF(env,spath));
            (*env)->DeleteLocalRef(env,cls);
            return result;
        }
    }

    return 0;
}

int64_t vlc_f_length(){
    JNIEnv* env = jni_get_env("length");
    jclass cls = (*env)->GetObjectClass(env,gInterfaceObject);
    if (cls != 0)
    {
        jmethodID mid = (*env)->GetStaticMethodID(env, cls, "FileSize", "()J");
        if (mid != 0)
        {
            jlong result = (*env)->CallStaticLongMethod(env, cls, mid);
            (*env)->DeleteLocalRef(env,cls);

            return result;
        }
    }
    return 0;
}

int vlc_f_read(char* buffer, int64_t offset, int size){
    JNIEnv* env = jni_get_env("read");
    jclass cls = (*env)->GetObjectClass(env,gInterfaceObject);

    if (cls != 0)
    {

        jmethodID mid = (*env)->GetStaticMethodID(env, cls,  "read", "([BJI)I");
        if (mid != 0)
        {

            jbyteArray arr = (*env)->NewByteArray(env,size);
            jint result = (*env)->CallStaticIntMethod(env, cls, mid, arr,offset,size);
            (*env)->GetByteArrayRegion(env,arr,0,result,buffer);
            (*env)->DeleteLocalRef(env,arr);
            (*env)->DeleteLocalRef(env,cls);

            return result;
        }
    }
    return 0;
}
int vlc_f_seek(int64_t offset){
    JNIEnv* env = jni_get_env("offset");
    jclass cls = (*env)->GetObjectClass(env,gInterfaceObject);
    if (cls != 0)
    {
        jmethodID mid = (*env)->GetStaticMethodID(env, cls,  "seek", "(J)J");
        if (mid != 0)
        {
            jint result = (*env)->CallStaticLongMethod(env, cls, mid,offset);
            (*env)->DeleteLocalRef(env,cls);

            return result;
        }
    }
    return 0;
}
int  vlc_f_close(){
    JNIEnv* env = jni_get_env("close");
    jclass cls = (*env)->GetObjectClass(env,gInterfaceObject);
    if (cls != 0)
    {
        jmethodID mid = (*env)->GetStaticMethodID(env, cls, "close", "()V");
        if (mid != 0)
        {
            (*env)->CallStaticVoidMethod(env, cls, mid);
            (*env)->DeleteLocalRef(env,cls);
            return 0;
        }
    }
    return 0;
}

這里的參數(shù)類型轉(zhuǎn)換一定要細(xì)心,比較容易搞混.
其中獲取JNIEnv這個結(jié)構(gòu)體的方法有個坑我把方法貼出來

JNIEnv *jni_get_env(const char *name)
{
    JNIEnv *env;

    env = pthread_getspecific(jni_env_key);
    if (env == NULL) {
        if ((*myVm)->GetEnv(myVm, (void **)&env, VLC_JNI_VERSION) != JNI_OK)
        {
            JavaVMAttachArgs args;
            jint result;
            args.version = VLC_JNI_VERSION;
            args.name = name;
            args.group = NULL;

            if ((*myVm)->AttachCurrentThread(myVm, &env, &args) != JNI_OK)
                return NULL;
            if (pthread_setspecific(jni_env_key, env) != 0)
            {
                (*myVm)->DetachCurrentThread(myVm);
                return NULL;
            }
        }
    }

    return env;
}

剛開始自己少了一個DetachCurrentThread函數(shù),這個函數(shù)的具體作用就是在結(jié)束的時候取消我們線程和虛擬機(jī)的綁定,在我自己測的幾部手機(jī)都是沒有問題的,但是在樂視的某些手機(jī)會直接崩潰...這個問題應(yīng)該是和手機(jī)的cpu有關(guān)..不過還是必須要加上的
接下來我們就要修改vlc中的代碼了,我都是按照vlc他的各個模塊的代碼來加的代碼..不得不說vlc的代碼真的具有藝術(shù)性,超高度解耦.
vlc/lib這個目錄下全部都是與jni打交道的.c文件 我是在media.c當(dāng)中加入

void libvlc_set_file_callback(f_open fo, f_read fr, f_seek fs, f_close fc, f_length fl){
vlc_set_file_callback( fo,  fr,  fs,  fc,  fl);
}

至于里面頭文件的申明和引用就不用多說了,最后一步就是重點(diǎn)了,如何修改vlc自帶的文件的讀取方法,我們可以在vlc/modules/access的目錄下找到file.c文件 這個文件就是vlc播放時控制流的讀取,我們可以先看下當(dāng)中的部分方法

/*****************************************************************************
 * FileOpen: open the file
 *****************************************************************************/
int FileOpen( vlc_object_t *p_this )
{
    stream_t *p_access = (stream_t*)p_this;

    /* Open file */
    int fd = -1;


//
     if (p_access->file_open)
        {
            uint64_t i_size = 0;
            int result = p_access->file_open(&i_size,p_access->psz_location);
            if( result > 0 )
            {
                access_sys_t *p_sys = vlc_obj_malloc(p_this, sizeof (*p_sys));
                char* file_path = p_access->psz_location;
                if (unlikely(p_sys == NULL))
                            goto error;
                        p_access->pf_read = Read;
                        p_access->pf_block = NULL;
                        p_access->pf_control = FileControl;
                        p_access->p_sys = p_sys;
                        p_sys->fd = DEFAULT_HANDLE;

                        p_access->pf_seek = FileSeek;
                        p_sys->b_pace_control = true;


                        /* Demuxers will need the beginning of the file for probing. */
                        posix_fadvise (fd, 0, 4096, POSIX_FADV_WILLNEED);
                        /* In most cases, we only read the file once. */
                        posix_fadvise (fd, 0, 0, POSIX_FADV_NOREUSE);

                        return VLC_SUCCESS;
            }

        }


    if (!strcasecmp (p_access->psz_name, "fd"))
    {
        char *end;
        int oldfd = strtol (p_access->psz_location, &end, 10);

        if (*end == '\0')
            fd = vlc_dup (oldfd);
        else if (*end == '/' && end > p_access->psz_location)
        {
            char *name = vlc_uri_decode_duplicate (end - 1);
            if (name != NULL)
            {
                name[0] = '.';
                fd = vlc_openat (oldfd, name, O_RDONLY | O_NONBLOCK);
                free (name);
            }
        }
    }
    else
    {
        if (unlikely(p_access->psz_filepath == NULL))
            return VLC_EGENERIC;
        fd = vlc_open (p_access->psz_filepath, O_RDONLY | O_NONBLOCK);
    }

    if (fd == -1)
    {
        msg_Err (p_access, "cannot open file %s (%s)",
                 p_access->psz_filepath ? p_access->psz_filepath
                                        : p_access->psz_location,
                 vlc_strerror_c(errno));
        return VLC_EGENERIC;
    }

    struct stat st;
    if (fstat (fd, &st))
    {
        msg_Err (p_access, "read error: %s", vlc_strerror_c(errno));
        goto error;
    }

#if O_NONBLOCK
    /* Force blocking mode back */
    fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) & ~O_NONBLOCK);
#endif

    /* Directories can be opened and read from, but only readdir() knows
     * how to parse the data. The directory plugin will do it. */
    if (S_ISDIR (st.st_mode))
    {
#ifdef HAVE_FDOPENDIR
        DIR *p_dir = fdopendir(fd);
        if (!p_dir) {
            msg_Err (p_access, "fdopendir error: %s", vlc_strerror_c(errno));
            goto error;
        }
        return DirInit (p_access, p_dir);
#else
        msg_Dbg (p_access, "ignoring directory");
        goto error;
#endif
    }

    access_sys_t *p_sys = vlc_obj_malloc(p_this, sizeof (*p_sys));
    if (unlikely(p_sys == NULL))
        goto error;
    p_access->pf_read = Read;
    p_access->pf_block = NULL;
    p_access->pf_control = FileControl;
    p_access->p_sys = p_sys;
    p_sys->fd = fd;

    if (S_ISREG (st.st_mode) || S_ISBLK (st.st_mode))
    {
        p_access->pf_seek = FileSeek;
        p_sys->b_pace_control = true;

        /* Demuxers will need the beginning of the file for probing. */
        posix_fadvise (fd, 0, 4096, POSIX_FADV_WILLNEED);
        /* In most cases, we only read the file once. */
        posix_fadvise (fd, 0, 0, POSIX_FADV_NOREUSE);
#ifdef F_NOCACHE
        fcntl (fd, F_NOCACHE, 0);
#endif
#ifdef F_RDAHEAD
        if (IsRemote(fd, p_access->psz_filepath))
            fcntl (fd, F_RDAHEAD, 0);
        else
            fcntl (fd, F_RDAHEAD, 1);
#endif
    }
    else
    {
        p_access->pf_seek = NoSeek;
        p_sys->b_pace_control = strcasecmp (p_access->psz_name, "stream");
    }

    return VLC_SUCCESS;

error:
    vlc_close (fd);
    return VLC_EGENERIC;
}

/*****************************************************************************
 * FileClose: close the target
 *****************************************************************************/
void FileClose (vlc_object_t * p_this)
{
    stream_t     *p_access = (stream_t*)p_this;

    if (p_access->pf_read == NULL)
    {
        DirClose (p_this);
        return;
    }

    access_sys_t *p_sys = p_access->p_sys;
    if (p_access->file_close && (DEFAULT_HANDLE == p_sys->fd))
    {
        p_access->file_close();
    }
    else
    {
        vlc_close (p_sys->fd);
    }

}


static ssize_t Read (stream_t *p_access, void *p_buffer, size_t i_len)
{
    access_sys_t *p_sys = p_access->p_sys;
    int fd = p_sys->fd;

    //ssize_t val = vlc_read_i11e (fd, p_buffer, i_len);
        ssize_t val = 0/**/;
        if (p_access->file_read && (DEFAULT_HANDLE == p_sys->fd))
        {
            val = p_access->file_read(p_buffer, 0, i_len);
        }
        else
        {
            vlc_read_i11e (fd, p_buffer, i_len);
        }
    if (val < 0)
    {
        switch (errno)
        {
            case EINTR:
            case EAGAIN:
                return -1;
        }

        msg_Err (p_access, "read error: %s", vlc_strerror_c(errno));
        val = 0;
    }

    return val;
}

/*****************************************************************************
 * Seek: seek to a specific location in a file
 *****************************************************************************/
static int FileSeek (stream_t *p_access, uint64_t i_pos)
{
    access_sys_t *sys = p_access->p_sys;
 if (p_access->file_seek && (DEFAULT_HANDLE == sys->fd))
    {
        p_access->file_seek(i_pos);
    }
    else
    {
        if (lseek(sys->fd, i_pos, SEEK_SET) == (off_t)-1)
                return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
static int FileControl( stream_t *p_access, int i_query, va_list args )
{
    access_sys_t *p_sys = p_access->p_sys;
    bool    *pb_bool;
    int64_t *pi_64;

    switch( i_query )
    {
        case STREAM_CAN_SEEK:
        case STREAM_CAN_FASTSEEK:
            pb_bool = va_arg( args, bool * );
            *pb_bool = (p_access->pf_seek != NoSeek);
            break;

        case STREAM_CAN_PAUSE:
        case STREAM_CAN_CONTROL_PACE:
            pb_bool = va_arg( args, bool * );
            *pb_bool = p_sys->b_pace_control;
            break;

        case STREAM_GET_SIZE:
        {    uint64_t i_size = 0;
             if(p_access->file_length && (DEFAULT_HANDLE == p_sys->fd))
             {
                i_size = p_access->file_length();
             }
             else
             {
                 struct stat st;
                 fstat (p_sys->fd, &st);
                 i_size = st.st_size;
             }
             *va_arg( args, uint64_t * ) = i_size;
            break;
        }

        case STREAM_GET_PTS_DELAY:
            pi_64 = va_arg( args, int64_t * );
            if (IsRemote (p_sys->fd, p_access->psz_filepath))
                *pi_64 = var_InheritInteger (p_access, "network-caching");
            else
                *pi_64 = var_InheritInteger (p_access, "file-caching");
            *pi_64 *= 1000;
            break;

        case STREAM_SET_PAUSE_STATE:
            /* Nothing to do */
            break;

        default:
            return VLC_EGENERIC;

    }
    return VLC_SUCCESS;

都有對文件的open,seek,read,close的操作,這個時候我們只需要將vlc播放的時候需要open,seek,read,close的操作,傳入我們自己定義的方法

int FileOpen( vlc_object_t *p_this )
{
    access_t     *p_access = (access_t*)p_this;

    /* Open file */
    int fd = -1;

    //cyxhlhaaaaaaaaaa
    if (p_access->file_open)
    {
        uint64_t i_size = 0;
        p_access->file_open(&i_size);
        access_sys_t *p_sys = malloc(sizeof(*p_sys));
        if (unlikely(p_sys == NULL))
            goto error;
        access_InitFields(p_access);
        p_access->pf_block = NULL;
        p_access->pf_control = FileControl;
        p_access->p_sys = p_sys;
        p_sys->fd = 6;

        p_access->pf_read = FileRead;
        p_access->pf_seek = FileSeek;
        p_sys->b_pace_control = true;
        p_sys->size = i_size;

        /* Demuxers will need the beginning of the file for probing. */
        posix_fadvise(fd, 0, 4096, POSIX_FADV_WILLNEED);
        /* In most cases, we only read the file once. */
        posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
        return VLC_SUCCESS;
    }

    if (!strcasecmp (p_access->psz_access, "fd"))
    {
        char *end;
        int oldfd = strtol (p_access->psz_location, &end, 10);

        if (*end == '\0')
            fd = vlc_dup (oldfd);
        else if (*end == '/' && end > p_access->psz_location)
        {
            char *name = decode_URI_duplicate (end - 1);
            if (name != NULL)
            {
                name[0] = '.';
                fd = vlc_openat (oldfd, name, O_RDONLY | O_NONBLOCK);
                free (name);
            }
        }
    }
    else
    {
        const char *path = p_access->psz_filepath;

        if (unlikely(path == NULL))
            return VLC_EGENERIC;
        msg_Dbg (p_access, "opening file `%s'", path);
        fd = vlc_open (path, O_RDONLY | O_NONBLOCK);
        if (fd == -1)
        {
            msg_Err (p_access, "cannot open file %s (%s)", path,
                     vlc_strerror_c(errno));
            dialog_Fatal (p_access, _("File reading failed"),
                          _("VLC could not open the file \"%s\" (%s)."), path,
                          vlc_strerror(errno));
        }
    }
    if (fd == -1)
        return VLC_EGENERIC;

    struct stat st;
    if (fstat (fd, &st))
    {
        msg_Err (p_access, "read error: %s", vlc_strerror_c(errno));
        goto error;
    }

#if O_NONBLOCK
    int flags = fcntl (fd, F_GETFL);
    if (S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode))
        /* Force non-blocking mode where applicable (fd://) */
        flags |= O_NONBLOCK;
    else
        /* Force blocking mode when not useful or not specified */
        flags &= ~O_NONBLOCK;
    fcntl (fd, F_SETFL, flags);
#endif

    /* Directories can be opened and read from, but only readdir() knows
     * how to parse the data. The directory plugin will do it. */
    if (S_ISDIR (st.st_mode))
    {
#ifdef HAVE_FDOPENDIR
        DIR *handle = fdopendir (fd);
        if (handle == NULL)
            goto error; /* Uh? */
        return DirInit (p_access, handle);
#else
        msg_Dbg (p_access, "ignoring directory");
        goto error;
#endif
    }

    access_sys_t *p_sys = malloc (sizeof (*p_sys));
    if (unlikely(p_sys == NULL))
        goto error;
    access_InitFields (p_access);
    p_access->pf_block = NULL;
    p_access->pf_control = FileControl;
    p_access->p_sys = p_sys;
    p_sys->fd = fd;

    if (S_ISREG (st.st_mode) || S_ISBLK (st.st_mode))
    {
        p_access->pf_read = FileRead;
        p_access->pf_seek = FileSeek;
        p_sys->b_pace_control = true;
        p_sys->size = st.st_size;

        /* Demuxers will need the beginning of the file for probing. */
        posix_fadvise (fd, 0, 4096, POSIX_FADV_WILLNEED);
        /* In most cases, we only read the file once. */
        posix_fadvise (fd, 0, 0, POSIX_FADV_NOREUSE);
#ifdef F_NOCACHE
        fcntl (fd, F_NOCACHE, 0);
#endif
#ifdef F_RDAHEAD
        if (IsRemote(fd, p_access->psz_filepath))
            fcntl (fd, F_RDAHEAD, 0);
        else
            fcntl (fd, F_RDAHEAD, 1);
#endif
    }
    else
    {
        p_access->pf_read = StreamRead;
        p_access->pf_seek = NoSeek;
        p_sys->b_pace_control = strcasecmp (p_access->psz_access, "stream");
        p_sys->size = 0;
    }

    return VLC_SUCCESS;

error:
    close (fd);
    return VLC_EGENERIC;
}

/*****************************************************************************
 * FileClose: close the target
 *****************************************************************************/
void FileClose (vlc_object_t * p_this)
{
    access_t     *p_access = (access_t*)p_this;

    if (p_access->pf_read == NULL)
    {
        DirClose (p_this);
        return;
    }

    access_sys_t *p_sys = p_access->p_sys;

    //cyxhlhaaaaaaaaaa
    if (p_access->file_close)
    {
        p_access->file_close();
    }
    //close (p_sys->fd);

    free (p_sys);
}


#include <vlc_network.h>

/**
 * Reads from a regular file.
 */
static ssize_t FileRead (access_t *p_access, uint8_t *p_buffer, size_t i_len)
{
    access_sys_t *p_sys = p_access->p_sys;
    int fd = p_sys->fd;

    //cyxhlhaaaaaaaaaa
    ssize_t val = 0/*read (fd, p_buffer, i_len)*/;
    if (p_access->file_read)
    {
        val = p_access->file_read(p_buffer, p_access->info.i_pos, i_len);
    }

    if (val < 0)
    {
        switch (errno)
        {
            case EINTR:
            case EAGAIN:
                return -1;
        }

        msg_Err (p_access, "read error: %s", vlc_strerror_c(errno));
        dialog_Fatal (p_access, _("File reading failed"),
                      _("VLC could not read the file (%s)."),
                      vlc_strerror(errno));
        val = 0;
    }

    p_access->info.i_pos += val;
    p_access->info.b_eof = !val;
    if (p_access->info.i_pos >= p_sys->size)
    {
        //cyxhlhaaaaaaaaaa
        uint64_t i_size = p_access->file_length();
        if (i_size > 0)
            p_sys->size = i_size;
        //struct stat st;

        //if (fstat (fd, &st) == 0)
            //p_sys->size = st.st_size;
    }
    return val;
}


/*****************************************************************************
 * Seek: seek to a specific location in a file
 *****************************************************************************/
static int FileSeek (access_t *p_access, uint64_t i_pos)
{
    p_access->info.i_pos = i_pos;
    p_access->info.b_eof = false;

    //cy
    if (p_access->file_seek)
    {
        p_access->file_seek(i_pos);
    }
    //lseek (p_access->p_sys->fd, i_pos, SEEK_SET);

    return VLC_SUCCESS;
}

/**
 * Reads from a non-seekable file.
 */
static ssize_t StreamRead (access_t *p_access, uint8_t *p_buffer, size_t i_len)
{
    access_sys_t *p_sys = p_access->p_sys;
    int fd = p_sys->fd;

#if !defined (_WIN32) && !defined (__OS2__)
    ssize_t val = net_Read (p_access, fd, NULL, p_buffer, i_len, false);
#else
    ssize_t val = read (fd, p_buffer, i_len);
#endif

    if (val < 0)
    {
        switch (errno)
        {
            case EINTR:
            case EAGAIN:
                return -1;
        }
        msg_Err (p_access, "read error: %s", vlc_strerror_c(errno));
        val = 0;
    }

    p_access->info.i_pos += val;
    p_access->info.b_eof = !val;
    return val;
}

static int NoSeek (access_t *p_access, uint64_t i_pos)
{
    /* assert(0); ?? */
    (void) p_access; (void) i_pos;
    return VLC_EGENERIC;
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
static int FileControl( access_t *p_access, int i_query, va_list args )
{
    access_sys_t *p_sys = p_access->p_sys;
    bool    *pb_bool;
    int64_t *pi_64;

    switch( i_query )
    {
        case ACCESS_CAN_SEEK:
        case ACCESS_CAN_FASTSEEK:
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = (p_access->pf_seek != NoSeek);
            break;

        case ACCESS_CAN_PAUSE:
        case ACCESS_CAN_CONTROL_PACE:
            pb_bool = (bool*)va_arg( args, bool* );
            *pb_bool = p_sys->b_pace_control;
            break;

        case ACCESS_GET_SIZE:
        {
            //cyxhlhaaaaaaaaaa
            //struct stat st;
            //if (fstat (p_sys->fd, &st) == 0)
                //p_sys->size = st.st_size;
            uint64_t i_size = p_access->file_length();
            if (i_size > 0)
                p_sys->size = i_size;

            *va_arg( args, uint64_t * ) = p_sys->size;
            break;
        }

        case ACCESS_GET_PTS_DELAY:
            pi_64 = (int64_t*)va_arg( args, int64_t * );
            if (IsRemote (p_sys->fd, p_access->psz_filepath))
                *pi_64 = var_InheritInteger (p_access, "network-caching");
            else
                *pi_64 = var_InheritInteger (p_access, "file-caching");
            *pi_64 *= 1000;
            break;

        case ACCESS_SET_PAUSE_STATE:
            /* Nothing to do */
            break;

        default:
            return VLC_EGENERIC;

    }
    return VLC_SUCCESS;
}

里面修改的地方我已經(jīng)做了注釋了,也沒什么好說明的,這篇文章主要給大家提供一個解決的思路,遇到的這種需求的人應(yīng)該比較少,不過也是對技術(shù)的提升

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秧饮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子穗泵,更是在濱河造成了極大的恐慌普气,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佃延,死亡現(xiàn)場離奇詭異现诀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)履肃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門仔沿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尺棋,你說我怎么就攤上這事于未。” “怎么了陡鹃?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵烘浦,是天一觀的道長。 經(jīng)常有香客問我萍鲸,道長闷叉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任脊阴,我火速辦了婚禮握侧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘿期。我一直安慰自己品擎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布备徐。 她就那樣靜靜地躺著萄传,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜜猾。 梳的紋絲不亂的頭發(fā)上秀菱,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天振诬,我揣著相機(jī)與錄音,去河邊找鬼衍菱。 笑死赶么,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脊串。 我是一名探鬼主播辫呻,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼琼锋!你這毒婦竟也來了放闺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤斩例,失蹤者是張志新(化名)和其女友劉穎雄人,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體念赶,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡础钠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叉谜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旗吁。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖停局,靈堂內(nèi)的尸體忽然破棺而出很钓,到底是詐尸還是另有隱情,我是刑警寧澤董栽,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布码倦,位于F島的核電站,受9級特大地震影響锭碳,放射性物質(zhì)發(fā)生泄漏袁稽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一擒抛、第九天 我趴在偏房一處隱蔽的房頂上張望推汽。 院中可真熱鬧,春花似錦歧沪、人聲如沸歹撒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暖夭。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鳞尔,已是汗流浹背嬉橙。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工早直, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寥假,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓霞扬,卻偏偏與公主長得像糕韧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子喻圃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

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