FFMPEG直通记录RTSP / H264到MP4容器编码错误

时间:2019-01-14 12:18:53

标签: encoding ffmpeg h.264

您好,我正在使用ffmpeg 3.4.2记录来自IP摄像机的RTSP h264蒸汽。我有一个有效的示例,但是开始时我看到一些损坏的图像,几秒钟后,视频可以正确显示。我想知道这是否是时间问题。

enter image description here

说明打开和读取RTSP流并将其写入MP4容器的源代码。

#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 个答案:

答案 0 :(得分:0)

H.264流由帧组(GOP)组成。通常,您只能在GOP边界开始解码。在将视频数据包传递到MP4刻录机之前,您可能必须等待IDR帧。