FFMPEG Can write the header to the RTSP server but not the frame

佐手、 提交于 2019-12-12 01:39:25

问题


I am trying to capture the content of a window, and stream it to a rtsp server (wowza). I can write the header (avformat_write_header) and I see that the wowza server receive a connection. But when it comes to writing the frame, av_write_frame just triggers a segfault. It is quite interesting as the addresse of the variable that the method is trying to access is normal (0x0000000033921D20)

here is the code :

FfmpegEncoder::FfmpegEncoder(char *url)
{
AVRational      tmp_time_base;
AVDictionary*   options = NULL;

this->pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (this->pCodec == NULL)
    throw myExceptions("Error: Can't initialize the encoder. FfmpegEncoder.cpp l:9\n");

this->pCodecCtx = avcodec_alloc_context3(this->pCodec);

//Alloc output context
if (avformat_alloc_output_context2(&outFormatCtx, NULL, "rtsp", url) < 0)
    throw myExceptions("Error: Can't alloc stream output. FfmpegEncoder.cpp l:17\n");

this->st = avformat_new_stream(this->outFormatCtx, this->pCodec);

this->st->id = this->outFormatCtx->nb_streams - 1;

if (this->st == NULL)
    throw myExceptions("Error: Can't create stream . FfmpegEncoder.cpp l:22\n");

av_dict_set(&options, "vprofile", "main", 0);
av_dict_set(&options, "tune", "zerolatency", 0);


//Define the framerate of the output. The numerator should stay 1. Denumerator is the framerate we are aiming for.

tmp_time_base.num = 1;
tmp_time_base.den = 60;

//TODO : parse these values
this->pCodecCtx->bit_rate = 3000000;
this->pCodecCtx->width = 1280;
this->pCodecCtx->height = 720;
//This set the fps. 60fps at this point.
this->pCodecCtx->time_base = tmp_time_base;
//Add a intra frame every 12 frames
this->pCodecCtx->gop_size = 12;
this->pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;

//Open Codec, using the context + x264 options
if (avcodec_open2(this->pCodecCtx, this->pCodec, &options) < 0)
    throw myExceptions("Error: Can't open the codec. FfmpegEncoder.cpp l:43\n");

if (avcodec_copy_context(this->st->codec, this->pCodecCtx) != 0) {
    throw myExceptions("Error : Can't copy codec context. FfmpegEncoder.cpp : l.46");
}

av_dump_format(this->outFormatCtx, 0, url, 1);

//write the header needed to start the stream.
if (avformat_write_header(this->outFormatCtx, NULL) != 0)
    throw myExceptions("Error: failed to connect to RTSP server. FfmpegEncoder.cpp l:48\n");
}

/*Encode the frame in order to send it over rtsp.*/

void FfmpegEncoder::encodeFrame(AVFrame * frame, int frameCount)
{
AVPacket    pkt = { 0 };
SwsContext  *ctx;
int         got_pkt;

frame->pts = frameCount;

FillYuvImage(frame, frameCount, this->pCodecCtx->width, this->pCodecCtx->height);

if (avcodec_send_frame(this->pCodecCtx, frame) != 0)
    throw myExceptions("Error: failed to send video frame to codec. FfmpegEncoder.cpp l:89\n");
if (avcodec_receive_packet(this->pCodecCtx, &pkt) != 0)
    throw myExceptions("Error: failed to receive video frame from codec. FfmpegEncoder.cpp l:91\n");
pkt.stream_index = this->st->index;
pkt.pts = av_rescale_q_rnd(pkt.pts, this->pCodecCtx->time_base, this->st->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));

std::cout << "stream index = " << pkt.stream_index << " pts = " << pkt.pts << std::endl;

try {
    av_write_frame(this->outFormatCtx, &pkt);
}
catch (myExceptions &e)
{
    std::cout << e.what() << std::endl;
    return;
}
}

/*Magic function from ffmpeg examples. It fills the frame to respect the YUV format.*/
void FfmpegEncoder::FillYuvImage(AVFrame * pict, int frame_index, int width, int height)
{
int x, y, i;

i = frame_index;

pict->format = AV_PIX_FMT_YUV420P;
pict->width = 1280;
pict->height = 720;
for (y = 0; y < height; y++)
{
    for (x = 0; x < width; x++)
        pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
}
for (y = 0; y < height / 2; y++)
{
    for (x = 0; x < width / 2; x++)
    {
        pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
        pict->data[2][y * pict->linesize[2] + x] = 64 + y + i * 5;
    }
}
}

Here is my code where I retrieve the frame. I can show the frame successfully on a SDL window.

while (av_read_frame(pFormatCtx, &packet) >= 0) {
    if (packet.stream_index == videoindex) {
        // Decode video frame
        avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
        if (frameFinished) {
            i++;
            DrawFrame();
            enc.encodeFrame(pFrameRGB, i);
        }
    }
    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
}

来源:https://stackoverflow.com/questions/39724543/ffmpeg-can-write-the-header-to-the-rtsp-server-but-not-the-frame

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!