Closed zjhellofss closed 2 years ago
代码和目前转换的结果如下:
#include <string>
#include "nvjmi.h"
#include "opencv2/opencv.hpp"
#include <cstdio>
#include "opencv2/cudawarping.hpp"
#include <string>
#define __STDC_CONSTANT_MACROS
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#ifdef __cplusplus
};
#endif
#include <chrono>
#define DEBUG true
typedef std::chrono::high_resolution_clock clock_;
typedef std::chrono::duration<float, std::milli> duration;
double ticks(clock_::time_point start) {
duration elapsed = clock_::now() - start;
return elapsed.count();
}
AVFormatContext *open_rtsp(const std::string &rtsp_address, const std::string &player_base) {
AVFormatContext *ifmt_ctx = nullptr;
AVStream *st = nullptr;
char err_buf[512];
AVDictionary *optionsDict = nullptr;
av_register_all();
avformat_network_init();
av_dict_set(&optionsDict, "rtsp_transport", "tcp", 0);
av_dict_set(&optionsDict, "stimeout", "2000000", 0); ///设置微秒超时时间
int ret;
if ((ret = avformat_open_input(&ifmt_ctx, rtsp_address.data(), 0, &optionsDict)) <
0) {
printf("Could not open input file '%s' (error '%s')\n", rtsp_address.data(),
av_make_error_string(err_buf, sizeof(err_buf), ret));
return nullptr;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, nullptr)) <
0) {
printf("Could not open find stream info (error '%s')\n", av_make_error_string(err_buf, sizeof(err_buf), ret));
return nullptr;
}
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
av_dump_format(ifmt_ctx, i, rtsp_address.c_str(), 0);
}
bool has_264_video = false;
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
st = ifmt_ctx->streams[i];
switch (st->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
break;
case AVMEDIA_TYPE_VIDEO:
has_264_video = true;
break;
default:
break;
}
}
if (has_264_video) {
return ifmt_ctx;
} else {
return nullptr;
}
}
int main() {
int height = 1920;
int width = 1080;
std::string rtsp_address = "rtsp://192.168.4.8:57554/scv/vfs/group-1634290456300783180/group-1634290456300783180_ch0";
auto fmt_ctx = open_rtsp(rtsp_address, "");
if (fmt_ctx) {
printf("Open successfully\n");
} else {
printf("Open failed");
// todo
}
AVPacket pkt;
av_init_packet(&pkt);
jmi::nvJmiCtxParam jmi_ctx_param;
if (width > 0 && height > 0) {
jmi_ctx_param.resize_width = width;
jmi_ctx_param.resize_height = height;
}
jmi_ctx_param.coding_type = jmi::NV_VIDEO_CodingH264;
std::string dec_name = "test_dec";
jmi::nvJmiCtx *jmi_ctx_ = jmi::nvjmi_create_decoder(dec_name.data(), &jmi_ctx_param);
jmi::nvPacket nvpacket;
auto start = clock_::now();
bool decode_success = false;
cv::Mat output_frame;
int index;
while (true) {
int ret = av_read_frame(fmt_ctx, &pkt);
if (ret != 0) {
break;
} else {
auto payload = pkt.data;
auto payload_size = pkt.size;
nvpacket.payload_size = payload_size;
nvpacket.payload = payload;
cv::Mat frame = cv::Mat(height, width, CV_8UC3);
if (payload != nullptr) {
ret = jmi::nvjmi_decoder_put_packet(jmi_ctx_, &nvpacket);
while (ret >= 0) {
jmi::nvFrameMeta nvframe_meta;
ret = jmi::nvjmi_decoder_get_frame_meta(jmi_ctx_, &nvframe_meta);
if (ret < 0) {
break;
}
ret = jmi::nvjmi_decoder_retrieve_frame_data(jmi_ctx_, &nvframe_meta, (void *) frame.data);
if (!ret) {
frame.download(output_frame);
cv::imwrite( std::to_string(index) + ".jpg", frame);
index += 1;
}
}
}
}
}
}
这个我这边只用到了nv12。转换为yuv420p可以看看有没有对应的参数,如果没有,应该也可以使用cuda能够转成yuv420p。
作者有没有做过相关测试,在jetson上的硬解和软解的速度比较。
硬解比软件快至少3倍。
感谢作者的贡献 我在使用ffmpeg接收rtsp数据流后使用该项目也是播不出来,参照了/usr/src/jetson_multimedia_api/samples/00_video_decode中的代码: 修改nvjmi_dec.cpp文件 ret = ctx->dec->setFrameInputMode(0) 修改为 ret = ctx->dec->setFrameInputMode(1) 因为av_read_frame返回的都是完整的nalu单元
流的封装是h264,传输的协议是rtsp,然后颜色空间是yuv420p。但是我用这个项目转换后得到的图像是条黑白纹状的无意义图像。我想知道是否本项目只支持nv12的颜色空间?