zoukankan      html  css  js  c++  java
  • ffmpeg 从视频流中抓取图片

    从视频中不断抓取图片的基本流程:打开视频流地址->获取视频流packt->解码成图片帧->输出图片

    一.初始化Ffmpeg

    void ffmpegInit()
    {
    av_register_all(); avformat_network_init(); av_log_set_level(AV_LOG_ERROR);
    }

      如果你不想输出log,设置log级别为AV_LOG_PANIC。

    二.打开视频。

    int Open(char* url)
    {
        context = avformat_alloc_context(); 
         context->interrupt_callback.opaque = this; //C++
         context->interrupt_callback.callback = interruptCallback;//设置回调函数,否则有可能ffmpeg一直被挂住。 
         context->start_time_realtime = av_gettime();

        AVDictionary* options = nullptr; av_dict_set(
    &options, "rtsp_transport", "udp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp av_dict_set(&options, "stimeout", "3000000", 0);  //设置超时断开连接时间  int ret = avformat_open_input(&context, url, nullptr, &options); //avformat_open_input 返回0表示open成功,小于0表示open失败
       if(ret < 0) return ret;
       ret = avformat_find_stream_info(context, options); ///avformat_find_stream_info 返回0表示查抄stream info成功 小于0表示失败。
        if(options!= nullptr)
        {
           av_dict_free(options);
        }
       return ret;   }
    int interrupt_cb(void *ctx) 
    { 
    if((av_gettime() - ffmpeg->lastFrameRealtime) > 10 * 1000 * 1000) //10s超时退出
        {
             return AVERROR_EOF;
        }
         return 0;            
     } 

    三 .读取视频包:

    shared_ptr<AVPacket> ReadPacket()
    {
        shared_ptr<AVPacket> packet((AVPacket*)av_malloc(sizeof(AVPacket)),   [&](AVPacket *p){av_free_packet(p);av_freep(&p);});
        av_init_packet(packet.get());
        lastFrameRealtime = av_gettime();
        int ret = av_read_frame(context, packet.get());
       if(ret >= 0)
       {
            return packet;
       }
       else 
       {
            return nullptr;
       }
    }

      说明一下:不一定要用智能指针。我确定这样写不会有内存泄露,所以就不改了,随手写的代码会有bug。

    四. 解码

        1. 初始化解码器

    InitDecoderCodec
    {
       int ret = -1;
       for(int i = 0;  i < context->nb_streams; ++i)
    { AVCodecContext
    *codecContext = context->streams[i]->codec; if(codecContext->codec_type == AVMEDIA_TYPE_VIDEO) {
          //返回小于0,打开解码器失败 ret = avcodec_open2(codecContext, avcodec_find_decoder(codecContext->codec_id), &options); }
    }
    return ret; }

       2. 解码视频包

    AVFrame* DecodeVideoPacket(AVCodecContext* codecContext)
    {
    AVFrame* videoFrame = av_frame_alloc();
    auto hr = avcodec_decode_video2(codecContext, frame, &gotFrame, packet); if(hr >= 0 && gotFrame != 0)
    {
        return videoFrame;
    }
       else
       {
        avcodec_free_frame(&videoFrame);
        return nullptr
       }
    }

    输出图片:

      uint8_t *GetPictureData(int width,int height, int *bufferSize)
    {
    pFrameYUV= av_frame_alloc(); uint8_t *out_buffer; out_buffer = new uint8_t[avpicture_get_size(PIX_FMT_RGB32, width, height)]; avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_RGB32, width, height); sws_scale(sws, (const uint8_t* const*)frame->data, frame->linesize, 0, height, pFrameYUV->data, pFrameYUV->linesize);
    *bufferSize = width * height * 4;
      return pFrameYUV->data[0];
    }

     context是全局变量,如果有问题,加群流媒体/Ffmpeg/音视频 127903734或者766718184进行交流

    视频下载地址:http://www.chungen90.com/?news_3/

     Demo下载地址: http://www.chungen90.com/?news_2

  • 相关阅读:
    扒皮下音悦台的“返回顶部”图标效果
    扒皮下京东首页楼层图标的动画效果实现方式
    总结前端开发中的一些特殊规范
    用JS识别各版本浏览器
    各主流浏览器内核介绍
    CSS百分比定义高度的冷知识
    图解js中常用的判断浏览器窗体、用户屏幕可视区域大小位置的方法
    从一个简单例子来理解js引用类型指针的工作方式
    仿京东首页商品分类底部色标随鼠标移动特效
    知乎网首页一个延时交互的小思路
  • 原文地址:https://www.cnblogs.com/wanggang123/p/5592350.html
Copyright © 2011-2022 走看看