Перейти к содержимому
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 вроде ж должна поддерживать).

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 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


 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
5 минут назад, 2expres сказал:

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

сам собирал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
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;
}

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
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, в нём реализовано всё необходимое. И уже его модифицировал под свои задачи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 минут назад, Nuzhny сказал:

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
7 минут назад, Nuzhny сказал:

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×