【问题标题】:FFMPEG passthrough recording RTSP/H264 to MP4 container bad encodingFFMPEG 直通记录 RTSP/H264 到 MP4 容器编码错误
【发布时间】:2019-06-08 10:31:04
【问题描述】:

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

说明打开和读取 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;
}

【问题讨论】:

    标签: encoding ffmpeg h.264


    【解决方案1】:

    H.264 流由帧组 (GOP) 组成。通常你只能在 GOP 边界开始解码。在将视频数据包传递给 MP4 写入器之前,您可能需要等待 IDR 帧。

    【讨论】:

    • 谢谢,知道如何使用上面的示例代码做到这一点吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 2015-08-07
    • 2020-12-08
    • 2016-08-01
    相关资源
    最近更新 更多