Android平台多个mpg文件连续播放
来源:互联网 发布:进驻淘宝协议 编辑:程序博客网 时间:2024/06/06 03:47
虽然Android4.1之后版本通过MediaPlayer的setNextMediaPlayer
()方法视频无缝播放,但是国产的N多ARM芯片并不支持这一特性,
如何才能让现有的平台达到无缝播放效果,方法有N多种,比如通过http的ts流方式或者将多个文件合并成一个文件在去播放,就可以变相解决该问题。
经过测试可以把同种编码格式的mpg文件cat在一起播放以达到目的,笔者顺着这个思路逐步从Linux kernel层到Android JNI和App层
逐步来实现;
java播放层
1、设置要播放的文件总大小
2、设置播放序列
3、将虚拟的proc内存文件赋值给播放器
int fd = MpgFS.open("/dev/mpg_fs"); int fileSize = 8290340 + 16240676 + 16240676 + 16240676; MpgFS.setFileSize(fd, fileSize); List<PlayNode> list = new ArrayList<PlayNode>(); list.add(new PlayNode("/mnt/sdcard/576/FM0.mpg", 8290340, 0)); list.add(new PlayNode("/mnt/sdcard/576/FM1.mpg", 16240676, 1)); list.add(new PlayNode("/mnt/sdcard/576/FM2.mpg", 16240676, 2)); list.add(new PlayNode("/mnt/sdcard/576/FM3.mpg", 16240676, 3)); MpgFS.setPlayList(list, fd); play.setVideoPath("/proc/mpg_fs");
JNI层的java部分
import java.util.List;public class MpgFS { static { System.loadLibrary("mpgfs_jni"); } public static final int NODE_SIZE = 128; public native static int open(String device); public native static int close(int fd); private native static int ioctl(int fd, int cmd, byte[] buf, long len); public static void int2buf(int value, byte[] buf, int offset) { buf[offset + 0] = (byte) ((value >> 0) & 0xff); buf[offset + 1] = (byte) ((value >> 8) & 0xff); buf[offset + 2] = (byte) ((value >> 16) & 0xff); buf[offset + 3] = (byte) ((value >> 24) & 0xff); } public static int setFileSize(int fd, long size) { return ioctl(fd, 5, null, size); } public static int setPlayList(List<PlayNode> list, int fd) { if (list == null || list.size() == 0) { return -1; } int size = list.size(); byte[] buffer = new byte[NODE_SIZE * size]; for (int i = 0; i < size; i++) { int offset = i * NODE_SIZE; PlayNode node = list.get(i); int2buf(node.size, buffer, offset); int2buf(node.seq, buffer, offset+4); int2buf(node.fd, buffer, offset+8); System.arraycopy(node.name.getBytes(), 0, buffer, offset+12, node.name.length()); } return ioctl(fd, 10000 + size, buffer, buffer.length); }}
JNI层的C部分
#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <stdint.h>#include <string.h>#include <jni.h>#include <android/log.h>#define LOG_TAG "MpgFS_JNI"#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)//#define LOGD(...)typedef struct play_node { int size; int seq; int fd; char name[128-12];} play_node_t;static const char *kClassName = "com/signway/mpgfs/MpgFS";jint openNative(JNIEnv *env, jobject obj, jstring name);jint closeNative(JNIEnv *env, jobject obj, jint fd);jint ioctlNative(JNIEnv *env, jobject obj, jint fd, jint cmd, jbyteArray buf, jlong length); static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ {"open", "(Ljava/lang/String;)I", (void*)openNative}, {"close", "(I)I", (void*)closeNative}, {"ioctl", "(II[BJ)I", (void*)ioctlNative}};jint openNative(JNIEnv *env, jobject obj, jstring name){ int fd = -1; const char *device = (*env)->GetStringUTFChars(env, name, NULL); fd = open(device, O_RDONLY); LOGD("device is %s and fd is %d", device, fd); (*env)->ReleaseStringUTFChars(env, name, device); return fd;}jint closeNative(JNIEnv *env, jobject obj, jint fd){ LOGD("close device"); close(fd);}jint ioctlNative(JNIEnv *env, jobject obj, jint fd, jint cmd, jbyteArray buf, jlong length){ int ret = 0; play_node_t play_file; memset(&play_file, 0, sizeof(play_node_t)); LOGD("ioctrl, cmd is:%d", cmd); switch (cmd) { case 0: case 1: case 2: case 3: case 4: case 5: // set file length ret = ioctl(fd, cmd, &length); break; default: if (cmd > 10000) { char *buffer = malloc(length); if (buffer) { (*env)->GetByteArrayRegion(env, buf, 0, (jsize)length, (jbyte*)buffer); ret = ioctl(fd, cmd, buffer); free(buffer); buffer = NULL; break; } LOGE("malloc error for buffer length is: %d", length); ret = -1; } break; } return ret;}jint JNI_OnLoad(JavaVM *vm, void *reserved){ JNIEnv *env = NULL; jclass cls; if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) { LOGE("current JNI not support JNI_VERSION_1_4"); return JNI_ERR; } cls = (*env)->FindClass(env, kClassName); if (cls == NULL) { LOGE("can not find class %s", kClassName); return JNI_ERR; } if ((*env)->RegisterNatives(env, cls, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK) { LOGE("can not register native methods"); return JNI_ERR; } return JNI_VERSION_1_4;}
kernel层的驱动部分
1、实现一个驱动/dev/mpg_fs,用于java层来控制播放列表
2、使用一个内存文件,/proc/mpg_fs,用来给mediaplayer作为播放文件路径
3、在kernel里读取文件,送往内存文件
#include <linux/module.h>#include <linux/module.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/init.h>#include <asm/uaccess.h>#include <linux/proc_fs.h>#include <linux/device.h>#include <linux/mutex.h>static struct proc_dir_entry* entry = NULL;static loff_t g_size = 0;static struct file *fd = NULL;static unsigned char buffer[16*1024];typedef struct play_node { int size; int seq; int fd; char name[128-12];} play_node_t;static play_node_t *play_list = NULL;static int play_list_count = 0;static DEFINE_MUTEX(mpg_fs_mutex);#define MUTEX_LOCK() mutex_lock(&mpg_fs_mutex)#define MUTEX_UNLOCK() mutex_unlock(&mpg_fs_mutex)#define DEVICE_NAME "mpg_fs"static int MPG_DEV_Major = 0;static struct class *mpg_dev_class;static int mpg_fs_open(struct inode *inode, struct file *file) { printk("mpg_fs_open()\n"); entry->size = g_size; return 0;}static int mpg_fs_release(struct inode *inode, struct file *file) { printk("mpg_fs_release()\n"); int i = 0; set_fs(KERNEL_DS); for (i = 0; i < play_list_count; i++) { filp_close(play_list[i].fd, NULL); } kfree(play_list); play_list = NULL; play_list_count = 0; return 0;}static int mpg_fs_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { int i = 0; int len = 0; int left = 0; int size = 0; loff_t pos = *f_pos; loff_t sum = 0; set_fs(KERNEL_DS); for (i = 0; i < play_list_count; i++) { size = play_list[i].size; if (pos + count <= sum + size) { fd = play_list[i].fd; fd->f_op->llseek(fd, pos-sum, 0); len = fd->f_op->read(fd, buffer, count, &fd->f_pos); break; } if (pos < sum + size) { left = sum + size - pos; play_list[i].fd; fd->f_op->llseek(fd, pos-sum, 0); fd->f_op->read(fd, buffer, left, &fd->f_pos); fd = play_list[i+1].fd; fd->f_op->llseek(fd, 0, 0); fd->f_op->read(fd, buffer+left, count-left, &fd->f_pos); len = count; break; } sum += size; } if (len > 0) { *f_pos += len; copy_to_user(buf, buffer, len); } else if (len == 0) { //TODO:: } return len;}static loff_t mpg_fs_llseek(struct file *file, loff_t f_pos, int orig) { if (orig == 0) { file->f_pos = f_pos; } else if (orig == 1) { file->f_pos += f_pos; } else if (orig == 2) { file->f_pos = g_size; } return file->f_pos;}static struct file_operations mpg_fs_fops = { .owner = THIS_MODULE, .open = mpg_fs_open, .release = mpg_fs_release, .read = mpg_fs_read, .llseek = mpg_fs_llseek,};static int mpg_dev_open(struct inode *inode, struct file *file) { printk("mpg_dev_open()\n"); return 0;}static int mpg_dev_release(struct inode *inode, struct file *file) { printk("mpg_dev_release()\n"); return 0;}static long mpg_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; printk("mpg_dev_ioctl(), cmd: %d\n", cmd); MUTEX_LOCK(); switch (cmd) { case 0: case 1: case 2: case 3: case 4: case 5: // set file size copy_from_user(&g_size, arg, sizeof(loff_t)); entry->size = g_size; printk("set file size: %lld\n", g_size); break; default: if (cmd > 10000) { int i = 0; play_list_count = cmd - 10000; play_list = kzalloc(play_list_count * sizeof(play_node_t), GFP_KERNEL); copy_from_user(play_list, arg, play_list_count * sizeof(play_node_t)); for (i = 0; i < play_list_count; i++) { play_list[i].fd = filp_open(play_list[i].name, O_RDONLY, 0666); printk("file name:%s size:%d seq:%d\n", play_list[i].name, play_list[i].size, play_list[i].seq); } } break; } MUTEX_UNLOCK(); return ret;}static struct file_operations mpg_dev_fops = { .owner = THIS_MODULE, .open = mpg_dev_open, .release = mpg_dev_release, .unlocked_ioctl = mpg_dev_ioctl};static int __init mpg_init(void) { printk("\nMPG FS DRIVER MODULE INIT\n"); entry = proc_create("mpg_fs", S_IRUGO, NULL, &mpg_fs_fops); MPG_DEV_Major = register_chrdev(0, DEVICE_NAME, &mpg_dev_fops); mpg_dev_class = class_create(THIS_MODULE, DEVICE_NAME); device_create(mpg_dev_class, NULL, MKDEV(MPG_DEV_Major, 0), NULL, DEVICE_NAME); return 0;}static void __exit mpg_exit(void) { printk("\nMPG FS DRIVER MODULE EXIT\n"); remove_proc_entry("mpg_fs", NULL); unregister_chrdev(MPG_DEV_Major, DEVICE_NAME); device_destroy(mpg_dev_class, MKDEV(MPG_DEV_Major, 0)); class_destroy(mpg_dev_class);}module_init(mpg_init);module_exit(mpg_exit);MODULE_AUTHOR("longchow@126.com");MODULE_DESCRIPTION("pmg-ps-fs");MODULE_LICENSE("GPL");
1 0
- Android平台多个mpg文件连续播放
- 播放所设置格式个音频文件,可播放MP3,asx,mpg,wav文件
- 连续播放多个音乐文件
- html5及android多个视频连续播放问题
- mpg文件切片之后,不能播放问题分析
- 连续播放多个视频音频文件
- android 无缝连续播放
- 让U盘把内容写入文件,让播放器播放mpg 或avi视频
- MPG文件结构理解
- MPG文件结构理解
- MPG文件结构理解
- MPG文件结构理解
- 如何实现space多个音乐自动连续播放
- matlab 连续读取多个文件
- C++连续读写多个文件
- Matlab连续读取多个文件
- C/C++ 连续读写多个文件
- MPG
- webstorm快捷键
- 队列的链式表示和实现----单链队列
- Manual JSON serialization from DataReader in ASP.NET Web API
- C和指针详解------数组
- read 系统调用剖析--file_operations中read/write函数与内核系统调用的关系
- Android平台多个mpg文件连续播放
- 【转】Android kernel启动流程
- linux内核启动第二阶段之setup_arch()函数分析-2.6.36
- while的典型应用例子
- Linux启动过程详解
- Codeforces 217D Bitonix' Patrol (dfs + bitset)
- linux内核启动过程学习总结
- [原创]Linux系统启动过程分析
- do_initcall解析