最近在看ffmpeg相关的知识,于是想使用ffmpeg实现最基本的视频解码播放的功能,查看了许多资料,于是有了一个基本思路:
- 使用ffmpeg解码视频获得音频数据和视频数据。
- 使用opengl绘制视频帧数据。
- 使用opensl播放音频数据。
下面是实现的截图
下面具体实现,详细的代码https://github.com/tenny1225/ffmpeg_android_video_player/tree/master
下面将需要注意的问题简单说一下。
ffmpeg的编译和引入
对于ffmpeg的编译,可以看一下http://blog.csdn.net/leixiaohua1020/article/details/47008825/ 这篇文章,可以生成一些列so文件,在我这个例子中,我使用了cmake方式引入so库,详情可以查看根目录下的CMakeLists.txt文件。
ffmpeg获取视频帧数据
在这个例子中,使用bool readFrame(FrameInfor &infor)
方法循环获取视频帧数据,因为不同的视频每毫秒播放的帧数是不同的,所以这里需要控制一下播放速度。
class VideoThread :public Thread{
public:
virtual void run() override {
JNIEnv *en;
time_t timep1 =GetUtcCaressing();//获取播放开始时的时间戳
while(true){
ffVideoReader.readFrame(p);//p是获取的FrameInfor数据
if(p._data==0){
break;
}
/**
p._timeBase是单位秒,p._pts是该帧播放的时间,d这里是微秒
**/
double d = p._timeBase*p._pts*1000*1000;
/**刷新glsurfaceview**/
g_jvm->AttachCurrentThread(&en, NULL);
jclass clazz = en->GetObjectClass(g_obj);
jmethodID mid =en->GetMethodID(clazz,"refresh","()V");
en->CallObjectMethod(g_obj,mid);
g_jvm->DetachCurrentThread();
time_t timep2=GetUtcCaressing();//获取获取视频帧后的时间戳
double temp = timep2-timep1;//获取帧数据消耗的时间
double sleeps = d-temp;//sleeps是需要等待的微秒数
if(sleeps>1){
usleep(sleeps);
}
}
}
};