最近在看ffmpeg相關的知識,于是想使用ffmpeg實現最基本的視頻解碼播放的功能,查看了許多資料,于是有了一個基本思路:
- 使用ffmpeg解碼視頻獲得音頻數據和視頻數據。
- 使用opengl繪制視頻幀數據。
- 使用opensl播放音頻數據。
下面是實現的截圖
Screenshot_2017-04-24-15-15-12-699_com.example.tenny.myapplication1.png
下面具體實現,詳細的代碼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);
}
}
}
};