1
votes

Hello I'm using the ffmpeg 3.4.2 to record a RTSP h264 steam from an IP camera. I have a working example however at the beginning I see some corrupted images, after a couple of seconds the video is shown properly. I was wondering if this is a timing issue.

enter image description here

The source code which illustrates opening and reading a RTSP stream, and writing it into an MP4 container.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/time.h>

extern "C" {
  #include <libavcodec/avcodec.h>
  #include <libavutil/opt.h>
  #include <libavutil/imgutils.h>
  #include <libavformat/avformat.h>
  #include <libavformat/avio.h>
  #include <libswscale/swscale.h>
}

time_t get_time()
{
  struct timeval tv;

  gettimeofday( &tv, NULL );

  return tv.tv_sec;
}

int main(int argc, char **argv)
{
    const char *filename, *codec_name;
    const AVCodec *codec;
    AVCodecContext *c= NULL;
    int i, ret, x, y;


    // Open the initial context variables that are needed
    AVFormatContext* format_ctx = avformat_alloc_context();
    int video_stream_index;

    // Register everything
    av_register_all();
    avformat_network_init();

    //open RTSP

    AVDictionary *ifmtdict;
    av_dict_set(&ifmtdict, "rtsp_transport", "tcp", 0);

    if (avformat_open_input(&format_ctx, "rtsp://192.168.0.84/user=admin_password=_channel=1_stream=0.sdp",
            NULL, &ifmtdict) != 0) {
        return EXIT_FAILURE;
    }

    if (avformat_find_stream_info(format_ctx, NULL) < 0) {
        return EXIT_FAILURE;
    }

    //search video stream
    for (int i = 0; i < format_ctx->nb_streams; i++) {
        if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
            video_stream_index = i;
    }

    AVPacket packet;
    av_init_packet(&packet);

    AVStream* stream = NULL;
    int cnt = 0;

    //start reading packets from stream and write them to file
    av_read_play(format_ctx);    //play RTSP

    // Get the codec
    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!codec) {
        exit(1);
    }

    // Prepare the output
    AVFormatContext* oc = avformat_alloc_context();
    oc->oformat = av_guess_format(NULL, "video.mp4", NULL);
    avio_open2(&oc->pb, "video.mp4", AVIO_FLAG_WRITE, NULL, NULL);

    // Write header
    stream = avformat_new_stream(oc, (AVCodec*) format_ctx->streams[video_stream_index]->codec->codec);
    avcodec_parameters_copy(stream->codecpar, format_ctx->streams[video_stream_index]->codecpar);
    stream->sample_aspect_ratio = format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio;
    stream->codecpar->codec_tag  = 0;
    stream->time_base = format_ctx->streams[video_stream_index]->time_base;
    avformat_write_header(oc, NULL);

    time_t timenow, timestart;
    timestart = timenow = get_time();
    bool got_key_frame = 0;

    while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 200000) { //read ~ 200000 frames
        if (packet.stream_index == video_stream_index) {    //packet is video
            // Make sure we start on a key frame
            if ( !got_key_frame && timestart == timenow && ! ( packet.flags & AV_PKT_FLAG_KEY ) ) {
              timestart = timenow = get_time();
              continue;
            }
            got_key_frame = 1;
            std::cout << cnt << std::endl;
            av_interleaved_write_frame( oc, &packet );
            cnt++;
        }
      av_free_packet(&packet);
      av_init_packet(&packet);
      timenow = get_time();
    }

    av_write_trailer(oc);
    avcodec_close(stream->codec);
    avio_close(oc->pb);
    avformat_free_context(oc);

    av_read_pause(format_ctx);

    avcodec_free_context(&c);
    avformat_network_deinit();

    return 0;
}
1

1 Answers

0
votes

A H.264 stream consists of Group of Frames (GOP). Usually you can only start decoding at GOP boundaries. You may have to wait for an IDR frame before you passthrough video packets to the MP4 writer.