之前一直想写这篇文章奈何没什么时间(注:本文需要您有一定的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;
}
}
};
跑题了,跑题了,接下来是我要表达的重点...就是vlc在jni中只提供了传入流的地址和文件的地址,而我们要播放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;
}
里面修改的地方我已经做了注释了,也没什么好说明的,这篇文章主要给大家提供一个解决的思路,遇到的这种需求的人应该比较少,不过也是对技术的提升