之前一直想寫這篇文章奈何沒什么時間(注:本文需要您有一定的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)...就是vlc在jni中只提供了傳入流的地址和文件的地址,而我們要播放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ù)的提升