AVPlayer 音视频学习iOS技术iOS开发

基于iOS平台的最简单的FFmpeg视频播放器(二)

2017-10-31  本文已影响335人  Aiewing

上一篇写了关于FFmpeg的对文件的处理以及初始化解码器,算是为本片做下了很重要的基础,需要看基础的同学还是推荐看雷神的博客

基于iOS平台的最简单的FFmpeg视频播放器(一)
基于iOS平台的最简单的FFmpeg视频播放器(二)
基于iOS平台的最简单的FFmpeg视频播放器(三)
废话不多说,让我们

正式开始

1.1 热身运动

- (void)setMovieDecoder:(AieDecoder *)decoder
{
    if (decoder) {
        _decoder = decoder;
        _dispatchQueue = dispatch_queue_create("AieMovie", DISPATCH_QUEUE_SERIAL);
        _videoFrames = [NSMutableArray array];
    }
    
    _minBufferedDuration = LOCAL_MIN_BUFFERED_DURATION;
    _maxBufferedDuration = LOCAL_MAX_BUFFERED_DURATION;
    
    if (self.isViewLoaded) {
        [self setupPresentView];
    }
}

1.2 再次热身(很重要)

- (void)asyncDecodeFrames
{
   __weak Aie1Controller * weakSelf = self;
   __weak AieDecoder * weakDecoder = _decoder;
   
   dispatch_async(_dispatchQueue, ^{

       // 当已经解码的视频总时间大于_maxBufferedDuration 停止解码
       BOOL good = YES;
       while (good) {
           good = NO;
           
           @autoreleasepool {
               __strong AieDecoder * strongDecoder = weakDecoder;
               
               if (strongDecoder) {
                   NSArray * frames = [strongDecoder decodeFrames:0.1];
                   
                   if (frames.count) {
                       __strong Aie1Controller * strongSelf = weakSelf;
                       
                       if (strongSelf) {
                           good = [strongSelf addFrames:frames];
                       }
                   }
               }
           }
       }
   });
}

2.1 开始解码

- (NSArray *)decodeFrames:(CGFloat)minDuration
{
    if (_videoStream == -1) {
        return nil;
    }
    
    NSMutableArray * result = [NSMutableArray array];
    AVPacket packet;
    CGFloat decodedDuration = 0;
    BOOL finished = NO;
    
    while (!finished) {
        if (av_read_frame(_formatCtx, &packet) < 0) {
            NSLog(@"读取Frame失败");
            break;
        }
        
        if (packet.stream_index == _videoStream) {

            int pktSize = packet.size;
            while (pktSize > 0) {
                int gotFrame = 0;
                int len = avcodec_decode_video2(_videoCodecCtx, _videoFrame, &gotFrame, &packet);
                if (len < 0) {
                    NSLog(@"解码失败");
                    break;
                }
                
                if (gotFrame) {
                    AieVideoFrame * frame = [self handleVideoFrame];
                    frame.type = AieFrameTypeVideo;
                    NSLog(@"当前帧的时间戳:%f, 当前帧的持续时间:%f", frame.position, frame.duration);
                    
                    if (frame) {
                        [result addObject:frame];
                        
                        _position = frame.position;
                        decodedDuration += frame.duration;
                        if (decodedDuration > minDuration) {
                            finished = YES;
                        }
                    }
                }
                
                if (0 == len) {
                    break;
                }
                pktSize -= len;
            }
        }
        av_free_packet(&packet);
    }
    return result;
}

2.1.1 从哪里来?

AVPacket packet;

2.1.2 怎么来?

if (av_read_frame(_formatCtx, &packet) < 0) {
   NSLog(@"读取Frame失败");
   break;
}

2.1.3 来干嘛?(这就是最重要的解码)

if (packet.stream_index == _videoStream) {

            int pktSize = packet.size;
            while (pktSize > 0) {
                int gotFrame = 0;
                int len = avcodec_decode_video2(_videoCodecCtx, _videoFrame, &gotFrame, &packet);
                
                if (len < 0) {
                    NSLog(@"解码失败");
                    break;
                }
                
                if (gotFrame) {
                }
                
                if (0 == len) {
                    break;
                }
                pktSize -= len;
                
            }
        }

2.1.4 怎么去?

AieVideoFrame * frame = [self handleVideoFrame];
frame.type = AieFrameTypeVideo;

2.1.5 去哪里?

if (frame) {
     [result addObject:frame];
     _position = frame.position;
     decodedDuration += frame.duration;
     if (decodedDuration > minDuration) {
         finished = YES;
     }
}

结尾

上一篇下一篇

猜你喜欢

热点阅读