阅读 338

FFmpeg的软解和硬解(android ffmpeg 硬解码)

前言

其实使用原生FFmpeg的软解和硬解很简单,硬解以iOS为例只需要编译的库里面含有videotoolbox模块。 注意:如果是使用ijk编译的库是直接调用硬解是不会成功的

软解流程

1.注册所有解码器

avcodec_register_all();复制代码

2.找到h264编解码器信息

AVCodec * codec_dec = avcodec_find_decoder(AV_CODEC_ID_H264);复制代码

3.通过编解码器信息创建上下文

AVCodecContext * c_dec = avcodec_alloc_context3(codec_dec);复制代码

4.通过配置参数初始化具体的解码器(第三个参数为AVDictionary可以配置解码器的具体参数)

        if (avcodec_open2(c_dec, codec_dec,NULL) < 0)
        {
            av_free(c_dec);
            return NULL;
        }复制代码

5.初始化AVFrame用于接收解码后的数据

AVFrame * pic_tmp = av_frame_alloc();
    if(pic_tmp == NULL)
    {
        avcodec_close(c_dec);
        av_free(c_dec);
        return ;
    }复制代码

6.Socket收到数据包后在CADisplayLink中调用解码

  • FramePacket:是自定义的传输数据包

  • XYQCodecCtx:就是AVCodecContext

  • XYQFrame:是AVFrame

  • 最后使用YUV420p渲染出来

  • _pframeList是缓存数据列表

- (UIImage *)decodeAndDisplay:(FramePacket *)fp{
      
    AVPacket       packet;
    av_new_packet(&packet, fp->len);
    memcpy(packet.data, fp->data, fp->len);
    int ret=0;
    ret = avcodec_send_packet(XYQCodecCtx, &packet);
 
    if (ret != 0) {
        NSLog(@"----6");
        av_packet_unref(&packet);
        [self->_pframeList DPListPopFront];
        return nil;
    }
    ret = avcodec_receive_frame(XYQCodecCtx, XYQFrame);
    if (ret == 0){
        NSLog(@"----7");
        dispatch_async(dispatch_get_main_queue(), ^{
            [self aVFrameToYUV420pToDisplay:self->XYQFrame];
        });
    }
    av_packet_unref(&packet);
    [self->_pframeList DPListPopFront];
    
    return nil;
}复制代码

硬解流程

和软解流程差不多只需要在第四步avcodec_open2前增加硬解的参数配置

1.找到videotoolbox硬解

    const char *codecName = av_hwdevice_get_type_name(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
    enum AVHWDeviceType type = av_hwdevice_find_type_by_name(codecName);
    if (type != AV_HWDEVICE_TYPE_VIDEOTOOLBOX) {
        return NULL;
    }复制代码

2.初始化硬解,将硬解加入到上下文中

AVBufferRef *hw_device_ctx = NULL;
static int InitHardwareDecoder(AVCodecContext *ctx, const enum AVHWDeviceType type) {
    int err = av_hwdevice_ctx_create(&hw_device_ctx, type, NULL, NULL, 0);
    if (err < 0) {
        log4cplus_error("XDXParseParse", "Failed to create specified HW device.\n");
        return err;
    }
    ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
    return err;
}复制代码

最后有一点需要注意,在硬解中我们是直接从AVFrame能拿到CVPixelBufferRef数据的,他是在data的第四个数据,而在软解中使用的是前三个数据

CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)videoFrame->data[3];复制代码

拿到之后就能使用opengl渲染了,这里就不多赘述了

扩展

前面是已知h264的情况下进行的解码,如果是未知的情况下可以用过读取流信息来赋予他解码信息

  1. 配置解码信息

  • formatContext:AVFormatContext

   int ret = av_find_best_stream(formatContext, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
   if (ret < 0) {
        log4cplus_error(kModuleName, "av_find_best_stream faliture");
        return NULL;
   }复制代码

2.配置解码参数

    ret = avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar);
    if (ret < 0){
        log4cplus_error(kModuleName, "avcodec_parameters_to_context faliture");
        return NULL;
    }复制代码

打开文件流的代码(创建AVFormatContext)

- (AVFormatContext *)createFormatContextbyFilePath:(NSString *)filePath {
    if (filePath == nil) {
        log4cplus_error(kModuleName, "%s: file path is NULL",__func__);
        return NULL;
    }
    
    AVFormatContext  *formatContext = NULL;
    AVDictionary     *opts          = NULL;
    
    av_dict_set(&opts, "timeout", "1000000", 0);//设置超时1秒
    
    formatContext = avformat_alloc_context();
    BOOL isSuccess = avformat_open_input(&formatContext, [filePath cStringUsingEncoding:NSUTF8StringEncoding], NULL, &opts) < 0 ? NO : YES;
    av_dict_free(&opts);
    if (!isSuccess) {
        if (formatContext) {
            avformat_free_context(formatContext);
        }
        return NULL;
    }
    
    if (avformat_find_stream_info(formatContext, NULL) < 0) {
        avformat_close_input(&formatContext);
        return NULL;
    }
    
    return formatContext;
}


作者:幻想无极
链接:https://juejin.cn/post/7054385866365485069


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐