libav c ++原始h264 TCP流到opencv Mat

时间:2018-11-10 18:16:42

标签: c++ opencv libavcodec libav

我为我的课堂编写了一个从无人机接收h264流的软件,我需要将视频流转换为opencv Mat。

我可以毫不费力地接收帧,如果将其保存到.264文件中,则可以使用VLC读取输出。

无人机正在发送IDR-Frame和P-Frame,因为我不需要看到视频流只是其中的某些帧,所以我在考虑仅使用IDR-Frame来获取图像,但是我遇到了麻烦要了解如何使用FFMPEG中的libavcodec,如何从我的IDR-Frame创建AVFrame,以及如何将其转换为cv :: Mat。

我尝试了以下代码,将完整的帧存储在.raw文件中,并尝试对其进行解码,但是当我尝试将数据包解析为帧时出现读取错误,我不认为是初始化正确方式将ARPacket的缓冲区缓冲:

AVFormatContext* fc = 0;
int vi = -1; // vi veut dire video index


inline cv::Mat avframe_to_mat(const AVFrame* avframe) 
{
    AVFrame dst;
    cv::Mat m;

memset(&dst, 0, sizeof(dst));

int w = avframe->width, h = avframe->height;

m = cv::Mat(h, w, CV_8UC3);
dst.data[0] = (uint8_t*)m.data;

avpicture_fill((AVPicture*)&dst, dst.data[0], AV_PIX_FMT_BGR24, w, h);

struct SwsContext *convert_ctx = NULL;

enum AVPixelFormat src_pixfmt = AV_PIX_FMT_BGR24;
enum AVPixelFormat dst_pixfmt = AV_PIX_FMT_BGR24;

convert_ctx = sws_getContext(w, h, src_pixfmt, w, h, dst_pixfmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);

sws_scale(convert_ctx, avframe->data, avframe->linesize, 0, h, dst.data, dst.linesize);
sws_freeContext(convert_ctx);

return m;

}

inline bool init_stream(unsigned char* data, int len)
{

const char* file = "test.avi";

const AVCodecID codec_id = AV_CODEC_ID_H264;
AVCodec* codec = avcodec_find_encoder(codec_id);
// Crée le container pour le stream
fc = avformat_alloc_context();

/*
AVOutputFormat *of = av_guess_format(0, file, 0);
fc = avformat_alloc_context();
fc->oformat = of;
strcpy(fc->filename, file);
*/
int br = 1000000;
int w = 640;
int h = 360;

int fps = 24;


// ajoute un stream video
AVStream* pst = avformat_new_stream(fc, codec); // Pourquoi je passe pas le codec ici ?
vi = pst->index;

codec_context = avcodec_alloc_context3(codec);

codec_context->bit_rate = br;
codec_context->width = w;
codec_context->height = h;
codec_context->time_base = {1,fps};
codec_context->gop_size = 10; // Emit one intra frame every ten frames
codec_context->max_b_frames = 1;
codec_context->pix_fmt = AV_PIX_FMT_YUV420P;

// Vu quon n'est en h264
av_opt_set(codec_context->priv_data, "preset", "slow", 0);


// Ouvre notre codec    
if(avcodec_open2(codec_context, codec,nullptr) < 0)
{
    cerr << "Impossible d'ouvrir le codec" << endl;
    return false;
}

if (!(fc->oformat->flags & AVFMT_NOFILE))
    avio_open(&fc->pb, fc->filename,0);

//  avformat_write_header(fc,nullptr);


return true;
}


inline void append_stream(uint8_t* data, int len)
{
if( 0 > vi)
{
    cerr << "video index is less than 0" << endl;
    return;
}
AVStream* pst = fc->streams[vi];

AVPacket pkt;


// Init un nouveau packet
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.data = data;
pkt.stream_index = pst->index;
pkt.size = len;

pkt.dts = AV_NOPTS_VALUE;
pkt.pts = AV_NOPTS_VALUE;

// ERROR accessing location
av_interleaved_write_frame(fc, &pkt);


}


inline void execute_staging_test(const fs::path& folder, int nbr_trame)
{
fs::path file_name = folder / "stream.bin";
if(!fs::exists(file_name))
{
    cerr << "The file " << file_name.string() << " does not exists" << endl;
    return;
}

avcodec_register_all();

av_log_set_level(AV_LOG_DEBUG);
int length = 0;
char* buffer;

for(int i = 0; i < nbr_trame;i++)
{
    fs::path file = std::to_string(i) + ".raw";
    file = folder / file;
    cout << "Got frame on " << file.string() << endl;
    ifstream ifs(file, ofstream::binary);

    // Get la longeur du fichier pour savoir le buffer a prendre
    ifs.seekg(0, ios::end);
    length = ifs.tellg();
    ifs.seekg(0, ios::beg);

    if (length == 0) {
        std::cerr << "No data in file " << file << std::endl;
        return;
    }

    buffer = new char[length];

    std::cout << "File " << file << " length is " << length << std::endl;

    ifs.read(buffer, length);

    cv::VideoWriter vw;
    int codec = cv::VideoWriter::fourcc('X', '2', '6', '4');


    if(!fc)
    {
        if(!init_stream((unsigned char*)buffer, length))
        {
            return;
        }
    }
    if(fc)
    {
        append_stream((unsigned char*)buffer, length);
    }   
}
}

非常感谢您的帮助,我是C ++的新手,而且我从未处理过视频流。如果您想查看完整的代码,请在github repo to this project

上查看其主机

0 个答案:

没有答案