主线程StartPlayer(prepare prepareAsync)
prepare方法是将资源同步缓存到内存中,一般加载本地较小的资源可以用这个,如果是较大的资源或者网络资源建议使用prepareAsync方法,异步加载。
在异步中,若想让资源start()起来,必须设置监听,否则拿不到这个资源。如果让线程睡眠一段时间,则可以取得资源,因为这个时候,异步线程已经取得资源,但不可能使用线程睡眠的方式来获取资源啊.所以就需要设置监听事件setOnPreparedListener()来通知MediaPlayer资源已经获取到了,然后实现onPrepared(MediaPlayermp)方法.在里面启动MediaPlayer。
http://blog.csdn.net/qq_24223073/article/details/69315856
status_t FFMPlayer::prepareAsync()
{//从initialized和stopped状态进入prepared状态
int status = getCurrentStatus();//得到mCurrentState
if ((status == PLAYER_INITIALIZED) || (status == PLAYER_STOPPED)) {
status = doPrepareAsync();
ALOGD("prepareAsync ok");
return status;
}
return UNKNOWN_ERROR;
}
status_t FFMPlayer::doPrepareAsync()
{
if (mCancelThreadStatus >= 0) {//若mCancelThreadStatus,需要等待线程mCancelThread结束(该线程在stop_l中创建)
if (pthread_join(mCancelThread, NULL) != 0) {
ALOGE("doPrepareAsync:Couldn't cancel CancelThread");
}
mCancelThreadStatus = -1;
}
setCurrentStatus(PLAYER_PREPARING); //将mCurrentState设置为PLAYER_PREPARING
mPlayer_sistarted = true;
mReadThreadStatus = pthread_create(&mReadThread, NULL, StartPlayer, (void*)this); //创建线程StartPlayer
mReadThreadCond.wait(mReadThreadLock);
return NO_ERROR;
}
void* FFMPlayer::StartPlayer(void* ptr)
{
//dump information for ffplayer
rkffplay_info::getInstance()->dumpFFPlayerInfo();//获得ffplayer的一些消息
prctl(PR_SET_NAME, (unsigned long)"FFParser", 0, 0, 0);
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_URGENT_DISPLAY);
FFMPlayer *player = (FFMPlayer *)ptr;
//1.prepare
if ( player->prepareDataSource(ptr) != NO_ERROR) {//会调用 AVFormatContext *s = getContext(); AVFormatContext为ffmpeg中的
ALOGD("startPlayer(): prepareDataSource error");
player->setCurrentStatus(PLAYER_STATE_ERROR);
player->notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, UNKNOWN_ERROR);
return NULL;
}
//2.readpacket
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
player->decodeMovie(ptr);
return NULL;
}
status_t FFMPlayer::doPrepareDataSource(const char *url, const char *fileurl)
{
AVFormatContext *s = getContext();//AVFormatContext为ffmpeg中的
enqueueMessage(new MessagePrepare(NULL, NULL));//创建一个类型CMD_PREPARE的meg,会调用doPrepare()
}
void FFMPlayer::decodeMovie(void* ptr)
{
//set the current thread to foreground
setFgCurrentThread();
while (mPlayer_sistarted) {
if ((getCurrentStatus() == PLAYER_DECODED)
|| (getCurrentStatus() == PLAYER_STOPPED)
|| (getCurrentStatus() == PLAYER_STATE_ERROR)
|| (getCurrentStatus() == PLAYER_IDLE)) {
break;
}
{
timeUs = readpacket();//主要内容
}
if (timeUs > 0) {
usleep(timeUs);
}
}
}
int64_t FFMPlayer::readpacket()
{
AVFormatContext* s = getContext();//得到AVFormatContext* FFMediaSource::mContext;
//1. Check end of stream
if (isPlayerEndOfStream() && (!isSeeking())) {
return completePlay();
}
//2. Do seek operation
if (isSeeking()&& !mHaveSeek) {
int result = doSeek();
if (result < 0) {
return 20;
}
}
//3. Check Buffer Size
cret = checkDecoderBuffer();
if (cret>0) return cret;
return doReadAVFrame(s);
}
int64_t FFMPlayer::doReadAVFrame(AVFormatContext* s)
{
AVPacket pPacket;
int ret = 0;
int64_t ret_time = readAVPacket(&pPacket, ret);
AVStream* stream_audio = getAudioStream();
AVStream* stream_video = getVideoStream();//得到AVFormatContext* s->streams[strmIdx];
// Is this a packet from the video stream?
if (isVideoStream(pPacket.stream_index)) {
//enqueue video packet
mReadVideoCounter ++;
//主要调用了mDecoderVideo->enqueue(&pPacket); 将pPacket放入PacketQueue* mQueue;
enqueueRet = enqueueVideoPacket(s, pPacket, stream_video);
if (enqueueRet >= 0) return enqueueRet;
} else if (isAudioStream(pPacket.stream_index)) {
//enqueue audio packet
mReadAudioCounter ++;
enqueueRet = enqueueAudioPacket(s, pPacket, stream_audio);
if (enqueueRet>=0) return enqueueRet;
} else if (isSubtitleStream(pPacket.stream_index)) {
//enqueue subtitle packet
if (mDecoderSub) {
mDecoderSub->enqueue(&pPacket);
} else {
av_free_packet(&pPacket);
return 20;
}
} else {
// Free the packet that was allocated by av_read_frame
pushOtherPacket(&pPacket);
av_free_packet(&pPacket);
}
return 20;
}
int64_t FFMediaSource::readAVPacket(AVPacket *pkt, int &ret)
{
if (mContext) {
ret = av_read_frame(mContext, pkt); //es //avpacket es==>pkt->data pts==>pkt->pts dts==>pkt->dts
// keyframe ==> pkt->key_frame
// pkt videostre //黑盒子 链接到ffmpeg中
}
return -1;
}
pkt是一帧的数据,已进行过分帧了。mpp中的分帧没有必要。