我正在编写自己的iOS视频播放器而我正面临下一个问题 - 帧的解码速度太慢。播放器以30/60 fps完美运行,但120 fps视频以慢动作播放。
经过一番研究,我确定了解码文件的主要问题。它太慢了。
现在我有3个帖子: 1)从文件中读取 2)avcodec_send_packet,avcodec_receive_frame并生成图片的原始数据3)视频显示
问题在于2个线程,包含avcodec_send_packet和avcodec_receive_frame。
我删除了#34;从AVFrame生成图片的原始数据"从2线程来测量avcodec_send_packet / avcodec_receive_frame的执行时间,并且使用这些函数的循环几乎不能产生120 fps。当我说"勉强"我的意思是在视频的第一秒将是滞后的。
这里是解码线程的日志:
2017-10-08 19:31:55.476538 VULCAM[910:85974] SEC! 106
2017-10-08 19:31:56.484544 VULCAM[910:85974] SEC! 110
2017-10-08 19:31:57.486751 VULCAM[910:85974] SEC! 119
2017-10-08 19:31:58.491270 VULCAM[910:85974] SEC! 122
2017-10-08 19:31:59.500061 VULCAM[910:85974] SEC! 119
2017-10-08 19:32:00.507599 VULCAM[910:85974] SEC! 126
2017-10-08 19:32:01.513110 VULCAM[910:85974] SEC! 126
2017-10-08 19:32:02.517102 VULCAM[910:85974] SEC! 125
2017-10-08 19:32:03.518195 VULCAM[910:85974] SEC! 121
2017-10-08 19:32:04.528745 VULCAM[910:85974] SEC! 120
2017-10-08 19:32:05.529884 VULCAM[910:85974] SEC! 122
2017-10-08 19:32:06.540589 VULCAM[910:85974] SEC! 123
我非常确定能够更有效地使用ffmpeg并缩短执行时间。这里有一些小代码片段,足以理解整个想法。
以下是启动视频解码的方法:
- (void)play:(PlayerState)state
{
[self decodePackets_loop];
[self decodeFrames_loop];
[self video_refresh];
}
此处decodePackets_loop
:
- (void)decodePackets_loop
{
dispatch_queue_t pktsQueue = dispatch_queue_create("decodePacketsQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(pktsQueue, ^{
while (_state == PlayerPlayForward) {
AVPacket packet;
int ret = av_read_frame(_pFormatCtx, &packet);
if (ret < 0) {
if (ret == AVERROR_EOF) {
_isCached = YES;
break;
}
else {
NSLog(@"av_read_frame error!");
continue;
}
}
[_picturesQueue put:&packet];
}
NSLog(@"DONE!");
});
}
此处decodeFrames_loop
:
- (void)decodeFrames_loop
{
dispatch_queue_t fmsQueue = dispatch_queue_create("decodeFramesQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(fmsQueue, ^{
AVFrame *pFrame = NULL;
pFrame = av_frame_alloc();
if (pFrame == NULL) {
NSLog(@"Couldn't init pFrame!");
return;
}
double pts = 0.0;
NSTimeInterval currTime = [NSDate timeIntervalSinceReferenceDate];
float sec = 0.0f;
int frames_cnt = 0;
while (_state == PlayerPlayForward) {
AVPacket pkt;
if ([_picturesQueue get:&pkt]) {
if (avcodec_send_packet(_pCodecCtx, &pkt) != 0) {
NSLog(@"Couldn't send packet");
continue;
}
if (avcodec_receive_frame(_pCodecCtx, pFrame) != 0) {
NSLog(@"Couldn't receive frame");
av_packet_unref(&pkt);
continue;
}
if (pkt.dts != AV_NOPTS_VALUE)
{
pts = av_frame_get_best_effort_timestamp(pFrame);
}
else
{
pts = 0.0f;
}
pts *= av_q2d(_activeStream->time_base);
av_packet_unref(&pkt);
[self synchronizeVideo:pFrame pts:pts];
//VideoPicture *vid_pic = [self generateVideoPictureFromFrame:pFrame withPts:pts withDts:pFrame->pkt_dts];
/*if (vid_pic) {
[_picturesPool addPicture:vid_pic];
}*/
//av_free(vid_pic.data);
frames_cnt++;
sec = [NSDate timeIntervalSinceReferenceDate] - currTime;
if (sec >= 1.0f) {
NSLog(@"SEC! %d", frames_cnt);
sec = 0.0f;
frames_cnt = 0;
currTime = [NSDate timeIntervalSinceReferenceDate];
}
}
}
av_frame_free(&pFrame);
});
}