• 实战FFmpeg + OpenGLES--iOS平台上视频解码和播放


      一个星期的努力终于搞定了视频的播放,利用FFmpeg解码视频,将解码的数据通过OpenGLES渲染播放。搞清楚了自己想知道的和完成了自己的学习计划,有点小兴奋。明天就是“五一”,放假三天,更开心啦。

      本文实现视频文件的播放是在自己之前写的文章实战FFmpeg--iOS平台使用FFmpeg将视频文件转换为YUV文件 、 实战OpenGLES--iOS平台使用OpenGLES渲染YUV图片 的基础上改进合成来完成的。不多种解释,直接上代码,清晰明了。

    NSString *path = [[NSBundle mainBundle] pathForResource:@"nwn" ofType:@"mp4"];
        const char *filepath= [path UTF8String];
        
        av_register_all();
        avformat_network_init();
        pFormatCtx = avformat_alloc_context();
        if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
            printf("Couldn't open input stream.
    ");
            exit(1);
        }
        
        /*
         * av_find_stream_info():ffmpeg版本更新后没有这个函数了,用avformat_find_stream_info这个函数,可以自己看一下版本更新改动
         */
        //    if(av_find_stream_info(pFormatCtx)<0)
        if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
        {
            printf("Couldn't find stream information.
    ");
            exit(1);
        }
        
        videoindex=-1;
        for(int i=0; i<pFormatCtx->nb_streams; i++)
            if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
            {
                videoindex=i;
                break;
            }
        if(videoindex==-1)
        {
            printf("Didn't find a video stream.
    ");
            exit(1);
        }
        pCodecCtx=pFormatCtx->streams[videoindex]->codec;
        pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
        if(pCodec==NULL)
        {
            printf("Codec not found.
    ");
            exit(1);
        }
        /*
         * avcodec_open():ffmpeg版本更新后没有这个函数了,用avformat_find_stream_info这个函数,可以自己看一下版本更新改动
         * avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
         */
        //    if(avcodec_open(pCodecCtx, pCodec)<0)
        if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
        {
            printf("Could not open codec.
    ");
            exit(1);
        }
        AVFrame    *pFrame,*pFrameYUV;
        pFrame=avcodec_alloc_frame();
        pFrameYUV=avcodec_alloc_frame();
        uint8_t *out_buffer;
        out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];
        avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
        
        int ret, got_picture;
        int y_size = pCodecCtx->width * pCodecCtx->height;
        
        AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));
        av_new_packet(packet, y_size);
        
        printf("video infomation:
    ");
        av_dump_format(pFormatCtx,0,filepath,0);
        
        while(av_read_frame(pFormatCtx, packet)>=0)
        {
            if(packet->stream_index==videoindex)
            {
                ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
                if(ret < 0)
                {
                    printf("Decode Error.
    ");
                    exit(1);
                }
                if(got_picture)
                {
                    char *buf = (char *)malloc(pFrame->width * pFrame->height * 3 / 2);
            
                    AVPicture *pict;
                    int w, h;
                    char *y, *u, *v;
                    pict = (AVPicture *)pFrame;//这里的frame就是解码出来的AVFrame
                    w = pFrame->width;
                    h = pFrame->height;
                    y = buf;
                    u = y + w * h;
                    v = u + w * h / 4;
                    
                    for (int i=0; i<h; i++)
                        memcpy(y + w * i, pict->data[0] + pict->linesize[0] * i, w);
                    for (int i=0; i<h/2; i++)
                        memcpy(u + w / 2 * i, pict->data[1] + pict->linesize[1] * i, w / 2);
                    for (int i=0; i<h/2; i++)
                        memcpy(v + w / 2 * i, pict->data[2] + pict->linesize[2] * i, w / 2);
                    
                    [myview setVideoSize:pFrame->width height:pFrame->height];
                    [myview displayYUV420pData:buf pFrame->width height:pFrame->height]; //利用OpenGLES渲染YUV
                    free(buf);
                }
            }
            av_free_packet(packet);
        }
        delete[] out_buffer;
        av_free(pFrameYUV);
        avcodec_close(pCodecCtx);
        avformat_close_input(&pFormatCtx);

      本周的学习任务完成啦,写完这篇博客就下班回家,哈哈。五一长假,我要休息下,列出自己下一步的学习计划。下周我想做的是本地音频文件解码播放,以及本地视频文件中音频与视频同步播放。现在所做的都是本地音视频文件的处理,因为本地文件处理起来方便一些,这也让自己学起来也快速一些。关于网络音视频实时流的同步与播放,这个涉及的内容就要复杂一些了,有效学习+时间规划,我肯定能玩透播放器的开发。

      本文完整工程 FFmpegDecode_OpenGLESRenderYUV 的下载地址为:http://pan.baidu.com/s/1dDvpECh

  • 相关阅读:
    Js前端路由管理器函数
    js前端登录js脚本
    docker部署certbot与nginx来获取ssl证书添加https及自动更新
    spring boot不同版本的优雅关闭(graceful shutdown)和在windows下winsw服务方式运行的配置
    php下载
    在k8s中导出jvm内存错误dump文件到OSS
    基于alpine构建jdk镜像遇到的坑
    UML建模综述
    Web安全攻防渗透测试实战指南之工具
    数字签名、数字证书是什么?
  • 原文地址:https://www.cnblogs.com/sunminmin/p/4469617.html
Copyright © 2020-2023  润新知