Jump to content
Compvision.ru
mult1plexer

VideoCapture аппаратное декодирование

Recommended Posts

11 час назад, Nuzhny сказал:

Например, команда "ffmpeg -hwaccels" выведен список доступных аппаратных кодеков.

Мне для аппаратного декодирования нужен qsv (Intel Quick Sync Video). Но на сайте ffmpeg читаю: 

  • Ensure the target machine has a supported CPU. Current versions only support gen8/gen9 graphics on expensive CPUs ("Xeon"/"Core i" branding). The same graphics cores on cheaper CPUs ("Pentium"/"Celeron"/"Atom" branding) are explicitly disabled, presumably for commercial reasons.

Т.е. для Pentium и процессоров ниже отключена аппаратная поддержка по коммерческим причинам. 

cv::CAP_MSMF - не работает с rtsp потоком (Хотя Microsoft Media Foundation вроде ж должна поддерживать).

Что применить???

Share this post


Link to post
Share on other sites

Тебе в качестве декодера в ffmpeg надо указать dxva2. MSMF его и использует, поэтому получается быстрее. Кажется, что лучше используовать ffmpeg напрямую, что все и делают в критических по производительности приложениях.

Share this post


Link to post
Share on other sites
В 2/5/2019 at 14:14, Nuzhny сказал:

Получать можно в том же ffmpeg:

1. Если не собран, то собрать ffmpeg с поддержкой cuvid. Проверка: ./ffmpeg -hwaccels

2. При создании AVCodec вызвать avcodec_find_decoder_by_name("h264_cuvid") или avcodec_find_decoder_by_name("mjpeg_cuvid").

3. Перед вызовом avcodec_decode_video2 устанавливать decCtx->pix_fmt = AV_PIX_FMT_CUDA

4. Тут уже нам возвращают указатель на видеопамять в AVFrame, можно копировать её к себе и обрабатывать:

4.1. Учитываем, что в данном случае у нас кадр не YUV420, а NV12: cudaMemcpy(data, picture->data[0], height * picture->linesize[0], cudaMemcpyDefault)

4.2.  Хочется RGB? Вызываем nppiNV12ToBGR_709HDTV_8u_P2C3R

4.3. Хочется засунуть в OpenCV? Вот: cv::cuda::GpuMat* gpuFrame = new cv::cuda::GpuMat(height, width, CV_8UC1, picture->data[0], picture->linesize[0])

Выгрузить из GPU memory и сохранить? Вот: cv::Mat frame; gpuFrame->download(frame);

4.4. Хочется отобразить кадр без копирования в ОЗУ? Создаём OpenGL окно: cv::namedWindow("wnd name", cv::WINDOW_OPENGL)

 

Это про декодирование на CUDA и обработку кадра средствами OpenCV без копирования в системную память.

Про TensorFlow: тут надо использовать С++ API, на Питончике такой возможности нет. Добавили такую возможность недавно в версии 1.12: вот обсуждение.

Дошли руки попробовать, но тут не сказано как это должно быть связано с загрузкой видеофайла или захвата видеопотока.

Моя попытка успехом не увенчалась:

 


 
static AVFormatContext *fmt_ctx = nullptr;
static AVCodecContext *dec_ctx = nullptr;
static int video_stream_index = -1;

static int open_input_file(const char *filename = videofilename)
{
    int ret;
    AVCodec *dec;
    if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
        return ret;
    }
    if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
        return ret;
    }
    /* select the video stream */
    ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
        return ret;
    }
    video_stream_index = ret;
    dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
    av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);

    avcodec_register_all();
    AVCodec* codec = avcodec_find_decoder_by_name("h264_cuvid");
    AVCodecContext * avctx = avcodec_alloc_context3(codec);
    dec_ctx = avctx;
    dec = codec;
    avctx->pix_fmt = AV_PIX_FMT_CUDA;
    //if (avcodec_open2(avctx, codec, opts) < 0)
    //    return;

    /* init the video decoder */
    if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
        return ret;
    }
    return 0;
}

Вывод приложения:

Цитата

 

[h264_cuvid @ 0x55fefb78a440] Codec h264_cuvid is not supported.

Cannot open video decoder

 

Вывод утилиты:

 

Цитата

(base) user@aspire:/opt/ffmpeg/v345/ffmpeg-3.4.5$ ./ffmpeg -hwaccels
ffmpeg version 3.4.5 Copyright (c) 2000-2018 the FFmpeg developers
  built with gcc 7 (Ubuntu 7.3.0-27ubuntu1~18.04)
  configuration: 
  libavutil      55. 78.100 / 55. 78.100
  libavcodec     57.107.100 / 57.107.100
  libavformat    57. 83.100 / 57. 83.100
  libavdevice    57. 10.100 / 57. 10.100
  libavfilter     6.107.100 /  6.107.100
  libswscale      4.  8.100 /  4.  8.100
  libswresample   2.  9.100 /  2.  9.100
Hardware acceleration methods:
cuvid


 

Share this post


Link to post
Share on other sites

Я использовал dxva2. Работает и с потоком и с файлами h264. Ты сам собирал ffmpeg или брал готовую сборку?

Share this post


Link to post
Share on other sites
5 минут назад, 2expres сказал:

Я использовал dxva2. Работает и с потоком и с файлами h264. Ты сам собирал ffmpeg или брал готовую сборку?

сам собирал.

Share this post


Link to post
Share on other sites

Возьми сборку зераное https://ffmpeg.zeranoe.com/builds/

 качаешь 2 архива shared и dev перед этим выбрав 32 или 64 бит. В архиве dev хранятся библиотеки (.lib) и include. Архив shared содержит необходимые .dll которые необходимо будет переписать в папку с вашей будущей программой - это для Windows. 

Share this post


Link to post
Share on other sites

Я за точку старта брал код для работы с ffmpeg из OpenCV, потому что точно знаю, что он работает. Вариант не идеальный, но, повторюсь, рабочий.

Кстати, проверь для видео стрима, который ты получил, что он правильный:

std::cout << avcodec_get_name(stream->codecpar->codec_id) << ": " << stream->codecpar->codec_id << std::endl;

Вообще, программировать с ffmpeg то ещё удовольствие, документация так себе, до правильного ответа приходится доходить чуть ли не методом тыка. Я не уверен, что всё делал правильно, но оно заработало. Эталонный вариант типа ffplay очень сложен: много тысяч строк в одном файле, всё смешано, куча goto.

Share this post


Link to post
Share on other sites
31 минуту назад, Nuzhny сказал:

Я за точку старта брал код для работы с ffmpeg из OpenCV, потому что точно знаю, что он работает. Вариант не идеальный, но, повторюсь, рабочий.

Кстати, проверь для видео стрима, который ты получил, что он правильный:


std::cout << avcodec_get_name(stream->codecpar->codec_id) << ": " << stream->codecpar->codec_id << std::endl;

Вообще, программировать с ffmpeg то ещё удовольствие, документация так себе, до правильного ответа приходится доходить чуть ли не методом тыка. Я не уверен, что всё делал правильно, но оно заработало. Эталонный вариант типа ffplay очень сложен: много тысяч строк в одном файле, всё смешано, куча goto.

 


 

У меня нет переменной stream в коде.

Код: 

    std::cout << avcodec_get_name(fmt_ctx->streams[video_stream_index]->codecpar->codec_id) << ": " << fmt_ctx->streams[video_stream_index]->codecpar->codec_id << std::endl;

Выдаёт:

mpeg4: 13

Сама структура ...->streams[video_stream_index]->codec; определена как деприкейтед и на замену предлогают 

streams[video_stream_index]->codecpar

Share this post


Link to post
Share on other sites
const char * imagefilename = "Image_paint.jpg";

static AVFormatContext *fmt_ctx = nullptr;
static AVCodecContext *dec_ctx = nullptr;
static int video_stream_index = -1;

static int open_input_file(const char *filename = videofilename)
{
    /*
    avcodec_register_all();
    AVCodec* codec = avcodec_find_decoder_by_name("mpeg4_cuvid");
    AVCodecContext * avctx = avcodec_alloc_context3(codec);
    avctx->pix_fmt = AV_PIX_FMT_CUDA;
    */
    int ret;
    AVCodec *dec;
    if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
        return ret;
    }
    if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
        return ret;
    }
    /* select the video stream */
    ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
        return ret;
    }
    video_stream_index = ret;
    dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
    av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);
    std::cout << avcodec_get_name(fmt_ctx->streams[video_stream_index]->codecpar->codec_id) << ": " << fmt_ctx->streams[video_stream_index]->codecpar->codec_id << std::endl;

    avcodec_register_all();
    AVCodec* codec = avcodec_find_decoder_by_name("mpeg4_cuvid");
    if (codec != nullptr)
    {
        std::cout << "codec found" << std::endl;
    }
    fmt_ctx->streams[video_stream_index]->codecpar->codec_id = codec->id;
    fmt_ctx->streams[video_stream_index]->id = codec->id;
    fmt_ctx->streams[video_stream_index]->codecpar->codec_type = codec->type;
    //fmt_ctx->streams[video_stream_index]->codecpar->format = *codec->pix_fmts;
    fmt_ctx->streams[video_stream_index]->codec->codec_id = codec->id;
    fmt_ctx->streams[video_stream_index]->codec->codec_type = codec->type;


    fmt_ctx->streams[video_stream_index]->codecpar->format = AV_PIX_FMT_CUDA;
    dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
    dec_ctx->pix_fmt = AV_PIX_FMT_CUDA;
    ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    std::cout << avcodec_get_name(fmt_ctx->streams[video_stream_index]->codecpar->codec_id) << ": " << fmt_ctx->streams[video_stream_index]->codecpar->codec_id << std::endl;

    //AVCodecContext * avctx = avcodec_alloc_context3(codec);
    //dec_ctx = avctx;
    //dec = codec;
    //avctx->pix_fmt = AV_PIX_FMT_CUDA;

    //if (avcodec_open2(avctx, codec, opts) < 0)
    //    return;

    /* init the video decoder */
    if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
        return ret;
    }
    AVFrame *mpDecodedFrame = av_frame_alloc();
    int got;
    AVPacket     tsPkt;
    av_init_packet(&tsPkt);
    avcodec_decode_video2(dec_ctx, mpDecodedFrame, &got, &tsPkt);
    return 0;
}

Вот так исполняется без ошибок, но надо понять как реализовать считывание кадра за кадром, и вдобавок как сделать перемотку назад.

Share this post


Link to post
Share on other sites
3 hours ago, Pechkin80 said:

 


    std::cout << avcodec_get_name(fmt_ctx->streams[video_stream_index]->codecpar->codec_id) << ": " << fmt_ctx->streams[video_stream_index]->codecpar->codec_id << std::endl;

Выдаёт:

mpeg4: 13

У меня на файл со сжатием h264 пишет: h264: 27. Ну и на ip-камеру, для которой всё это и делалось, аналогично.

А команда "ffmpeg -hwaccels" даёт:

Quote

Hardware acceleration methods:
cuda
opencl
cuvid

 

3 hours ago, Pechkin80 said:

Сама структура ...->streams[video_stream_index]->codec; определена как деприкейтед и на замену предлогают 


streams[video_stream_index]->codecpar

Это да, никто codec и не предлагал использовать.

 

Ещё раз повторюсь, что я брал за точку старта код из OpenCV, в нём реализовано всё необходимое. И уже его модифицировал под свои задачи.

Share this post


Link to post
Share on other sites

У меня их несколько и все из этого списка

Share this post


Link to post
Share on other sites
6 минут назад, Nuzhny сказал:

У меня их несколько и все из этого списка

А на джетсоне они тоже из этого сиска ?

 

Share this post


Link to post
Share on other sites

На джетсоне, если ты имеешь в виду Nano, всё должно быть иначе, потому что на нём нет выделенной видеопамяти, она общая системная.

Ну и его использовать можно иначе: подключать не ip камеру, а веб или промышленную, получать с неё сразу несжатое видео.

Share this post


Link to post
Share on other sites
7 минут назад, Nuzhny сказал:

На джетсоне, если ты имеешь в виду Nano, всё должно быть иначе, потому что на нём нет выделенной видеопамяти, она общая системная.

Ну и его использовать можно иначе: подключать не ip камеру, а веб или промышленную, получать с неё сразу несжатое видео.

Спасибо. с пайплайном почти разобрался. Еслибы ещё входной и выходной тензор у тф научился бы окунать в gpu, то былобы вообще супер.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×