android播放外接U盘(OTG)中的视频音频文件(使用vlc)

之前一直想写这篇文章奈何没什么时间(注:本文需要您有一定的JNI基础,C/C++基础,以及在Linux环境下编译vlc的so文件的能力),做的一个关于U盘挂载然后播放里面的视频文件(视频文件经过特定的编码处理,所以我们这边的播放器也是定制,使用的是vlc),其中一个比较蛋疼的地方就是拿到U盘中某个文件的真实路径,然后传入vlc播放,但是现在的厂商的ROM啊................虽然通过判断各种挂载信息有可能拿到真实路径,但是不怎么准确,我这里使用了一个第三方的项目来获取U盘的文件信息以及能够拿到文件流

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

网上也有比较多关于这个库的使用,我就不做赘述了
在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)) {  //允许权限申请
                        if (usbDevice != null) {  //Do something
                            Toast.makeText(OtgActivity.this,"用户已授权,可以进行读取操作",Toast.LENGTH_SHORT).show();
                            readDevice(getUsbMass(usbDevice));
                        } else {
                            Toast.makeText(OtgActivity.this,"未获取到设备信息",Toast.LENGTH_SHORT).show();
                        }
                    } else {
                        Toast.makeText(OtgActivity.this,"用户未授权,读取失败",Toast.LENGTH_SHORT).show();
                    }
                    break;
                case UsbManager.ACTION_USB_DEVICE_ATTACHED://接收到存储设备插入广播
                    UsbDevice device_add = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device_add != null) {
                        Toast.makeText(OtgActivity.this,"存储设备已插入,尝试读取",Toast.LENGTH_SHORT).show();
                        redDeviceList();
                    }
                    break;
                case UsbManager.ACTION_USB_DEVICE_DETACHED://接收到存储设备拔出广播
                    UsbDevice device_remove = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (device_remove != null) {
                        Toast.makeText(OtgActivity.this,"存储设备已拔出",Toast.LENGTH_SHORT).show();
                        usbFiles.clear();
                        adapter.notifyDataSetChanged();
                        cFolder = null;
                    }
                    break;
            }
        }
    };

跑题了,跑题了,接下来是我要表达的重点...就是vlcjni中只提供了传入流的地址和文件的地址,而我们要播放U盘中的视频只能够拿到流(当然你也可以复制到SD卡里面去播放,几个G的视频那...)的情况下有两个思路去播放@1我们将手机自己作为一个服务器,然后拿到地址传到vlc(可以用netty),第二个思路就是播放器播放的时候拿到不也是个流然后进行解封装解码来播放,按照这个思路我们可以进行如下操作...
先定义一个FileRead的文件读取类供jni调用,实际上是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代码也是在原基础上加的,我这里偷懒直接把我们注册方法写入到他原有的方法里面了,懒得去一个一个写注册了.一步一步来
第一我们要注册声明我们类文件实际上这里也是用的反射获取的

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里面要调用的方法我这里定义为了

    libvlc_set_file_callback(vlc_f_open, vlc_f_read, vlc_f_seek, vlc_f_close, vlc_f_length);//这个方法是我们vlc要调用的

第三步就是vlc中各个方法的具体对应调用我们的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;
}

这里的参数类型转换一定要细心,比较容易搞混.
其中获取JNIEnv这个结构体的方法有个坑我把方法贴出来

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函数,这个函数的具体作用就是在结束的时候取消我们线程和虚拟机的绑定,在我自己测的几部手机都是没有问题的,但是在乐视的某些手机会直接崩溃...这个问题应该是和手机的cpu有关..不过还是必须要加上的
接下来我们就要修改vlc中的代码了,我都是按照vlc他的各个模块的代码来加的代码..不得不说vlc的代码真的具有艺术性,超高度解耦.
vlc/lib这个目录下全部都是与jni打交道的.c文件 我是在media.c当中加入

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播放时控制流的读取,我们可以先看下当中的部分方法

/*****************************************************************************
 * 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;
}

里面修改的地方我已经做了注释了,也没什么好说明的,这篇文章主要给大家提供一个解决的思路,遇到的这种需求的人应该比较少,不过也是对技术的提升

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容