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

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

跑題了,跑題了,接下來是我要表達的重點...就是vlcjni中只提供了傳入流的地址和文件的地址,而我們要播放U盤中的視頻只能夠拿到流(當(dāng)然你也可以復(fù)制到SD卡里面去播放,幾個G的視頻那...)的情況下有兩個思路去播放@1我們將手機自己作為一個服務(wù)器,然后拿到地址傳到vlc(可以用netty),第二個思路就是播放器播放的時候拿到不也是個流然后進行解封裝解碼來播放,按照這個思路我們可以進行如下操作...
先定義一個FileRead的文件讀取類供jni調(diào)用,實際上是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ǔ)上加的,我這里偷懶直接把我們注冊方法寫入到他原有的方法里面了,懶得去一個一個寫注冊了.一步一步來
第一我們要注冊聲明我們類文件實際上這里也是用的反射獲取的

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)換一定要細心,比較容易搞混.
其中獲取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é)束的時候取消我們線程和虛擬機的綁定,在我自己測的幾部手機都是沒有問題的,但是在樂視的某些手機會直接崩潰...這個問題應(yīng)該是和手機的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);
}

至于里面頭文件的申明和引用就不用多說了,最后一步就是重點了,如何修改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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容